• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/openssl-1.0.0q/crypto/bio/
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	union { size_t s; int i; } sz = {0};
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
200		sz.i = sizeof(timeout);
201		if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
202					   (void*)&timeout, &sz.i) < 0)
203			{ perror("getsockopt"); }
204		else
205			{
206			data->socket_timeout.tv_sec = timeout / 1000;
207			data->socket_timeout.tv_usec = (timeout % 1000) * 1000;
208			}
209#else
210		sz.i = sizeof(data->socket_timeout);
211		if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
212						&(data->socket_timeout), (void *)&sz) < 0)
213			{ perror("getsockopt"); }
214		else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
215			OPENSSL_assert(sz.s<=sizeof(data->socket_timeout));
216#endif
217
218		/* Get current time */
219		get_current_time(&timenow);
220
221		/* Calculate time left until timer expires */
222		memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval));
223		timeleft.tv_sec -= timenow.tv_sec;
224		timeleft.tv_usec -= timenow.tv_usec;
225		if (timeleft.tv_usec < 0)
226			{
227			timeleft.tv_sec--;
228			timeleft.tv_usec += 1000000;
229			}
230
231		if (timeleft.tv_sec < 0)
232			{
233			timeleft.tv_sec = 0;
234			timeleft.tv_usec = 1;
235			}
236
237		/* Adjust socket timeout if next handhake message timer
238		 * will expire earlier.
239		 */
240		if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) ||
241			(data->socket_timeout.tv_sec > timeleft.tv_sec) ||
242			(data->socket_timeout.tv_sec == timeleft.tv_sec &&
243			 data->socket_timeout.tv_usec >= timeleft.tv_usec))
244			{
245#ifdef OPENSSL_SYS_WINDOWS
246			timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000;
247			if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
248						   (void*)&timeout, sizeof(timeout)) < 0)
249				{ perror("setsockopt"); }
250#else
251			if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft,
252							sizeof(struct timeval)) < 0)
253				{ perror("setsockopt"); }
254#endif
255			}
256		}
257#endif
258	}
259
260static void dgram_reset_rcv_timeout(BIO *b)
261	{
262#if defined(SO_RCVTIMEO)
263	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
264
265	/* Is a timer active? */
266	if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0)
267		{
268#ifdef OPENSSL_SYS_WINDOWS
269		int timeout = data->socket_timeout.tv_sec * 1000 +
270					  data->socket_timeout.tv_usec / 1000;
271		if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
272					   (void*)&timeout, sizeof(timeout)) < 0)
273			{ perror("setsockopt"); }
274#else
275		if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout),
276						sizeof(struct timeval)) < 0)
277			{ perror("setsockopt"); }
278#endif
279		}
280#endif
281	}
282
283static int dgram_read(BIO *b, char *out, int outl)
284	{
285	int ret=0;
286	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
287
288	struct	{
289	/*
290	 * See commentary in b_sock.c. <appro>
291	 */
292	union	{ size_t s; int i; } len;
293	union	{
294		struct sockaddr sa;
295		struct sockaddr_in sa_in;
296#if OPENSSL_USE_IPV6
297		struct sockaddr_in6 sa_in6;
298#endif
299		} peer;
300	} sa;
301
302	sa.len.s=0;
303	sa.len.i=sizeof(sa.peer);
304
305	if (out != NULL)
306		{
307		clear_socket_error();
308		memset(&sa.peer, 0x00, sizeof(sa.peer));
309		dgram_adjust_rcv_timeout(b);
310		ret=recvfrom(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len);
311		if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0)
312			{
313			OPENSSL_assert(sa.len.s<=sizeof(sa.peer));
314			sa.len.i = (int)sa.len.s;
315			}
316
317		if ( ! data->connected  && ret >= 0)
318			BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer);
319
320		BIO_clear_retry_flags(b);
321		if (ret < 0)
322			{
323			if (BIO_dgram_should_retry(ret))
324				{
325				BIO_set_retry_read(b);
326				data->_errno = get_last_socket_error();
327				}
328			}
329
330		dgram_reset_rcv_timeout(b);
331		}
332	return(ret);
333	}
334
335static int dgram_write(BIO *b, const char *in, int inl)
336	{
337	int ret;
338	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
339	clear_socket_error();
340
341	if ( data->connected )
342		ret=writesocket(b->num,in,inl);
343	else
344		{
345		int peerlen = sizeof(data->peer);
346
347		if (data->peer.sa.sa_family == AF_INET)
348			peerlen = sizeof(data->peer.sa_in);
349#if OPENSSL_USE_IPV6
350		else if (data->peer.sa.sa_family == AF_INET6)
351			peerlen = sizeof(data->peer.sa_in6);
352#endif
353#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
354		ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen);
355#else
356		ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen);
357#endif
358		}
359
360	BIO_clear_retry_flags(b);
361	if (ret <= 0)
362		{
363		if (BIO_dgram_should_retry(ret))
364			{
365			BIO_set_retry_write(b);
366			data->_errno = get_last_socket_error();
367
368#if 0 /* higher layers are responsible for querying MTU, if necessary */
369			if ( data->_errno == EMSGSIZE)
370				/* retrieve the new MTU */
371				BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
372#endif
373			}
374		}
375	return(ret);
376	}
377
378static long dgram_get_mtu_overhead(bio_dgram_data *data)
379	{
380	long ret;
381
382	switch (data->peer.sa.sa_family)
383		{
384		case AF_INET:
385			/* Assume this is UDP - 20 bytes for IP, 8 bytes for UDP */
386			ret = 28;
387			break;
388#if OPENSSL_USE_IPV6
389		case AF_INET6:
390#ifdef IN6_IS_ADDR_V4MAPPED
391			if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr))
392				/* Assume this is UDP - 20 bytes for IP, 8 bytes for UDP */
393				ret = 28;
394			else
395#endif
396				/* Assume this is UDP - 40 bytes for IP, 8 bytes for UDP */
397				ret = 48;
398			break;
399#endif
400		default:
401			/* We don't know. Go with the historical default */
402			ret = 28;
403			break;
404		}
405	return ret;
406	}
407
408static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
409	{
410	long ret=1;
411	int *ip;
412	struct sockaddr *to = NULL;
413	bio_dgram_data *data = NULL;
414#if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU))
415	int sockopt_val = 0;
416	socklen_t sockopt_len;	/* assume that system supporting IP_MTU is
417				 * modern enough to define socklen_t */
418	socklen_t addr_len;
419	union	{
420		struct sockaddr	sa;
421		struct sockaddr_in s4;
422#if OPENSSL_USE_IPV6
423		struct sockaddr_in6 s6;
424#endif
425		} addr;
426#endif
427
428	data = (bio_dgram_data *)b->ptr;
429
430	switch (cmd)
431		{
432	case BIO_CTRL_RESET:
433		num=0;
434	case BIO_C_FILE_SEEK:
435		ret=0;
436		break;
437	case BIO_C_FILE_TELL:
438	case BIO_CTRL_INFO:
439		ret=0;
440		break;
441	case BIO_C_SET_FD:
442		dgram_clear(b);
443		b->num= *((int *)ptr);
444		b->shutdown=(int)num;
445		b->init=1;
446		break;
447	case BIO_C_GET_FD:
448		if (b->init)
449			{
450			ip=(int *)ptr;
451			if (ip != NULL) *ip=b->num;
452			ret=b->num;
453			}
454		else
455			ret= -1;
456		break;
457	case BIO_CTRL_GET_CLOSE:
458		ret=b->shutdown;
459		break;
460	case BIO_CTRL_SET_CLOSE:
461		b->shutdown=(int)num;
462		break;
463	case BIO_CTRL_PENDING:
464	case BIO_CTRL_WPENDING:
465		ret=0;
466		break;
467	case BIO_CTRL_DUP:
468	case BIO_CTRL_FLUSH:
469		ret=1;
470		break;
471	case BIO_CTRL_DGRAM_CONNECT:
472		to = (struct sockaddr *)ptr;
473#if 0
474		if (connect(b->num, to, sizeof(struct sockaddr)) < 0)
475			{ perror("connect"); ret = 0; }
476		else
477			{
478#endif
479			switch (to->sa_family)
480				{
481				case AF_INET:
482					memcpy(&data->peer,to,sizeof(data->peer.sa_in));
483					break;
484#if OPENSSL_USE_IPV6
485				case AF_INET6:
486					memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
487					break;
488#endif
489				default:
490					memcpy(&data->peer,to,sizeof(data->peer.sa));
491					break;
492				}
493#if 0
494			}
495#endif
496		break;
497		/* (Linux)kernel sets DF bit on outgoing IP packets */
498	case BIO_CTRL_DGRAM_MTU_DISCOVER:
499#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO)
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		switch (addr.sa.sa_family)
508			{
509		case AF_INET:
510			sockopt_val = IP_PMTUDISC_DO;
511			if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
512				&sockopt_val, sizeof(sockopt_val))) < 0)
513				perror("setsockopt");
514			break;
515#if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO)
516		case AF_INET6:
517			sockopt_val = IPV6_PMTUDISC_DO;
518			if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
519				&sockopt_val, sizeof(sockopt_val))) < 0)
520				perror("setsockopt");
521			break;
522#endif
523		default:
524			ret = -1;
525			break;
526			}
527		ret = -1;
528#else
529		break;
530#endif
531	case BIO_CTRL_DGRAM_QUERY_MTU:
532#if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU)
533		addr_len = (socklen_t)sizeof(addr);
534		memset((void *)&addr, 0, sizeof(addr));
535		if (getsockname(b->num, &addr.sa, &addr_len) < 0)
536			{
537			ret = 0;
538			break;
539			}
540		sockopt_len = sizeof(sockopt_val);
541		switch (addr.sa.sa_family)
542			{
543		case AF_INET:
544			if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val,
545				&sockopt_len)) < 0 || sockopt_val < 0)
546				{
547				ret = 0;
548				}
549			else
550				{
551				/* we assume that the transport protocol is UDP and no
552				 * IP options are used.
553				 */
554				data->mtu = sockopt_val - 8 - 20;
555				ret = data->mtu;
556				}
557			break;
558#if OPENSSL_USE_IPV6 && defined(IPV6_MTU)
559		case AF_INET6:
560			if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val,
561				&sockopt_len)) < 0 || sockopt_val < 0)
562				{
563				ret = 0;
564				}
565			else
566				{
567				/* we assume that the transport protocol is UDP and no
568				 * IPV6 options are used.
569				 */
570				data->mtu = sockopt_val - 8 - 40;
571				ret = data->mtu;
572				}
573			break;
574#endif
575		default:
576			ret = 0;
577			break;
578			}
579#else
580		ret = 0;
581#endif
582		break;
583	case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
584		ret = -dgram_get_mtu_overhead(data);
585		switch (data->peer.sa.sa_family)
586			{
587			case AF_INET:
588				ret += 576;
589				break;
590#if OPENSSL_USE_IPV6
591			case AF_INET6:
592#ifdef IN6_IS_ADDR_V4MAPPED
593				if (IN6_IS_ADDR_V4MAPPED(&data->peer.sa_in6.sin6_addr))
594					ret += 576;
595				else
596#endif
597					ret += 1280;
598				break;
599#endif
600			default:
601				ret += 576;
602				break;
603			}
604		break;
605	case BIO_CTRL_DGRAM_GET_MTU:
606		return data->mtu;
607		break;
608	case BIO_CTRL_DGRAM_SET_MTU:
609		data->mtu = num;
610		ret = num;
611		break;
612	case BIO_CTRL_DGRAM_SET_CONNECTED:
613		to = (struct sockaddr *)ptr;
614
615		if ( to != NULL)
616			{
617			data->connected = 1;
618			switch (to->sa_family)
619				{
620				case AF_INET:
621					memcpy(&data->peer,to,sizeof(data->peer.sa_in));
622					break;
623#if OPENSSL_USE_IPV6
624				case AF_INET6:
625					memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
626					break;
627#endif
628				default:
629					memcpy(&data->peer,to,sizeof(data->peer.sa));
630					break;
631				}
632			}
633		else
634			{
635			data->connected = 0;
636			memset(&(data->peer), 0x00, sizeof(data->peer));
637			}
638		break;
639	case BIO_CTRL_DGRAM_GET_PEER:
640		switch (data->peer.sa.sa_family)
641			{
642			case AF_INET:
643				ret=sizeof(data->peer.sa_in);
644				break;
645#if OPENSSL_USE_IPV6
646			case AF_INET6:
647				ret=sizeof(data->peer.sa_in6);
648				break;
649#endif
650			default:
651				ret=sizeof(data->peer.sa);
652				break;
653			}
654		if (num==0 || num>ret)
655			num=ret;
656		memcpy(ptr,&data->peer,(ret=num));
657		break;
658	case BIO_CTRL_DGRAM_SET_PEER:
659		to = (struct sockaddr *) ptr;
660		switch (to->sa_family)
661			{
662			case AF_INET:
663				memcpy(&data->peer,to,sizeof(data->peer.sa_in));
664				break;
665#if OPENSSL_USE_IPV6
666			case AF_INET6:
667				memcpy(&data->peer,to,sizeof(data->peer.sa_in6));
668				break;
669#endif
670			default:
671				memcpy(&data->peer,to,sizeof(data->peer.sa));
672				break;
673			}
674		break;
675	case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
676		memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
677		break;
678#if defined(SO_RCVTIMEO)
679	case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
680#ifdef OPENSSL_SYS_WINDOWS
681		{
682		struct timeval *tv = (struct timeval *)ptr;
683		int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
684		if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
685			(void*)&timeout, sizeof(timeout)) < 0)
686			{ perror("setsockopt"); ret = -1; }
687		}
688#else
689		if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
690			sizeof(struct timeval)) < 0)
691			{ perror("setsockopt");	ret = -1; }
692#endif
693		break;
694	case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
695		{
696		union { size_t s; int i; } sz = {0};
697#ifdef OPENSSL_SYS_WINDOWS
698		int timeout;
699		struct timeval *tv = (struct timeval *)ptr;
700
701		sz.i = sizeof(timeout);
702		if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
703			(void*)&timeout, &sz.i) < 0)
704			{ perror("getsockopt"); ret = -1; }
705		else
706			{
707			tv->tv_sec = timeout / 1000;
708			tv->tv_usec = (timeout % 1000) * 1000;
709			ret = sizeof(*tv);
710			}
711#else
712		sz.i = sizeof(struct timeval);
713		if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
714			ptr, (void *)&sz) < 0)
715			{ perror("getsockopt"); ret = -1; }
716		else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
717			{
718			OPENSSL_assert(sz.s<=sizeof(struct timeval));
719			ret = (int)sz.s;
720			}
721		else
722			ret = sz.i;
723#endif
724		}
725		break;
726#endif
727#if defined(SO_SNDTIMEO)
728	case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
729#ifdef OPENSSL_SYS_WINDOWS
730		{
731		struct timeval *tv = (struct timeval *)ptr;
732		int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
733		if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
734			(void*)&timeout, sizeof(timeout)) < 0)
735			{ perror("setsockopt"); ret = -1; }
736		}
737#else
738		if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
739			sizeof(struct timeval)) < 0)
740			{ perror("setsockopt");	ret = -1; }
741#endif
742		break;
743	case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
744		{
745		union { size_t s; int i; } sz = {0};
746#ifdef OPENSSL_SYS_WINDOWS
747		int timeout;
748		struct timeval *tv = (struct timeval *)ptr;
749
750		sz.i = sizeof(timeout);
751		if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
752			(void*)&timeout, &sz.i) < 0)
753			{ perror("getsockopt"); ret = -1; }
754		else
755			{
756			tv->tv_sec = timeout / 1000;
757			tv->tv_usec = (timeout % 1000) * 1000;
758			ret = sizeof(*tv);
759			}
760#else
761		sz.i = sizeof(struct timeval);
762		if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
763			ptr, (void *)&sz) < 0)
764			{ perror("getsockopt"); ret = -1; }
765		else if (sizeof(sz.s)!=sizeof(sz.i) && sz.i==0)
766			{
767			OPENSSL_assert(sz.s<=sizeof(struct timeval));
768			ret = (int)sz.s;
769			}
770		else
771			ret = sz.i;
772#endif
773		}
774		break;
775#endif
776	case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
777		/* fall-through */
778	case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
779#ifdef OPENSSL_SYS_WINDOWS
780		if ( data->_errno == WSAETIMEDOUT)
781#else
782		if ( data->_errno == EAGAIN)
783#endif
784			{
785			ret = 1;
786			data->_errno = 0;
787			}
788		else
789			ret = 0;
790		break;
791#ifdef EMSGSIZE
792	case BIO_CTRL_DGRAM_MTU_EXCEEDED:
793		if ( data->_errno == EMSGSIZE)
794			{
795			ret = 1;
796			data->_errno = 0;
797			}
798		else
799			ret = 0;
800		break;
801#endif
802	case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD:
803		ret = dgram_get_mtu_overhead(data);
804		break;
805	default:
806		ret=0;
807		break;
808		}
809	return(ret);
810	}
811
812static int dgram_puts(BIO *bp, const char *str)
813	{
814	int n,ret;
815
816	n=strlen(str);
817	ret=dgram_write(bp,str,n);
818	return(ret);
819	}
820
821static int BIO_dgram_should_retry(int i)
822	{
823	int err;
824
825	if ((i == 0) || (i == -1))
826		{
827		err=get_last_socket_error();
828
829#if defined(OPENSSL_SYS_WINDOWS)
830	/* If the socket return value (i) is -1
831	 * and err is unexpectedly 0 at this point,
832	 * the error code was overwritten by
833	 * another system call before this error
834	 * handling is called.
835	 */
836#endif
837
838		return(BIO_dgram_non_fatal_error(err));
839		}
840	return(0);
841	}
842
843int BIO_dgram_non_fatal_error(int err)
844	{
845	switch (err)
846		{
847#if defined(OPENSSL_SYS_WINDOWS)
848# if defined(WSAEWOULDBLOCK)
849	case WSAEWOULDBLOCK:
850# endif
851
852# if 0 /* This appears to always be an error */
853#  if defined(WSAENOTCONN)
854	case WSAENOTCONN:
855#  endif
856# endif
857#endif
858
859#ifdef EWOULDBLOCK
860# ifdef WSAEWOULDBLOCK
861#  if WSAEWOULDBLOCK != EWOULDBLOCK
862	case EWOULDBLOCK:
863#  endif
864# else
865	case EWOULDBLOCK:
866# endif
867#endif
868
869#ifdef EINTR
870	case EINTR:
871#endif
872
873#ifdef EAGAIN
874#if EWOULDBLOCK != EAGAIN
875	case EAGAIN:
876# endif
877#endif
878
879#ifdef EPROTO
880	case EPROTO:
881#endif
882
883#ifdef EINPROGRESS
884	case EINPROGRESS:
885#endif
886
887#ifdef EALREADY
888	case EALREADY:
889#endif
890
891		return(1);
892		/* break; */
893	default:
894		break;
895		}
896	return(0);
897	}
898
899static void get_current_time(struct timeval *t)
900	{
901#ifdef OPENSSL_SYS_WIN32
902	struct _timeb tb;
903	_ftime(&tb);
904	t->tv_sec = (long)tb.time;
905	t->tv_usec = (long)tb.millitm * 1000;
906#elif defined(OPENSSL_SYS_VMS)
907	struct timeb tb;
908	ftime(&tb);
909	t->tv_sec = (long)tb.time;
910	t->tv_usec = (long)tb.millitm * 1000;
911#else
912	gettimeofday(t, NULL);
913#endif
914	}
915
916#endif
917