OpenDNSSEC-signer  1.4.1
tcpset.c
Go to the documentation of this file.
1 /*
2  * $Id: tcpset.c 4958 2011-04-18 07:11:09Z matthijs $
3  *
4  * Copyright (c) 2011 NLNet Labs. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
34 #include "config.h"
35 #include "wire/tcpset.h"
36 
37 #include <string.h>
38 
39 static const char* tcp_str = "tcp";
40 
41 
48 {
49  tcp_conn_type* tcp_conn = NULL;
50  if (!allocator) {
51  return NULL;
52  }
53  tcp_conn = (tcp_conn_type*) allocator_alloc(allocator,
54  sizeof(tcp_conn_type));
55  if (!tcp_conn) {
56  return NULL;
57  }
58  memset(tcp_conn, 0, sizeof(tcp_conn_type));
59  tcp_conn->packet = buffer_create(allocator, PACKET_BUFFER_SIZE);
60  if (!tcp_conn->packet) {
61  allocator_deallocate(allocator, (void*)tcp_conn);
62  return NULL;
63  }
64  tcp_conn->msglen = 0;
65  tcp_conn->total_bytes = 0;
66  tcp_conn->fd = -1;
67  return tcp_conn;
68 }
69 
70 
77 {
78  size_t i = 0;
79  tcp_set_type* tcp_set = NULL;
80  tcp_set = (tcp_set_type*) allocator_alloc(allocator, sizeof(tcp_set_type));
81  memset(tcp_set, 0, sizeof(tcp_set_type));
82  tcp_set->tcp_count = 0;
83  for (i=0; i < TCPSET_MAX; i++) {
84  tcp_set->tcp_conn[i] = tcp_conn_create(allocator);
85  }
86  tcp_set->tcp_waiting_first = NULL;
87  tcp_set->tcp_waiting_last = NULL;
88  return tcp_set;
89 }
90 
91 
97 void
99 {
100  ods_log_assert(tcp);
101  tcp->total_bytes = 0;
102  tcp->msglen = 0;
103  buffer_clear(tcp->packet);
104  return;
105 }
106 
107 
108 /*
109  * Read from a tcp connection.
110  *
111  */
112 int
114 {
115  ssize_t received = 0;
116  ods_log_assert(tcp);
117  ods_log_assert(tcp->fd != -1);
118  /* receive leading packet length bytes */
119  if (tcp->total_bytes < sizeof(tcp->msglen)) {
120  received = read(tcp->fd, (char*) &tcp->msglen + tcp->total_bytes,
121  sizeof(tcp->msglen) - tcp->total_bytes);
122  if (received == -1) {
123  if (errno == EAGAIN || errno == EINTR) {
124  /* read would block, try later */
125  return 0;
126  } else {
127  if (errno != ECONNRESET) {
128  ods_log_error("[%s] error read() sz: %s", tcp_str,
129  strerror(errno));
130  }
131  return -1;
132  }
133  } else if (received == 0) {
134  /* EOF */
135  return -1;
136  }
137  tcp->total_bytes += received;
138  if (tcp->total_bytes < sizeof(tcp->msglen)) {
139  /* not complete yet, try later */
140  return 0;
141  }
142  ods_log_assert(tcp->total_bytes == sizeof(tcp->msglen));
143  tcp->msglen = ntohs(tcp->msglen);
144  if (tcp->msglen > buffer_capacity(tcp->packet)) {
145  /* packet to big, drop connection */
146  ods_log_error("[%s] packet too big, dropping connection", tcp_str);
147  return 0;
148  }
149  buffer_set_limit(tcp->packet, tcp->msglen);
150  }
152 
153  received = read(tcp->fd, buffer_current(tcp->packet),
154  buffer_remaining(tcp->packet));
155  if (received == -1) {
156  if (errno == EAGAIN || errno == EINTR) {
157  /* read would block, try later */
158  return 0;
159  } else {
160  if (errno != ECONNRESET) {
161  ods_log_error("[%s] error read(): %s", tcp_str,
162  strerror(errno));
163  }
164  return -1;
165  }
166  } else if (received == 0) {
167  /* EOF */
168  return -1;
169  }
170  tcp->total_bytes += received;
171  buffer_skip(tcp->packet, received);
172  if (buffer_remaining(tcp->packet) > 0) {
173  /* not complete yet, wait for more */
174  return 0;
175  }
176  /* completed */
178  return 1;
179 }
180 
181 
182 /*
183  * Write to a tcp connection.
184  *
185  */
186 int
188 {
189  ssize_t sent = 0;
190  ods_log_assert(tcp);
191  ods_log_assert(tcp->fd != -1);
192  if (tcp->total_bytes < sizeof(tcp->msglen)) {
193  uint16_t sendlen = htons(tcp->msglen);
194  sent = write(tcp->fd, (const char*)&sendlen + tcp->total_bytes,
195  sizeof(tcp->msglen) - tcp->total_bytes);
196  if (sent == -1) {
197  if (errno == EAGAIN || errno == EINTR) {
198  /* write would block, try later */
199  return 0;
200  } else {
201  return -1;
202  }
203  }
204  tcp->total_bytes += sent;
205  if (tcp->total_bytes < sizeof(tcp->msglen)) {
206  /* incomplete write, resume later */
207  return 0;
208  }
209  ods_log_assert(tcp->total_bytes == sizeof(tcp->msglen));
210  }
211  ods_log_assert(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen));
212  sent = write(tcp->fd, buffer_current(tcp->packet),
213  buffer_remaining(tcp->packet));
214  if (sent == -1) {
215  if (errno == EAGAIN || errno == EINTR) {
216  /* write would block, try later */
217  return 0;
218  } else {
219  return -1;
220  }
221  }
222  buffer_skip(tcp->packet, sent);
223  tcp->total_bytes += sent;
224  if (tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)) {
225  /* more to write when socket becomes writable again */
226  return 0;
227  }
228  ods_log_assert(tcp->total_bytes == tcp->msglen + sizeof(tcp->msglen));
229  return 1;
230 }
231 
232 
237 static void
238 tcp_conn_cleanup(tcp_conn_type* conn, allocator_type* allocator)
239 {
240  if (!conn || !allocator) {
241  return;
242  }
243  buffer_cleanup(conn->packet, allocator);
244  allocator_deallocate(allocator, (void*) conn);
245  return;
246 }
247 
252 void
254 {
255  size_t i = 0;
256  if (!set || !allocator) {
257  return;
258  }
259  for (i=0; i < TCPSET_MAX; i++) {
260  tcp_conn_cleanup(set->tcp_conn[i], allocator);
261  }
262  allocator_deallocate(allocator, (void*) set);
263  return;
264 }