1/* crypto/bio/bio_dgram.c */ 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 61#include <stdio.h> 62#include <errno.h> 63#define USE_SOCKETS 64#include "cryptlib.h" 65 66#include <openssl/bio.h> 67#ifndef OPENSSL_NO_DGRAM 68 69#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) 70#include <sys/timeb.h> 71#endif 72 73#ifdef OPENSSL_SYS_LINUX 74#define IP_MTU 14 /* linux is lame */ 75#endif 76 77#ifdef WATT32 78#define sock_write SockWrite /* Watt-32 uses same names */ 79#define sock_read SockRead 80#define sock_puts SockPuts 81#endif 82 83static int dgram_write(BIO *h, const char *buf, int num); 84static int dgram_read(BIO *h, char *buf, int size); 85static int dgram_puts(BIO *h, const char *str); 86static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); 87static int dgram_new(BIO *h); 88static int dgram_free(BIO *data); 89static int dgram_clear(BIO *bio); 90 91static int BIO_dgram_should_retry(int s); 92 93static void get_current_time(struct timeval *t); 94 95static BIO_METHOD methods_dgramp= 96 { 97 BIO_TYPE_DGRAM, 98 "datagram socket", 99 dgram_write, 100 dgram_read, 101 dgram_puts, 102 NULL, /* dgram_gets, */ 103 dgram_ctrl, 104 dgram_new, 105 dgram_free, 106 NULL, 107 }; 108 109typedef struct bio_dgram_data_st 110 { 111 union { 112 struct sockaddr sa; 113 struct sockaddr_in sa_in; 114#if OPENSSL_USE_IPV6 115 struct sockaddr_in6 sa_in6; 116#endif 117 } peer; 118 unsigned int connected; 119 unsigned int _errno; 120 unsigned int mtu; 121 struct timeval next_timeout; 122 struct timeval socket_timeout; 123 } bio_dgram_data; 124 125BIO_METHOD *BIO_s_datagram(void) 126 { 127 return(&methods_dgramp); 128 } 129 130BIO *BIO_new_dgram(int fd, int close_flag) 131 { 132 BIO *ret; 133 134 ret=BIO_new(BIO_s_datagram()); 135 if (ret == NULL) return(NULL); 136 BIO_set_fd(ret,fd,close_flag); 137 return(ret); 138 } 139 140static int dgram_new(BIO *bi) 141 { 142 bio_dgram_data *data = NULL; 143 144 bi->init=0; 145 bi->num=0; 146 data = OPENSSL_malloc(sizeof(bio_dgram_data)); 147 if (data == NULL) 148 return 0; 149 memset(data, 0x00, sizeof(bio_dgram_data)); 150 bi->ptr = data; 151 152 bi->flags=0; 153 return(1); 154 } 155 156static int dgram_free(BIO *a) 157 { 158 bio_dgram_data *data; 159 160 if (a == NULL) return(0); 161 if ( ! dgram_clear(a)) 162 return 0; 163 164 data = (bio_dgram_data *)a->ptr; 165 if(data != NULL) OPENSSL_free(data); 166 167 return(1); 168 } 169 170static int dgram_clear(BIO *a) 171 { 172 if (a == NULL) return(0); 173 if (a->shutdown) 174 { 175 if (a->init) 176 { 177 SHUTDOWN2(a->num); 178 } 179 a->init=0; 180 a->flags=0; 181 } 182 return(1); 183 } 184 185static void dgram_adjust_rcv_timeout(BIO *b) 186 { 187#if defined(SO_RCVTIMEO) 188 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 189 union { size_t s; int i; } sz = {0}; 190 191 /* Is a timer active? */ 192 if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) 193 { 194 struct timeval timenow, timeleft; 195 196 /* Read current socket timeout */ 197#ifdef OPENSSL_SYS_WINDOWS 198 int timeout; 199 200 sz.i = sizeof(timeout); 201 if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 202 (void*)&timeout, &sz.i) < 0) 203 { perror("getsockopt"); } 204 else 205 { 206 data->socket_timeout.tv_sec = timeout / 1000; 207 data->socket_timeout.tv_usec = (timeout % 1000) * 1000; 208 } 209#else 210 sz.i = sizeof(data->socket_timeout); 211 if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 212 &(data->socket_timeout), (void *)&sz) < 0) 213 { perror("getsockopt"); } 214 else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0) 215 OPENSSL_assert(sz.s<=sizeof(data->socket_timeout)); 216#endif 217 218 /* Get current time */ 219 get_current_time(&timenow); 220 221 /* Calculate time left until timer expires */ 222 memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); 223 timeleft.tv_sec -= timenow.tv_sec; 224 timeleft.tv_usec -= timenow.tv_usec; 225 if (timeleft.tv_usec < 0) 226 { 227 timeleft.tv_sec--; 228 timeleft.tv_usec += 1000000; 229 } 230 231 if (timeleft.tv_sec < 0) 232 { 233 timeleft.tv_sec = 0; 234 timeleft.tv_usec = 1; 235 } 236 237 /* Adjust socket timeout if next handhake message timer 238 * will expire earlier. 239 */ 240 if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) || 241 (data->socket_timeout.tv_sec > timeleft.tv_sec) || 242 (data->socket_timeout.tv_sec == timeleft.tv_sec && 243 data->socket_timeout.tv_usec >= timeleft.tv_usec)) 244 { 245#ifdef OPENSSL_SYS_WINDOWS 246 timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; 247 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 248 (void*)&timeout, sizeof(timeout)) < 0) 249 { perror("setsockopt"); } 250#else 251 if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, 252 sizeof(struct timeval)) < 0) 253 { perror("setsockopt"); } 254#endif 255 } 256 } 257#endif 258 } 259 260static void dgram_reset_rcv_timeout(BIO *b) 261 { 262#if defined(SO_RCVTIMEO) 263 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 264 265 /* Is a timer active? */ 266 if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) 267 { 268#ifdef OPENSSL_SYS_WINDOWS 269 int timeout = data->socket_timeout.tv_sec * 1000 + 270 data->socket_timeout.tv_usec / 1000; 271 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 272 (void*)&timeout, sizeof(timeout)) < 0) 273 { perror("setsockopt"); } 274#else 275 if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), 276 sizeof(struct timeval)) < 0) 277 { perror("setsockopt"); } 278#endif 279 } 280#endif 281 } 282 283static int dgram_read(BIO *b, char *out, int outl) 284 { 285 int ret=0; 286 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 287 288 struct { 289 /* 290 * See commentary in b_sock.c. <appro> 291 */ 292 union { size_t s; int i; } len; 293 union { 294 struct sockaddr sa; 295 struct sockaddr_in sa_in; 296#if OPENSSL_USE_IPV6 297 struct sockaddr_in6 sa_in6; 298#endif 299 } peer; 300 } sa; 301 302 sa.len.s=0; 303 sa.len.i=sizeof(sa.peer); 304 305 if (out != NULL) 306 { 307 clear_socket_error(); 308 memset(&sa.peer, 0x00, sizeof(sa.peer)); 309 dgram_adjust_rcv_timeout(b); 310 ret=recvfrom(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len); 311 if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0) 312 { 313 OPENSSL_assert(sa.len.s<=sizeof(sa.peer)); 314 sa.len.i = (int)sa.len.s; 315 } 316 317 if ( ! data->connected && ret >= 0) 318 BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer); 319 320 BIO_clear_retry_flags(b); 321 if (ret < 0) 322 { 323 if (BIO_dgram_should_retry(ret)) 324 { 325 BIO_set_retry_read(b); 326 data->_errno = get_last_socket_error(); 327 } 328 } 329 330 dgram_reset_rcv_timeout(b); 331 } 332 return(ret); 333 } 334 335static int dgram_write(BIO *b, const char *in, int inl) 336 { 337 int ret; 338 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 339 clear_socket_error(); 340 341 if ( data->connected ) 342 ret=writesocket(b->num,in,inl); 343 else 344 { 345 int peerlen = sizeof(data->peer); 346 347 if (data->peer.sa.sa_family == AF_INET) 348 peerlen = sizeof(data->peer.sa_in); 349#if OPENSSL_USE_IPV6 350 else if (data->peer.sa.sa_family == AF_INET6) 351 peerlen = sizeof(data->peer.sa_in6); 352#endif 353#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) 354 ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen); 355#else 356 ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen); 357#endif 358 } 359 360 BIO_clear_retry_flags(b); 361 if (ret <= 0) 362 { 363 if (BIO_dgram_should_retry(ret)) 364 { 365 BIO_set_retry_write(b); 366 data->_errno = get_last_socket_error(); 367 368#if 0 /* higher layers are responsible for querying MTU, if necessary */ 369 if ( data->_errno == EMSGSIZE) 370 /* retrieve the new MTU */ 371 BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); 372#endif 373 } 374 } 375 return(ret); 376 } 377 378static long dgram_get_mtu_overhead(bio_dgram_data *data) 379 { 380 long ret; 381 382 switch (data->peer.sa.sa_family) 383 { 384 case AF_INET: 385 /* Assume this is UDP - 20 bytes for IP, 8 bytes for UDP */ 386 ret = 28; 387 break; 388#if OPENSSL_USE_IPV6 389 case AF_INET6: 390#ifdef IN6_IS_ADDR_V4MAPPED 391 if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) 392 /* Assume this is UDP - 20 bytes for IP, 8 bytes for UDP */ 393 ret = 28; 394 else 395#endif 396 /* Assume this is UDP - 40 bytes for IP, 8 bytes for UDP */ 397 ret = 48; 398 break; 399#endif 400 default: 401 /* We don't know. Go with the historical default */ 402 ret = 28; 403 break; 404 } 405 return ret; 406 } 407 408static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) 409 { 410 long ret=1; 411 int *ip; 412 struct sockaddr *to = NULL; 413 bio_dgram_data *data = NULL; 414#if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU)) 415 int sockopt_val = 0; 416 socklen_t sockopt_len; /* assume that system supporting IP_MTU is 417 * modern enough to define socklen_t */ 418 socklen_t addr_len; 419 union { 420 struct sockaddr sa; 421 struct sockaddr_in s4; 422#if OPENSSL_USE_IPV6 423 struct sockaddr_in6 s6; 424#endif 425 } addr; 426#endif 427 428 data = (bio_dgram_data *)b->ptr; 429 430 switch (cmd) 431 { 432 case BIO_CTRL_RESET: 433 num=0; 434 case BIO_C_FILE_SEEK: 435 ret=0; 436 break; 437 case BIO_C_FILE_TELL: 438 case BIO_CTRL_INFO: 439 ret=0; 440 break; 441 case BIO_C_SET_FD: 442 dgram_clear(b); 443 b->num= *((int *)ptr); 444 b->shutdown=(int)num; 445 b->init=1; 446 break; 447 case BIO_C_GET_FD: 448 if (b->init) 449 { 450 ip=(int *)ptr; 451 if (ip != NULL) *ip=b->num; 452 ret=b->num; 453 } 454 else 455 ret= -1; 456 break; 457 case BIO_CTRL_GET_CLOSE: 458 ret=b->shutdown; 459 break; 460 case BIO_CTRL_SET_CLOSE: 461 b->shutdown=(int)num; 462 break; 463 case BIO_CTRL_PENDING: 464 case BIO_CTRL_WPENDING: 465 ret=0; 466 break; 467 case BIO_CTRL_DUP: 468 case BIO_CTRL_FLUSH: 469 ret=1; 470 break; 471 case BIO_CTRL_DGRAM_CONNECT: 472 to = (struct sockaddr *)ptr; 473#if 0 474 if (connect(b->num, to, sizeof(struct sockaddr)) < 0) 475 { perror("connect"); ret = 0; } 476 else 477 { 478#endif 479 switch (to->sa_family) 480 { 481 case AF_INET: 482 memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 483 break; 484#if OPENSSL_USE_IPV6 485 case AF_INET6: 486 memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 487 break; 488#endif 489 default: 490 memcpy(&data->peer,to,sizeof(data->peer.sa)); 491 break; 492 } 493#if 0 494 } 495#endif 496 break; 497 /* (Linux)kernel sets DF bit on outgoing IP packets */ 498 case BIO_CTRL_DGRAM_MTU_DISCOVER: 499#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) 500 addr_len = (socklen_t)sizeof(addr); 501 memset((void *)&addr, 0, sizeof(addr)); 502 if (getsockname(b->num, &addr.sa, &addr_len) < 0) 503 { 504 ret = 0; 505 break; 506 } 507 switch (addr.sa.sa_family) 508 { 509 case AF_INET: 510 sockopt_val = IP_PMTUDISC_DO; 511 if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, 512 &sockopt_val, sizeof(sockopt_val))) < 0) 513 perror("setsockopt"); 514 break; 515#if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) 516 case AF_INET6: 517 sockopt_val = IPV6_PMTUDISC_DO; 518 if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, 519 &sockopt_val, sizeof(sockopt_val))) < 0) 520 perror("setsockopt"); 521 break; 522#endif 523 default: 524 ret = -1; 525 break; 526 } 527 ret = -1; 528#else 529 break; 530#endif 531 case BIO_CTRL_DGRAM_QUERY_MTU: 532#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU) 533 addr_len = (socklen_t)sizeof(addr); 534 memset((void *)&addr, 0, sizeof(addr)); 535 if (getsockname(b->num, &addr.sa, &addr_len) < 0) 536 { 537 ret = 0; 538 break; 539 } 540 sockopt_len = sizeof(sockopt_val); 541 switch (addr.sa.sa_family) 542 { 543 case AF_INET: 544 if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, 545 &sockopt_len)) < 0 || sockopt_val < 0) 546 { 547 ret = 0; 548 } 549 else 550 { 551 /* we assume that the transport protocol is UDP and no 552 * IP options are used. 553 */ 554 data->mtu = sockopt_val - 8 - 20; 555 ret = data->mtu; 556 } 557 break; 558#if OPENSSL_USE_IPV6 && defined(IPV6_MTU) 559 case AF_INET6: 560 if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val, 561 &sockopt_len)) < 0 || sockopt_val < 0) 562 { 563 ret = 0; 564 } 565 else 566 { 567 /* we assume that the transport protocol is UDP and no 568 * IPV6 options are used. 569 */ 570 data->mtu = sockopt_val - 8 - 40; 571 ret = data->mtu; 572 } 573 break; 574#endif 575 default: 576 ret = 0; 577 break; 578 } 579#else 580 ret = 0; 581#endif 582 break; 583 case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: 584 ret = -dgram_get_mtu_overhead(data); 585 switch (data->peer.sa.sa_family) 586 { 587 case AF_INET: 588 ret += 576; 589 break; 590#if OPENSSL_USE_IPV6 591 case AF_INET6: 592#ifdef IN6_IS_ADDR_V4MAPPED 593 if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr)) 594 ret += 576; 595 else 596#endif 597 ret += 1280; 598 break; 599#endif 600 default: 601 ret += 576; 602 break; 603 } 604 break; 605 case BIO_CTRL_DGRAM_GET_MTU: 606 return data->mtu; 607 break; 608 case BIO_CTRL_DGRAM_SET_MTU: 609 data->mtu = num; 610 ret = num; 611 break; 612 case BIO_CTRL_DGRAM_SET_CONNECTED: 613 to = (struct sockaddr *)ptr; 614 615 if ( to != NULL) 616 { 617 data->connected = 1; 618 switch (to->sa_family) 619 { 620 case AF_INET: 621 memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 622 break; 623#if OPENSSL_USE_IPV6 624 case AF_INET6: 625 memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 626 break; 627#endif 628 default: 629 memcpy(&data->peer,to,sizeof(data->peer.sa)); 630 break; 631 } 632 } 633 else 634 { 635 data->connected = 0; 636 memset(&(data->peer), 0x00, sizeof(data->peer)); 637 } 638 break; 639 case BIO_CTRL_DGRAM_GET_PEER: 640 switch (data->peer.sa.sa_family) 641 { 642 case AF_INET: 643 ret=sizeof(data->peer.sa_in); 644 break; 645#if OPENSSL_USE_IPV6 646 case AF_INET6: 647 ret=sizeof(data->peer.sa_in6); 648 break; 649#endif 650 default: 651 ret=sizeof(data->peer.sa); 652 break; 653 } 654 if (num==0 || num>ret) 655 num=ret; 656 memcpy(ptr,&data->peer,(ret=num)); 657 break; 658 case BIO_CTRL_DGRAM_SET_PEER: 659 to = (struct sockaddr *) ptr; 660 switch (to->sa_family) 661 { 662 case AF_INET: 663 memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 664 break; 665#if OPENSSL_USE_IPV6 666 case AF_INET6: 667 memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 668 break; 669#endif 670 default: 671 memcpy(&data->peer,to,sizeof(data->peer.sa)); 672 break; 673 } 674 break; 675 case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: 676 memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); 677 break; 678#if defined(SO_RCVTIMEO) 679 case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: 680#ifdef OPENSSL_SYS_WINDOWS 681 { 682 struct timeval *tv = (struct timeval *)ptr; 683 int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; 684 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 685 (void*)&timeout, sizeof(timeout)) < 0) 686 { perror("setsockopt"); ret = -1; } 687 } 688#else 689 if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, 690 sizeof(struct timeval)) < 0) 691 { perror("setsockopt"); ret = -1; } 692#endif 693 break; 694 case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: 695 { 696 union { size_t s; int i; } sz = {0}; 697#ifdef OPENSSL_SYS_WINDOWS 698 int timeout; 699 struct timeval *tv = (struct timeval *)ptr; 700 701 sz.i = sizeof(timeout); 702 if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 703 (void*)&timeout, &sz.i) < 0) 704 { perror("getsockopt"); ret = -1; } 705 else 706 { 707 tv->tv_sec = timeout / 1000; 708 tv->tv_usec = (timeout % 1000) * 1000; 709 ret = sizeof(*tv); 710 } 711#else 712 sz.i = sizeof(struct timeval); 713 if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 714 ptr, (void *)&sz) < 0) 715 { perror("getsockopt"); ret = -1; } 716 else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0) 717 { 718 OPENSSL_assert(sz.s<=sizeof(struct timeval)); 719 ret = (int)sz.s; 720 } 721 else 722 ret = sz.i; 723#endif 724 } 725 break; 726#endif 727#if defined(SO_SNDTIMEO) 728 case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: 729#ifdef OPENSSL_SYS_WINDOWS 730 { 731 struct timeval *tv = (struct timeval *)ptr; 732 int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; 733 if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 734 (void*)&timeout, sizeof(timeout)) < 0) 735 { perror("setsockopt"); ret = -1; } 736 } 737#else 738 if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, 739 sizeof(struct timeval)) < 0) 740 { perror("setsockopt"); ret = -1; } 741#endif 742 break; 743 case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: 744 { 745 union { size_t s; int i; } sz = {0}; 746#ifdef OPENSSL_SYS_WINDOWS 747 int timeout; 748 struct timeval *tv = (struct timeval *)ptr; 749 750 sz.i = sizeof(timeout); 751 if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 752 (void*)&timeout, &sz.i) < 0) 753 { perror("getsockopt"); ret = -1; } 754 else 755 { 756 tv->tv_sec = timeout / 1000; 757 tv->tv_usec = (timeout % 1000) * 1000; 758 ret = sizeof(*tv); 759 } 760#else 761 sz.i = sizeof(struct timeval); 762 if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 763 ptr, (void *)&sz) < 0) 764 { perror("getsockopt"); ret = -1; } 765 else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0) 766 { 767 OPENSSL_assert(sz.s<=sizeof(struct timeval)); 768 ret = (int)sz.s; 769 } 770 else 771 ret = sz.i; 772#endif 773 } 774 break; 775#endif 776 case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: 777 /* fall-through */ 778 case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: 779#ifdef OPENSSL_SYS_WINDOWS 780 if ( data->_errno == WSAETIMEDOUT) 781#else 782 if ( data->_errno == EAGAIN) 783#endif 784 { 785 ret = 1; 786 data->_errno = 0; 787 } 788 else 789 ret = 0; 790 break; 791#ifdef EMSGSIZE 792 case BIO_CTRL_DGRAM_MTU_EXCEEDED: 793 if ( data->_errno == EMSGSIZE) 794 { 795 ret = 1; 796 data->_errno = 0; 797 } 798 else 799 ret = 0; 800 break; 801#endif 802 case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: 803 ret = dgram_get_mtu_overhead(data); 804 break; 805 default: 806 ret=0; 807 break; 808 } 809 return(ret); 810 } 811 812static int dgram_puts(BIO *bp, const char *str) 813 { 814 int n,ret; 815 816 n=strlen(str); 817 ret=dgram_write(bp,str,n); 818 return(ret); 819 } 820 821static int BIO_dgram_should_retry(int i) 822 { 823 int err; 824 825 if ((i == 0) || (i == -1)) 826 { 827 err=get_last_socket_error(); 828 829#if defined(OPENSSL_SYS_WINDOWS) 830 /* If the socket return value (i) is -1 831 * and err is unexpectedly 0 at this point, 832 * the error code was overwritten by 833 * another system call before this error 834 * handling is called. 835 */ 836#endif 837 838 return(BIO_dgram_non_fatal_error(err)); 839 } 840 return(0); 841 } 842 843int BIO_dgram_non_fatal_error(int err) 844 { 845 switch (err) 846 { 847#if defined(OPENSSL_SYS_WINDOWS) 848# if defined(WSAEWOULDBLOCK) 849 case WSAEWOULDBLOCK: 850# endif 851 852# if 0 /* This appears to always be an error */ 853# if defined(WSAENOTCONN) 854 case WSAENOTCONN: 855# endif 856# endif 857#endif 858 859#ifdef EWOULDBLOCK 860# ifdef WSAEWOULDBLOCK 861# if WSAEWOULDBLOCK != EWOULDBLOCK 862 case EWOULDBLOCK: 863# endif 864# else 865 case EWOULDBLOCK: 866# endif 867#endif 868 869#ifdef EINTR 870 case EINTR: 871#endif 872 873#ifdef EAGAIN 874#if EWOULDBLOCK != EAGAIN 875 case EAGAIN: 876# endif 877#endif 878 879#ifdef EPROTO 880 case EPROTO: 881#endif 882 883#ifdef EINPROGRESS 884 case EINPROGRESS: 885#endif 886 887#ifdef EALREADY 888 case EALREADY: 889#endif 890 891 return(1); 892 /* break; */ 893 default: 894 break; 895 } 896 return(0); 897 } 898 899static void get_current_time(struct timeval *t) 900 { 901#ifdef OPENSSL_SYS_WIN32 902 struct _timeb tb; 903 _ftime(&tb); 904 t->tv_sec = (long)tb.time; 905 t->tv_usec = (long)tb.millitm * 1000; 906#elif defined(OPENSSL_SYS_VMS) 907 struct timeb tb; 908 ftime(&tb); 909 t->tv_sec = (long)tb.time; 910 t->tv_usec = (long)tb.millitm * 1000; 911#else 912 gettimeofday(t, NULL); 913#endif 914 } 915 916#endif 917