bss_dgram.c revision 21c841450af61d0a9119cdc863e93d019127bfe1
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
61#include <stdio.h>
62#include <errno.h>
63#define USE_SOCKETS
64#include "cryptlib.h"
65
66#include <openssl/bio.h>
67#ifndef OPENSSL_NO_DGRAM
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
312		if ( ! data->connected  && ret >= 0)
313			BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer);
314
315		BIO_clear_retry_flags(b);
316		if (ret < 0)
317			{
318			if (BIO_dgram_should_retry(ret))
319				{
320				BIO_set_retry_read(b);
321				data->_errno = get_last_socket_error();
322				}
323			}
324
325		dgram_reset_rcv_timeout(b);
326		}
327	return(ret);
328	}
329
330static int dgram_write(BIO *b, const char *in, int inl)
331	{
332	int ret;
333	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
334	clear_socket_error();
335
336	if ( data->connected )
337		ret=writesocket(b->num,in,inl);
338	else
339		{
340		int peerlen = sizeof(data->peer);
341
342		if (data->peer.sa.sa_family == AF_INET)
343			peerlen = sizeof(data->peer.sa_in);
344#if OPENSSL_USE_IPV6
345		else if (data->peer.sa.sa_family == AF_INET6)
346			peerlen = sizeof(data->peer.sa_in6);
347#endif
348#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
349		ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen);
350#else
351		ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen);
352#endif
353		}
354
355	BIO_clear_retry_flags(b);
356	if (ret <= 0)
357		{
358		if (BIO_dgram_should_retry(ret))
359			{
360			BIO_set_retry_write(b);
361			data->_errno = get_last_socket_error();
362
363#if 0 /* higher layers are responsible for querying MTU, if necessary */
364			if ( data->_errno == EMSGSIZE)
365				/* retrieve the new MTU */
366				BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
367#endif
368			}
369		}
370	return(ret);
371	}
372
373static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
374	{
375	long ret=1;
376	int *ip;
377	struct sockaddr *to = NULL;
378	bio_dgram_data *data = NULL;
379#if defined(IP_MTU_DISCOVER) || defined(IP_MTU)
380	long sockopt_val = 0;
381	unsigned int sockopt_len = 0;
382#endif
383#ifdef OPENSSL_SYS_LINUX
384	socklen_t addr_len;
385	union	{
386		struct sockaddr	sa;
387		struct sockaddr_in s4;
388#if OPENSSL_USE_IPV6
389		struct sockaddr_in6 s6;
390#endif
391		} addr;
392#endif
393
394	data = (bio_dgram_data *)b->ptr;
395
396	switch (cmd)
397		{
398	case BIO_CTRL_RESET:
399		num=0;
400	case BIO_C_FILE_SEEK:
401		ret=0;
402		break;
403	case BIO_C_FILE_TELL:
404	case BIO_CTRL_INFO:
405		ret=0;
406		break;
407	case BIO_C_SET_FD:
408		dgram_clear(b);
409		b->num= *((int *)ptr);
410		b->shutdown=(int)num;
411		b->init=1;
412		break;
413	case BIO_C_GET_FD:
414		if (b->init)
415			{
416			ip=(int *)ptr;
417			if (ip != NULL) *ip=b->num;
418			ret=b->num;
419			}
420		else
421			ret= -1;
422		break;
423	case BIO_CTRL_GET_CLOSE:
424		ret=b->shutdown;
425		break;
426	case BIO_CTRL_SET_CLOSE:
427		b->shutdown=(int)num;
428		break;
429	case BIO_CTRL_PENDING:
430	case BIO_CTRL_WPENDING:
431		ret=0;
432		break;
433	case BIO_CTRL_DUP:
434	case BIO_CTRL_FLUSH:
435		ret=1;
436		break;
437	case BIO_CTRL_DGRAM_CONNECT:
438		to = (struct sockaddr *)ptr;
439#if 0
440		if (connect(b->num, to, sizeof(struct sockaddr)) < 0)
441			{ perror("connect"); ret = 0; }
442		else
443			{
444#endif
445			switch (to->sa_family)
446				{
447				case AF_INET:
448					memcpy(&data->peer,to,sizeof(data->peer.sa_in));
449					break;
450#if OPENSSL_USE_IPV6
451				case AF_INET6:
452					memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
453					break;
454#endif
455				default:
456					memcpy(&data->peer,to,sizeof(data->peer.sa));
457					break;
458				}
459#if 0
460			}
461#endif
462		break;
463		/* (Linux)kernel sets DF bit on outgoing IP packets */
464	case BIO_CTRL_DGRAM_MTU_DISCOVER:
465#ifdef OPENSSL_SYS_LINUX
466		addr_len = (socklen_t)sizeof(addr);
467		memset((void *)&addr, 0, sizeof(addr));
468		if (getsockname(b->num, &addr.sa, &addr_len) < 0)
469			{
470			ret = 0;
471			break;
472			}
473		sockopt_len = sizeof(sockopt_val);
474		switch (addr.sa.sa_family)
475			{
476		case AF_INET:
477			sockopt_val = IP_PMTUDISC_DO;
478			if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
479				&sockopt_val, sizeof(sockopt_val))) < 0)
480				perror("setsockopt");
481			break;
482#if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER)
483		case AF_INET6:
484			sockopt_val = IPV6_PMTUDISC_DO;
485			if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
486				&sockopt_val, sizeof(sockopt_val))) < 0)
487				perror("setsockopt");
488			break;
489#endif
490		default:
491			ret = -1;
492			break;
493			}
494		ret = -1;
495#else
496		break;
497#endif
498	case BIO_CTRL_DGRAM_QUERY_MTU:
499#ifdef OPENSSL_SYS_LINUX
500		addr_len = (socklen_t)sizeof(addr);
501		memset((void *)&addr, 0, sizeof(addr));
502		if (getsockname(b->num, &addr.sa, &addr_len) < 0)
503			{
504			ret = 0;
505			break;
506			}
507		sockopt_len = sizeof(sockopt_val);
508		switch (addr.sa.sa_family)
509			{
510		case AF_INET:
511			if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val,
512				&sockopt_len)) < 0 || sockopt_val < 0)
513				{
514				ret = 0;
515				}
516			else
517				{
518				/* we assume that the transport protocol is UDP and no
519				 * IP options are used.
520				 */
521				data->mtu = sockopt_val - 8 - 20;
522				ret = data->mtu;
523				}
524			break;
525#if OPENSSL_USE_IPV6 && defined(IPV6_MTU)
526		case AF_INET6:
527			if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val,
528				&sockopt_len)) < 0 || sockopt_val < 0)
529				{
530				ret = 0;
531				}
532			else
533				{
534				/* we assume that the transport protocol is UDP and no
535				 * IPV6 options are used.
536				 */
537				data->mtu = sockopt_val - 8 - 40;
538				ret = data->mtu;
539				}
540			break;
541#endif
542		default:
543			ret = 0;
544			break;
545			}
546#else
547		ret = 0;
548#endif
549		break;
550	case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
551		switch (data->peer.sa.sa_family)
552			{
553			case AF_INET:
554				ret = 576 - 20 - 8;
555				break;
556#if OPENSSL_USE_IPV6
557			case AF_INET6:
558#ifdef IN6_IS_ADDR_V4MAPPED
559				if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr))
560					ret = 576 - 20 - 8;
561				else
562#endif
563					ret = 1280 - 40 - 8;
564				break;
565#endif
566			default:
567				ret = 576 - 20 - 8;
568				break;
569			}
570		break;
571	case BIO_CTRL_DGRAM_GET_MTU:
572		return data->mtu;
573		break;
574	case BIO_CTRL_DGRAM_SET_MTU:
575		data->mtu = num;
576		ret = num;
577		break;
578	case BIO_CTRL_DGRAM_SET_CONNECTED:
579		to = (struct sockaddr *)ptr;
580
581		if ( to != NULL)
582			{
583			data->connected = 1;
584			switch (to->sa_family)
585				{
586				case AF_INET:
587					memcpy(&data->peer,to,sizeof(data->peer.sa_in));
588					break;
589#if OPENSSL_USE_IPV6
590				case AF_INET6:
591					memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
592					break;
593#endif
594				default:
595					memcpy(&data->peer,to,sizeof(data->peer.sa));
596					break;
597				}
598			}
599		else
600			{
601			data->connected = 0;
602			memset(&(data->peer), 0x00, sizeof(data->peer));
603			}
604		break;
605	case BIO_CTRL_DGRAM_GET_PEER:
606		switch (data->peer.sa.sa_family)
607			{
608			case AF_INET:
609				ret=sizeof(data->peer.sa_in);
610				break;
611#if OPENSSL_USE_IPV6
612			case AF_INET6:
613				ret=sizeof(data->peer.sa_in6);
614				break;
615#endif
616			default:
617				ret=sizeof(data->peer.sa);
618				break;
619			}
620		if (num==0 || num>ret)
621			num=ret;
622		memcpy(ptr,&data->peer,(ret=num));
623		break;
624	case BIO_CTRL_DGRAM_SET_PEER:
625		to = (struct sockaddr *) ptr;
626		switch (to->sa_family)
627			{
628			case AF_INET:
629				memcpy(&data->peer,to,sizeof(data->peer.sa_in));
630				break;
631#if OPENSSL_USE_IPV6
632			case AF_INET6:
633				memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
634				break;
635#endif
636			default:
637				memcpy(&data->peer,to,sizeof(data->peer.sa));
638				break;
639			}
640		break;
641	case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
642		memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
643		break;
644#if defined(SO_RCVTIMEO)
645	case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
646#ifdef OPENSSL_SYS_WINDOWS
647		{
648		struct timeval *tv = (struct timeval *)ptr;
649		int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
650		if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
651			(void*)&timeout, sizeof(timeout)) < 0)
652			{ perror("setsockopt"); ret = -1; }
653		}
654#else
655		if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
656			sizeof(struct timeval)) < 0)
657			{ perror("setsockopt");	ret = -1; }
658#endif
659		break;
660	case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
661#ifdef OPENSSL_SYS_WINDOWS
662		{
663		int timeout, sz = sizeof(timeout);
664		struct timeval *tv = (struct timeval *)ptr;
665		if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
666			(void*)&timeout, &sz) < 0)
667			{ perror("getsockopt"); ret = -1; }
668		else
669			{
670			tv->tv_sec = timeout / 1000;
671			tv->tv_usec = (timeout % 1000) * 1000;
672			ret = sizeof(*tv);
673			}
674		}
675#else
676		if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
677			ptr, (void *)&ret) < 0)
678			{ perror("getsockopt"); ret = -1; }
679#endif
680		break;
681#endif
682#if defined(SO_SNDTIMEO)
683	case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
684#ifdef OPENSSL_SYS_WINDOWS
685		{
686		struct timeval *tv = (struct timeval *)ptr;
687		int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
688		if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
689			(void*)&timeout, sizeof(timeout)) < 0)
690			{ perror("setsockopt"); ret = -1; }
691		}
692#else
693		if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
694			sizeof(struct timeval)) < 0)
695			{ perror("setsockopt");	ret = -1; }
696#endif
697		break;
698	case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
699#ifdef OPENSSL_SYS_WINDOWS
700		{
701		int timeout, sz = sizeof(timeout);
702		struct timeval *tv = (struct timeval *)ptr;
703		if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
704			(void*)&timeout, &sz) < 0)
705			{ perror("getsockopt"); ret = -1; }
706		else
707			{
708			tv->tv_sec = timeout / 1000;
709			tv->tv_usec = (timeout % 1000) * 1000;
710			ret = sizeof(*tv);
711			}
712		}
713#else
714		if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
715			ptr, (void *)&ret) < 0)
716			{ perror("getsockopt"); ret = -1; }
717#endif
718		break;
719#endif
720	case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
721		/* fall-through */
722	case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
723#ifdef OPENSSL_SYS_WINDOWS
724		if ( data->_errno == WSAETIMEDOUT)
725#else
726		if ( data->_errno == EAGAIN)
727#endif
728			{
729			ret = 1;
730			data->_errno = 0;
731			}
732		else
733			ret = 0;
734		break;
735#ifdef EMSGSIZE
736	case BIO_CTRL_DGRAM_MTU_EXCEEDED:
737		if ( data->_errno == EMSGSIZE)
738			{
739			ret = 1;
740			data->_errno = 0;
741			}
742		else
743			ret = 0;
744		break;
745#endif
746	default:
747		ret=0;
748		break;
749		}
750	return(ret);
751	}
752
753static int dgram_puts(BIO *bp, const char *str)
754	{
755	int n,ret;
756
757	n=strlen(str);
758	ret=dgram_write(bp,str,n);
759	return(ret);
760	}
761
762static int BIO_dgram_should_retry(int i)
763	{
764	int err;
765
766	if ((i == 0) || (i == -1))
767		{
768		err=get_last_socket_error();
769
770#if defined(OPENSSL_SYS_WINDOWS)
771	/* If the socket return value (i) is -1
772	 * and err is unexpectedly 0 at this point,
773	 * the error code was overwritten by
774	 * another system call before this error
775	 * handling is called.
776	 */
777#endif
778
779		return(BIO_dgram_non_fatal_error(err));
780		}
781	return(0);
782	}
783
784int BIO_dgram_non_fatal_error(int err)
785	{
786	switch (err)
787		{
788#if defined(OPENSSL_SYS_WINDOWS)
789# if defined(WSAEWOULDBLOCK)
790	case WSAEWOULDBLOCK:
791# endif
792
793# if 0 /* This appears to always be an error */
794#  if defined(WSAENOTCONN)
795	case WSAENOTCONN:
796#  endif
797# endif
798#endif
799
800#ifdef EWOULDBLOCK
801# ifdef WSAEWOULDBLOCK
802#  if WSAEWOULDBLOCK != EWOULDBLOCK
803	case EWOULDBLOCK:
804#  endif
805# else
806	case EWOULDBLOCK:
807# endif
808#endif
809
810#ifdef EINTR
811	case EINTR:
812#endif
813
814#ifdef EAGAIN
815#if EWOULDBLOCK != EAGAIN
816	case EAGAIN:
817# endif
818#endif
819
820#ifdef EPROTO
821	case EPROTO:
822#endif
823
824#ifdef EINPROGRESS
825	case EINPROGRESS:
826#endif
827
828#ifdef EALREADY
829	case EALREADY:
830#endif
831
832		return(1);
833		/* break; */
834	default:
835		break;
836		}
837	return(0);
838	}
839
840static void get_current_time(struct timeval *t)
841	{
842#ifdef OPENSSL_SYS_WIN32
843	struct _timeb tb;
844	_ftime(&tb);
845	t->tv_sec = (long)tb.time;
846	t->tv_usec = (long)tb.millitm * 1000;
847#elif defined(OPENSSL_SYS_VMS)
848	struct timeb tb;
849	ftime(&tb);
850	t->tv_sec = (long)tb.time;
851	t->tv_usec = (long)tb.millitm * 1000;
852#else
853	gettimeofday(t, NULL);
854#endif
855	}
856
857#endif
858