Home | History | Annotate | Download | only in bio
      1 /* crypto/bio/bio_dgram.c */
      2 /*
      3  * DTLS implementation written by Nagendra Modadugu
      4  * (nagendra (at) 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 (at) 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 (at) cryptsoft.com).  This product includes software written by Tim
     56  * Hudson (tjh (at) 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