OpenDNSSEC-signer 2.1.13
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
37static 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
88void
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 */
102int
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),
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 */
176int
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),
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
227static void
228tcp_conn_cleanup(tcp_conn_type* conn)
229{
230 if (!conn) {
231 return;
232 }
233 buffer_cleanup(conn->packet);
234 free(conn);
235}
236
241void
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}
size_t buffer_capacity(buffer_type *buffer)
Definition: buffer.c:401
void buffer_clear(buffer_type *buffer)
Definition: buffer.c:99
void buffer_cleanup(buffer_type *buffer)
Definition: buffer.c:1145
uint8_t * buffer_current(buffer_type *buffer)
Definition: buffer.c:438
void buffer_set_limit(buffer_type *buffer, size_t limit)
Definition: buffer.c:385
size_t buffer_position(buffer_type *buffer)
Definition: buffer.c:125
void buffer_skip(buffer_type *buffer, ssize_t count)
Definition: buffer.c:150
size_t buffer_remaining(buffer_type *buffer)
Definition: buffer.c:463
buffer_type * buffer_create(size_t capacity)
Definition: buffer.c:78
#define PACKET_BUFFER_SIZE
Definition: buffer.h:50
uint16_t msglen
Definition: tcpset.h:56
buffer_type * packet
Definition: tcpset.h:58
uint32_t total_bytes
Definition: tcpset.h:54
xfrd_type * tcp_waiting_first
Definition: tcpset.h:69
xfrd_type * tcp_waiting_last
Definition: tcpset.h:70
tcp_conn_type * tcp_conn[TCPSET_MAX]
Definition: tcpset.h:68
size_t tcp_count
Definition: tcpset.h:71
void tcp_conn_ready(tcp_conn_type *tcp)
Definition: tcpset.c:89
void tcp_set_cleanup(tcp_set_type *set)
Definition: tcpset.c:242
int tcp_conn_read(tcp_conn_type *tcp)
Definition: tcpset.c:103
tcp_conn_type * tcp_conn_create()
Definition: tcpset.c:45
int tcp_conn_write(tcp_conn_type *tcp)
Definition: tcpset.c:177
tcp_set_type * tcp_set_create()
Definition: tcpset.c:67
#define TCPSET_MAX
Definition: tcpset.h:45