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