bss_dgram.c revision 237998
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	struct sockaddr peer;
112	unsigned int connected;
113	unsigned int _errno;
114	unsigned int mtu;
115	struct timeval next_timeout;
116	struct timeval socket_timeout;
117	} bio_dgram_data;
118
119BIO_METHOD *BIO_s_datagram(void)
120	{
121	return(&methods_dgramp);
122	}
123
124BIO *BIO_new_dgram(int fd, int close_flag)
125	{
126	BIO *ret;
127
128	ret=BIO_new(BIO_s_datagram());
129	if (ret == NULL) return(NULL);
130	BIO_set_fd(ret,fd,close_flag);
131	return(ret);
132	}
133
134static int dgram_new(BIO *bi)
135	{
136	bio_dgram_data *data = NULL;
137
138	bi->init=0;
139	bi->num=0;
140	data = OPENSSL_malloc(sizeof(bio_dgram_data));
141	if (data == NULL)
142		return 0;
143	memset(data, 0x00, sizeof(bio_dgram_data));
144    bi->ptr = data;
145
146	bi->flags=0;
147	return(1);
148	}
149
150static int dgram_free(BIO *a)
151	{
152	bio_dgram_data *data;
153
154	if (a == NULL) return(0);
155	if ( ! dgram_clear(a))
156		return 0;
157
158	data = (bio_dgram_data *)a->ptr;
159	if(data != NULL) OPENSSL_free(data);
160
161	return(1);
162	}
163
164static int dgram_clear(BIO *a)
165	{
166	if (a == NULL) return(0);
167	if (a->shutdown)
168		{
169		if (a->init)
170			{
171			SHUTDOWN2(a->num);
172			}
173		a->init=0;
174		a->flags=0;
175		}
176	return(1);
177	}
178
179static void dgram_adjust_rcv_timeout(BIO *b)
180	{
181#if defined(SO_RCVTIMEO)
182	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
183	int sz = sizeof(int);
184
185	/* Is a timer active? */
186	if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0)
187		{
188		struct timeval timenow, timeleft;
189
190		/* Read current socket timeout */
191#ifdef OPENSSL_SYS_WINDOWS
192		int timeout;
193		if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
194					   (void*)&timeout, &sz) < 0)
195			{ perror("getsockopt"); }
196		else
197			{
198			data->socket_timeout.tv_sec = timeout / 1000;
199			data->socket_timeout.tv_usec = (timeout % 1000) * 1000;
200			}
201#else
202		if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
203						&(data->socket_timeout), (void *)&sz) < 0)
204			{ perror("getsockopt"); }
205#endif
206
207		/* Get current time */
208		get_current_time(&timenow);
209
210		/* Calculate time left until timer expires */
211		memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval));
212		timeleft.tv_sec -= timenow.tv_sec;
213		timeleft.tv_usec -= timenow.tv_usec;
214		if (timeleft.tv_usec < 0)
215			{
216			timeleft.tv_sec--;
217			timeleft.tv_usec += 1000000;
218			}
219
220		if (timeleft.tv_sec < 0)
221			{
222			timeleft.tv_sec = 0;
223			timeleft.tv_usec = 1;
224			}
225
226		/* Adjust socket timeout if next handhake message timer
227		 * will expire earlier.
228		 */
229		if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) ||
230			(data->socket_timeout.tv_sec > timeleft.tv_sec) ||
231			(data->socket_timeout.tv_sec == timeleft.tv_sec &&
232			 data->socket_timeout.tv_usec >= timeleft.tv_usec))
233			{
234#ifdef OPENSSL_SYS_WINDOWS
235			timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000;
236			if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
237						   (void*)&timeout, sizeof(timeout)) < 0)
238				{ perror("setsockopt"); }
239#else
240			if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft,
241							sizeof(struct timeval)) < 0)
242				{ perror("setsockopt"); }
243#endif
244			}
245		}
246#endif
247	}
248
249static void dgram_reset_rcv_timeout(BIO *b)
250	{
251#if defined(SO_RCVTIMEO)
252	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
253
254	/* Is a timer active? */
255	if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0)
256		{
257#ifdef OPENSSL_SYS_WINDOWS
258		int timeout = data->socket_timeout.tv_sec * 1000 +
259					  data->socket_timeout.tv_usec / 1000;
260		if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
261					   (void*)&timeout, sizeof(timeout)) < 0)
262			{ perror("setsockopt"); }
263#else
264		if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout),
265						sizeof(struct timeval)) < 0)
266			{ perror("setsockopt"); }
267#endif
268		}
269#endif
270	}
271
272static int dgram_read(BIO *b, char *out, int outl)
273	{
274	int ret=0;
275	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
276
277	struct sockaddr peer;
278	int peerlen = sizeof(peer);
279
280	if (out != NULL)
281		{
282		clear_socket_error();
283		memset(&peer, 0x00, peerlen);
284		/* Last arg in recvfrom is signed on some platforms and
285		 * unsigned on others. It is of type socklen_t on some
286		 * but this is not universal. Cast to (void *) to avoid
287		 * compiler warnings.
288		 */
289		dgram_adjust_rcv_timeout(b);
290		ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen);
291
292		if ( ! data->connected  && ret >= 0)
293			BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer);
294
295		BIO_clear_retry_flags(b);
296		if (ret < 0)
297			{
298			if (BIO_dgram_should_retry(ret))
299				{
300				BIO_set_retry_read(b);
301				data->_errno = get_last_socket_error();
302				}
303			}
304
305		dgram_reset_rcv_timeout(b);
306		}
307	return(ret);
308	}
309
310static int dgram_write(BIO *b, const char *in, int inl)
311	{
312	int ret;
313	bio_dgram_data *data = (bio_dgram_data *)b->ptr;
314	clear_socket_error();
315
316    if ( data->connected )
317        ret=writesocket(b->num,in,inl);
318    else
319#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
320        ret=sendto(b->num, (char *)in, inl, 0, &data->peer, sizeof(data->peer));
321#else
322        ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer));
323#endif
324
325	BIO_clear_retry_flags(b);
326	if (ret <= 0)
327		{
328		if (BIO_dgram_should_retry(ret))
329			{
330			BIO_set_retry_write(b);
331			data->_errno = get_last_socket_error();
332
333#if 0 /* higher layers are responsible for querying MTU, if necessary */
334			if ( data->_errno == EMSGSIZE)
335				/* retrieve the new MTU */
336				BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL);
337#endif
338			}
339		}
340	return(ret);
341	}
342
343static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
344	{
345	long ret=1;
346	int *ip;
347	struct sockaddr *to = NULL;
348	bio_dgram_data *data = NULL;
349#if defined(IP_MTU_DISCOVER) || defined(IP_MTU)
350	long sockopt_val = 0;
351	unsigned int sockopt_len = 0;
352#endif
353#ifdef OPENSSL_SYS_LINUX
354	socklen_t addr_len;
355	struct sockaddr_storage addr;
356#endif
357
358	data = (bio_dgram_data *)b->ptr;
359
360	switch (cmd)
361		{
362	case BIO_CTRL_RESET:
363		num=0;
364	case BIO_C_FILE_SEEK:
365		ret=0;
366		break;
367	case BIO_C_FILE_TELL:
368	case BIO_CTRL_INFO:
369		ret=0;
370		break;
371	case BIO_C_SET_FD:
372		dgram_clear(b);
373		b->num= *((int *)ptr);
374		b->shutdown=(int)num;
375		b->init=1;
376		break;
377	case BIO_C_GET_FD:
378		if (b->init)
379			{
380			ip=(int *)ptr;
381			if (ip != NULL) *ip=b->num;
382			ret=b->num;
383			}
384		else
385			ret= -1;
386		break;
387	case BIO_CTRL_GET_CLOSE:
388		ret=b->shutdown;
389		break;
390	case BIO_CTRL_SET_CLOSE:
391		b->shutdown=(int)num;
392		break;
393	case BIO_CTRL_PENDING:
394	case BIO_CTRL_WPENDING:
395		ret=0;
396		break;
397	case BIO_CTRL_DUP:
398	case BIO_CTRL_FLUSH:
399		ret=1;
400		break;
401	case BIO_CTRL_DGRAM_CONNECT:
402		to = (struct sockaddr *)ptr;
403#if 0
404		if (connect(b->num, to, sizeof(struct sockaddr)) < 0)
405			{ perror("connect"); ret = 0; }
406		else
407			{
408#endif
409			memcpy(&(data->peer),to, sizeof(struct sockaddr));
410#if 0
411			}
412#endif
413		break;
414		/* (Linux)kernel sets DF bit on outgoing IP packets */
415	case BIO_CTRL_DGRAM_MTU_DISCOVER:
416#ifdef OPENSSL_SYS_LINUX
417		addr_len = (socklen_t)sizeof(struct sockaddr_storage);
418		memset((void *)&addr, 0, sizeof(struct sockaddr_storage));
419		if (getsockname(b->num, (void *)&addr, &addr_len) < 0)
420			{
421			ret = 0;
422			break;
423			}
424		sockopt_len = sizeof(sockopt_val);
425		switch (addr.ss_family)
426			{
427		case AF_INET:
428			sockopt_val = IP_PMTUDISC_DO;
429			if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER,
430				&sockopt_val, sizeof(sockopt_val))) < 0)
431				perror("setsockopt");
432			break;
433		case AF_INET6:
434			sockopt_val = IPV6_PMTUDISC_DO;
435			if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER,
436				&sockopt_val, sizeof(sockopt_val))) < 0)
437				perror("setsockopt");
438			break;
439		default:
440			ret = -1;
441			break;
442			}
443		ret = -1;
444#else
445		break;
446#endif
447	case BIO_CTRL_DGRAM_QUERY_MTU:
448#ifdef OPENSSL_SYS_LINUX
449		addr_len = (socklen_t)sizeof(struct sockaddr_storage);
450		memset((void *)&addr, 0, sizeof(struct sockaddr_storage));
451		if (getsockname(b->num, (void *)&addr, &addr_len) < 0)
452			{
453			ret = 0;
454			break;
455			}
456		sockopt_len = sizeof(sockopt_val);
457		switch (addr.ss_family)
458			{
459		case AF_INET:
460			if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val,
461				&sockopt_len)) < 0 || sockopt_val < 0)
462				{
463				ret = 0;
464				}
465			else
466				{
467				/* we assume that the transport protocol is UDP and no
468				 * IP options are used.
469				 */
470				data->mtu = sockopt_val - 8 - 20;
471				ret = data->mtu;
472				}
473			break;
474		case AF_INET6:
475			if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val,
476				&sockopt_len)) < 0 || sockopt_val < 0)
477				{
478				ret = 0;
479				}
480			else
481				{
482				/* we assume that the transport protocol is UDP and no
483				 * IPV6 options are used.
484				 */
485				data->mtu = sockopt_val - 8 - 40;
486				ret = data->mtu;
487				}
488			break;
489		default:
490			ret = 0;
491			break;
492			}
493#else
494		ret = 0;
495#endif
496		break;
497	case BIO_CTRL_DGRAM_GET_FALLBACK_MTU:
498		ret = 576 - 20 - 8;
499		break;
500	case BIO_CTRL_DGRAM_GET_MTU:
501		return data->mtu;
502		break;
503	case BIO_CTRL_DGRAM_SET_MTU:
504		data->mtu = num;
505		ret = num;
506		break;
507	case BIO_CTRL_DGRAM_SET_CONNECTED:
508		to = (struct sockaddr *)ptr;
509
510		if ( to != NULL)
511			{
512			data->connected = 1;
513			memcpy(&(data->peer),to, sizeof(struct sockaddr));
514			}
515		else
516			{
517			data->connected = 0;
518			memset(&(data->peer), 0x00, sizeof(struct sockaddr));
519			}
520		break;
521    case BIO_CTRL_DGRAM_GET_PEER:
522        to = (struct sockaddr *) ptr;
523
524        memcpy(to, &(data->peer), sizeof(struct sockaddr));
525		ret = sizeof(struct sockaddr);
526        break;
527    case BIO_CTRL_DGRAM_SET_PEER:
528        to = (struct sockaddr *) ptr;
529
530        memcpy(&(data->peer), to, sizeof(struct sockaddr));
531        break;
532	case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT:
533		memcpy(&(data->next_timeout), ptr, sizeof(struct timeval));
534		break;
535#if defined(SO_RCVTIMEO)
536	case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
537#ifdef OPENSSL_SYS_WINDOWS
538		{
539		struct timeval *tv = (struct timeval *)ptr;
540		int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
541		if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
542			(void*)&timeout, sizeof(timeout)) < 0)
543			{ perror("setsockopt"); ret = -1; }
544		}
545#else
546		if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr,
547			sizeof(struct timeval)) < 0)
548			{ perror("setsockopt");	ret = -1; }
549#endif
550		break;
551	case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT:
552#ifdef OPENSSL_SYS_WINDOWS
553		{
554		int timeout, sz = sizeof(timeout);
555		struct timeval *tv = (struct timeval *)ptr;
556		if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
557			(void*)&timeout, &sz) < 0)
558			{ perror("getsockopt"); ret = -1; }
559		else
560			{
561			tv->tv_sec = timeout / 1000;
562			tv->tv_usec = (timeout % 1000) * 1000;
563			ret = sizeof(*tv);
564			}
565		}
566#else
567		if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO,
568			ptr, (void *)&ret) < 0)
569			{ perror("getsockopt"); ret = -1; }
570#endif
571		break;
572#endif
573#if defined(SO_SNDTIMEO)
574	case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT:
575#ifdef OPENSSL_SYS_WINDOWS
576		{
577		struct timeval *tv = (struct timeval *)ptr;
578		int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000;
579		if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
580			(void*)&timeout, sizeof(timeout)) < 0)
581			{ perror("setsockopt"); ret = -1; }
582		}
583#else
584		if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr,
585			sizeof(struct timeval)) < 0)
586			{ perror("setsockopt");	ret = -1; }
587#endif
588		break;
589	case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT:
590#ifdef OPENSSL_SYS_WINDOWS
591		{
592		int timeout, sz = sizeof(timeout);
593		struct timeval *tv = (struct timeval *)ptr;
594		if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
595			(void*)&timeout, &sz) < 0)
596			{ perror("getsockopt"); ret = -1; }
597		else
598			{
599			tv->tv_sec = timeout / 1000;
600			tv->tv_usec = (timeout % 1000) * 1000;
601			ret = sizeof(*tv);
602			}
603		}
604#else
605		if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO,
606			ptr, (void *)&ret) < 0)
607			{ perror("getsockopt"); ret = -1; }
608#endif
609		break;
610#endif
611	case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP:
612		/* fall-through */
613	case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP:
614#ifdef OPENSSL_SYS_WINDOWS
615		if ( data->_errno == WSAETIMEDOUT)
616#else
617		if ( data->_errno == EAGAIN)
618#endif
619			{
620			ret = 1;
621			data->_errno = 0;
622			}
623		else
624			ret = 0;
625		break;
626#ifdef EMSGSIZE
627	case BIO_CTRL_DGRAM_MTU_EXCEEDED:
628		if ( data->_errno == EMSGSIZE)
629			{
630			ret = 1;
631			data->_errno = 0;
632			}
633		else
634			ret = 0;
635		break;
636#endif
637	default:
638		ret=0;
639		break;
640		}
641	return(ret);
642	}
643
644static int dgram_puts(BIO *bp, const char *str)
645	{
646	int n,ret;
647
648	n=strlen(str);
649	ret=dgram_write(bp,str,n);
650	return(ret);
651	}
652
653static int BIO_dgram_should_retry(int i)
654	{
655	int err;
656
657	if ((i == 0) || (i == -1))
658		{
659		err=get_last_socket_error();
660
661#if defined(OPENSSL_SYS_WINDOWS)
662	/* If the socket return value (i) is -1
663	 * and err is unexpectedly 0 at this point,
664	 * the error code was overwritten by
665	 * another system call before this error
666	 * handling is called.
667	 */
668#endif
669
670		return(BIO_dgram_non_fatal_error(err));
671		}
672	return(0);
673	}
674
675int BIO_dgram_non_fatal_error(int err)
676	{
677	switch (err)
678		{
679#if defined(OPENSSL_SYS_WINDOWS)
680# if defined(WSAEWOULDBLOCK)
681	case WSAEWOULDBLOCK:
682# endif
683
684# if 0 /* This appears to always be an error */
685#  if defined(WSAENOTCONN)
686	case WSAENOTCONN:
687#  endif
688# endif
689#endif
690
691#ifdef EWOULDBLOCK
692# ifdef WSAEWOULDBLOCK
693#  if WSAEWOULDBLOCK != EWOULDBLOCK
694	case EWOULDBLOCK:
695#  endif
696# else
697	case EWOULDBLOCK:
698# endif
699#endif
700
701#ifdef EINTR
702	case EINTR:
703#endif
704
705#ifdef EAGAIN
706#if EWOULDBLOCK != EAGAIN
707	case EAGAIN:
708# endif
709#endif
710
711#ifdef EPROTO
712	case EPROTO:
713#endif
714
715#ifdef EINPROGRESS
716	case EINPROGRESS:
717#endif
718
719#ifdef EALREADY
720	case EALREADY:
721#endif
722
723		return(1);
724		/* break; */
725	default:
726		break;
727		}
728	return(0);
729	}
730
731static void get_current_time(struct timeval *t)
732	{
733#ifdef OPENSSL_SYS_WIN32
734	struct _timeb tb;
735	_ftime(&tb);
736	t->tv_sec = (long)tb.time;
737	t->tv_usec = (long)tb.millitm * 1000;
738#elif defined(OPENSSL_SYS_VMS)
739	struct timeb tb;
740	ftime(&tb);
741	t->tv_sec = (long)tb.time;
742	t->tv_usec = (long)tb.millitm * 1000;
743#else
744	gettimeofday(t, NULL);
745#endif
746	}
747
748#endif
749