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