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