]>
Commit | Line | Data |
---|---|---|
36d16f8e BL |
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 | ||
36d16f8e BL |
60 | |
61 | #include <stdio.h> | |
62 | #include <errno.h> | |
63 | #define USE_SOCKETS | |
64 | #include "cryptlib.h" | |
65 | ||
36d16f8e | 66 | #include <openssl/bio.h> |
4ff1a2da | 67 | #ifndef OPENSSL_NO_DGRAM |
36d16f8e | 68 | |
2c827540 | 69 | #if defined(OPENSSL_SYS_WIN32) || defined(OPENSSL_SYS_VMS) |
10acacb3 DSH |
70 | #include <sys/timeb.h> |
71 | #endif | |
72 | ||
e065e6cd DSH |
73 | #ifndef OPENSSL_NO_SCTP |
74 | #include <netinet/sctp.h> | |
75 | #include <fcntl.h> | |
76 | #define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00 | |
77 | #define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0 | |
78 | #endif | |
79 | ||
0454f2c4 | 80 | #ifdef OPENSSL_SYS_LINUX |
36d16f8e | 81 | #define IP_MTU 14 /* linux is lame */ |
0454f2c4 | 82 | #endif |
36d16f8e BL |
83 | |
84 | #ifdef WATT32 | |
85 | #define sock_write SockWrite /* Watt-32 uses same names */ | |
86 | #define sock_read SockRead | |
87 | #define sock_puts SockPuts | |
88 | #endif | |
89 | ||
90 | static int dgram_write(BIO *h, const char *buf, int num); | |
91 | static int dgram_read(BIO *h, char *buf, int size); | |
92 | static int dgram_puts(BIO *h, const char *str); | |
93 | static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); | |
94 | static int dgram_new(BIO *h); | |
95 | static int dgram_free(BIO *data); | |
96 | static int dgram_clear(BIO *bio); | |
97 | ||
e065e6cd DSH |
98 | #ifndef OPENSSL_NO_SCTP |
99 | static int dgram_sctp_write(BIO *h, const char *buf, int num); | |
100 | static int dgram_sctp_read(BIO *h, char *buf, int size); | |
101 | static int dgram_sctp_puts(BIO *h, const char *str); | |
102 | static long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2); | |
103 | static int dgram_sctp_new(BIO *h); | |
104 | static int dgram_sctp_free(BIO *data); | |
105 | #ifdef SCTP_AUTHENTICATION_EVENT | |
106 | static void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp); | |
107 | #endif | |
108 | #endif | |
109 | ||
b3e72fc3 | 110 | static int BIO_dgram_should_retry(int s); |
36d16f8e | 111 | |
c44544a1 RL |
112 | static void get_current_time(struct timeval *t); |
113 | ||
36d16f8e BL |
114 | static BIO_METHOD methods_dgramp= |
115 | { | |
116 | BIO_TYPE_DGRAM, | |
117 | "datagram socket", | |
118 | dgram_write, | |
119 | dgram_read, | |
120 | dgram_puts, | |
121 | NULL, /* dgram_gets, */ | |
122 | dgram_ctrl, | |
123 | dgram_new, | |
124 | dgram_free, | |
125 | NULL, | |
126 | }; | |
127 | ||
e065e6cd DSH |
128 | #ifndef OPENSSL_NO_SCTP |
129 | static BIO_METHOD methods_dgramp_sctp= | |
130 | { | |
131 | BIO_TYPE_DGRAM_SCTP, | |
132 | "datagram sctp socket", | |
133 | dgram_sctp_write, | |
134 | dgram_sctp_read, | |
135 | dgram_sctp_puts, | |
136 | NULL, /* dgram_gets, */ | |
137 | dgram_sctp_ctrl, | |
138 | dgram_sctp_new, | |
139 | dgram_sctp_free, | |
140 | NULL, | |
141 | }; | |
142 | #endif | |
143 | ||
36d16f8e BL |
144 | typedef struct bio_dgram_data_st |
145 | { | |
e4572e52 AP |
146 | union { |
147 | struct sockaddr sa; | |
148 | struct sockaddr_in sa_in; | |
28418076 | 149 | #if OPENSSL_USE_IPV6 |
e4572e52 | 150 | struct sockaddr_in6 sa_in6; |
28418076 | 151 | #endif |
e4572e52 | 152 | } peer; |
36d16f8e BL |
153 | unsigned int connected; |
154 | unsigned int _errno; | |
155 | unsigned int mtu; | |
d6584eba DSH |
156 | struct timeval next_timeout; |
157 | struct timeval socket_timeout; | |
36d16f8e BL |
158 | } bio_dgram_data; |
159 | ||
e065e6cd DSH |
160 | #ifndef OPENSSL_NO_SCTP |
161 | typedef struct bio_dgram_sctp_save_message_st | |
162 | { | |
163 | BIO *bio; | |
164 | char *data; | |
165 | int length; | |
166 | } bio_dgram_sctp_save_message; | |
167 | ||
168 | typedef struct bio_dgram_sctp_data_st | |
169 | { | |
170 | union { | |
171 | struct sockaddr sa; | |
172 | struct sockaddr_in sa_in; | |
173 | #if OPENSSL_USE_IPV6 | |
174 | struct sockaddr_in6 sa_in6; | |
175 | #endif | |
176 | } peer; | |
177 | unsigned int connected; | |
178 | unsigned int _errno; | |
179 | unsigned int mtu; | |
180 | struct bio_dgram_sctp_sndinfo sndinfo; | |
181 | struct bio_dgram_sctp_rcvinfo rcvinfo; | |
182 | struct bio_dgram_sctp_prinfo prinfo; | |
183 | void (*handle_notifications)(BIO *bio, void *context, void *buf); | |
184 | void* notification_context; | |
185 | int in_handshake; | |
186 | int ccs_rcvd; | |
187 | int ccs_sent; | |
188 | int save_shutdown; | |
189 | int peer_auth_tested; | |
190 | bio_dgram_sctp_save_message saved_message; | |
191 | } bio_dgram_sctp_data; | |
192 | #endif | |
193 | ||
36d16f8e BL |
194 | BIO_METHOD *BIO_s_datagram(void) |
195 | { | |
196 | return(&methods_dgramp); | |
197 | } | |
198 | ||
199 | BIO *BIO_new_dgram(int fd, int close_flag) | |
200 | { | |
201 | BIO *ret; | |
202 | ||
203 | ret=BIO_new(BIO_s_datagram()); | |
204 | if (ret == NULL) return(NULL); | |
205 | BIO_set_fd(ret,fd,close_flag); | |
206 | return(ret); | |
207 | } | |
208 | ||
209 | static int dgram_new(BIO *bi) | |
210 | { | |
211 | bio_dgram_data *data = NULL; | |
212 | ||
213 | bi->init=0; | |
214 | bi->num=0; | |
215 | data = OPENSSL_malloc(sizeof(bio_dgram_data)); | |
216 | if (data == NULL) | |
217 | return 0; | |
218 | memset(data, 0x00, sizeof(bio_dgram_data)); | |
219 | bi->ptr = data; | |
220 | ||
221 | bi->flags=0; | |
222 | return(1); | |
223 | } | |
224 | ||
225 | static int dgram_free(BIO *a) | |
226 | { | |
227 | bio_dgram_data *data; | |
228 | ||
229 | if (a == NULL) return(0); | |
230 | if ( ! dgram_clear(a)) | |
231 | return 0; | |
232 | ||
233 | data = (bio_dgram_data *)a->ptr; | |
234 | if(data != NULL) OPENSSL_free(data); | |
235 | ||
236 | return(1); | |
237 | } | |
238 | ||
239 | static int dgram_clear(BIO *a) | |
240 | { | |
241 | if (a == NULL) return(0); | |
242 | if (a->shutdown) | |
243 | { | |
244 | if (a->init) | |
245 | { | |
246 | SHUTDOWN2(a->num); | |
247 | } | |
248 | a->init=0; | |
249 | a->flags=0; | |
250 | } | |
251 | return(1); | |
252 | } | |
d6584eba DSH |
253 | |
254 | static void dgram_adjust_rcv_timeout(BIO *b) | |
255 | { | |
256 | #if defined(SO_RCVTIMEO) | |
257 | bio_dgram_data *data = (bio_dgram_data *)b->ptr; | |
258 | int sz = sizeof(int); | |
259 | ||
260 | /* Is a timer active? */ | |
261 | if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) | |
262 | { | |
263 | struct timeval timenow, timeleft; | |
264 | ||
265 | /* Read current socket timeout */ | |
266 | #ifdef OPENSSL_SYS_WINDOWS | |
267 | int timeout; | |
268 | if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, | |
269 | (void*)&timeout, &sz) < 0) | |
270 | { perror("getsockopt"); } | |
271 | else | |
272 | { | |
273 | data->socket_timeout.tv_sec = timeout / 1000; | |
274 | data->socket_timeout.tv_usec = (timeout % 1000) * 1000; | |
275 | } | |
276 | #else | |
277 | if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, | |
278 | &(data->socket_timeout), (void *)&sz) < 0) | |
279 | { perror("getsockopt"); } | |
280 | #endif | |
281 | ||
282 | /* Get current time */ | |
283 | get_current_time(&timenow); | |
284 | ||
285 | /* Calculate time left until timer expires */ | |
286 | memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); | |
287 | timeleft.tv_sec -= timenow.tv_sec; | |
288 | timeleft.tv_usec -= timenow.tv_usec; | |
289 | if (timeleft.tv_usec < 0) | |
290 | { | |
291 | timeleft.tv_sec--; | |
292 | timeleft.tv_usec += 1000000; | |
293 | } | |
294 | ||
4e63da06 DSH |
295 | if (timeleft.tv_sec < 0) |
296 | { | |
297 | timeleft.tv_sec = 0; | |
298 | timeleft.tv_usec = 1; | |
299 | } | |
300 | ||
d6584eba DSH |
301 | /* Adjust socket timeout if next handhake message timer |
302 | * will expire earlier. | |
303 | */ | |
4e63da06 DSH |
304 | if ((data->socket_timeout.tv_sec == 0 && data->socket_timeout.tv_usec == 0) || |
305 | (data->socket_timeout.tv_sec > timeleft.tv_sec) || | |
d6584eba | 306 | (data->socket_timeout.tv_sec == timeleft.tv_sec && |
4e63da06 | 307 | data->socket_timeout.tv_usec >= timeleft.tv_usec)) |
d6584eba DSH |
308 | { |
309 | #ifdef OPENSSL_SYS_WINDOWS | |
310 | timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; | |
311 | if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, | |
312 | (void*)&timeout, sizeof(timeout)) < 0) | |
313 | { perror("setsockopt"); } | |
314 | #else | |
315 | if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, | |
316 | sizeof(struct timeval)) < 0) | |
317 | { perror("setsockopt"); } | |
318 | #endif | |
319 | } | |
320 | } | |
321 | #endif | |
322 | } | |
323 | ||
324 | static void dgram_reset_rcv_timeout(BIO *b) | |
325 | { | |
326 | #if defined(SO_RCVTIMEO) | |
327 | bio_dgram_data *data = (bio_dgram_data *)b->ptr; | |
d069a4d1 DSH |
328 | |
329 | /* Is a timer active? */ | |
330 | if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) | |
331 | { | |
d6584eba | 332 | #ifdef OPENSSL_SYS_WINDOWS |
d069a4d1 DSH |
333 | int timeout = data->socket_timeout.tv_sec * 1000 + |
334 | data->socket_timeout.tv_usec / 1000; | |
335 | if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, | |
336 | (void*)&timeout, sizeof(timeout)) < 0) | |
337 | { perror("setsockopt"); } | |
d6584eba | 338 | #else |
d069a4d1 DSH |
339 | if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), |
340 | sizeof(struct timeval)) < 0) | |
341 | { perror("setsockopt"); } | |
d6584eba | 342 | #endif |
d069a4d1 | 343 | } |
d6584eba DSH |
344 | #endif |
345 | } | |
346 | ||
36d16f8e BL |
347 | static int dgram_read(BIO *b, char *out, int outl) |
348 | { | |
349 | int ret=0; | |
350 | bio_dgram_data *data = (bio_dgram_data *)b->ptr; | |
351 | ||
e4572e52 AP |
352 | struct { |
353 | /* | |
354 | * See commentary in b_sock.c. <appro> | |
355 | */ | |
356 | union { size_t s; int i; } len; | |
357 | union { | |
358 | struct sockaddr sa; | |
359 | struct sockaddr_in sa_in; | |
28418076 | 360 | #if OPENSSL_USE_IPV6 |
e4572e52 | 361 | struct sockaddr_in6 sa_in6; |
28418076 | 362 | #endif |
e4572e52 AP |
363 | } peer; |
364 | } sa; | |
365 | ||
366 | sa.len.s=0; | |
367 | sa.len.i=sizeof(sa.peer); | |
36d16f8e BL |
368 | |
369 | if (out != NULL) | |
370 | { | |
371 | clear_socket_error(); | |
e4572e52 | 372 | memset(&sa.peer, 0x00, sizeof(sa.peer)); |
d6584eba | 373 | dgram_adjust_rcv_timeout(b); |
e4572e52 AP |
374 | ret=recvfrom(b->num,out,outl,0,&sa.peer.sa,(void *)&sa.len); |
375 | if (sizeof(sa.len.i)!=sizeof(sa.len.s) && sa.len.i==0) | |
376 | { | |
377 | OPENSSL_assert(sa.len.s<=sizeof(sa.peer)); | |
378 | sa.len.i = (int)sa.len.s; | |
379 | } | |
36d16f8e | 380 | |
2e9802b7 | 381 | if ( ! data->connected && ret >= 0) |
e4572e52 | 382 | BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &sa.peer); |
36d16f8e BL |
383 | |
384 | BIO_clear_retry_flags(b); | |
2e9802b7 | 385 | if (ret < 0) |
36d16f8e BL |
386 | { |
387 | if (BIO_dgram_should_retry(ret)) | |
388 | { | |
389 | BIO_set_retry_read(b); | |
390 | data->_errno = get_last_socket_error(); | |
391 | } | |
aab790a6 | 392 | } |
0e4f5cfb DSH |
393 | |
394 | dgram_reset_rcv_timeout(b); | |
36d16f8e BL |
395 | } |
396 | return(ret); | |
397 | } | |
398 | ||
399 | static int dgram_write(BIO *b, const char *in, int inl) | |
400 | { | |
401 | int ret; | |
402 | bio_dgram_data *data = (bio_dgram_data *)b->ptr; | |
403 | clear_socket_error(); | |
404 | ||
28418076 DSH |
405 | if ( data->connected ) |
406 | ret=writesocket(b->num,in,inl); | |
407 | else | |
a32f7fb8 AP |
408 | { |
409 | int peerlen = sizeof(data->peer); | |
410 | ||
411 | if (data->peer.sa.sa_family == AF_INET) | |
412 | peerlen = sizeof(data->peer.sa_in); | |
291a26e6 | 413 | #if OPENSSL_USE_IPV6 |
a32f7fb8 AP |
414 | else if (data->peer.sa.sa_family == AF_INET6) |
415 | peerlen = sizeof(data->peer.sa_in6); | |
416 | #endif | |
eef0c1f3 | 417 | #if defined(NETWARE_CLIB) && defined(NETWARE_BSDSOCK) |
a32f7fb8 | 418 | ret=sendto(b->num, (char *)in, inl, 0, &data->peer.sa, peerlen); |
eef0c1f3 | 419 | #else |
a32f7fb8 | 420 | ret=sendto(b->num, in, inl, 0, &data->peer.sa, peerlen); |
eef0c1f3 | 421 | #endif |
a32f7fb8 | 422 | } |
36d16f8e BL |
423 | |
424 | BIO_clear_retry_flags(b); | |
425 | if (ret <= 0) | |
426 | { | |
0cc0db32 | 427 | if (BIO_dgram_should_retry(ret)) |
36d16f8e BL |
428 | { |
429 | BIO_set_retry_write(b); | |
430 | data->_errno = get_last_socket_error(); | |
431 | ||
432 | #if 0 /* higher layers are responsible for querying MTU, if necessary */ | |
433 | if ( data->_errno == EMSGSIZE) | |
434 | /* retrieve the new MTU */ | |
435 | BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); | |
436 | #endif | |
437 | } | |
438 | } | |
439 | return(ret); | |
440 | } | |
441 | ||
442 | static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) | |
443 | { | |
444 | long ret=1; | |
445 | int *ip; | |
446 | struct sockaddr *to = NULL; | |
447 | bio_dgram_data *data = NULL; | |
15b0a565 | 448 | #if defined(IP_MTU_DISCOVER) || defined(IP_MTU) |
36d16f8e BL |
449 | long sockopt_val = 0; |
450 | unsigned int sockopt_len = 0; | |
15b0a565 | 451 | #endif |
0454f2c4 DSH |
452 | #ifdef OPENSSL_SYS_LINUX |
453 | socklen_t addr_len; | |
496cf69e AP |
454 | union { |
455 | struct sockaddr sa; | |
456 | struct sockaddr_in s4; | |
457 | #if OPENSSL_USE_IPV6 | |
458 | struct sockaddr_in6 s6; | |
459 | #endif | |
460 | } addr; | |
0454f2c4 | 461 | #endif |
36d16f8e BL |
462 | |
463 | data = (bio_dgram_data *)b->ptr; | |
464 | ||
465 | switch (cmd) | |
466 | { | |
467 | case BIO_CTRL_RESET: | |
468 | num=0; | |
469 | case BIO_C_FILE_SEEK: | |
470 | ret=0; | |
471 | break; | |
472 | case BIO_C_FILE_TELL: | |
473 | case BIO_CTRL_INFO: | |
474 | ret=0; | |
475 | break; | |
476 | case BIO_C_SET_FD: | |
477 | dgram_clear(b); | |
478 | b->num= *((int *)ptr); | |
479 | b->shutdown=(int)num; | |
480 | b->init=1; | |
481 | break; | |
482 | case BIO_C_GET_FD: | |
483 | if (b->init) | |
484 | { | |
485 | ip=(int *)ptr; | |
486 | if (ip != NULL) *ip=b->num; | |
487 | ret=b->num; | |
488 | } | |
489 | else | |
490 | ret= -1; | |
491 | break; | |
492 | case BIO_CTRL_GET_CLOSE: | |
493 | ret=b->shutdown; | |
494 | break; | |
495 | case BIO_CTRL_SET_CLOSE: | |
496 | b->shutdown=(int)num; | |
497 | break; | |
498 | case BIO_CTRL_PENDING: | |
499 | case BIO_CTRL_WPENDING: | |
500 | ret=0; | |
501 | break; | |
502 | case BIO_CTRL_DUP: | |
503 | case BIO_CTRL_FLUSH: | |
504 | ret=1; | |
505 | break; | |
506 | case BIO_CTRL_DGRAM_CONNECT: | |
507 | to = (struct sockaddr *)ptr; | |
508 | #if 0 | |
509 | if (connect(b->num, to, sizeof(struct sockaddr)) < 0) | |
510 | { perror("connect"); ret = 0; } | |
511 | else | |
512 | { | |
513 | #endif | |
e4572e52 AP |
514 | switch (to->sa_family) |
515 | { | |
516 | case AF_INET: | |
517 | memcpy(&data->peer,to,sizeof(data->peer.sa_in)); | |
518 | break; | |
28418076 | 519 | #if OPENSSL_USE_IPV6 |
e4572e52 AP |
520 | case AF_INET6: |
521 | memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); | |
522 | break; | |
28418076 | 523 | #endif |
e4572e52 AP |
524 | default: |
525 | memcpy(&data->peer,to,sizeof(data->peer.sa)); | |
526 | break; | |
527 | } | |
36d16f8e BL |
528 | #if 0 |
529 | } | |
530 | #endif | |
531 | break; | |
532 | /* (Linux)kernel sets DF bit on outgoing IP packets */ | |
36d16f8e | 533 | case BIO_CTRL_DGRAM_MTU_DISCOVER: |
0454f2c4 | 534 | #ifdef OPENSSL_SYS_LINUX |
496cf69e AP |
535 | addr_len = (socklen_t)sizeof(addr); |
536 | memset((void *)&addr, 0, sizeof(addr)); | |
537 | if (getsockname(b->num, &addr.sa, &addr_len) < 0) | |
0454f2c4 DSH |
538 | { |
539 | ret = 0; | |
540 | break; | |
541 | } | |
542 | sockopt_len = sizeof(sockopt_val); | |
496cf69e | 543 | switch (addr.sa.sa_family) |
0454f2c4 DSH |
544 | { |
545 | case AF_INET: | |
546 | sockopt_val = IP_PMTUDISC_DO; | |
547 | if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, | |
548 | &sockopt_val, sizeof(sockopt_val))) < 0) | |
549 | perror("setsockopt"); | |
550 | break; | |
496cf69e | 551 | #if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) |
0454f2c4 DSH |
552 | case AF_INET6: |
553 | sockopt_val = IPV6_PMTUDISC_DO; | |
554 | if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, | |
555 | &sockopt_val, sizeof(sockopt_val))) < 0) | |
556 | perror("setsockopt"); | |
557 | break; | |
b8dc932c | 558 | #endif |
0454f2c4 DSH |
559 | default: |
560 | ret = -1; | |
561 | break; | |
562 | } | |
563 | ret = -1; | |
564 | #else | |
36d16f8e BL |
565 | break; |
566 | #endif | |
567 | case BIO_CTRL_DGRAM_QUERY_MTU: | |
0454f2c4 | 568 | #ifdef OPENSSL_SYS_LINUX |
496cf69e AP |
569 | addr_len = (socklen_t)sizeof(addr); |
570 | memset((void *)&addr, 0, sizeof(addr)); | |
571 | if (getsockname(b->num, &addr.sa, &addr_len) < 0) | |
0454f2c4 DSH |
572 | { |
573 | ret = 0; | |
574 | break; | |
575 | } | |
576 | sockopt_len = sizeof(sockopt_val); | |
496cf69e | 577 | switch (addr.sa.sa_family) |
36d16f8e | 578 | { |
0454f2c4 DSH |
579 | case AF_INET: |
580 | if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, | |
581 | &sockopt_len)) < 0 || sockopt_val < 0) | |
582 | { | |
583 | ret = 0; | |
584 | } | |
585 | else | |
586 | { | |
587 | /* we assume that the transport protocol is UDP and no | |
588 | * IP options are used. | |
589 | */ | |
590 | data->mtu = sockopt_val - 8 - 20; | |
591 | ret = data->mtu; | |
592 | } | |
593 | break; | |
496cf69e | 594 | #if OPENSSL_USE_IPV6 && defined(IPV6_MTU) |
0454f2c4 DSH |
595 | case AF_INET6: |
596 | if ((ret = getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, (void *)&sockopt_val, | |
597 | &sockopt_len)) < 0 || sockopt_val < 0) | |
598 | { | |
599 | ret = 0; | |
600 | } | |
601 | else | |
602 | { | |
603 | /* we assume that the transport protocol is UDP and no | |
604 | * IPV6 options are used. | |
605 | */ | |
606 | data->mtu = sockopt_val - 8 - 40; | |
607 | ret = data->mtu; | |
608 | } | |
609 | break; | |
b8dc932c | 610 | #endif |
0454f2c4 DSH |
611 | default: |
612 | ret = 0; | |
613 | break; | |
36d16f8e | 614 | } |
0454f2c4 DSH |
615 | #else |
616 | ret = 0; | |
617 | #endif | |
36d16f8e BL |
618 | break; |
619 | case BIO_CTRL_DGRAM_GET_MTU: | |
620 | return data->mtu; | |
621 | break; | |
622 | case BIO_CTRL_DGRAM_SET_MTU: | |
5f911774 DSH |
623 | data->mtu = num; |
624 | ret = num; | |
36d16f8e BL |
625 | break; |
626 | case BIO_CTRL_DGRAM_SET_CONNECTED: | |
627 | to = (struct sockaddr *)ptr; | |
628 | ||
629 | if ( to != NULL) | |
630 | { | |
631 | data->connected = 1; | |
e4572e52 AP |
632 | switch (to->sa_family) |
633 | { | |
634 | case AF_INET: | |
635 | memcpy(&data->peer,to,sizeof(data->peer.sa_in)); | |
636 | break; | |
28418076 | 637 | #if OPENSSL_USE_IPV6 |
e4572e52 AP |
638 | case AF_INET6: |
639 | memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); | |
640 | break; | |
28418076 | 641 | #endif |
e4572e52 AP |
642 | default: |
643 | memcpy(&data->peer,to,sizeof(data->peer.sa)); | |
644 | break; | |
645 | } | |
36d16f8e BL |
646 | } |
647 | else | |
648 | { | |
649 | data->connected = 0; | |
e4572e52 | 650 | memset(&(data->peer), 0x00, sizeof(data->peer)); |
36d16f8e BL |
651 | } |
652 | break; | |
28418076 | 653 | case BIO_CTRL_DGRAM_GET_PEER: |
8b9b2360 | 654 | switch (data->peer.sa.sa_family) |
e4572e52 AP |
655 | { |
656 | case AF_INET: | |
8b9b2360 | 657 | ret=sizeof(data->peer.sa_in); |
e4572e52 | 658 | break; |
28418076 | 659 | #if OPENSSL_USE_IPV6 |
e4572e52 | 660 | case AF_INET6: |
8b9b2360 | 661 | ret=sizeof(data->peer.sa_in6); |
e4572e52 | 662 | break; |
28418076 | 663 | #endif |
e4572e52 | 664 | default: |
8b9b2360 | 665 | ret=sizeof(data->peer.sa); |
e4572e52 AP |
666 | break; |
667 | } | |
8b9b2360 AP |
668 | if (num==0 || num>ret) |
669 | num=ret; | |
670 | memcpy(ptr,&data->peer,(ret=num)); | |
28418076 DSH |
671 | break; |
672 | case BIO_CTRL_DGRAM_SET_PEER: | |
673 | to = (struct sockaddr *) ptr; | |
e4572e52 AP |
674 | switch (to->sa_family) |
675 | { | |
676 | case AF_INET: | |
677 | memcpy(&data->peer,to,sizeof(data->peer.sa_in)); | |
678 | break; | |
28418076 | 679 | #if OPENSSL_USE_IPV6 |
e4572e52 AP |
680 | case AF_INET6: |
681 | memcpy(&data->peer,to,sizeof(data->peer.sa_in6)); | |
682 | break; | |
28418076 | 683 | #endif |
e4572e52 AP |
684 | default: |
685 | memcpy(&data->peer,to,sizeof(data->peer.sa)); | |
686 | break; | |
687 | } | |
28418076 | 688 | break; |
d6584eba | 689 | case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: |
28418076 | 690 | memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); |
aab790a6 | 691 | break; |
4700aea9 | 692 | #if defined(SO_RCVTIMEO) |
36d16f8e | 693 | case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: |
b9790c1c AP |
694 | #ifdef OPENSSL_SYS_WINDOWS |
695 | { | |
696 | struct timeval *tv = (struct timeval *)ptr; | |
697 | int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; | |
d7235a9d | 698 | if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, |
b9790c1c AP |
699 | (void*)&timeout, sizeof(timeout)) < 0) |
700 | { perror("setsockopt"); ret = -1; } | |
701 | } | |
702 | #else | |
36d16f8e BL |
703 | if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, |
704 | sizeof(struct timeval)) < 0) | |
705 | { perror("setsockopt"); ret = -1; } | |
b9790c1c | 706 | #endif |
36d16f8e BL |
707 | break; |
708 | case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: | |
b9790c1c AP |
709 | #ifdef OPENSSL_SYS_WINDOWS |
710 | { | |
711 | int timeout, sz = sizeof(timeout); | |
712 | struct timeval *tv = (struct timeval *)ptr; | |
d7235a9d AP |
713 | if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, |
714 | (void*)&timeout, &sz) < 0) | |
b9790c1c AP |
715 | { perror("getsockopt"); ret = -1; } |
716 | else | |
717 | { | |
718 | tv->tv_sec = timeout / 1000; | |
719 | tv->tv_usec = (timeout % 1000) * 1000; | |
720 | ret = sizeof(*tv); | |
721 | } | |
722 | } | |
723 | #else | |
36d16f8e | 724 | if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, |
6c61726b | 725 | ptr, (void *)&ret) < 0) |
36d16f8e | 726 | { perror("getsockopt"); ret = -1; } |
b9790c1c | 727 | #endif |
36d16f8e | 728 | break; |
4700aea9 UM |
729 | #endif |
730 | #if defined(SO_SNDTIMEO) | |
36d16f8e | 731 | case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: |
b9790c1c AP |
732 | #ifdef OPENSSL_SYS_WINDOWS |
733 | { | |
734 | struct timeval *tv = (struct timeval *)ptr; | |
735 | int timeout = tv->tv_sec * 1000 + tv->tv_usec/1000; | |
d7235a9d | 736 | if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, |
b9790c1c AP |
737 | (void*)&timeout, sizeof(timeout)) < 0) |
738 | { perror("setsockopt"); ret = -1; } | |
739 | } | |
740 | #else | |
36d16f8e BL |
741 | if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, |
742 | sizeof(struct timeval)) < 0) | |
743 | { perror("setsockopt"); ret = -1; } | |
b9790c1c | 744 | #endif |
36d16f8e BL |
745 | break; |
746 | case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: | |
b9790c1c AP |
747 | #ifdef OPENSSL_SYS_WINDOWS |
748 | { | |
749 | int timeout, sz = sizeof(timeout); | |
750 | struct timeval *tv = (struct timeval *)ptr; | |
d7235a9d AP |
751 | if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, |
752 | (void*)&timeout, &sz) < 0) | |
b9790c1c AP |
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 | } | |
761 | #else | |
36d16f8e | 762 | if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, |
6c61726b | 763 | ptr, (void *)&ret) < 0) |
36d16f8e | 764 | { perror("getsockopt"); ret = -1; } |
b9790c1c | 765 | #endif |
36d16f8e | 766 | break; |
4700aea9 | 767 | #endif |
36d16f8e BL |
768 | case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: |
769 | /* fall-through */ | |
770 | case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: | |
b9790c1c | 771 | #ifdef OPENSSL_SYS_WINDOWS |
d7235a9d | 772 | if ( data->_errno == WSAETIMEDOUT) |
b9790c1c | 773 | #else |
36d16f8e | 774 | if ( data->_errno == EAGAIN) |
b9790c1c | 775 | #endif |
36d16f8e BL |
776 | { |
777 | ret = 1; | |
778 | data->_errno = 0; | |
779 | } | |
780 | else | |
781 | ret = 0; | |
782 | break; | |
6c61726b | 783 | #ifdef EMSGSIZE |
36d16f8e BL |
784 | case BIO_CTRL_DGRAM_MTU_EXCEEDED: |
785 | if ( data->_errno == EMSGSIZE) | |
786 | { | |
787 | ret = 1; | |
788 | data->_errno = 0; | |
789 | } | |
790 | else | |
791 | ret = 0; | |
792 | break; | |
6c61726b | 793 | #endif |
36d16f8e BL |
794 | default: |
795 | ret=0; | |
796 | break; | |
797 | } | |
798 | return(ret); | |
799 | } | |
800 | ||
801 | static int dgram_puts(BIO *bp, const char *str) | |
802 | { | |
803 | int n,ret; | |
804 | ||
805 | n=strlen(str); | |
806 | ret=dgram_write(bp,str,n); | |
807 | return(ret); | |
808 | } | |
809 | ||
e065e6cd DSH |
810 | #ifndef OPENSSL_NO_SCTP |
811 | BIO_METHOD *BIO_s_datagram_sctp(void) | |
812 | { | |
813 | return(&methods_dgramp_sctp); | |
814 | } | |
815 | ||
816 | BIO *BIO_new_dgram_sctp(int fd, int close_flag) | |
817 | { | |
818 | BIO *bio; | |
819 | int ret, optval = 20000; | |
820 | int auth_data = 0, auth_forward = 0; | |
821 | unsigned char *p; | |
822 | struct sctp_authchunk auth; | |
823 | struct sctp_authchunks *authchunks; | |
824 | socklen_t sockopt_len; | |
825 | #ifdef SCTP_AUTHENTICATION_EVENT | |
826 | #ifdef SCTP_EVENT | |
827 | struct sctp_event event; | |
828 | #else | |
829 | struct sctp_event_subscribe event; | |
830 | #endif | |
831 | #endif | |
832 | ||
833 | bio=BIO_new(BIO_s_datagram_sctp()); | |
834 | if (bio == NULL) return(NULL); | |
835 | BIO_set_fd(bio,fd,close_flag); | |
836 | ||
837 | /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */ | |
838 | auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE; | |
839 | ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk)); | |
840 | OPENSSL_assert(ret >= 0); | |
841 | auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE; | |
842 | ret = setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, sizeof(struct sctp_authchunk)); | |
843 | OPENSSL_assert(ret >= 0); | |
844 | ||
845 | /* Test if activation was successful. When using accept(), | |
846 | * SCTP-AUTH has to be activated for the listening socket | |
847 | * already, otherwise the connected socket won't use it. */ | |
848 | sockopt_len = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); | |
849 | authchunks = OPENSSL_malloc(sockopt_len); | |
850 | memset(authchunks, 0, sizeof(sockopt_len)); | |
851 | ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, &sockopt_len); | |
852 | OPENSSL_assert(ret >= 0); | |
853 | ||
854 | for (p = (unsigned char*) authchunks + sizeof(sctp_assoc_t); | |
855 | p < (unsigned char*) authchunks + sockopt_len; | |
856 | p += sizeof(uint8_t)) | |
857 | { | |
858 | if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1; | |
859 | if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1; | |
860 | } | |
861 | ||
862 | OPENSSL_free(authchunks); | |
863 | ||
864 | OPENSSL_assert(auth_data); | |
865 | OPENSSL_assert(auth_forward); | |
866 | ||
867 | #ifdef SCTP_AUTHENTICATION_EVENT | |
868 | #ifdef SCTP_EVENT | |
869 | memset(&event, 0, sizeof(struct sctp_event)); | |
870 | event.se_assoc_id = 0; | |
871 | event.se_type = SCTP_AUTHENTICATION_EVENT; | |
872 | event.se_on = 1; | |
873 | ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); | |
874 | OPENSSL_assert(ret >= 0); | |
875 | #else | |
876 | sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe); | |
877 | ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len); | |
878 | OPENSSL_assert(ret >= 0); | |
879 | ||
880 | event.sctp_authentication_event = 1; | |
881 | ||
882 | ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); | |
883 | OPENSSL_assert(ret >= 0); | |
884 | #endif | |
885 | #endif | |
886 | ||
887 | /* Disable partial delivery by setting the min size | |
888 | * larger than the max record size of 2^14 + 2048 + 13 | |
889 | */ | |
890 | ret = setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, sizeof(optval)); | |
891 | OPENSSL_assert(ret >= 0); | |
892 | ||
893 | return(bio); | |
894 | } | |
895 | ||
896 | int BIO_dgram_is_sctp(BIO *bio) | |
897 | { | |
898 | return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP); | |
899 | } | |
900 | ||
901 | static int dgram_sctp_new(BIO *bi) | |
902 | { | |
903 | bio_dgram_sctp_data *data = NULL; | |
904 | ||
905 | bi->init=0; | |
906 | bi->num=0; | |
907 | data = OPENSSL_malloc(sizeof(bio_dgram_sctp_data)); | |
908 | if (data == NULL) | |
909 | return 0; | |
910 | memset(data, 0x00, sizeof(bio_dgram_sctp_data)); | |
911 | #ifdef SCTP_PR_SCTP_NONE | |
912 | data->prinfo.pr_policy = SCTP_PR_SCTP_NONE; | |
913 | #endif | |
914 | bi->ptr = data; | |
915 | ||
916 | bi->flags=0; | |
917 | return(1); | |
918 | } | |
919 | ||
920 | static int dgram_sctp_free(BIO *a) | |
921 | { | |
922 | bio_dgram_sctp_data *data; | |
923 | ||
924 | if (a == NULL) return(0); | |
925 | if ( ! dgram_clear(a)) | |
926 | return 0; | |
927 | ||
928 | data = (bio_dgram_sctp_data *)a->ptr; | |
929 | if(data != NULL) OPENSSL_free(data); | |
930 | ||
931 | return(1); | |
932 | } | |
933 | ||
934 | #ifdef SCTP_AUTHENTICATION_EVENT | |
935 | void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification *snp) | |
936 | { | |
937 | unsigned int sockopt_len = 0; | |
938 | int ret; | |
939 | struct sctp_authkey_event* authkeyevent = &snp->sn_auth_event; | |
940 | ||
941 | if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY) | |
942 | { | |
943 | struct sctp_authkeyid authkeyid; | |
944 | ||
945 | /* delete key */ | |
946 | authkeyid.scact_keynumber = authkeyevent->auth_keynumber; | |
947 | sockopt_len = sizeof(struct sctp_authkeyid); | |
948 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, | |
949 | &authkeyid, sockopt_len); | |
950 | } | |
951 | } | |
952 | #endif | |
953 | ||
954 | static int dgram_sctp_read(BIO *b, char *out, int outl) | |
955 | { | |
956 | int ret = 0, n = 0, i, optval; | |
957 | socklen_t optlen; | |
958 | bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; | |
959 | union sctp_notification *snp; | |
960 | struct msghdr msg; | |
961 | struct iovec iov; | |
962 | struct cmsghdr *cmsg; | |
963 | char cmsgbuf[512]; | |
964 | ||
965 | if (out != NULL) | |
966 | { | |
967 | clear_socket_error(); | |
968 | ||
969 | do | |
970 | { | |
971 | memset(&data->rcvinfo, 0x00, sizeof(struct bio_dgram_sctp_rcvinfo)); | |
972 | iov.iov_base = out; | |
973 | iov.iov_len = outl; | |
974 | msg.msg_name = NULL; | |
975 | msg.msg_namelen = 0; | |
976 | msg.msg_iov = &iov; | |
977 | msg.msg_iovlen = 1; | |
978 | msg.msg_control = cmsgbuf; | |
979 | msg.msg_controllen = 512; | |
980 | msg.msg_flags = 0; | |
981 | n = recvmsg(b->num, &msg, 0); | |
982 | ||
983 | if (msg.msg_controllen > 0) | |
984 | { | |
985 | for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) | |
986 | { | |
987 | if (cmsg->cmsg_level != IPPROTO_SCTP) | |
988 | continue; | |
989 | #ifdef SCTP_RCVINFO | |
990 | if (cmsg->cmsg_type == SCTP_RCVINFO) | |
991 | { | |
992 | struct sctp_rcvinfo *rcvinfo; | |
993 | ||
994 | rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); | |
995 | data->rcvinfo.rcv_sid = rcvinfo->rcv_sid; | |
996 | data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn; | |
997 | data->rcvinfo.rcv_flags = rcvinfo->rcv_flags; | |
998 | data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid; | |
999 | data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn; | |
1000 | data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn; | |
1001 | data->rcvinfo.rcv_context = rcvinfo->rcv_context; | |
1002 | } | |
1003 | #endif | |
1004 | #ifdef SCTP_SNDRCV | |
1005 | if (cmsg->cmsg_type == SCTP_SNDRCV) | |
1006 | { | |
1007 | struct sctp_sndrcvinfo *sndrcvinfo; | |
1008 | ||
1009 | sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); | |
1010 | data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream; | |
1011 | data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn; | |
1012 | data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags; | |
1013 | data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid; | |
1014 | data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn; | |
1015 | data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn; | |
1016 | data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context; | |
1017 | } | |
1018 | #endif | |
1019 | } | |
1020 | } | |
1021 | ||
1022 | if (n <= 0) | |
1023 | { | |
1024 | if (n < 0) | |
1025 | ret = n; | |
1026 | break; | |
1027 | } | |
1028 | ||
1029 | if (msg.msg_flags & MSG_NOTIFICATION) | |
1030 | { | |
1031 | snp = (union sctp_notification*) out; | |
1032 | if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) | |
1033 | { | |
1034 | #ifdef SCTP_EVENT | |
1035 | struct sctp_event event; | |
1036 | #else | |
1037 | struct sctp_event_subscribe event; | |
1038 | socklen_t eventsize; | |
1039 | #endif | |
1040 | /* If a message has been delayed until the socket | |
1041 | * is dry, it can be sent now. | |
1042 | */ | |
1043 | if (data->saved_message.length > 0) | |
1044 | { | |
1045 | dgram_sctp_write(data->saved_message.bio, data->saved_message.data, | |
1046 | data->saved_message.length); | |
1047 | OPENSSL_free(data->saved_message.data); | |
1048 | data->saved_message.length = 0; | |
1049 | } | |
1050 | ||
1051 | /* disable sender dry event */ | |
1052 | #ifdef SCTP_EVENT | |
1053 | memset(&event, 0, sizeof(struct sctp_event)); | |
1054 | event.se_assoc_id = 0; | |
1055 | event.se_type = SCTP_SENDER_DRY_EVENT; | |
1056 | event.se_on = 0; | |
1057 | i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); | |
1058 | OPENSSL_assert(i >= 0); | |
1059 | #else | |
1060 | eventsize = sizeof(struct sctp_event_subscribe); | |
1061 | i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); | |
1062 | OPENSSL_assert(i >= 0); | |
1063 | ||
1064 | event.sctp_sender_dry_event = 0; | |
1065 | ||
1066 | i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); | |
1067 | OPENSSL_assert(i >= 0); | |
1068 | #endif | |
1069 | } | |
1070 | ||
1071 | #ifdef SCTP_AUTHENTICATION_EVENT | |
1072 | if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) | |
1073 | dgram_sctp_handle_auth_free_key_event(b, snp); | |
1074 | #endif | |
1075 | ||
1076 | if (data->handle_notifications != NULL) | |
1077 | data->handle_notifications(b, data->notification_context, (void*) out); | |
1078 | ||
1079 | memset(out, 0, outl); | |
1080 | } | |
1081 | else | |
1082 | ret += n; | |
1083 | } | |
1084 | while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) && (ret < outl)); | |
1085 | ||
1086 | if (ret > 0 && !(msg.msg_flags & MSG_EOR)) | |
1087 | { | |
1088 | /* Partial message read, this should never happen! */ | |
1089 | ||
1090 | /* The buffer was too small, this means the peer sent | |
1091 | * a message that was larger than allowed. */ | |
1092 | if (ret == outl) | |
1093 | return -1; | |
1094 | ||
1095 | /* Test if socket buffer can handle max record | |
1096 | * size (2^14 + 2048 + 13) | |
1097 | */ | |
1098 | optlen = (socklen_t) sizeof(int); | |
1099 | ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); | |
1100 | OPENSSL_assert(ret >= 0); | |
1101 | OPENSSL_assert(optval >= 18445); | |
1102 | ||
1103 | /* Test if SCTP doesn't partially deliver below | |
1104 | * max record size (2^14 + 2048 + 13) | |
1105 | */ | |
1106 | optlen = (socklen_t) sizeof(int); | |
1107 | ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, | |
1108 | &optval, &optlen); | |
1109 | OPENSSL_assert(ret >= 0); | |
1110 | OPENSSL_assert(optval >= 18445); | |
1111 | ||
1112 | /* Partially delivered notification??? Probably a bug.... */ | |
1113 | OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION)); | |
1114 | ||
1115 | /* Everything seems ok till now, so it's most likely | |
1116 | * a message dropped by PR-SCTP. | |
1117 | */ | |
1118 | memset(out, 0, outl); | |
1119 | BIO_set_retry_read(b); | |
1120 | return -1; | |
1121 | } | |
1122 | ||
1123 | BIO_clear_retry_flags(b); | |
1124 | if (ret < 0) | |
1125 | { | |
1126 | if (BIO_dgram_should_retry(ret)) | |
1127 | { | |
1128 | BIO_set_retry_read(b); | |
1129 | data->_errno = get_last_socket_error(); | |
1130 | } | |
1131 | } | |
1132 | ||
1133 | /* Test if peer uses SCTP-AUTH before continuing */ | |
1134 | if (!data->peer_auth_tested) | |
1135 | { | |
1136 | int ii, auth_data = 0, auth_forward = 0; | |
1137 | unsigned char *p; | |
1138 | struct sctp_authchunks *authchunks; | |
1139 | ||
1140 | optlen = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); | |
1141 | authchunks = OPENSSL_malloc(optlen); | |
1142 | memset(authchunks, 0, sizeof(optlen)); | |
1143 | ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, authchunks, &optlen); | |
1144 | OPENSSL_assert(ii >= 0); | |
1145 | ||
1146 | for (p = (unsigned char*) authchunks + sizeof(sctp_assoc_t); | |
1147 | p < (unsigned char*) authchunks + optlen; | |
1148 | p += sizeof(uint8_t)) | |
1149 | { | |
1150 | if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1; | |
1151 | if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1; | |
1152 | } | |
1153 | ||
1154 | OPENSSL_free(authchunks); | |
1155 | ||
1156 | if (!auth_data || !auth_forward) | |
1157 | { | |
1158 | BIOerr(BIO_F_BIO_READ,BIO_R_CONNECT_ERROR); | |
1159 | return -1; | |
1160 | } | |
1161 | ||
1162 | data->peer_auth_tested = 1; | |
1163 | } | |
1164 | } | |
1165 | return(ret); | |
1166 | } | |
1167 | ||
1168 | static int dgram_sctp_write(BIO *b, const char *in, int inl) | |
1169 | { | |
1170 | int ret; | |
1171 | bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; | |
1172 | struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo); | |
1173 | struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo); | |
1174 | struct bio_dgram_sctp_sndinfo handshake_sinfo; | |
1175 | struct iovec iov[1]; | |
1176 | struct msghdr msg; | |
1177 | struct cmsghdr *cmsg; | |
1178 | #if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) | |
1179 | char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + CMSG_SPACE(sizeof(struct sctp_prinfo))]; | |
1180 | struct sctp_sndinfo *sndinfo; | |
1181 | struct sctp_prinfo *prinfo; | |
1182 | #else | |
1183 | char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; | |
1184 | struct sctp_sndrcvinfo *sndrcvinfo; | |
1185 | #endif | |
1186 | ||
1187 | clear_socket_error(); | |
1188 | ||
1189 | /* If we're send anything else than application data, | |
1190 | * disable all user parameters and flags. | |
1191 | */ | |
1192 | if (in[0] != 23) { | |
1193 | memset(&handshake_sinfo, 0x00, sizeof(struct bio_dgram_sctp_sndinfo)); | |
1194 | #ifdef SCTP_SACK_IMMEDIATELY | |
1195 | handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY; | |
1196 | #endif | |
1197 | sinfo = &handshake_sinfo; | |
1198 | } | |
1199 | ||
1200 | /* If we have to send a shutdown alert message and the | |
1201 | * socket is not dry yet, we have to save it and send it | |
1202 | * as soon as the socket gets dry. | |
1203 | */ | |
1204 | if (data->save_shutdown && !BIO_dgram_sctp_wait_for_dry(b)) | |
1205 | { | |
1206 | data->saved_message.bio = b; | |
1207 | data->saved_message.length = inl; | |
1208 | data->saved_message.data = OPENSSL_malloc(inl); | |
1209 | memcpy(data->saved_message.data, in, inl); | |
1210 | return inl; | |
1211 | } | |
1212 | ||
1213 | iov[0].iov_base = (char *)in; | |
1214 | iov[0].iov_len = inl; | |
1215 | msg.msg_name = NULL; | |
1216 | msg.msg_namelen = 0; | |
1217 | msg.msg_iov = iov; | |
1218 | msg.msg_iovlen = 1; | |
1219 | msg.msg_control = (caddr_t)cmsgbuf; | |
1220 | msg.msg_controllen = 0; | |
1221 | msg.msg_flags = 0; | |
1222 | #if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) | |
1223 | cmsg = (struct cmsghdr *)cmsgbuf; | |
1224 | cmsg->cmsg_level = IPPROTO_SCTP; | |
1225 | cmsg->cmsg_type = SCTP_SNDINFO; | |
1226 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); | |
1227 | sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg); | |
1228 | memset(sndinfo, 0, sizeof(struct sctp_sndinfo)); | |
1229 | sndinfo->snd_sid = sinfo->snd_sid; | |
1230 | sndinfo->snd_flags = sinfo->snd_flags; | |
1231 | sndinfo->snd_ppid = sinfo->snd_ppid; | |
1232 | sndinfo->snd_context = sinfo->snd_context; | |
1233 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); | |
1234 | ||
1235 | cmsg = (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))]; | |
1236 | cmsg->cmsg_level = IPPROTO_SCTP; | |
1237 | cmsg->cmsg_type = SCTP_PRINFO; | |
1238 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); | |
1239 | prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg); | |
1240 | memset(prinfo, 0, sizeof(struct sctp_prinfo)); | |
1241 | prinfo->pr_policy = pinfo->pr_policy; | |
1242 | prinfo->pr_value = pinfo->pr_value; | |
1243 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); | |
1244 | #else | |
1245 | cmsg = (struct cmsghdr *)cmsgbuf; | |
1246 | cmsg->cmsg_level = IPPROTO_SCTP; | |
1247 | cmsg->cmsg_type = SCTP_SNDRCV; | |
1248 | cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); | |
1249 | sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); | |
1250 | memset(sndrcvinfo, 0, sizeof(struct sctp_sndrcvinfo)); | |
1251 | sndrcvinfo->sinfo_stream = sinfo->snd_sid; | |
1252 | sndrcvinfo->sinfo_flags = sinfo->snd_flags; | |
1253 | #ifdef __FreeBSD__ | |
1254 | sndrcvinfo->sinfo_flags |= pinfo->pr_policy; | |
1255 | #endif | |
1256 | sndrcvinfo->sinfo_ppid = sinfo->snd_ppid; | |
1257 | sndrcvinfo->sinfo_context = sinfo->snd_context; | |
1258 | sndrcvinfo->sinfo_timetolive = pinfo->pr_value; | |
1259 | msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); | |
1260 | #endif | |
1261 | ||
1262 | ret = sendmsg(b->num, &msg, 0); | |
1263 | ||
1264 | BIO_clear_retry_flags(b); | |
1265 | if (ret <= 0) | |
1266 | { | |
1267 | if (BIO_dgram_should_retry(ret)) | |
1268 | { | |
1269 | BIO_set_retry_write(b); | |
1270 | data->_errno = get_last_socket_error(); | |
1271 | } | |
1272 | } | |
1273 | return(ret); | |
1274 | } | |
1275 | ||
1276 | static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) | |
1277 | { | |
1278 | long ret=1; | |
1279 | bio_dgram_sctp_data *data = NULL; | |
1280 | unsigned int sockopt_len = 0; | |
1281 | struct sctp_authkeyid authkeyid; | |
1282 | struct sctp_authkey *authkey; | |
1283 | ||
1284 | data = (bio_dgram_sctp_data *)b->ptr; | |
1285 | ||
1286 | switch (cmd) | |
1287 | { | |
1288 | case BIO_CTRL_DGRAM_QUERY_MTU: | |
1289 | /* Set to maximum (2^14) | |
1290 | * and ignore user input to enable transport | |
1291 | * protocol fragmentation. | |
1292 | * Returns always 2^14. | |
1293 | */ | |
1294 | data->mtu = 16384; | |
1295 | ret = data->mtu; | |
1296 | break; | |
1297 | case BIO_CTRL_DGRAM_SET_MTU: | |
1298 | /* Set to maximum (2^14) | |
1299 | * and ignore input to enable transport | |
1300 | * protocol fragmentation. | |
1301 | * Returns always 2^14. | |
1302 | */ | |
1303 | data->mtu = 16384; | |
1304 | ret = data->mtu; | |
1305 | break; | |
1306 | case BIO_CTRL_DGRAM_SET_CONNECTED: | |
1307 | case BIO_CTRL_DGRAM_CONNECT: | |
1308 | /* Returns always -1. */ | |
1309 | ret = -1; | |
1310 | break; | |
1311 | case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: | |
1312 | /* SCTP doesn't need the DTLS timer | |
1313 | * Returns always 1. | |
1314 | */ | |
1315 | break; | |
1316 | case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: | |
1317 | if (num > 0) | |
1318 | data->in_handshake = 1; | |
1319 | else | |
1320 | data->in_handshake = 0; | |
1321 | ||
1322 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, &data->in_handshake, sizeof(int)); | |
1323 | break; | |
1324 | case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY: | |
1325 | /* New shared key for SCTP AUTH. | |
1326 | * Returns 0 on success, -1 otherwise. | |
1327 | */ | |
1328 | ||
1329 | /* Get active key */ | |
1330 | sockopt_len = sizeof(struct sctp_authkeyid); | |
1331 | ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len); | |
1332 | if (ret < 0) break; | |
1333 | ||
1334 | /* Add new key */ | |
1335 | sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t); | |
1336 | authkey = OPENSSL_malloc(sockopt_len); | |
1337 | memset(authkey, 0x00, sockopt_len); | |
1338 | authkey->sca_keynumber = authkeyid.scact_keynumber + 1; | |
1339 | #ifndef __FreeBSD__ | |
1340 | /* This field is missing in FreeBSD 8.2 and earlier, | |
1341 | * and FreeBSD 8.3 and higher work without it. | |
1342 | */ | |
1343 | authkey->sca_keylength = 64; | |
1344 | #endif | |
1345 | memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t)); | |
1346 | ||
1347 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, sockopt_len); | |
1348 | if (ret < 0) break; | |
1349 | ||
1350 | /* Reset active key */ | |
1351 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, | |
1352 | &authkeyid, sizeof(struct sctp_authkeyid)); | |
1353 | if (ret < 0) break; | |
1354 | ||
1355 | break; | |
1356 | case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY: | |
1357 | /* Returns 0 on success, -1 otherwise. */ | |
1358 | ||
1359 | /* Get active key */ | |
1360 | sockopt_len = sizeof(struct sctp_authkeyid); | |
1361 | ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len); | |
1362 | if (ret < 0) break; | |
1363 | ||
1364 | /* Set active key */ | |
1365 | authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1; | |
1366 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, | |
1367 | &authkeyid, sizeof(struct sctp_authkeyid)); | |
1368 | if (ret < 0) break; | |
1369 | ||
1370 | /* CCS has been sent, so remember that and fall through | |
1371 | * to check if we need to deactivate an old key | |
1372 | */ | |
1373 | data->ccs_sent = 1; | |
1374 | ||
1375 | case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD: | |
1376 | /* Returns 0 on success, -1 otherwise. */ | |
1377 | ||
1378 | /* Has this command really been called or is this just a fall-through? */ | |
1379 | if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD) | |
1380 | data->ccs_rcvd = 1; | |
1381 | ||
1382 | /* CSS has been both, received and sent, so deactivate an old key */ | |
1383 | if (data->ccs_rcvd == 1 && data->ccs_sent == 1) | |
1384 | { | |
1385 | /* Get active key */ | |
1386 | sockopt_len = sizeof(struct sctp_authkeyid); | |
1387 | ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, &sockopt_len); | |
1388 | if (ret < 0) break; | |
1389 | ||
1390 | /* Deactivate key or delete second last key if | |
1391 | * SCTP_AUTHENTICATION_EVENT is not available. | |
1392 | */ | |
1393 | authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; | |
1394 | #ifdef SCTP_AUTH_DEACTIVATE_KEY | |
1395 | sockopt_len = sizeof(struct sctp_authkeyid); | |
1396 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY, | |
1397 | &authkeyid, sockopt_len); | |
1398 | if (ret < 0) break; | |
1399 | #endif | |
1400 | #ifndef SCTP_AUTHENTICATION_EVENT | |
1401 | if (authkeyid.scact_keynumber > 0) | |
1402 | { | |
1403 | authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; | |
1404 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, | |
1405 | &authkeyid, sizeof(struct sctp_authkeyid)); | |
1406 | if (ret < 0) break; | |
1407 | } | |
1408 | #endif | |
1409 | ||
1410 | data->ccs_rcvd = 0; | |
1411 | data->ccs_sent = 0; | |
1412 | } | |
1413 | break; | |
1414 | case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO: | |
1415 | /* Returns the size of the copied struct. */ | |
1416 | if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo)) | |
1417 | num = sizeof(struct bio_dgram_sctp_sndinfo); | |
1418 | ||
1419 | memcpy(ptr, &(data->sndinfo), num); | |
1420 | ret = num; | |
1421 | break; | |
1422 | case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO: | |
1423 | /* Returns the size of the copied struct. */ | |
1424 | if (num > (long) sizeof(struct bio_dgram_sctp_sndinfo)) | |
1425 | num = sizeof(struct bio_dgram_sctp_sndinfo); | |
1426 | ||
1427 | memcpy(&(data->sndinfo), ptr, num); | |
1428 | break; | |
1429 | case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO: | |
1430 | /* Returns the size of the copied struct. */ | |
1431 | if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo)) | |
1432 | num = sizeof(struct bio_dgram_sctp_rcvinfo); | |
1433 | ||
1434 | memcpy(ptr, &data->rcvinfo, num); | |
1435 | ||
1436 | ret = num; | |
1437 | break; | |
1438 | case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO: | |
1439 | /* Returns the size of the copied struct. */ | |
1440 | if (num > (long) sizeof(struct bio_dgram_sctp_rcvinfo)) | |
1441 | num = sizeof(struct bio_dgram_sctp_rcvinfo); | |
1442 | ||
1443 | memcpy(&(data->rcvinfo), ptr, num); | |
1444 | break; | |
1445 | case BIO_CTRL_DGRAM_SCTP_GET_PRINFO: | |
1446 | /* Returns the size of the copied struct. */ | |
1447 | if (num > (long) sizeof(struct bio_dgram_sctp_prinfo)) | |
1448 | num = sizeof(struct bio_dgram_sctp_prinfo); | |
1449 | ||
1450 | memcpy(ptr, &(data->prinfo), num); | |
1451 | ret = num; | |
1452 | break; | |
1453 | case BIO_CTRL_DGRAM_SCTP_SET_PRINFO: | |
1454 | /* Returns the size of the copied struct. */ | |
1455 | if (num > (long) sizeof(struct bio_dgram_sctp_prinfo)) | |
1456 | num = sizeof(struct bio_dgram_sctp_prinfo); | |
1457 | ||
1458 | memcpy(&(data->prinfo), ptr, num); | |
1459 | break; | |
1460 | case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN: | |
1461 | /* Returns always 1. */ | |
1462 | if (num > 0) | |
1463 | data->save_shutdown = 1; | |
1464 | else | |
1465 | data->save_shutdown = 0; | |
1466 | break; | |
1467 | ||
1468 | default: | |
1469 | /* Pass to default ctrl function to | |
1470 | * process SCTP unspecific commands | |
1471 | */ | |
1472 | ret=dgram_ctrl(b, cmd, num, ptr); | |
1473 | break; | |
1474 | } | |
1475 | return(ret); | |
1476 | } | |
1477 | ||
1478 | int BIO_dgram_sctp_notification_cb(BIO *b, | |
1479 | void (*handle_notifications)(BIO *bio, void *context, void *buf), | |
1480 | void *context) | |
1481 | { | |
1482 | bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; | |
1483 | ||
1484 | if (handle_notifications != NULL) | |
1485 | { | |
1486 | data->handle_notifications = handle_notifications; | |
1487 | data->notification_context = context; | |
1488 | } | |
1489 | else | |
1490 | return -1; | |
1491 | ||
1492 | return 0; | |
1493 | } | |
1494 | ||
1495 | int BIO_dgram_sctp_wait_for_dry(BIO *b) | |
1496 | { | |
1497 | int is_dry = 0; | |
1498 | int n, sockflags, ret; | |
1499 | union sctp_notification snp; | |
1500 | struct msghdr msg; | |
1501 | struct iovec iov; | |
1502 | #ifdef SCTP_EVENT | |
1503 | struct sctp_event event; | |
1504 | #else | |
1505 | struct sctp_event_subscribe event; | |
1506 | socklen_t eventsize; | |
1507 | #endif | |
1508 | bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; | |
1509 | ||
1510 | /* set sender dry event */ | |
1511 | #ifdef SCTP_EVENT | |
1512 | memset(&event, 0, sizeof(struct sctp_event)); | |
1513 | event.se_assoc_id = 0; | |
1514 | event.se_type = SCTP_SENDER_DRY_EVENT; | |
1515 | event.se_on = 1; | |
1516 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); | |
1517 | #else | |
1518 | eventsize = sizeof(struct sctp_event_subscribe); | |
1519 | ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); | |
1520 | if (ret < 0) | |
1521 | return -1; | |
1522 | ||
1523 | event.sctp_sender_dry_event = 1; | |
1524 | ||
1525 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); | |
1526 | #endif | |
1527 | if (ret < 0) | |
1528 | return -1; | |
1529 | ||
1530 | /* peek for notification */ | |
1531 | memset(&snp, 0x00, sizeof(union sctp_notification)); | |
1532 | iov.iov_base = (char *)&snp; | |
1533 | iov.iov_len = sizeof(union sctp_notification); | |
1534 | msg.msg_name = NULL; | |
1535 | msg.msg_namelen = 0; | |
1536 | msg.msg_iov = &iov; | |
1537 | msg.msg_iovlen = 1; | |
1538 | msg.msg_control = NULL; | |
1539 | msg.msg_controllen = 0; | |
1540 | msg.msg_flags = 0; | |
1541 | ||
1542 | n = recvmsg(b->num, &msg, MSG_PEEK); | |
1543 | if (n <= 0) | |
1544 | { | |
1545 | if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) | |
1546 | return -1; | |
1547 | else | |
1548 | return 0; | |
1549 | } | |
1550 | ||
1551 | /* if we find a notification, process it and try again if necessary */ | |
1552 | while (msg.msg_flags & MSG_NOTIFICATION) | |
1553 | { | |
1554 | memset(&snp, 0x00, sizeof(union sctp_notification)); | |
1555 | iov.iov_base = (char *)&snp; | |
1556 | iov.iov_len = sizeof(union sctp_notification); | |
1557 | msg.msg_name = NULL; | |
1558 | msg.msg_namelen = 0; | |
1559 | msg.msg_iov = &iov; | |
1560 | msg.msg_iovlen = 1; | |
1561 | msg.msg_control = NULL; | |
1562 | msg.msg_controllen = 0; | |
1563 | msg.msg_flags = 0; | |
1564 | ||
1565 | n = recvmsg(b->num, &msg, 0); | |
1566 | if (n <= 0) | |
1567 | { | |
1568 | if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) | |
1569 | return -1; | |
1570 | else | |
1571 | return is_dry; | |
1572 | } | |
1573 | ||
1574 | if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) | |
1575 | { | |
1576 | is_dry = 1; | |
1577 | ||
1578 | /* disable sender dry event */ | |
1579 | #ifdef SCTP_EVENT | |
1580 | memset(&event, 0, sizeof(struct sctp_event)); | |
1581 | event.se_assoc_id = 0; | |
1582 | event.se_type = SCTP_SENDER_DRY_EVENT; | |
1583 | event.se_on = 0; | |
1584 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); | |
1585 | #else | |
1586 | eventsize = (socklen_t) sizeof(struct sctp_event_subscribe); | |
1587 | ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); | |
1588 | if (ret < 0) | |
1589 | return -1; | |
1590 | ||
1591 | event.sctp_sender_dry_event = 0; | |
1592 | ||
1593 | ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); | |
1594 | #endif | |
1595 | if (ret < 0) | |
1596 | return -1; | |
1597 | } | |
1598 | ||
1599 | #ifdef SCTP_AUTHENTICATION_EVENT | |
1600 | if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) | |
1601 | dgram_sctp_handle_auth_free_key_event(b, &snp); | |
1602 | #endif | |
1603 | ||
1604 | if (data->handle_notifications != NULL) | |
1605 | data->handle_notifications(b, data->notification_context, (void*) &snp); | |
1606 | ||
1607 | /* found notification, peek again */ | |
1608 | memset(&snp, 0x00, sizeof(union sctp_notification)); | |
1609 | iov.iov_base = (char *)&snp; | |
1610 | iov.iov_len = sizeof(union sctp_notification); | |
1611 | msg.msg_name = NULL; | |
1612 | msg.msg_namelen = 0; | |
1613 | msg.msg_iov = &iov; | |
1614 | msg.msg_iovlen = 1; | |
1615 | msg.msg_control = NULL; | |
1616 | msg.msg_controllen = 0; | |
1617 | msg.msg_flags = 0; | |
1618 | ||
1619 | /* if we have seen the dry already, don't wait */ | |
1620 | if (is_dry) | |
1621 | { | |
1622 | sockflags = fcntl(b->num, F_GETFL, 0); | |
1623 | fcntl(b->num, F_SETFL, O_NONBLOCK); | |
1624 | } | |
1625 | ||
1626 | n = recvmsg(b->num, &msg, MSG_PEEK); | |
1627 | ||
1628 | if (is_dry) | |
1629 | { | |
1630 | fcntl(b->num, F_SETFL, sockflags); | |
1631 | } | |
1632 | ||
1633 | if (n <= 0) | |
1634 | { | |
1635 | if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) | |
1636 | return -1; | |
1637 | else | |
1638 | return is_dry; | |
1639 | } | |
1640 | } | |
1641 | ||
1642 | /* read anything else */ | |
1643 | return is_dry; | |
1644 | } | |
1645 | ||
1646 | int BIO_dgram_sctp_msg_waiting(BIO *b) | |
1647 | { | |
1648 | int n, sockflags; | |
1649 | union sctp_notification snp; | |
1650 | struct msghdr msg; | |
1651 | struct iovec iov; | |
1652 | bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; | |
1653 | ||
1654 | /* Check if there are any messages waiting to be read */ | |
1655 | do | |
1656 | { | |
1657 | memset(&snp, 0x00, sizeof(union sctp_notification)); | |
1658 | iov.iov_base = (char *)&snp; | |
1659 | iov.iov_len = sizeof(union sctp_notification); | |
1660 | msg.msg_name = NULL; | |
1661 | msg.msg_namelen = 0; | |
1662 | msg.msg_iov = &iov; | |
1663 | msg.msg_iovlen = 1; | |
1664 | msg.msg_control = NULL; | |
1665 | msg.msg_controllen = 0; | |
1666 | msg.msg_flags = 0; | |
1667 | ||
1668 | sockflags = fcntl(b->num, F_GETFL, 0); | |
1669 | fcntl(b->num, F_SETFL, O_NONBLOCK); | |
1670 | n = recvmsg(b->num, &msg, MSG_PEEK); | |
1671 | fcntl(b->num, F_SETFL, sockflags); | |
1672 | ||
1673 | /* if notification, process and try again */ | |
1674 | if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)) | |
1675 | { | |
1676 | #ifdef SCTP_AUTHENTICATION_EVENT | |
1677 | if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) | |
1678 | dgram_sctp_handle_auth_free_key_event(b, &snp); | |
1679 | #endif | |
1680 | ||
1681 | memset(&snp, 0x00, sizeof(union sctp_notification)); | |
1682 | iov.iov_base = (char *)&snp; | |
1683 | iov.iov_len = sizeof(union sctp_notification); | |
1684 | msg.msg_name = NULL; | |
1685 | msg.msg_namelen = 0; | |
1686 | msg.msg_iov = &iov; | |
1687 | msg.msg_iovlen = 1; | |
1688 | msg.msg_control = NULL; | |
1689 | msg.msg_controllen = 0; | |
1690 | msg.msg_flags = 0; | |
1691 | n = recvmsg(b->num, &msg, 0); | |
1692 | ||
1693 | if (data->handle_notifications != NULL) | |
1694 | data->handle_notifications(b, data->notification_context, (void*) &snp); | |
1695 | } | |
1696 | ||
1697 | } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)); | |
1698 | ||
1699 | /* Return 1 if there is a message to be read, return 0 otherwise. */ | |
1700 | if (n > 0) | |
1701 | return 1; | |
1702 | else | |
1703 | return 0; | |
1704 | } | |
1705 | ||
1706 | static int dgram_sctp_puts(BIO *bp, const char *str) | |
1707 | { | |
1708 | int n,ret; | |
1709 | ||
1710 | n=strlen(str); | |
1711 | ret=dgram_sctp_write(bp,str,n); | |
1712 | return(ret); | |
1713 | } | |
1714 | #endif | |
1715 | ||
b3e72fc3 | 1716 | static int BIO_dgram_should_retry(int i) |
36d16f8e BL |
1717 | { |
1718 | int err; | |
1719 | ||
1720 | if ((i == 0) || (i == -1)) | |
1721 | { | |
1722 | err=get_last_socket_error(); | |
1723 | ||
0e4f5cfb DSH |
1724 | #if defined(OPENSSL_SYS_WINDOWS) |
1725 | /* If the socket return value (i) is -1 | |
1726 | * and err is unexpectedly 0 at this point, | |
1727 | * the error code was overwritten by | |
1728 | * another system call before this error | |
1729 | * handling is called. | |
1730 | */ | |
36d16f8e BL |
1731 | #endif |
1732 | ||
1733 | return(BIO_dgram_non_fatal_error(err)); | |
1734 | } | |
1735 | return(0); | |
1736 | } | |
1737 | ||
1738 | int BIO_dgram_non_fatal_error(int err) | |
1739 | { | |
1740 | switch (err) | |
1741 | { | |
1742 | #if defined(OPENSSL_SYS_WINDOWS) | |
1743 | # if defined(WSAEWOULDBLOCK) | |
1744 | case WSAEWOULDBLOCK: | |
1745 | # endif | |
1746 | ||
1747 | # if 0 /* This appears to always be an error */ | |
1748 | # if defined(WSAENOTCONN) | |
1749 | case WSAENOTCONN: | |
1750 | # endif | |
1751 | # endif | |
1752 | #endif | |
1753 | ||
1754 | #ifdef EWOULDBLOCK | |
1755 | # ifdef WSAEWOULDBLOCK | |
1756 | # if WSAEWOULDBLOCK != EWOULDBLOCK | |
1757 | case EWOULDBLOCK: | |
1758 | # endif | |
1759 | # else | |
1760 | case EWOULDBLOCK: | |
1761 | # endif | |
1762 | #endif | |
1763 | ||
36d16f8e BL |
1764 | #ifdef EINTR |
1765 | case EINTR: | |
1766 | #endif | |
1767 | ||
1768 | #ifdef EAGAIN | |
1769 | #if EWOULDBLOCK != EAGAIN | |
1770 | case EAGAIN: | |
1771 | # endif | |
1772 | #endif | |
1773 | ||
1774 | #ifdef EPROTO | |
1775 | case EPROTO: | |
1776 | #endif | |
1777 | ||
1778 | #ifdef EINPROGRESS | |
1779 | case EINPROGRESS: | |
1780 | #endif | |
1781 | ||
1782 | #ifdef EALREADY | |
1783 | case EALREADY: | |
1784 | #endif | |
1785 | ||
36d16f8e BL |
1786 | return(1); |
1787 | /* break; */ | |
1788 | default: | |
1789 | break; | |
1790 | } | |
1791 | return(0); | |
1792 | } | |
c44544a1 RL |
1793 | |
1794 | static void get_current_time(struct timeval *t) | |
1795 | { | |
1796 | #ifdef OPENSSL_SYS_WIN32 | |
1797 | struct _timeb tb; | |
1798 | _ftime(&tb); | |
1799 | t->tv_sec = (long)tb.time; | |
1800 | t->tv_usec = (long)tb.millitm * 1000; | |
1801 | #elif defined(OPENSSL_SYS_VMS) | |
1802 | struct timeb tb; | |
1803 | ftime(&tb); | |
1804 | t->tv_sec = (long)tb.time; | |
1805 | t->tv_usec = (long)tb.millitm * 1000; | |
1806 | #else | |
1807 | gettimeofday(t, NULL); | |
1808 | #endif | |
1809 | } | |
4ff1a2da DSH |
1810 | |
1811 | #endif |