bss_dgram.c revision 81c4de7869b646592127e952cda763abf8305069
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	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
125BIO_METHOD *BIO_s_datagram(void)
126	{
127	return(&methods_dgramp);
128	}
129
130BIO *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
140static 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
156static 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
170static 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
185static 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
255static 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
278static 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
329static 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_IPV6
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
372static 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
731static 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
740static 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
758int 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
815static 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