update libressl to v2.7.4
[unleashed.git] / lib / libcrypto / bio / bss_dgram.c
bloba9657402ce62e7dfa4387032a2e43a37cbad9b7f
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.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
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.
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/)"
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.
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.
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/)"
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 * ====================================================================
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).
60 #include <sys/socket.h>
61 #include <sys/time.h>
63 #include <netinet/in.h>
65 #include <errno.h>
66 #include <netdb.h>
67 #include <stdio.h>
68 #include <string.h>
69 #include <unistd.h>
71 #include <openssl/opensslconf.h>
73 #include <openssl/bio.h>
75 #ifndef OPENSSL_NO_DGRAM
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);
87 static int BIO_dgram_should_retry(int s);
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
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;
115 BIO_METHOD *
116 BIO_s_datagram(void)
118 return (&methods_dgramp);
121 BIO *
122 BIO_new_dgram(int fd, int close_flag)
124 BIO *ret;
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);
133 static int
134 dgram_new(BIO *bi)
136 bio_dgram_data *data = NULL;
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;
145 bi->flags = 0;
146 return (1);
149 static int
150 dgram_free(BIO *a)
152 bio_dgram_data *data;
154 if (a == NULL)
155 return (0);
156 if (!dgram_clear(a))
157 return 0;
159 data = (bio_dgram_data *)a->ptr;
160 free(data);
162 return (1);
165 static int
166 dgram_clear(BIO *a)
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);
175 a->init = 0;
176 a->flags = 0;
178 return (1);
181 static void
182 dgram_adjust_rcv_timeout(BIO *b)
184 #if defined(SO_RCVTIMEO)
185 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
187 /* Is a timer active? */
188 if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) {
189 struct timeval timenow, timeleft;
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");
198 /* Get current time */
199 gettimeofday(&timenow, NULL);
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;
210 if (timeleft.tv_sec < 0) {
211 timeleft.tv_sec = 0;
212 timeleft.tv_usec = 1;
215 /* Adjust socket timeout if next handhake message timer
216 * will expire earlier.
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");
229 #endif
232 static void
233 dgram_reset_rcv_timeout(BIO *b)
235 #if defined(SO_RCVTIMEO)
236 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
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");
245 #endif
248 static int
249 dgram_read(BIO *b, char *out, int outl)
251 int ret = 0;
252 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
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;
263 sa.len = sizeof(sa.peer);
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);
271 if (! data->connected && ret >= 0)
272 BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer);
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;
282 dgram_reset_rcv_timeout(b);
284 return (ret);
287 static int
288 dgram_write(BIO *b, const char *in, int inl)
290 int ret;
291 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
292 errno = 0;
294 if (data->connected)
295 ret = write(b->num, in, inl);
296 else {
297 int peerlen = sizeof(data->peer);
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);
306 BIO_clear_retry_flags(b);
307 if (ret <= 0) {
308 if (BIO_dgram_should_retry(ret)) {
309 BIO_set_retry_write(b);
311 data->_errno = errno;
313 * higher layers are responsible for querying MTU,
314 * if necessary
318 return (ret);
321 static long
322 dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
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
340 data = (bio_dgram_data *)b->ptr;
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;
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;
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;
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;
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.
449 data->mtu = sockopt_val - 8 - 20;
450 ret = data->mtu;
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.
463 data->mtu = sockopt_val - 8 - 40;
464 ret = data->mtu;
466 break;
467 #endif
468 default:
469 ret = 0;
470 break;
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;
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;
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;
517 } else {
518 data->connected = 0;
519 memset(&(data->peer), 0, sizeof(data->peer));
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;
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;
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;
562 break;
563 case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
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;
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;
582 break;
583 case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
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;
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;
617 return (ret);
620 static int
621 dgram_puts(BIO *bp, const char *str)
623 int n, ret;
625 n = strlen(str);
626 ret = dgram_write(bp, str, n);
627 return (ret);
631 static int
632 BIO_dgram_should_retry(int i)
634 int err;
636 if ((i == 0) || (i == -1)) {
637 err = errno;
638 return (BIO_dgram_non_fatal_error(err));
640 return (0);
644 BIO_dgram_non_fatal_error(int err)
646 switch (err) {
647 case EINTR:
648 case EAGAIN:
649 case EINPROGRESS:
650 case EALREADY:
651 return (1);
652 default:
653 break;
655 return (0);
658 #endif