bss_dgram.c 11 KB

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