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 #ifndef OPENSSL_NO_DGRAM 61 62 #include <stdio.h> 63 #include <errno.h> 64 #define USE_SOCKETS 65 #include "cryptlib.h" 66 67 #include <openssl/bio.h> 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 83 static int dgram_write(BIO *h, const char *buf, int num); 84 static int dgram_read(BIO *h, char *buf, int size); 85 static int dgram_puts(BIO *h, const char *str); 86 static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); 87 static int dgram_new(BIO *h); 88 static int dgram_free(BIO *data); 89 static int dgram_clear(BIO *bio); 90 91 static int BIO_dgram_should_retry(int s); 92 93 static void get_current_time(struct timeval *t); 94 95 static 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 109 typedef 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 125 BIO_METHOD *BIO_s_datagram(void) 126 { 127 return(&methods_dgramp); 128 } 129 130 BIO *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 140 static 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 156 static 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 170 static 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 185 static void dgram_adjust_rcv_timeout(BIO *b) 186 { 187 #if defined(SO_RCVTIMEO) 188 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 189 int sz = sizeof(int); 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 if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 200 (void*)&timeout, &sz) < 0) 201 { perror("getsockopt"); } 202 else 203 { 204 data->socket_timeout.tv_sec = timeout / 1000; 205 data->socket_timeout.tv_usec = (timeout % 1000) * 1000; 206 } 207 #else 208 if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 209 &(data->socket_timeout), (void *)&sz) < 0) 210 { perror("getsockopt"); } 211 #endif 212 213 /* Get current time */ 214 get_current_time(&timenow); 215 216 /* Calculate time left until timer expires */ 217 memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); 218 timeleft.tv_sec -= timenow.tv_sec; 219 timeleft.tv_usec -= timenow.tv_usec; 220 if (timeleft.tv_usec < 0) 221 { 222 timeleft.tv_sec--; 223 timeleft.tv_usec += 1000000; 224 } 225 226 if (timeleft.tv_sec < 0) 227 { 228 timeleft.tv_sec = 0; 229 timeleft.tv_usec = 1; 230 } 231 232 /* Adjust socket timeout if next handhake message timer 233 * will expire earlier. 234 */ 235 if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) || 236 (data->socket_timeout.tv_sec > timeleft.tv_sec) || 237 (data->socket_timeout.tv_sec == timeleft.tv_sec && 238 data->socket_timeout.tv_usec >= timeleft.tv_usec)) 239 { 240 #ifdef OPENSSL_SYS_WINDOWS 241 timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; 242 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 243 (void*)&timeout, sizeof(timeout)) < 0) 244 { perror("setsockopt"); } 245 #else 246 if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, 247 sizeof(struct timeval)) < 0) 248 { perror("setsockopt"); } 249 #endif 250 } 251 } 252 #endif 253 } 254 255 static void dgram_reset_rcv_timeout(BIO *b) 256 { 257 #if defined(SO_RCVTIMEO) 258 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 259 260 /* Is a timer active? */ 261 if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) 262 { 263 #ifdef OPENSSL_SYS_WINDOWS 264 int timeout = data->socket_timeout.tv_sec * 1000 + 265 data->socket_timeout.tv_usec / 1000; 266 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 267 (void*)&timeout, sizeof(timeout)) < 0) 268 { perror("setsockopt"); } 269 #else 270 if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), 271 sizeof(struct timeval)) < 0) 272 { perror("setsockopt"); } 273 #endif 274 } 275 #endif 276 } 277 278 static int dgram_read(BIO *b, char *out, int outl) 279 { 280 int ret=0; 281 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 282 283 struct { 284 /* 285 * See commentary in b_sock.c. <appro> 286 */ 287 union { size_t s; int i; } len; 288 union { 289 struct sockaddr sa; 290 struct sockaddr_in sa_in; 291 #if OPENSSL_USE_IPV6 292 struct sockaddr_in6 sa_in6; 293 #endif 294 } peer; 295 } sa; 296 297 sa.len.s=0; 298 sa.len.i=sizeof(sa.peer); 299 300 if (out != NULL) 301 { 302 clear_socket_error(); 303 memset(&sa.peer, 0x00, sizeof(sa.peer)); 304 dgram_adjust_rcv_timeout(b); 305 ret=recvfrom(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len); 306 if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0) 307 { 308 OPENSSL_assert(sa.len.s<=sizeof(sa.peer)); 309 sa.len.i = (int)sa.len.s; 310 } 311 dgram_reset_rcv_timeout(b); 312 313 if ( ! data->connected && ret >= 0) 314 BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer); 315 316 BIO_clear_retry_flags(b); 317 if (ret < 0) 318 { 319 if (BIO_dgram_should_retry(ret)) 320 { 321 BIO_set_retry_read(b); 322 data->_errno = get_last_socket_error(); 323 } 324 } 325 } 326 return(ret); 327 } 328 329 static int dgram_write(BIO *b, const char *in, int inl) 330 { 331 int ret; 332 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 333 clear_socket_error(); 334 335 if ( data->connected ) 336 ret=writesocket(b->num,in,inl); 337 else 338 { 339 int peerlen = sizeof(data->peer); 340 341 if (data->peer.sa.sa_family == AF_INET) 342 peerlen = sizeof(data->peer.sa_in); 343 #if OPENSSL_USE_IVP6 344 else if (data->peer.sa.sa_family == AF_INET6) 345 peerlen = sizeof(data->peer.sa_in6); 346 #endif 347 #if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) 348 ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen); 349 #else 350 ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen); 351 #endif 352 } 353 354 BIO_clear_retry_flags(b); 355 if (ret <= 0) 356 { 357 if (BIO_dgram_should_retry(ret)) 358 { 359 BIO_set_retry_write(b); 360 data->_errno = get_last_socket_error(); 361 362 #if 0 /* higher layers are responsible for querying MTU, if necessary */ 363 if ( data->_errno == EMSGSIZE) 364 /* retrieve the new MTU */ 365 BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); 366 #endif 367 } 368 } 369 return(ret); 370 } 371 372 static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) 373 { 374 long ret=1; 375 int *ip; 376 struct sockaddr *to = NULL; 377 bio_dgram_data *data = NULL; 378 #if defined(IP_MTU_DISCOVER) || defined(IP_MTU) 379 long sockopt_val = 0; 380 unsigned int sockopt_len = 0; 381 #endif 382 #ifdef OPENSSL_SYS_LINUX 383 socklen_t addr_len; 384 union { 385 struct sockaddr sa; 386 struct sockaddr_in s4; 387 #if OPENSSL_USE_IPV6 388 struct sockaddr_in6 s6; 389 #endif 390 } addr; 391 #endif 392 393 data = (bio_dgram_data *)b->ptr; 394 395 switch (cmd) 396 { 397 case BIO_CTRL_RESET: 398 num=0; 399 case BIO_C_FILE_SEEK: 400 ret=0; 401 break; 402 case BIO_C_FILE_TELL: 403 case BIO_CTRL_INFO: 404 ret=0; 405 break; 406 case BIO_C_SET_FD: 407 dgram_clear(b); 408 b->num= *((int *)ptr); 409 b->shutdown=(int)num; 410 b->init=1; 411 break; 412 case BIO_C_GET_FD: 413 if (b->init) 414 { 415 ip=(int *)ptr; 416 if (ip != NULL) *ip=b->num; 417 ret=b->num; 418 } 419 else 420 ret= -1; 421 break; 422 case BIO_CTRL_GET_CLOSE: 423 ret=b->shutdown; 424 break; 425 case BIO_CTRL_SET_CLOSE: 426 b->shutdown=(int)num; 427 break; 428 case BIO_CTRL_PENDING: 429 case BIO_CTRL_WPENDING: 430 ret=0; 431 break; 432 case BIO_CTRL_DUP: 433 case BIO_CTRL_FLUSH: 434 ret=1; 435 break; 436 case BIO_CTRL_DGRAM_CONNECT: 437 to = (struct sockaddr *)ptr; 438 #if 0 439 if (connect(b->num, to, sizeof(struct sockaddr)) < 0) 440 { perror("connect"); ret = 0; } 441 else 442 { 443 #endif 444 switch (to->sa_family) 445 { 446 case AF_INET: 447 memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 448 break; 449 #if OPENSSL_USE_IPV6 450 case AF_INET6: 451 memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 452 break; 453 #endif 454 default: 455 memcpy(&data->peer,to,sizeof(data->peer.sa)); 456 break; 457 } 458 #if 0 459 } 460 #endif 461 break; 462 /* (Linux)kernel sets DF bit on outgoing IP packets */ 463 case BIO_CTRL_DGRAM_MTU_DISCOVER: 464 #ifdef OPENSSL_SYS_LINUX 465 addr_len = (socklen_t)sizeof(addr); 466 memset((void *)&addr, 0, sizeof(addr)); 467 if (getsockname(b->num, &addr.sa, &addr_len) < 0) 468 { 469 ret = 0; 470 break; 471 } 472 sockopt_len = sizeof(sockopt_val); 473 switch (addr.sa.sa_family) 474 { 475 case AF_INET: 476 sockopt_val = IP_PMTUDISC_DO; 477 if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, 478 &sockopt_val, sizeof(sockopt_val))) < 0) 479 perror("setsockopt"); 480 break; 481 #if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) 482 case AF_INET6: 483 sockopt_val = IPV6_PMTUDISC_DO; 484 if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, 485 &sockopt_val, sizeof(sockopt_val))) < 0) 486 perror("setsockopt"); 487 break; 488 #endif 489 default: 490 ret = -1; 491 break; 492 } 493 ret = -1; 494 #else 495 break; 496 #endif 497 case BIO_CTRL_DGRAM_QUERY_MTU: 498 #ifdef OPENSSL_SYS_LINUX 499 addr_len = (socklen_t)sizeof(addr); 500 memset((void *)&addr, 0, sizeof(addr)); 501 if (getsockname(b->num, &addr.sa, &addr_len) < 0) 502 { 503 ret = 0; 504 break; 505 } 506 sockopt_len = sizeof(sockopt_val); 507 switch (addr.sa.sa_family) 508 { 509 case AF_INET: 510 if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, 511 &sockopt_len)) < 0 || sockopt_val < 0) 512 { 513 ret = 0; 514 } 515 else 516 { 517 /* we assume that the transport protocol is UDP and no 518 * IP options are used. 519 */ 520 data->mtu = sockopt_val - 8 - 20; 521 ret = data->mtu; 522 } 523 break; 524 #if OPENSSL_USE_IPV6 && defined(IPV6_MTU) 525 case AF_INET6: 526 if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val, 527 &sockopt_len)) < 0 || sockopt_val < 0) 528 { 529 ret = 0; 530 } 531 else 532 { 533 /* we assume that the transport protocol is UDP and no 534 * IPV6 options are used. 535 */ 536 data->mtu = sockopt_val - 8 - 40; 537 ret = data->mtu; 538 } 539 break; 540 #endif 541 default: 542 ret = 0; 543 break; 544 } 545 #else 546 ret = 0; 547 #endif 548 break; 549 case BIO_CTRL_DGRAM_GET_MTU: 550 return data->mtu; 551 break; 552 case BIO_CTRL_DGRAM_SET_MTU: 553 data->mtu = num; 554 ret = num; 555 break; 556 case BIO_CTRL_DGRAM_SET_CONNECTED: 557 to = (struct sockaddr *)ptr; 558 559 if ( to != NULL) 560 { 561 data->connected = 1; 562 switch (to->sa_family) 563 { 564 case AF_INET: 565 memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 566 break; 567 #if OPENSSL_USE_IPV6 568 case AF_INET6: 569 memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 570 break; 571 #endif 572 default: 573 memcpy(&data->peer,to,sizeof(data->peer.sa)); 574 break; 575 } 576 } 577 else 578 { 579 data->connected = 0; 580 memset(&(data->peer), 0x00, sizeof(data->peer)); 581 } 582 break; 583 case BIO_CTRL_DGRAM_GET_PEER: 584 switch (data->peer.sa.sa_family) 585 { 586 case AF_INET: 587 ret=sizeof(data->peer.sa_in); 588 break; 589 #if OPENSSL_USE_IPV6 590 case AF_INET6: 591 ret=sizeof(data->peer.sa_in6); 592 break; 593 #endif 594 default: 595 ret=sizeof(data->peer.sa); 596 break; 597 } 598 if (num==0 || num>ret) 599 num=ret; 600 memcpy(ptr,&data->peer,(ret=num)); 601 break; 602 case BIO_CTRL_DGRAM_SET_PEER: 603 to = (struct sockaddr *) ptr; 604 switch (to->sa_family) 605 { 606 case AF_INET: 607 memcpy(&data->peer,to,sizeof(data->peer.sa_in)); 608 break; 609 #if OPENSSL_USE_IPV6 610 case AF_INET6: 611 memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); 612 break; 613 #endif 614 default: 615 memcpy(&data->peer,to,sizeof(data->peer.sa)); 616 break; 617 } 618 break; 619 case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: 620 memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); 621 break; 622 #if defined(SO_RCVTIMEO) 623 case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: 624 #ifdef OPENSSL_SYS_WINDOWS 625 { 626 struct timeval *tv = (struct timeval *)ptr; 627 int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; 628 if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 629 (void*)&timeout, sizeof(timeout)) < 0) 630 { perror("setsockopt"); ret = -1; } 631 } 632 #else 633 if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, 634 sizeof(struct timeval)) < 0) 635 { perror("setsockopt"); ret = -1; } 636 #endif 637 break; 638 case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: 639 #ifdef OPENSSL_SYS_WINDOWS 640 { 641 int timeout, sz = sizeof(timeout); 642 struct timeval *tv = (struct timeval *)ptr; 643 if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 644 (void*)&timeout, &sz) < 0) 645 { perror("getsockopt"); ret = -1; } 646 else 647 { 648 tv->tv_sec = timeout / 1000; 649 tv->tv_usec = (timeout % 1000) * 1000; 650 ret = sizeof(*tv); 651 } 652 } 653 #else 654 if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, 655 ptr, (void *)&ret) < 0) 656 { perror("getsockopt"); ret = -1; } 657 #endif 658 break; 659 #endif 660 #if defined(SO_SNDTIMEO) 661 case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: 662 #ifdef OPENSSL_SYS_WINDOWS 663 { 664 struct timeval *tv = (struct timeval *)ptr; 665 int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; 666 if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 667 (void*)&timeout, sizeof(timeout)) < 0) 668 { perror("setsockopt"); ret = -1; } 669 } 670 #else 671 if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, 672 sizeof(struct timeval)) < 0) 673 { perror("setsockopt"); ret = -1; } 674 #endif 675 break; 676 case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: 677 #ifdef OPENSSL_SYS_WINDOWS 678 { 679 int timeout, sz = sizeof(timeout); 680 struct timeval *tv = (struct timeval *)ptr; 681 if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 682 (void*)&timeout, &sz) < 0) 683 { perror("getsockopt"); ret = -1; } 684 else 685 { 686 tv->tv_sec = timeout / 1000; 687 tv->tv_usec = (timeout % 1000) * 1000; 688 ret = sizeof(*tv); 689 } 690 } 691 #else 692 if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, 693 ptr, (void *)&ret) < 0) 694 { perror("getsockopt"); ret = -1; } 695 #endif 696 break; 697 #endif 698 case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: 699 /* fall-through */ 700 case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: 701 #ifdef OPENSSL_SYS_WINDOWS 702 if ( data->_errno == WSAETIMEDOUT) 703 #else 704 if ( data->_errno == EAGAIN) 705 #endif 706 { 707 ret = 1; 708 data->_errno = 0; 709 } 710 else 711 ret = 0; 712 break; 713 #ifdef EMSGSIZE 714 case BIO_CTRL_DGRAM_MTU_EXCEEDED: 715 if ( data->_errno == EMSGSIZE) 716 { 717 ret = 1; 718 data->_errno = 0; 719 } 720 else 721 ret = 0; 722 break; 723 #endif 724 default: 725 ret=0; 726 break; 727 } 728 return(ret); 729 } 730 731 static int dgram_puts(BIO *bp, const char *str) 732 { 733 int n,ret; 734 735 n=strlen(str); 736 ret=dgram_write(bp,str,n); 737 return(ret); 738 } 739 740 static int BIO_dgram_should_retry(int i) 741 { 742 int err; 743 744 if ((i == 0) || (i == -1)) 745 { 746 err=get_last_socket_error(); 747 748 #if defined(OPENSSL_SYS_WINDOWS) && 0 /* more microsoft stupidity? perhaps not? Ben 4/1/99 */ 749 if ((i == -1) && (err == 0)) 750 return(1); 751 #endif 752 753 return(BIO_dgram_non_fatal_error(err)); 754 } 755 return(0); 756 } 757 758 int BIO_dgram_non_fatal_error(int err) 759 { 760 switch (err) 761 { 762 #if defined(OPENSSL_SYS_WINDOWS) 763 # if defined(WSAEWOULDBLOCK) 764 case WSAEWOULDBLOCK: 765 # endif 766 767 # if 0 /* This appears to always be an error */ 768 # if defined(WSAENOTCONN) 769 case WSAENOTCONN: 770 # endif 771 # endif 772 #endif 773 774 #ifdef EWOULDBLOCK 775 # ifdef WSAEWOULDBLOCK 776 # if WSAEWOULDBLOCK != EWOULDBLOCK 777 case EWOULDBLOCK: 778 # endif 779 # else 780 case EWOULDBLOCK: 781 # endif 782 #endif 783 784 #ifdef EINTR 785 case EINTR: 786 #endif 787 788 #ifdef EAGAIN 789 #if EWOULDBLOCK != EAGAIN 790 case EAGAIN: 791 # endif 792 #endif 793 794 #ifdef EPROTO 795 case EPROTO: 796 #endif 797 798 #ifdef EINPROGRESS 799 case EINPROGRESS: 800 #endif 801 802 #ifdef EALREADY 803 case EALREADY: 804 #endif 805 806 return(1); 807 /* break; */ 808 default: 809 break; 810 } 811 return(0); 812 } 813 #endif 814 815 static void get_current_time(struct timeval *t) 816 { 817 #ifdef OPENSSL_SYS_WIN32 818 struct _timeb tb; 819 _ftime(&tb); 820 t->tv_sec = (long)tb.time; 821 t->tv_usec = (long)tb.millitm * 1000; 822 #elif defined(OPENSSL_SYS_VMS) 823 struct timeb tb; 824 ftime(&tb); 825 t->tv_sec = (long)tb.time; 826 t->tv_usec = (long)tb.millitm * 1000; 827 #else 828 gettimeofday(t, NULL); 829 #endif 830 } 831