summaryrefslogtreecommitdiff
path: root/src/lib/libcrypto/bio/bss_dgram.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libcrypto/bio/bss_dgram.c')
-rw-r--r--src/lib/libcrypto/bio/bss_dgram.c380
1 files changed, 331 insertions, 49 deletions
diff --git a/src/lib/libcrypto/bio/bss_dgram.c b/src/lib/libcrypto/bio/bss_dgram.c
index c3da6dc82f..eb7e365467 100644
--- a/src/lib/libcrypto/bio/bss_dgram.c
+++ b/src/lib/libcrypto/bio/bss_dgram.c
@@ -66,7 +66,13 @@
66 66
67#include <openssl/bio.h> 67#include <openssl/bio.h>
68 68
69#if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS)
70#include <sys/timeb.h>
71#endif
72
73#ifdef OPENSSL_SYS_LINUX
69#define IP_MTU 14 /* linux is lame */ 74#define IP_MTU 14 /* linux is lame */
75#endif
70 76
71#ifdef WATT32 77#ifdef WATT32
72#define sock_write SockWrite /* Watt-32 uses same names */ 78#define sock_write SockWrite /* Watt-32 uses same names */
@@ -84,6 +90,8 @@ static int dgram_clear(BIO *bio);
84 90
85static int BIO_dgram_should_retry(int s); 91static int BIO_dgram_should_retry(int s);
86 92
93static void get_current_time(struct timeval *t);
94
87static BIO_METHOD methods_dgramp= 95static BIO_METHOD methods_dgramp=
88 { 96 {
89 BIO_TYPE_DGRAM, 97 BIO_TYPE_DGRAM,
@@ -100,10 +108,18 @@ static BIO_METHOD methods_dgramp=
100 108
101typedef struct bio_dgram_data_st 109typedef struct bio_dgram_data_st
102 { 110 {
103 struct sockaddr peer; 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;
104 unsigned int connected; 118 unsigned int connected;
105 unsigned int _errno; 119 unsigned int _errno;
106 unsigned int mtu; 120 unsigned int mtu;
121 struct timeval next_timeout;
122 struct timeval socket_timeout;
107 } bio_dgram_data; 123 } bio_dgram_data;
108 124
109BIO_METHOD *BIO_s_datagram(void) 125BIO_METHOD *BIO_s_datagram(void)
@@ -165,31 +181,140 @@ static int dgram_clear(BIO *a)
165 } 181 }
166 return(1); 182 return(1);
167 } 183 }
168 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
169static int dgram_read(BIO *b, char *out, int outl) 278static int dgram_read(BIO *b, char *out, int outl)
170 { 279 {
171 int ret=0; 280 int ret=0;
172 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 281 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
173 282
174 struct sockaddr peer; 283 struct {
175 int peerlen = sizeof(peer); 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);
176 299
177 if (out != NULL) 300 if (out != NULL)
178 { 301 {
179 clear_socket_error(); 302 clear_socket_error();
180 memset(&peer, 0x00, peerlen); 303 memset(&sa.peer, 0x00, sizeof(sa.peer));
181 /* Last arg in recvfrom is signed on some platforms and 304 dgram_adjust_rcv_timeout(b);
182 * unsigned on others. It is of type socklen_t on some 305 ret=recvfrom(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len);
183 * but this is not universal. Cast to (void *) to avoid 306 if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0)
184 * compiler warnings. 307 {
185 */ 308 OPENSSL_assert(sa.len.s<=sizeof(sa.peer));
186 ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen); 309 sa.len.i = (int)sa.len.s;
310 }
311 dgram_reset_rcv_timeout(b);
187 312
188 if ( ! data->connected && ret > 0) 313 if ( ! data->connected && ret >= 0)
189 BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer); 314 BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer);
190 315
191 BIO_clear_retry_flags(b); 316 BIO_clear_retry_flags(b);
192 if (ret <= 0) 317 if (ret < 0)
193 { 318 {
194 if (BIO_dgram_should_retry(ret)) 319 if (BIO_dgram_should_retry(ret))
195 { 320 {
@@ -207,19 +332,29 @@ static int dgram_write(BIO *b, const char *in, int inl)
207 bio_dgram_data *data = (bio_dgram_data *)b->ptr; 332 bio_dgram_data *data = (bio_dgram_data *)b->ptr;
208 clear_socket_error(); 333 clear_socket_error();
209 334
210 if ( data->connected ) 335 if ( data->connected )
211 ret=writesocket(b->num,in,inl); 336 ret=writesocket(b->num,in,inl);
212 else 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_IVP6
344 else if (data->peer.sa.sa_family == AF_INET6)
345 peerlen = sizeof(data->peer.sa_in6);
346#endif
213#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) 347#if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK)
214 ret=sendto(b->num, (char *)in, inl, 0, &data->peer, sizeof(data->peer)); 348 ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen);
215#else 349#else
216 ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer)); 350 ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen);
217#endif 351#endif
352 }
218 353
219 BIO_clear_retry_flags(b); 354 BIO_clear_retry_flags(b);
220 if (ret <= 0) 355 if (ret <= 0)
221 { 356 {
222 if (BIO_sock_should_retry(ret)) 357 if (BIO_dgram_should_retry(ret))
223 { 358 {
224 BIO_set_retry_write(b); 359 BIO_set_retry_write(b);
225 data->_errno = get_last_socket_error(); 360 data->_errno = get_last_socket_error();
@@ -240,8 +375,20 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
240 int *ip; 375 int *ip;
241 struct sockaddr *to = NULL; 376 struct sockaddr *to = NULL;
242 bio_dgram_data *data = NULL; 377 bio_dgram_data *data = NULL;
378#if defined(IP_MTU_DISCOVER) || defined(IP_MTU)
243 long sockopt_val = 0; 379 long sockopt_val = 0;
244 unsigned int sockopt_len = 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
245 392
246 data = (bio_dgram_data *)b->ptr; 393 data = (bio_dgram_data *)b->ptr;
247 394
@@ -294,30 +441,110 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
294 else 441 else
295 { 442 {
296#endif 443#endif
297 memcpy(&(data->peer),to, sizeof(struct sockaddr)); 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 }
298#if 0 458#if 0
299 } 459 }
300#endif 460#endif
301 break; 461 break;
302 /* (Linux)kernel sets DF bit on outgoing IP packets */ 462 /* (Linux)kernel sets DF bit on outgoing IP packets */
303#ifdef IP_MTU_DISCOVER
304 case BIO_CTRL_DGRAM_MTU_DISCOVER: 463 case BIO_CTRL_DGRAM_MTU_DISCOVER:
305 sockopt_val = IP_PMTUDISC_DO; 464#ifdef OPENSSL_SYS_LINUX
306 if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, 465 addr_len = (socklen_t)sizeof(addr);
307 &sockopt_val, sizeof(sockopt_val))) < 0) 466 memset((void *)&addr, 0, sizeof(addr));
308 perror("setsockopt"); 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
309 break; 495 break;
310#endif 496#endif
311 case BIO_CTRL_DGRAM_QUERY_MTU: 497 case BIO_CTRL_DGRAM_QUERY_MTU:
312 sockopt_len = sizeof(sockopt_val); 498#ifdef OPENSSL_SYS_LINUX
313 if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, 499 addr_len = (socklen_t)sizeof(addr);
314 &sockopt_len)) < 0 || sockopt_val < 0) 500 memset((void *)&addr, 0, sizeof(addr));
315 { ret = 0; } 501 if (getsockname(b->num, &addr.sa, &addr_len) < 0)
316 else 502 {
503 ret = 0;
504 break;
505 }
506 sockopt_len = sizeof(sockopt_val);
507 switch (addr.sa.sa_family)
317 { 508 {
318 data->mtu = sockopt_val; 509 case AF_INET:
319 ret = data->mtu; 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;
320 } 544 }
545#else
546 ret = 0;
547#endif
321 break; 548 break;
322 case BIO_CTRL_DGRAM_GET_MTU: 549 case BIO_CTRL_DGRAM_GET_MTU:
323 return data->mtu; 550 return data->mtu;
@@ -332,19 +559,66 @@ static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr)
332 if ( to != NULL) 559 if ( to != NULL)
333 { 560 {
334 data->connected = 1; 561 data->connected = 1;
335 memcpy(&(data->peer),to, sizeof(struct sockaddr)); 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 }
336 } 576 }
337 else 577 else
338 { 578 {
339 data->connected = 0; 579 data->connected = 0;
340 memset(&(data->peer), 0x00, sizeof(struct sockaddr)); 580 memset(&(data->peer), 0x00, sizeof(data->peer));
341 } 581 }
342 break; 582 break;
343 case BIO_CTRL_DGRAM_SET_PEER: 583 case BIO_CTRL_DGRAM_GET_PEER:
344 to = (struct sockaddr *) ptr; 584 switch (data->peer.sa.sa_family)
345 585 {
346 memcpy(&(data->peer), to, sizeof(struct sockaddr)); 586 case AF_INET:
347 break; 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;
348#if defined(SO_RCVTIMEO) 622#if defined(SO_RCVTIMEO)
349 case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: 623 case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT:
350#ifdef OPENSSL_SYS_WINDOWS 624#ifdef OPENSSL_SYS_WINDOWS
@@ -507,10 +781,6 @@ int BIO_dgram_non_fatal_error(int err)
507# endif 781# endif
508#endif 782#endif
509 783
510#if defined(ENOTCONN)
511 case ENOTCONN:
512#endif
513
514#ifdef EINTR 784#ifdef EINTR
515 case EINTR: 785 case EINTR:
516#endif 786#endif
@@ -533,11 +803,6 @@ int BIO_dgram_non_fatal_error(int err)
533 case EALREADY: 803 case EALREADY:
534#endif 804#endif
535 805
536/* DF bit set, and packet larger than MTU */
537#ifdef EMSGSIZE
538 case EMSGSIZE:
539#endif
540
541 return(1); 806 return(1);
542 /* break; */ 807 /* break; */
543 default: 808 default:
@@ -546,3 +811,20 @@ int BIO_dgram_non_fatal_error(int err)
546 return(0); 811 return(0);
547 } 812 }
548#endif 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 }