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