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