OpenDNSSEC-signer  2.0.3
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  CHECKALLOC(tcp_conn = (tcp_conn_type*) malloc(sizeof(tcp_conn_type)));
49  memset(tcp_conn, 0, sizeof(tcp_conn_type));
51  if (!tcp_conn->packet) {
52  free(tcp_conn);
53  return NULL;
54  }
55  tcp_conn->msglen = 0;
56  tcp_conn->total_bytes = 0;
57  tcp_conn->fd = -1;
58  return tcp_conn;
59 }
60 
61 
68 {
69  size_t i = 0;
70  tcp_set_type* tcp_set = NULL;
71  CHECKALLOC(tcp_set = (tcp_set_type*) malloc(sizeof(tcp_set_type)));
72  memset(tcp_set, 0, sizeof(tcp_set_type));
73  tcp_set->tcp_count = 0;
74  for (i=0; i < TCPSET_MAX; i++) {
75  tcp_set->tcp_conn[i] = tcp_conn_create();
76  }
77  tcp_set->tcp_waiting_first = NULL;
78  tcp_set->tcp_waiting_last = NULL;
79  return tcp_set;
80 }
81 
82 
88 void
90 {
91  ods_log_assert(tcp);
92  tcp->total_bytes = 0;
93  tcp->msglen = 0;
94  buffer_clear(tcp->packet);
95 }
96 
97 
98 /*
99  * Read from a tcp connection.
100  *
101  */
102 int
104 {
105  ssize_t received = 0;
106  ods_log_assert(tcp);
107  ods_log_assert(tcp->fd != -1);
108  /* receive leading packet length bytes */
109  if (tcp->total_bytes < sizeof(tcp->msglen)) {
110  received = read(tcp->fd, (char*) &tcp->msglen + tcp->total_bytes,
111  sizeof(tcp->msglen) - tcp->total_bytes);
112  if (received == -1) {
113  if (errno == EAGAIN || errno == EINTR) {
114  /* read would block, try later */
115  return 0;
116  } else {
117  if (errno != ECONNRESET) {
118  ods_log_error("[%s] error read() sz: %s", tcp_str,
119  strerror(errno));
120  }
121  return -1;
122  }
123  } else if (received == 0) {
124  /* EOF */
125  return -1;
126  }
127  tcp->total_bytes += received;
128  if (tcp->total_bytes < sizeof(tcp->msglen)) {
129  /* not complete yet, try later */
130  return 0;
131  }
132  ods_log_assert(tcp->total_bytes == sizeof(tcp->msglen));
133  tcp->msglen = ntohs(tcp->msglen);
134  if (tcp->msglen > buffer_capacity(tcp->packet)) {
135  /* packet to big, drop connection */
136  ods_log_error("[%s] packet too big, dropping connection", tcp_str);
137  return 0;
138  }
139  buffer_set_limit(tcp->packet, tcp->msglen);
140  }
141  ods_log_assert(buffer_remaining(tcp->packet) > 0);
142 
143  received = read(tcp->fd, buffer_current(tcp->packet),
144  buffer_remaining(tcp->packet));
145  if (received == -1) {
146  if (errno == EAGAIN || errno == EINTR) {
147  /* read would block, try later */
148  return 0;
149  } else {
150  if (errno != ECONNRESET) {
151  ods_log_error("[%s] error read(): %s", tcp_str,
152  strerror(errno));
153  }
154  return -1;
155  }
156  } else if (received == 0) {
157  /* EOF */
158  return -1;
159  }
160  tcp->total_bytes += received;
161  buffer_skip(tcp->packet, received);
162  if (buffer_remaining(tcp->packet) > 0) {
163  /* not complete yet, wait for more */
164  return 0;
165  }
166  /* completed */
167  ods_log_assert(buffer_position(tcp->packet) == tcp->msglen);
168  return 1;
169 }
170 
171 
172 /*
173  * Write to a tcp connection.
174  *
175  */
176 int
178 {
179  ssize_t sent = 0;
180  ods_log_assert(tcp);
181  ods_log_assert(tcp->fd != -1);
182  if (tcp->total_bytes < sizeof(tcp->msglen)) {
183  uint16_t sendlen = htons(tcp->msglen);
184  sent = write(tcp->fd, (const char*)&sendlen + tcp->total_bytes,
185  sizeof(tcp->msglen) - tcp->total_bytes);
186  if (sent == -1) {
187  if (errno == EAGAIN || errno == EINTR) {
188  /* write would block, try later */
189  return 0;
190  } else {
191  return -1;
192  }
193  }
194  tcp->total_bytes += sent;
195  if (tcp->total_bytes < sizeof(tcp->msglen)) {
196  /* incomplete write, resume later */
197  return 0;
198  }
199  ods_log_assert(tcp->total_bytes == sizeof(tcp->msglen));
200  }
201  ods_log_assert(tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen));
202  sent = write(tcp->fd, buffer_current(tcp->packet),
203  buffer_remaining(tcp->packet));
204  if (sent == -1) {
205  if (errno == EAGAIN || errno == EINTR) {
206  /* write would block, try later */
207  return 0;
208  } else {
209  return -1;
210  }
211  }
212  buffer_skip(tcp->packet, sent);
213  tcp->total_bytes += sent;
214  if (tcp->total_bytes < tcp->msglen + sizeof(tcp->msglen)) {
215  /* more to write when socket becomes writable again */
216  return 0;
217  }
218  ods_log_assert(tcp->total_bytes == tcp->msglen + sizeof(tcp->msglen));
219  return 1;
220 }
221 
222 
227 static void
228 tcp_conn_cleanup(tcp_conn_type* conn)
229 {
230  if (!conn) {
231  return;
232  }
233  buffer_cleanup(conn->packet);
234  free(conn);
235 }
236 
241 void
243 {
244  size_t i = 0;
245  if (!set) {
246  return;
247  }
248  for (i=0; i < TCPSET_MAX; i++) {
249  tcp_conn_cleanup(set->tcp_conn[i]);
250  }
251  free(set);
252 }
xfrd_type * tcp_waiting_last
Definition: tcpset.h:70
size_t tcp_count
Definition: tcpset.h:71
void buffer_skip(buffer_type *buffer, ssize_t count)
Definition: buffer.c:150
void buffer_clear(buffer_type *buffer)
Definition: buffer.c:99
tcp_conn_type * tcp_conn[TCPSET_MAX]
Definition: tcpset.h:68
xfrd_type * tcp_waiting_first
Definition: tcpset.h:69
int tcp_conn_write(tcp_conn_type *tcp)
Definition: tcpset.c:177
buffer_type * packet
Definition: tcpset.h:58
uint8_t * buffer_current(buffer_type *buffer)
Definition: buffer.c:438
tcp_conn_type * tcp_conn_create()
Definition: tcpset.c:45
void buffer_set_limit(buffer_type *buffer, size_t limit)
Definition: buffer.c:385
void buffer_cleanup(buffer_type *buffer)
Definition: buffer.c:1145
size_t buffer_capacity(buffer_type *buffer)
Definition: buffer.c:401
uint16_t msglen
Definition: tcpset.h:56
void tcp_set_cleanup(tcp_set_type *set)
Definition: tcpset.c:242
#define PACKET_BUFFER_SIZE
Definition: buffer.h:50
uint32_t total_bytes
Definition: tcpset.h:54
int tcp_conn_read(tcp_conn_type *tcp)
Definition: tcpset.c:103
size_t buffer_remaining(buffer_type *buffer)
Definition: buffer.c:463
#define TCPSET_MAX
Definition: tcpset.h:45
void tcp_conn_ready(tcp_conn_type *tcp)
Definition: tcpset.c:89
size_t buffer_position(buffer_type *buffer)
Definition: buffer.c:125
tcp_set_type * tcp_set_create()
Definition: tcpset.c:67
buffer_type * buffer_create(size_t capacity)
Definition: buffer.c:78