1 |
|
|
/* $OpenBSD: bss_dgram.c,v 1.41 2015/07/20 23:15:28 doug Exp $ */ |
2 |
|
|
/* |
3 |
|
|
* DTLS implementation written by Nagendra Modadugu |
4 |
|
|
* (nagendra@cs.stanford.edu) for the OpenSSL project 2005. |
5 |
|
|
*/ |
6 |
|
|
/* ==================================================================== |
7 |
|
|
* Copyright (c) 1999-2005 The OpenSSL Project. All rights reserved. |
8 |
|
|
* |
9 |
|
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
|
* modification, are permitted provided that the following conditions |
11 |
|
|
* are met: |
12 |
|
|
* |
13 |
|
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
|
* |
16 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
17 |
|
|
* notice, this list of conditions and the following disclaimer in |
18 |
|
|
* the documentation and/or other materials provided with the |
19 |
|
|
* distribution. |
20 |
|
|
* |
21 |
|
|
* 3. All advertising materials mentioning features or use of this |
22 |
|
|
* software must display the following acknowledgment: |
23 |
|
|
* "This product includes software developed by the OpenSSL Project |
24 |
|
|
* for use in the OpenSSL Toolkit. (http://www.OpenSSL.org/)" |
25 |
|
|
* |
26 |
|
|
* 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to |
27 |
|
|
* endorse or promote products derived from this software without |
28 |
|
|
* prior written permission. For written permission, please contact |
29 |
|
|
* openssl-core@OpenSSL.org. |
30 |
|
|
* |
31 |
|
|
* 5. Products derived from this software may not be called "OpenSSL" |
32 |
|
|
* nor may "OpenSSL" appear in their names without prior written |
33 |
|
|
* permission of the OpenSSL Project. |
34 |
|
|
* |
35 |
|
|
* 6. Redistributions of any form whatsoever must retain the following |
36 |
|
|
* acknowledgment: |
37 |
|
|
* "This product includes software developed by the OpenSSL Project |
38 |
|
|
* for use in the OpenSSL Toolkit (http://www.OpenSSL.org/)" |
39 |
|
|
* |
40 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY |
41 |
|
|
* EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
42 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
43 |
|
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR |
44 |
|
|
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
45 |
|
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
46 |
|
|
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
47 |
|
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
48 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
49 |
|
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
50 |
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED |
51 |
|
|
* OF THE POSSIBILITY OF SUCH DAMAGE. |
52 |
|
|
* ==================================================================== |
53 |
|
|
* |
54 |
|
|
* This product includes cryptographic software written by Eric Young |
55 |
|
|
* (eay@cryptsoft.com). This product includes software written by Tim |
56 |
|
|
* Hudson (tjh@cryptsoft.com). |
57 |
|
|
* |
58 |
|
|
*/ |
59 |
|
|
|
60 |
|
|
#include <sys/socket.h> |
61 |
|
|
#include <sys/time.h> |
62 |
|
|
|
63 |
|
|
#include <netinet/in.h> |
64 |
|
|
|
65 |
|
|
#include <errno.h> |
66 |
|
|
#include <netdb.h> |
67 |
|
|
#include <stdio.h> |
68 |
|
|
#include <string.h> |
69 |
|
|
#include <unistd.h> |
70 |
|
|
|
71 |
|
|
#include <openssl/opensslconf.h> |
72 |
|
|
|
73 |
|
|
#include <openssl/bio.h> |
74 |
|
|
|
75 |
|
|
#ifndef OPENSSL_NO_DGRAM |
76 |
|
|
|
77 |
|
|
|
78 |
|
|
static int dgram_write(BIO *h, const char *buf, int num); |
79 |
|
|
static int dgram_read(BIO *h, char *buf, int size); |
80 |
|
|
static int dgram_puts(BIO *h, const char *str); |
81 |
|
|
static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); |
82 |
|
|
static int dgram_new(BIO *h); |
83 |
|
|
static int dgram_free(BIO *data); |
84 |
|
|
static int dgram_clear(BIO *bio); |
85 |
|
|
|
86 |
|
|
|
87 |
|
|
static int BIO_dgram_should_retry(int s); |
88 |
|
|
|
89 |
|
|
static BIO_METHOD methods_dgramp = { |
90 |
|
|
.type = BIO_TYPE_DGRAM, |
91 |
|
|
.name = "datagram socket", |
92 |
|
|
.bwrite = dgram_write, |
93 |
|
|
.bread = dgram_read, |
94 |
|
|
.bputs = dgram_puts, |
95 |
|
|
.ctrl = dgram_ctrl, |
96 |
|
|
.create = dgram_new, |
97 |
|
|
.destroy = dgram_free |
98 |
|
|
}; |
99 |
|
|
|
100 |
|
|
|
101 |
|
|
typedef struct bio_dgram_data_st { |
102 |
|
|
union { |
103 |
|
|
struct sockaddr sa; |
104 |
|
|
struct sockaddr_in sa_in; |
105 |
|
|
struct sockaddr_in6 sa_in6; |
106 |
|
|
} peer; |
107 |
|
|
unsigned int connected; |
108 |
|
|
unsigned int _errno; |
109 |
|
|
unsigned int mtu; |
110 |
|
|
struct timeval next_timeout; |
111 |
|
|
struct timeval socket_timeout; |
112 |
|
|
} bio_dgram_data; |
113 |
|
|
|
114 |
|
|
|
115 |
|
|
BIO_METHOD * |
116 |
|
|
BIO_s_datagram(void) |
117 |
|
|
{ |
118 |
|
|
return (&methods_dgramp); |
119 |
|
|
} |
120 |
|
|
|
121 |
|
|
BIO * |
122 |
|
|
BIO_new_dgram(int fd, int close_flag) |
123 |
|
|
{ |
124 |
|
|
BIO *ret; |
125 |
|
|
|
126 |
|
|
ret = BIO_new(BIO_s_datagram()); |
127 |
|
|
if (ret == NULL) |
128 |
|
|
return (NULL); |
129 |
|
|
BIO_set_fd(ret, fd, close_flag); |
130 |
|
|
return (ret); |
131 |
|
|
} |
132 |
|
|
|
133 |
|
|
static int |
134 |
|
|
dgram_new(BIO *bi) |
135 |
|
|
{ |
136 |
|
|
bio_dgram_data *data = NULL; |
137 |
|
|
|
138 |
|
|
bi->init = 0; |
139 |
|
|
bi->num = 0; |
140 |
|
|
data = calloc(1, sizeof(bio_dgram_data)); |
141 |
|
|
if (data == NULL) |
142 |
|
|
return 0; |
143 |
|
|
bi->ptr = data; |
144 |
|
|
|
145 |
|
|
bi->flags = 0; |
146 |
|
|
return (1); |
147 |
|
|
} |
148 |
|
|
|
149 |
|
|
static int |
150 |
|
|
dgram_free(BIO *a) |
151 |
|
|
{ |
152 |
|
|
bio_dgram_data *data; |
153 |
|
|
|
154 |
|
|
if (a == NULL) |
155 |
|
|
return (0); |
156 |
|
|
if (!dgram_clear(a)) |
157 |
|
|
return 0; |
158 |
|
|
|
159 |
|
|
data = (bio_dgram_data *)a->ptr; |
160 |
|
|
free(data); |
161 |
|
|
|
162 |
|
|
return (1); |
163 |
|
|
} |
164 |
|
|
|
165 |
|
|
static int |
166 |
|
|
dgram_clear(BIO *a) |
167 |
|
|
{ |
168 |
|
|
if (a == NULL) |
169 |
|
|
return (0); |
170 |
|
|
if (a->shutdown) { |
171 |
|
|
if (a->init) { |
172 |
|
|
shutdown(a->num, SHUT_RDWR); |
173 |
|
|
close(a->num); |
174 |
|
|
} |
175 |
|
|
a->init = 0; |
176 |
|
|
a->flags = 0; |
177 |
|
|
} |
178 |
|
|
return (1); |
179 |
|
|
} |
180 |
|
|
|
181 |
|
|
static void |
182 |
|
|
dgram_adjust_rcv_timeout(BIO *b) |
183 |
|
|
{ |
184 |
|
|
#if defined(SO_RCVTIMEO) |
185 |
|
|
bio_dgram_data *data = (bio_dgram_data *)b->ptr; |
186 |
|
|
|
187 |
|
|
/* Is a timer active? */ |
188 |
|
|
if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { |
189 |
|
|
struct timeval timenow, timeleft; |
190 |
|
|
|
191 |
|
|
/* Read current socket timeout */ |
192 |
|
|
socklen_t sz = sizeof(data->socket_timeout); |
193 |
|
|
if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, |
194 |
|
|
&(data->socket_timeout), &sz) < 0) { |
195 |
|
|
perror("getsockopt"); |
196 |
|
|
} |
197 |
|
|
|
198 |
|
|
/* Get current time */ |
199 |
|
|
gettimeofday(&timenow, NULL); |
200 |
|
|
|
201 |
|
|
/* Calculate time left until timer expires */ |
202 |
|
|
memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); |
203 |
|
|
timeleft.tv_sec -= timenow.tv_sec; |
204 |
|
|
timeleft.tv_usec -= timenow.tv_usec; |
205 |
|
|
if (timeleft.tv_usec < 0) { |
206 |
|
|
timeleft.tv_sec--; |
207 |
|
|
timeleft.tv_usec += 1000000; |
208 |
|
|
} |
209 |
|
|
|
210 |
|
|
if (timeleft.tv_sec < 0) { |
211 |
|
|
timeleft.tv_sec = 0; |
212 |
|
|
timeleft.tv_usec = 1; |
213 |
|
|
} |
214 |
|
|
|
215 |
|
|
/* Adjust socket timeout if next handhake message timer |
216 |
|
|
* will expire earlier. |
217 |
|
|
*/ |
218 |
|
|
if ((data->socket_timeout.tv_sec == 0 && |
219 |
|
|
data->socket_timeout.tv_usec == 0) || |
220 |
|
|
(data->socket_timeout.tv_sec > timeleft.tv_sec) || |
221 |
|
|
(data->socket_timeout.tv_sec == timeleft.tv_sec && |
222 |
|
|
data->socket_timeout.tv_usec >= timeleft.tv_usec)) { |
223 |
|
|
if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, |
224 |
|
|
&timeleft, sizeof(struct timeval)) < 0) { |
225 |
|
|
perror("setsockopt"); |
226 |
|
|
} |
227 |
|
|
} |
228 |
|
|
} |
229 |
|
|
#endif |
230 |
|
|
} |
231 |
|
|
|
232 |
|
|
static void |
233 |
|
|
dgram_reset_rcv_timeout(BIO *b) |
234 |
|
|
{ |
235 |
|
|
#if defined(SO_RCVTIMEO) |
236 |
|
|
bio_dgram_data *data = (bio_dgram_data *)b->ptr; |
237 |
|
|
|
238 |
|
|
/* Is a timer active? */ |
239 |
|
|
if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { |
240 |
|
|
if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, |
241 |
|
|
&(data->socket_timeout), sizeof(struct timeval)) < 0) { |
242 |
|
|
perror("setsockopt"); |
243 |
|
|
} |
244 |
|
|
} |
245 |
|
|
#endif |
246 |
|
|
} |
247 |
|
|
|
248 |
|
|
static int |
249 |
|
|
dgram_read(BIO *b, char *out, int outl) |
250 |
|
|
{ |
251 |
|
|
int ret = 0; |
252 |
|
|
bio_dgram_data *data = (bio_dgram_data *)b->ptr; |
253 |
|
|
|
254 |
|
|
struct { |
255 |
|
|
socklen_t len; |
256 |
|
|
union { |
257 |
|
|
struct sockaddr sa; |
258 |
|
|
struct sockaddr_in sa_in; |
259 |
|
|
struct sockaddr_in6 sa_in6; |
260 |
|
|
} peer; |
261 |
|
|
} sa; |
262 |
|
|
|
263 |
|
|
sa.len = sizeof(sa.peer); |
264 |
|
|
|
265 |
|
|
if (out != NULL) { |
266 |
|
|
errno = 0; |
267 |
|
|
memset(&sa.peer, 0, sizeof(sa.peer)); |
268 |
|
|
dgram_adjust_rcv_timeout(b); |
269 |
|
|
ret = recvfrom(b->num, out, outl, 0, &sa.peer.sa, &sa.len); |
270 |
|
|
|
271 |
|
|
if (! data->connected && ret >= 0) |
272 |
|
|
BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer); |
273 |
|
|
|
274 |
|
|
BIO_clear_retry_flags(b); |
275 |
|
|
if (ret < 0) { |
276 |
|
|
if (BIO_dgram_should_retry(ret)) { |
277 |
|
|
BIO_set_retry_read(b); |
278 |
|
|
data->_errno = errno; |
279 |
|
|
} |
280 |
|
|
} |
281 |
|
|
|
282 |
|
|
dgram_reset_rcv_timeout(b); |
283 |
|
|
} |
284 |
|
|
return (ret); |
285 |
|
|
} |
286 |
|
|
|
287 |
|
|
static int |
288 |
|
|
dgram_write(BIO *b, const char *in, int inl) |
289 |
|
|
{ |
290 |
|
|
int ret; |
291 |
|
|
bio_dgram_data *data = (bio_dgram_data *)b->ptr; |
292 |
|
|
errno = 0; |
293 |
|
|
|
294 |
|
|
if (data->connected) |
295 |
|
|
ret = write(b->num, in, inl); |
296 |
|
|
else { |
297 |
|
|
int peerlen = sizeof(data->peer); |
298 |
|
|
|
299 |
|
|
if (data->peer.sa.sa_family == AF_INET) |
300 |
|
|
peerlen = sizeof(data->peer.sa_in); |
301 |
|
|
else if (data->peer.sa.sa_family == AF_INET6) |
302 |
|
|
peerlen = sizeof(data->peer.sa_in6); |
303 |
|
|
ret = sendto(b->num, in, inl, 0, &data->peer.sa, peerlen); |
304 |
|
|
} |
305 |
|
|
|
306 |
|
|
BIO_clear_retry_flags(b); |
307 |
|
|
if (ret <= 0) { |
308 |
|
|
if (BIO_dgram_should_retry(ret)) { |
309 |
|
|
BIO_set_retry_write(b); |
310 |
|
|
|
311 |
|
|
data->_errno = errno; |
312 |
|
|
/* |
313 |
|
|
* higher layers are responsible for querying MTU, |
314 |
|
|
* if necessary |
315 |
|
|
*/ |
316 |
|
|
} |
317 |
|
|
} |
318 |
|
|
return (ret); |
319 |
|
|
} |
320 |
|
|
|
321 |
|
|
static long |
322 |
|
|
dgram_ctrl(BIO *b, int cmd, long num, void *ptr) |
323 |
|
|
{ |
324 |
|
|
long ret = 1; |
325 |
|
|
int *ip; |
326 |
|
|
struct sockaddr *to = NULL; |
327 |
|
|
bio_dgram_data *data = NULL; |
328 |
|
|
#if (defined(IP_MTU_DISCOVER) || defined(IP_MTU)) |
329 |
|
|
int sockopt_val = 0; |
330 |
|
|
socklen_t sockopt_len; /* assume that system supporting IP_MTU is |
331 |
|
|
* modern enough to define socklen_t */ |
332 |
|
|
socklen_t addr_len; |
333 |
|
|
union { |
334 |
|
|
struct sockaddr sa; |
335 |
|
|
struct sockaddr_in s4; |
336 |
|
|
struct sockaddr_in6 s6; |
337 |
|
|
} addr; |
338 |
|
|
#endif |
339 |
|
|
|
340 |
|
|
data = (bio_dgram_data *)b->ptr; |
341 |
|
|
|
342 |
|
|
switch (cmd) { |
343 |
|
|
case BIO_CTRL_RESET: |
344 |
|
|
num = 0; |
345 |
|
|
case BIO_C_FILE_SEEK: |
346 |
|
|
ret = 0; |
347 |
|
|
break; |
348 |
|
|
case BIO_C_FILE_TELL: |
349 |
|
|
case BIO_CTRL_INFO: |
350 |
|
|
ret = 0; |
351 |
|
|
break; |
352 |
|
|
case BIO_C_SET_FD: |
353 |
|
|
dgram_clear(b); |
354 |
|
|
b->num= *((int *)ptr); |
355 |
|
|
b->shutdown = (int)num; |
356 |
|
|
b->init = 1; |
357 |
|
|
break; |
358 |
|
|
case BIO_C_GET_FD: |
359 |
|
|
if (b->init) { |
360 |
|
|
ip = (int *)ptr; |
361 |
|
|
if (ip != NULL) |
362 |
|
|
*ip = b->num; |
363 |
|
|
ret = b->num; |
364 |
|
|
} else |
365 |
|
|
ret = -1; |
366 |
|
|
break; |
367 |
|
|
case BIO_CTRL_GET_CLOSE: |
368 |
|
|
ret = b->shutdown; |
369 |
|
|
break; |
370 |
|
|
case BIO_CTRL_SET_CLOSE: |
371 |
|
|
b->shutdown = (int)num; |
372 |
|
|
break; |
373 |
|
|
case BIO_CTRL_PENDING: |
374 |
|
|
case BIO_CTRL_WPENDING: |
375 |
|
|
ret = 0; |
376 |
|
|
break; |
377 |
|
|
case BIO_CTRL_DUP: |
378 |
|
|
case BIO_CTRL_FLUSH: |
379 |
|
|
ret = 1; |
380 |
|
|
break; |
381 |
|
|
case BIO_CTRL_DGRAM_CONNECT: |
382 |
|
|
to = (struct sockaddr *)ptr; |
383 |
|
|
switch (to->sa_family) { |
384 |
|
|
case AF_INET: |
385 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa_in)); |
386 |
|
|
break; |
387 |
|
|
case AF_INET6: |
388 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa_in6)); |
389 |
|
|
break; |
390 |
|
|
default: |
391 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa)); |
392 |
|
|
break; |
393 |
|
|
} |
394 |
|
|
break; |
395 |
|
|
/* (Linux)kernel sets DF bit on outgoing IP packets */ |
396 |
|
|
case BIO_CTRL_DGRAM_MTU_DISCOVER: |
397 |
|
|
#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) |
398 |
|
|
addr_len = (socklen_t)sizeof(addr); |
399 |
|
|
memset((void *)&addr, 0, sizeof(addr)); |
400 |
|
|
if (getsockname(b->num, &addr.sa, &addr_len) < 0) { |
401 |
|
|
ret = 0; |
402 |
|
|
break; |
403 |
|
|
} |
404 |
|
|
switch (addr.sa.sa_family) { |
405 |
|
|
case AF_INET: |
406 |
|
|
sockopt_val = IP_PMTUDISC_DO; |
407 |
|
|
ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, |
408 |
|
|
&sockopt_val, sizeof(sockopt_val)); |
409 |
|
|
if (ret < 0) |
410 |
|
|
perror("setsockopt"); |
411 |
|
|
break; |
412 |
|
|
#if defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) |
413 |
|
|
case AF_INET6: |
414 |
|
|
sockopt_val = IPV6_PMTUDISC_DO; |
415 |
|
|
ret = setsockopt(b->num, IPPROTO_IPV6, |
416 |
|
|
IPV6_MTU_DISCOVER, &sockopt_val, |
417 |
|
|
sizeof(sockopt_val)); |
418 |
|
|
if (ret < 0) |
419 |
|
|
perror("setsockopt"); |
420 |
|
|
break; |
421 |
|
|
#endif |
422 |
|
|
default: |
423 |
|
|
ret = -1; |
424 |
|
|
break; |
425 |
|
|
} |
426 |
|
|
#else |
427 |
|
|
ret = -1; |
428 |
|
|
#endif |
429 |
|
|
break; |
430 |
|
|
case BIO_CTRL_DGRAM_QUERY_MTU: |
431 |
|
|
#if defined(IP_MTU) |
432 |
|
|
addr_len = (socklen_t)sizeof(addr); |
433 |
|
|
memset((void *)&addr, 0, sizeof(addr)); |
434 |
|
|
if (getsockname(b->num, &addr.sa, &addr_len) < 0) { |
435 |
|
|
ret = 0; |
436 |
|
|
break; |
437 |
|
|
} |
438 |
|
|
sockopt_len = sizeof(sockopt_val); |
439 |
|
|
switch (addr.sa.sa_family) { |
440 |
|
|
case AF_INET: |
441 |
|
|
ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, |
442 |
|
|
&sockopt_val, &sockopt_len); |
443 |
|
|
if (ret < 0 || sockopt_val < 0) { |
444 |
|
|
ret = 0; |
445 |
|
|
} else { |
446 |
|
|
/* we assume that the transport protocol is UDP and no |
447 |
|
|
* IP options are used. |
448 |
|
|
*/ |
449 |
|
|
data->mtu = sockopt_val - 8 - 20; |
450 |
|
|
ret = data->mtu; |
451 |
|
|
} |
452 |
|
|
break; |
453 |
|
|
#if defined(IPV6_MTU) |
454 |
|
|
case AF_INET6: |
455 |
|
|
ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, |
456 |
|
|
&sockopt_val, &sockopt_len); |
457 |
|
|
if (ret < 0 || sockopt_val < 0) { |
458 |
|
|
ret = 0; |
459 |
|
|
} else { |
460 |
|
|
/* we assume that the transport protocol is UDP and no |
461 |
|
|
* IPV6 options are used. |
462 |
|
|
*/ |
463 |
|
|
data->mtu = sockopt_val - 8 - 40; |
464 |
|
|
ret = data->mtu; |
465 |
|
|
} |
466 |
|
|
break; |
467 |
|
|
#endif |
468 |
|
|
default: |
469 |
|
|
ret = 0; |
470 |
|
|
break; |
471 |
|
|
} |
472 |
|
|
#else |
473 |
|
|
ret = 0; |
474 |
|
|
#endif |
475 |
|
|
break; |
476 |
|
|
case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: |
477 |
|
|
switch (data->peer.sa.sa_family) { |
478 |
|
|
case AF_INET: |
479 |
|
|
ret = 576 - 20 - 8; |
480 |
|
|
break; |
481 |
|
|
case AF_INET6: |
482 |
|
|
#ifdef IN6_IS_ADDR_V4MAPPED |
483 |
|
|
if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) |
484 |
|
|
ret = 576 - 20 - 8; |
485 |
|
|
else |
486 |
|
|
#endif |
487 |
|
|
ret = 1280 - 40 - 8; |
488 |
|
|
break; |
489 |
|
|
default: |
490 |
|
|
ret = 576 - 20 - 8; |
491 |
|
|
break; |
492 |
|
|
} |
493 |
|
|
break; |
494 |
|
|
case BIO_CTRL_DGRAM_GET_MTU: |
495 |
|
|
return data->mtu; |
496 |
|
|
break; |
497 |
|
|
case BIO_CTRL_DGRAM_SET_MTU: |
498 |
|
|
data->mtu = num; |
499 |
|
|
ret = num; |
500 |
|
|
break; |
501 |
|
|
case BIO_CTRL_DGRAM_SET_CONNECTED: |
502 |
|
|
to = (struct sockaddr *)ptr; |
503 |
|
|
|
504 |
|
|
if (to != NULL) { |
505 |
|
|
data->connected = 1; |
506 |
|
|
switch (to->sa_family) { |
507 |
|
|
case AF_INET: |
508 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa_in)); |
509 |
|
|
break; |
510 |
|
|
case AF_INET6: |
511 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa_in6)); |
512 |
|
|
break; |
513 |
|
|
default: |
514 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa)); |
515 |
|
|
break; |
516 |
|
|
} |
517 |
|
|
} else { |
518 |
|
|
data->connected = 0; |
519 |
|
|
memset(&(data->peer), 0, sizeof(data->peer)); |
520 |
|
|
} |
521 |
|
|
break; |
522 |
|
|
case BIO_CTRL_DGRAM_GET_PEER: |
523 |
|
|
switch (data->peer.sa.sa_family) { |
524 |
|
|
case AF_INET: |
525 |
|
|
ret = sizeof(data->peer.sa_in); |
526 |
|
|
break; |
527 |
|
|
case AF_INET6: |
528 |
|
|
ret = sizeof(data->peer.sa_in6); |
529 |
|
|
break; |
530 |
|
|
default: |
531 |
|
|
ret = sizeof(data->peer.sa); |
532 |
|
|
break; |
533 |
|
|
} |
534 |
|
|
if (num == 0 || num > ret) |
535 |
|
|
num = ret; |
536 |
|
|
memcpy(ptr, &data->peer, (ret = num)); |
537 |
|
|
break; |
538 |
|
|
case BIO_CTRL_DGRAM_SET_PEER: |
539 |
|
|
to = (struct sockaddr *) ptr; |
540 |
|
|
switch (to->sa_family) { |
541 |
|
|
case AF_INET: |
542 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa_in)); |
543 |
|
|
break; |
544 |
|
|
case AF_INET6: |
545 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa_in6)); |
546 |
|
|
break; |
547 |
|
|
default: |
548 |
|
|
memcpy(&data->peer, to, sizeof(data->peer.sa)); |
549 |
|
|
break; |
550 |
|
|
} |
551 |
|
|
break; |
552 |
|
|
case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: |
553 |
|
|
memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); |
554 |
|
|
break; |
555 |
|
|
#if defined(SO_RCVTIMEO) |
556 |
|
|
case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: |
557 |
|
|
if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, |
558 |
|
|
sizeof(struct timeval)) < 0) { |
559 |
|
|
perror("setsockopt"); |
560 |
|
|
ret = -1; |
561 |
|
|
} |
562 |
|
|
break; |
563 |
|
|
case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: |
564 |
|
|
{ |
565 |
|
|
socklen_t sz = sizeof(struct timeval); |
566 |
|
|
if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, |
567 |
|
|
ptr, &sz) < 0) { |
568 |
|
|
perror("getsockopt"); |
569 |
|
|
ret = -1; |
570 |
|
|
} else |
571 |
|
|
ret = sz; |
572 |
|
|
} |
573 |
|
|
break; |
574 |
|
|
#endif |
575 |
|
|
#if defined(SO_SNDTIMEO) |
576 |
|
|
case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: |
577 |
|
|
if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, |
578 |
|
|
sizeof(struct timeval)) < 0) { |
579 |
|
|
perror("setsockopt"); |
580 |
|
|
ret = -1; |
581 |
|
|
} |
582 |
|
|
break; |
583 |
|
|
case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: |
584 |
|
|
{ |
585 |
|
|
socklen_t sz = sizeof(struct timeval); |
586 |
|
|
if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, |
587 |
|
|
ptr, &sz) < 0) { |
588 |
|
|
perror("getsockopt"); |
589 |
|
|
ret = -1; |
590 |
|
|
} else |
591 |
|
|
ret = sz; |
592 |
|
|
} |
593 |
|
|
break; |
594 |
|
|
#endif |
595 |
|
|
case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: |
596 |
|
|
/* fall-through */ |
597 |
|
|
case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: |
598 |
|
|
if (data->_errno == EAGAIN) { |
599 |
|
|
ret = 1; |
600 |
|
|
data->_errno = 0; |
601 |
|
|
} else |
602 |
|
|
ret = 0; |
603 |
|
|
break; |
604 |
|
|
#ifdef EMSGSIZE |
605 |
|
|
case BIO_CTRL_DGRAM_MTU_EXCEEDED: |
606 |
|
|
if (data->_errno == EMSGSIZE) { |
607 |
|
|
ret = 1; |
608 |
|
|
data->_errno = 0; |
609 |
|
|
} else |
610 |
|
|
ret = 0; |
611 |
|
|
break; |
612 |
|
|
#endif |
613 |
|
|
default: |
614 |
|
|
ret = 0; |
615 |
|
|
break; |
616 |
|
|
} |
617 |
|
|
return (ret); |
618 |
|
|
} |
619 |
|
|
|
620 |
|
|
static int |
621 |
|
|
dgram_puts(BIO *bp, const char *str) |
622 |
|
|
{ |
623 |
|
|
int n, ret; |
624 |
|
|
|
625 |
|
|
n = strlen(str); |
626 |
|
|
ret = dgram_write(bp, str, n); |
627 |
|
|
return (ret); |
628 |
|
|
} |
629 |
|
|
|
630 |
|
|
|
631 |
|
|
static int |
632 |
|
|
BIO_dgram_should_retry(int i) |
633 |
|
|
{ |
634 |
|
|
int err; |
635 |
|
|
|
636 |
|
|
if ((i == 0) || (i == -1)) { |
637 |
|
|
err = errno; |
638 |
|
|
return (BIO_dgram_non_fatal_error(err)); |
639 |
|
|
} |
640 |
|
|
return (0); |
641 |
|
|
} |
642 |
|
|
|
643 |
|
|
int |
644 |
|
|
BIO_dgram_non_fatal_error(int err) |
645 |
|
|
{ |
646 |
|
|
switch (err) { |
647 |
|
|
case EINTR: |
648 |
|
|
case EAGAIN: |
649 |
|
|
case EINPROGRESS: |
650 |
|
|
case EALREADY: |
651 |
|
|
return (1); |
652 |
|
|
default: |
653 |
|
|
break; |
654 |
|
|
} |
655 |
|
|
return (0); |
656 |
|
|
} |
657 |
|
|
|
658 |
|
|
#endif |