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