|
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 © Portions copyright (c) 2006 Nokia Corporation. All rights reserved. |
|
62 */ |
|
63 |
|
64 #ifndef OPENSSL_NO_DGRAM |
|
65 |
|
66 #include <stdio.h> |
|
67 #include <errno.h> |
|
68 #define USE_SOCKETS |
|
69 #include "cryptlib.h" |
|
70 |
|
71 #include <openssl/bio.h> |
|
72 #if (defined(SYMBIAN) && (defined(__WINSCW__) || defined(__WINS__))) |
|
73 #include "libcrypto_wsd_macros.h" |
|
74 #include "libcrypto_wsd.h" |
|
75 #endif |
|
76 |
|
77 #define IP_MTU 14 /* linux is lame */ |
|
78 |
|
79 #ifdef WATT32 |
|
80 #define sock_write SockWrite /* Watt-32 uses same names */ |
|
81 #define sock_read SockRead |
|
82 #define sock_puts SockPuts |
|
83 #endif |
|
84 |
|
85 static int dgram_write(BIO *h, const char *buf, int num); |
|
86 static int dgram_read(BIO *h, char *buf, int size); |
|
87 static int dgram_puts(BIO *h, const char *str); |
|
88 static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); |
|
89 static int dgram_new(BIO *h); |
|
90 static int dgram_free(BIO *data); |
|
91 static int dgram_clear(BIO *bio); |
|
92 |
|
93 int BIO_dgram_should_retry(int s); |
|
94 |
|
95 #ifndef EMULATOR |
|
96 static BIO_METHOD methods_dgramp= |
|
97 { |
|
98 BIO_TYPE_DGRAM, |
|
99 "datagram socket", |
|
100 dgram_write, |
|
101 dgram_read, |
|
102 dgram_puts, |
|
103 NULL, /* dgram_gets, */ |
|
104 dgram_ctrl, |
|
105 dgram_new, |
|
106 dgram_free, |
|
107 NULL, |
|
108 }; |
|
109 #else |
|
110 GET_STATIC_VAR_FROM_TLS(methods_dgramp,bss_dgram,BIO_METHOD) |
|
111 #define methods_dgramp (*GET_WSD_VAR_NAME(methods_dgramp,bss_dgram,s)()) |
|
112 const BIO_METHOD temp_s_methods_dgramp= |
|
113 { |
|
114 BIO_TYPE_DGRAM, |
|
115 "datagram socket", |
|
116 dgram_write, |
|
117 dgram_read, |
|
118 dgram_puts, |
|
119 NULL, /* dgram_gets, */ |
|
120 dgram_ctrl, |
|
121 dgram_new, |
|
122 dgram_free, |
|
123 NULL, |
|
124 }; |
|
125 |
|
126 #endif |
|
127 |
|
128 typedef struct bio_dgram_data_st |
|
129 { |
|
130 struct sockaddr peer; |
|
131 unsigned int connected; |
|
132 unsigned int _errno; |
|
133 unsigned int mtu; |
|
134 } bio_dgram_data; |
|
135 |
|
136 EXPORT_C BIO_METHOD *BIO_s_datagram(void) |
|
137 { |
|
138 return(&methods_dgramp); |
|
139 } |
|
140 |
|
141 EXPORT_C BIO *BIO_new_dgram(int fd, int close_flag) |
|
142 { |
|
143 BIO *ret; |
|
144 |
|
145 ret=BIO_new(BIO_s_datagram()); |
|
146 if (ret == NULL) return(NULL); |
|
147 BIO_set_fd(ret,fd,close_flag); |
|
148 return(ret); |
|
149 } |
|
150 |
|
151 static int dgram_new(BIO *bi) |
|
152 { |
|
153 bio_dgram_data *data = NULL; |
|
154 |
|
155 bi->init=0; |
|
156 bi->num=0; |
|
157 data = OPENSSL_malloc(sizeof(bio_dgram_data)); |
|
158 if (data == NULL) |
|
159 return 0; |
|
160 memset(data, 0x00, sizeof(bio_dgram_data)); |
|
161 bi->ptr = data; |
|
162 |
|
163 bi->flags=0; |
|
164 return(1); |
|
165 } |
|
166 |
|
167 static int dgram_free(BIO *a) |
|
168 { |
|
169 bio_dgram_data *data; |
|
170 |
|
171 if (a == NULL) return(0); |
|
172 if ( ! dgram_clear(a)) |
|
173 return 0; |
|
174 |
|
175 data = (bio_dgram_data *)a->ptr; |
|
176 if(data != NULL) OPENSSL_free(data); |
|
177 |
|
178 return(1); |
|
179 } |
|
180 |
|
181 static int dgram_clear(BIO *a) |
|
182 { |
|
183 if (a == NULL) return(0); |
|
184 if (a->shutdown) |
|
185 { |
|
186 if (a->init) |
|
187 { |
|
188 SHUTDOWN2(a->num); |
|
189 } |
|
190 a->init=0; |
|
191 a->flags=0; |
|
192 } |
|
193 return(1); |
|
194 } |
|
195 |
|
196 static int dgram_read(BIO *b, char *out, int outl) |
|
197 { |
|
198 int ret=0; |
|
199 bio_dgram_data *data = (bio_dgram_data *)b->ptr; |
|
200 |
|
201 struct sockaddr peer; |
|
202 int peerlen = sizeof(peer); |
|
203 |
|
204 if (out != NULL) |
|
205 { |
|
206 clear_socket_error(); |
|
207 memset(&peer, 0x00, peerlen); |
|
208 /* Last arg in recvfrom is signed on some platforms and |
|
209 * unsigned on others. It is of type socklen_t on some |
|
210 * but this is not universal. Cast to (void *) to avoid |
|
211 * compiler warnings. |
|
212 */ |
|
213 ret=recvfrom(b->num,out,outl,0,&peer,(void *)&peerlen); |
|
214 |
|
215 if ( ! data->connected && ret > 0) |
|
216 BIO_ctrl(b, BIO_CTRL_DGRAM_CONNECT, 0, &peer); |
|
217 |
|
218 BIO_clear_retry_flags(b); |
|
219 if (ret <= 0) |
|
220 { |
|
221 if (BIO_dgram_should_retry(ret)) |
|
222 { |
|
223 BIO_set_retry_read(b); |
|
224 data->_errno = get_last_socket_error(); |
|
225 } |
|
226 } |
|
227 } |
|
228 return(ret); |
|
229 } |
|
230 |
|
231 static int dgram_write(BIO *b, const char *in, int inl) |
|
232 { |
|
233 int ret; |
|
234 bio_dgram_data *data = (bio_dgram_data *)b->ptr; |
|
235 clear_socket_error(); |
|
236 |
|
237 if ( data->connected ) |
|
238 ret=send(b->num,in,inl,0); |
|
239 else |
|
240 ret=sendto(b->num, in, inl, 0, &data->peer, sizeof(data->peer)); |
|
241 |
|
242 BIO_clear_retry_flags(b); |
|
243 if (ret <= 0) |
|
244 { |
|
245 if (BIO_sock_should_retry(ret)) |
|
246 { |
|
247 BIO_set_retry_write(b); |
|
248 data->_errno = get_last_socket_error(); |
|
249 |
|
250 #if 0 /* higher layers are responsible for querying MTU, if necessary */ |
|
251 if ( data->_errno == EMSGSIZE) |
|
252 /* retrieve the new MTU */ |
|
253 BIO_ctrl(b, BIO_CTRL_DGRAM_QUERY_MTU, 0, NULL); |
|
254 #endif |
|
255 } |
|
256 } |
|
257 return(ret); |
|
258 } |
|
259 |
|
260 static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) |
|
261 { |
|
262 long ret=1; |
|
263 int *ip; |
|
264 struct sockaddr *to = NULL; |
|
265 bio_dgram_data *data = NULL; |
|
266 long sockopt_val = 0; |
|
267 unsigned int sockopt_len = 0; |
|
268 |
|
269 data = (bio_dgram_data *)b->ptr; |
|
270 |
|
271 switch (cmd) |
|
272 { |
|
273 case BIO_CTRL_RESET: |
|
274 num=0; |
|
275 case BIO_C_FILE_SEEK: |
|
276 ret=0; |
|
277 break; |
|
278 case BIO_C_FILE_TELL: |
|
279 case BIO_CTRL_INFO: |
|
280 ret=0; |
|
281 break; |
|
282 case BIO_C_SET_FD: |
|
283 dgram_clear(b); |
|
284 b->num= *((int *)ptr); |
|
285 b->shutdown=(int)num; |
|
286 b->init=1; |
|
287 break; |
|
288 case BIO_C_GET_FD: |
|
289 if (b->init) |
|
290 { |
|
291 ip=(int *)ptr; |
|
292 if (ip != NULL) *ip=b->num; |
|
293 ret=b->num; |
|
294 } |
|
295 else |
|
296 ret= -1; |
|
297 break; |
|
298 case BIO_CTRL_GET_CLOSE: |
|
299 ret=b->shutdown; |
|
300 break; |
|
301 case BIO_CTRL_SET_CLOSE: |
|
302 b->shutdown=(int)num; |
|
303 break; |
|
304 case BIO_CTRL_PENDING: |
|
305 case BIO_CTRL_WPENDING: |
|
306 ret=0; |
|
307 break; |
|
308 case BIO_CTRL_DUP: |
|
309 case BIO_CTRL_FLUSH: |
|
310 ret=1; |
|
311 break; |
|
312 case BIO_CTRL_DGRAM_CONNECT: |
|
313 to = (struct sockaddr *)ptr; |
|
314 #if 0 |
|
315 if (connect(b->num, to, sizeof(struct sockaddr)) < 0) |
|
316 { perror("connect"); ret = 0; } |
|
317 else |
|
318 { |
|
319 #endif |
|
320 memcpy(&(data->peer),to, sizeof(struct sockaddr)); |
|
321 #if 0 |
|
322 } |
|
323 #endif |
|
324 break; |
|
325 /* (Linux)kernel sets DF bit on outgoing IP packets */ |
|
326 #ifdef IP_MTU_DISCOVER |
|
327 case BIO_CTRL_DGRAM_MTU_DISCOVER: |
|
328 sockopt_val = IP_PMTUDISC_DO; |
|
329 if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, |
|
330 &sockopt_val, sizeof(sockopt_val))) < 0) |
|
331 perror("setsockopt"); |
|
332 break; |
|
333 #endif |
|
334 case BIO_CTRL_DGRAM_QUERY_MTU: |
|
335 sockopt_len = sizeof(sockopt_val); |
|
336 if ((ret = getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, |
|
337 &sockopt_len)) < 0 || sockopt_val < 0) |
|
338 { ret = 0; } |
|
339 else |
|
340 { |
|
341 data->mtu = sockopt_val; |
|
342 ret = data->mtu; |
|
343 } |
|
344 break; |
|
345 case BIO_CTRL_DGRAM_GET_MTU: |
|
346 return data->mtu; |
|
347 break; |
|
348 case BIO_CTRL_DGRAM_SET_MTU: |
|
349 data->mtu = num; |
|
350 ret = num; |
|
351 break; |
|
352 case BIO_CTRL_DGRAM_SET_CONNECTED: |
|
353 to = (struct sockaddr *)ptr; |
|
354 |
|
355 if ( to != NULL) |
|
356 { |
|
357 data->connected = 1; |
|
358 memcpy(&(data->peer),to, sizeof(struct sockaddr)); |
|
359 } |
|
360 else |
|
361 { |
|
362 data->connected = 0; |
|
363 memset(&(data->peer), 0x00, sizeof(struct sockaddr)); |
|
364 } |
|
365 break; |
|
366 case BIO_CTRL_DGRAM_SET_PEER: |
|
367 to = (struct sockaddr *) ptr; |
|
368 |
|
369 memcpy(&(data->peer), to, sizeof(struct sockaddr)); |
|
370 break; |
|
371 case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: |
|
372 if ( setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, |
|
373 sizeof(struct timeval)) < 0) |
|
374 { perror("setsockopt"); ret = -1; } |
|
375 break; |
|
376 case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: |
|
377 if ( getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, |
|
378 ptr, (void *)&ret) < 0) |
|
379 { perror("getsockopt"); ret = -1; } |
|
380 break; |
|
381 case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: |
|
382 if ( setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, |
|
383 sizeof(struct timeval)) < 0) |
|
384 { perror("setsockopt"); ret = -1; } |
|
385 break; |
|
386 case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: |
|
387 if ( getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, |
|
388 ptr, (void *)&ret) < 0) |
|
389 { perror("getsockopt"); ret = -1; } |
|
390 break; |
|
391 case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: |
|
392 /* fall-through */ |
|
393 case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: |
|
394 if ( data->_errno == EAGAIN) |
|
395 { |
|
396 ret = 1; |
|
397 data->_errno = 0; |
|
398 } |
|
399 else |
|
400 ret = 0; |
|
401 break; |
|
402 #ifdef EMSGSIZE |
|
403 case BIO_CTRL_DGRAM_MTU_EXCEEDED: |
|
404 if ( data->_errno == EMSGSIZE) |
|
405 { |
|
406 ret = 1; |
|
407 data->_errno = 0; |
|
408 } |
|
409 else |
|
410 ret = 0; |
|
411 break; |
|
412 #endif |
|
413 default: |
|
414 ret=0; |
|
415 break; |
|
416 } |
|
417 return(ret); |
|
418 } |
|
419 |
|
420 static int dgram_puts(BIO *bp, const char *str) |
|
421 { |
|
422 int n,ret; |
|
423 |
|
424 n=strlen(str); |
|
425 ret=dgram_write(bp,str,n); |
|
426 return(ret); |
|
427 } |
|
428 |
|
429 int BIO_dgram_should_retry(int i) |
|
430 { |
|
431 int err; |
|
432 |
|
433 if ((i == 0) || (i == -1)) |
|
434 { |
|
435 err=get_last_socket_error(); |
|
436 |
|
437 #if defined(OPENSSL_SYS_WINDOWS) && 0 /* more microsoft stupidity? perhaps not? Ben 4/1/99 */ |
|
438 if ((i == -1) && (err == 0)) |
|
439 return(1); |
|
440 #endif |
|
441 |
|
442 return(BIO_dgram_non_fatal_error(err)); |
|
443 } |
|
444 return(0); |
|
445 } |
|
446 |
|
447 EXPORT_C int BIO_dgram_non_fatal_error(int err) |
|
448 { |
|
449 switch (err) |
|
450 { |
|
451 #if defined(OPENSSL_SYS_WINDOWS) |
|
452 # if defined(WSAEWOULDBLOCK) |
|
453 case WSAEWOULDBLOCK: |
|
454 # endif |
|
455 |
|
456 # if 0 /* This appears to always be an error */ |
|
457 # if defined(WSAENOTCONN) |
|
458 case WSAENOTCONN: |
|
459 # endif |
|
460 # endif |
|
461 #endif |
|
462 |
|
463 #ifdef EWOULDBLOCK |
|
464 # ifdef WSAEWOULDBLOCK |
|
465 # if WSAEWOULDBLOCK != EWOULDBLOCK |
|
466 case EWOULDBLOCK: |
|
467 # endif |
|
468 # else |
|
469 case EWOULDBLOCK: |
|
470 # endif |
|
471 #endif |
|
472 |
|
473 #if defined(ENOTCONN) |
|
474 case ENOTCONN: |
|
475 #endif |
|
476 |
|
477 #ifdef EINTR |
|
478 case EINTR: |
|
479 #endif |
|
480 |
|
481 #ifdef EAGAIN |
|
482 #if EWOULDBLOCK != EAGAIN |
|
483 case EAGAIN: |
|
484 # endif |
|
485 #endif |
|
486 |
|
487 #ifdef EPROTO |
|
488 case EPROTO: |
|
489 #endif |
|
490 |
|
491 #ifdef EINPROGRESS |
|
492 case EINPROGRESS: |
|
493 #endif |
|
494 |
|
495 #ifdef EALREADY |
|
496 case EALREADY: |
|
497 #endif |
|
498 |
|
499 /* DF bit set, and packet larger than MTU */ |
|
500 #ifdef EMSGSIZE |
|
501 case EMSGSIZE: |
|
502 #endif |
|
503 |
|
504 return(1); |
|
505 /* break; */ |
|
506 default: |
|
507 break; |
|
508 } |
|
509 return(0); |
|
510 } |
|
511 #endif |