api_lib.c 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995
  1. /**
  2. * @file
  3. * Sequential API External module
  4. *
  5. * @defgroup netconn Netconn API
  6. * @ingroup sequential_api
  7. * Thread-safe, to be called from non-TCPIP threads only.
  8. * TX/RX handling based on @ref netbuf (containing @ref pbuf)
  9. * to avoid copying data around.
  10. *
  11. * @defgroup netconn_common Common functions
  12. * @ingroup netconn
  13. * For use with TCP and UDP
  14. *
  15. * @defgroup netconn_tcp TCP only
  16. * @ingroup netconn
  17. * TCP only functions
  18. *
  19. * @defgroup netconn_udp UDP only
  20. * @ingroup netconn
  21. * UDP only functions
  22. */
  23. /*
  24. * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
  25. * All rights reserved.
  26. *
  27. * Redistribution and use in source and binary forms, with or without modification,
  28. * are permitted provided that the following conditions are met:
  29. *
  30. * 1. Redistributions of source code must retain the above copyright notice,
  31. * this list of conditions and the following disclaimer.
  32. * 2. Redistributions in binary form must reproduce the above copyright notice,
  33. * this list of conditions and the following disclaimer in the documentation
  34. * and/or other materials provided with the distribution.
  35. * 3. The name of the author may not be used to endorse or promote products
  36. * derived from this software without specific prior written permission.
  37. *
  38. * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
  39. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  40. * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
  41. * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  42. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
  43. * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  44. * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  45. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  46. * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  47. * OF SUCH DAMAGE.
  48. *
  49. * This file is part of the lwIP TCP/IP stack.
  50. *
  51. * Author: Adam Dunkels <adam@sics.se>
  52. */
  53. /* This is the part of the API that is linked with
  54. the application */
  55. #include "lwip/opt.h"
  56. #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
  57. #include "lwip/api.h"
  58. #include "lwip/memp.h"
  59. #include "lwip/ip.h"
  60. #include "lwip/raw.h"
  61. #include "lwip/udp.h"
  62. #include "lwip/priv/api_msg.h"
  63. #include "lwip/priv/tcp_priv.h"
  64. #include "lwip/priv/tcpip_priv.h"
  65. #include <string.h>
  66. #define API_MSG_VAR_REF(name) API_VAR_REF(name)
  67. #define API_MSG_VAR_DECLARE(name) API_VAR_DECLARE(struct api_msg, name)
  68. #define API_MSG_VAR_ALLOC(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, ERR_MEM)
  69. #define API_MSG_VAR_ALLOC_RETURN_NULL(name) API_VAR_ALLOC(struct api_msg, MEMP_API_MSG, name, NULL)
  70. #define API_MSG_VAR_FREE(name) API_VAR_FREE(MEMP_API_MSG, name)
  71. static err_t netconn_close_shutdown(struct netconn *conn, u8_t how);
  72. /**
  73. * Call the lower part of a netconn_* function
  74. * This function is then running in the thread context
  75. * of tcpip_thread and has exclusive access to lwIP core code.
  76. *
  77. * @param fn function to call
  78. * @param apimsg a struct containing the function to call and its parameters
  79. * @return ERR_OK if the function was called, another err_t if not
  80. */
  81. static err_t
  82. netconn_apimsg(tcpip_callback_fn fn, struct api_msg *apimsg)
  83. {
  84. err_t err;
  85. #ifdef LWIP_DEBUG
  86. /* catch functions that don't set err */
  87. apimsg->err = ERR_VAL;
  88. #endif /* LWIP_DEBUG */
  89. #if LWIP_NETCONN_SEM_PER_THREAD
  90. apimsg->op_completed_sem = LWIP_NETCONN_THREAD_SEM_GET();
  91. #endif /* LWIP_NETCONN_SEM_PER_THREAD */
  92. err = tcpip_send_msg_wait_sem(fn, apimsg, LWIP_API_MSG_SEM(apimsg));
  93. if (err == ERR_OK) {
  94. return apimsg->err;
  95. }
  96. return err;
  97. }
  98. /**
  99. * Create a new netconn (of a specific type) that has a callback function.
  100. * The corresponding pcb is also created.
  101. *
  102. * @param t the type of 'connection' to create (@see enum netconn_type)
  103. * @param proto the IP protocol for RAW IP pcbs
  104. * @param callback a function to call on status changes (RX available, TX'ed)
  105. * @return a newly allocated struct netconn or
  106. * NULL on memory error
  107. */
  108. struct netconn*
  109. netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
  110. {
  111. struct netconn *conn;
  112. API_MSG_VAR_DECLARE(msg);
  113. API_MSG_VAR_ALLOC_RETURN_NULL(msg);
  114. conn = netconn_alloc(t, callback);
  115. if (conn != NULL) {
  116. err_t err;
  117. API_MSG_VAR_REF(msg).msg.n.proto = proto;
  118. API_MSG_VAR_REF(msg).conn = conn;
  119. err = netconn_apimsg(lwip_netconn_do_newconn, &API_MSG_VAR_REF(msg));
  120. if (err != ERR_OK) {
  121. LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
  122. LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
  123. #if LWIP_TCP
  124. LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
  125. #endif /* LWIP_TCP */
  126. #if !LWIP_NETCONN_SEM_PER_THREAD
  127. LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
  128. sys_sem_free(&conn->op_completed);
  129. #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
  130. sys_mbox_free(&conn->recvmbox);
  131. memp_free(MEMP_NETCONN, conn);
  132. API_MSG_VAR_FREE(msg);
  133. return NULL;
  134. }
  135. }
  136. API_MSG_VAR_FREE(msg);
  137. return conn;
  138. }
  139. /**
  140. * @ingroup netconn_common
  141. * Close a netconn 'connection' and free its resources.
  142. * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
  143. * after this returns.
  144. *
  145. * @param conn the netconn to delete
  146. * @return ERR_OK if the connection was deleted
  147. */
  148. err_t
  149. netconn_delete(struct netconn *conn)
  150. {
  151. err_t err;
  152. API_MSG_VAR_DECLARE(msg);
  153. /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
  154. if (conn == NULL) {
  155. return ERR_OK;
  156. }
  157. API_MSG_VAR_ALLOC(msg);
  158. API_MSG_VAR_REF(msg).conn = conn;
  159. #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
  160. /* get the time we started, which is later compared to
  161. sys_now() + conn->send_timeout */
  162. API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
  163. #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
  164. #if LWIP_TCP
  165. API_MSG_VAR_REF(msg).msg.sd.polls_left =
  166. ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
  167. #endif /* LWIP_TCP */
  168. #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
  169. err = netconn_apimsg(lwip_netconn_do_delconn, &API_MSG_VAR_REF(msg));
  170. API_MSG_VAR_FREE(msg);
  171. if (err != ERR_OK) {
  172. return err;
  173. }
  174. netconn_free(conn);
  175. return ERR_OK;
  176. }
  177. /**
  178. * Get the local or remote IP address and port of a netconn.
  179. * For RAW netconns, this returns the protocol instead of a port!
  180. *
  181. * @param conn the netconn to query
  182. * @param addr a pointer to which to save the IP address
  183. * @param port a pointer to which to save the port (or protocol for RAW)
  184. * @param local 1 to get the local IP address, 0 to get the remote one
  185. * @return ERR_CONN for invalid connections
  186. * ERR_OK if the information was retrieved
  187. */
  188. err_t
  189. netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
  190. {
  191. API_MSG_VAR_DECLARE(msg);
  192. err_t err;
  193. LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
  194. LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
  195. LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
  196. API_MSG_VAR_ALLOC(msg);
  197. API_MSG_VAR_REF(msg).conn = conn;
  198. API_MSG_VAR_REF(msg).msg.ad.local = local;
  199. #if LWIP_MPU_COMPATIBLE
  200. err = netconn_apimsg(lwip_netconn_do_getaddr, &API_MSG_VAR_REF(msg));
  201. *addr = msg->msg.ad.ipaddr;
  202. *port = msg->msg.ad.port;
  203. #else /* LWIP_MPU_COMPATIBLE */
  204. msg.msg.ad.ipaddr = addr;
  205. msg.msg.ad.port = port;
  206. err = netconn_apimsg(lwip_netconn_do_getaddr, &msg);
  207. #endif /* LWIP_MPU_COMPATIBLE */
  208. API_MSG_VAR_FREE(msg);
  209. return err;
  210. }
  211. /**
  212. * @ingroup netconn_common
  213. * Bind a netconn to a specific local IP address and port.
  214. * Binding one netconn twice might not always be checked correctly!
  215. *
  216. * @param conn the netconn to bind
  217. * @param addr the local IP address to bind the netconn to
  218. * (use IP4_ADDR_ANY/IP6_ADDR_ANY to bind to all addresses)
  219. * @param port the local port to bind the netconn to (not used for RAW)
  220. * @return ERR_OK if bound, any other err_t on failure
  221. */
  222. err_t
  223. netconn_bind(struct netconn *conn, const ip_addr_t *addr, u16_t port)
  224. {
  225. API_MSG_VAR_DECLARE(msg);
  226. err_t err;
  227. LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
  228. /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
  229. if (addr == NULL) {
  230. addr = IP4_ADDR_ANY;
  231. }
  232. API_MSG_VAR_ALLOC(msg);
  233. API_MSG_VAR_REF(msg).conn = conn;
  234. API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
  235. API_MSG_VAR_REF(msg).msg.bc.port = port;
  236. err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
  237. API_MSG_VAR_FREE(msg);
  238. return err;
  239. }
  240. /**
  241. * @ingroup netconn_common
  242. * Connect a netconn to a specific remote IP address and port.
  243. *
  244. * @param conn the netconn to connect
  245. * @param addr the remote IP address to connect to
  246. * @param port the remote port to connect to (no used for RAW)
  247. * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
  248. */
  249. err_t
  250. netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
  251. {
  252. API_MSG_VAR_DECLARE(msg);
  253. err_t err;
  254. LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
  255. /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
  256. if (addr == NULL) {
  257. addr = IP4_ADDR_ANY;
  258. }
  259. API_MSG_VAR_ALLOC(msg);
  260. API_MSG_VAR_REF(msg).conn = conn;
  261. API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
  262. API_MSG_VAR_REF(msg).msg.bc.port = port;
  263. err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
  264. API_MSG_VAR_FREE(msg);
  265. return err;
  266. }
  267. /**
  268. * @ingroup netconn_udp
  269. * Disconnect a netconn from its current peer (only valid for UDP netconns).
  270. *
  271. * @param conn the netconn to disconnect
  272. * @return See @ref err_t
  273. */
  274. err_t
  275. netconn_disconnect(struct netconn *conn)
  276. {
  277. API_MSG_VAR_DECLARE(msg);
  278. err_t err;
  279. LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
  280. API_MSG_VAR_ALLOC(msg);
  281. API_MSG_VAR_REF(msg).conn = conn;
  282. err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
  283. API_MSG_VAR_FREE(msg);
  284. return err;
  285. }
  286. /**
  287. * @ingroup netconn_tcp
  288. * Set a TCP netconn into listen mode
  289. *
  290. * @param conn the tcp netconn to set to listen mode
  291. * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
  292. * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
  293. * don't return any error (yet?))
  294. */
  295. err_t
  296. netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
  297. {
  298. #if LWIP_TCP
  299. API_MSG_VAR_DECLARE(msg);
  300. err_t err;
  301. /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
  302. LWIP_UNUSED_ARG(backlog);
  303. LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
  304. API_MSG_VAR_ALLOC(msg);
  305. API_MSG_VAR_REF(msg).conn = conn;
  306. #if TCP_LISTEN_BACKLOG
  307. API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
  308. #endif /* TCP_LISTEN_BACKLOG */
  309. err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
  310. API_MSG_VAR_FREE(msg);
  311. return err;
  312. #else /* LWIP_TCP */
  313. LWIP_UNUSED_ARG(conn);
  314. LWIP_UNUSED_ARG(backlog);
  315. return ERR_ARG;
  316. #endif /* LWIP_TCP */
  317. }
  318. /**
  319. * @ingroup netconn_tcp
  320. * Accept a new connection on a TCP listening netconn.
  321. *
  322. * @param conn the TCP listen netconn
  323. * @param new_conn pointer where the new connection is stored
  324. * @return ERR_OK if a new connection has been received or an error
  325. * code otherwise
  326. */
  327. err_t
  328. netconn_accept(struct netconn *conn, struct netconn **new_conn)
  329. {
  330. #if LWIP_TCP
  331. void *accept_ptr;
  332. struct netconn *newconn;
  333. err_t err;
  334. #if TCP_LISTEN_BACKLOG
  335. API_MSG_VAR_DECLARE(msg);
  336. #endif /* TCP_LISTEN_BACKLOG */
  337. LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
  338. *new_conn = NULL;
  339. LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
  340. err = conn->last_err;
  341. if (ERR_IS_FATAL(err)) {
  342. /* don't recv on fatal errors: this might block the application task
  343. waiting on acceptmbox forever! */
  344. return err;
  345. }
  346. if (!sys_mbox_valid(&conn->acceptmbox)) {
  347. return ERR_CLSD;
  348. }
  349. #if TCP_LISTEN_BACKLOG
  350. API_MSG_VAR_ALLOC(msg);
  351. #endif /* TCP_LISTEN_BACKLOG */
  352. #if LWIP_SO_RCVTIMEO
  353. if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
  354. #if TCP_LISTEN_BACKLOG
  355. API_MSG_VAR_FREE(msg);
  356. #endif /* TCP_LISTEN_BACKLOG */
  357. return ERR_TIMEOUT;
  358. }
  359. #else
  360. sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
  361. #endif /* LWIP_SO_RCVTIMEO*/
  362. newconn = (struct netconn *)accept_ptr;
  363. /* Register event with callback */
  364. API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
  365. if (accept_ptr == &netconn_aborted) {
  366. /* a connection has been aborted: out of pcbs or out of netconns during accept */
  367. /* @todo: set netconn error, but this would be fatal and thus block further accepts */
  368. #if TCP_LISTEN_BACKLOG
  369. API_MSG_VAR_FREE(msg);
  370. #endif /* TCP_LISTEN_BACKLOG */
  371. return ERR_ABRT;
  372. }
  373. if (newconn == NULL) {
  374. /* connection has been aborted */
  375. /* in this special case, we set the netconn error from application thread, as
  376. on a ready-to-accept listening netconn, there should not be anything running
  377. in tcpip_thread */
  378. NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
  379. #if TCP_LISTEN_BACKLOG
  380. API_MSG_VAR_FREE(msg);
  381. #endif /* TCP_LISTEN_BACKLOG */
  382. return ERR_CLSD;
  383. }
  384. #if TCP_LISTEN_BACKLOG
  385. /* Let the stack know that we have accepted the connection. */
  386. API_MSG_VAR_REF(msg).conn = newconn;
  387. /* don't care for the return value of lwip_netconn_do_recv */
  388. netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
  389. API_MSG_VAR_FREE(msg);
  390. #endif /* TCP_LISTEN_BACKLOG */
  391. *new_conn = newconn;
  392. /* don't set conn->last_err: it's only ERR_OK, anyway */
  393. return ERR_OK;
  394. #else /* LWIP_TCP */
  395. LWIP_UNUSED_ARG(conn);
  396. LWIP_UNUSED_ARG(new_conn);
  397. return ERR_ARG;
  398. #endif /* LWIP_TCP */
  399. }
  400. /**
  401. * @ingroup netconn_common
  402. * Receive data: actual implementation that doesn't care whether pbuf or netbuf
  403. * is received
  404. *
  405. * @param conn the netconn from which to receive data
  406. * @param new_buf pointer where a new pbuf/netbuf is stored when received data
  407. * @return ERR_OK if data has been received, an error code otherwise (timeout,
  408. * memory error or another error)
  409. */
  410. static err_t
  411. netconn_recv_data(struct netconn *conn, void **new_buf)
  412. {
  413. void *buf = NULL;
  414. u16_t len;
  415. err_t err;
  416. #if LWIP_TCP
  417. API_MSG_VAR_DECLARE(msg);
  418. #if LWIP_MPU_COMPATIBLE
  419. msg = NULL;
  420. #endif
  421. #endif /* LWIP_TCP */
  422. LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
  423. *new_buf = NULL;
  424. LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
  425. #if LWIP_TCP
  426. #if (LWIP_UDP || LWIP_RAW)
  427. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  428. #endif /* (LWIP_UDP || LWIP_RAW) */
  429. {
  430. if (!sys_mbox_valid(&conn->recvmbox)) {
  431. /* This happens when calling this function after receiving FIN */
  432. return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD;
  433. }
  434. }
  435. #endif /* LWIP_TCP */
  436. LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
  437. err = conn->last_err;
  438. if (ERR_IS_FATAL(err)) {
  439. /* don't recv on fatal errors: this might block the application task
  440. waiting on recvmbox forever! */
  441. /* @todo: this does not allow us to fetch data that has been put into recvmbox
  442. before the fatal error occurred - is that a problem? */
  443. return err;
  444. }
  445. #if LWIP_TCP
  446. #if (LWIP_UDP || LWIP_RAW)
  447. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  448. #endif /* (LWIP_UDP || LWIP_RAW) */
  449. {
  450. API_MSG_VAR_ALLOC(msg);
  451. }
  452. #endif /* LWIP_TCP */
  453. #if LWIP_SO_RCVTIMEO
  454. if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
  455. #if LWIP_TCP
  456. #if (LWIP_UDP || LWIP_RAW)
  457. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  458. #endif /* (LWIP_UDP || LWIP_RAW) */
  459. {
  460. API_MSG_VAR_FREE(msg);
  461. }
  462. #endif /* LWIP_TCP */
  463. return ERR_TIMEOUT;
  464. }
  465. #else
  466. sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
  467. #endif /* LWIP_SO_RCVTIMEO*/
  468. #if LWIP_TCP
  469. #if (LWIP_UDP || LWIP_RAW)
  470. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  471. #endif /* (LWIP_UDP || LWIP_RAW) */
  472. {
  473. /* Let the stack know that we have taken the data. */
  474. /* @todo: Speedup: Don't block and wait for the answer here
  475. (to prevent multiple thread-switches). */
  476. API_MSG_VAR_REF(msg).conn = conn;
  477. if (buf != NULL) {
  478. API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len;
  479. } else {
  480. API_MSG_VAR_REF(msg).msg.r.len = 1;
  481. }
  482. /* don't care for the return value of lwip_netconn_do_recv */
  483. netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg));
  484. API_MSG_VAR_FREE(msg);
  485. /* If we are closed, we indicate that we no longer wish to use the socket */
  486. if (buf == NULL) {
  487. API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
  488. if (conn->pcb.ip == NULL) {
  489. /* race condition: RST during recv */
  490. return conn->last_err == ERR_OK ? ERR_RST : conn->last_err;
  491. }
  492. /* RX side is closed, so deallocate the recvmbox */
  493. netconn_close_shutdown(conn, NETCONN_SHUT_RD);
  494. /* Don' store ERR_CLSD as conn->err since we are only half-closed */
  495. return ERR_CLSD;
  496. }
  497. len = ((struct pbuf *)buf)->tot_len;
  498. }
  499. #endif /* LWIP_TCP */
  500. #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
  501. else
  502. #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
  503. #if (LWIP_UDP || LWIP_RAW)
  504. {
  505. LWIP_ASSERT("buf != NULL", buf != NULL);
  506. len = netbuf_len((struct netbuf *)buf);
  507. }
  508. #endif /* (LWIP_UDP || LWIP_RAW) */
  509. #if LWIP_SO_RCVBUF
  510. SYS_ARCH_DEC(conn->recv_avail, len);
  511. #endif /* LWIP_SO_RCVBUF */
  512. /* Register event with callback */
  513. API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
  514. LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
  515. *new_buf = buf;
  516. /* don't set conn->last_err: it's only ERR_OK, anyway */
  517. return ERR_OK;
  518. }
  519. /**
  520. * @ingroup netconn_tcp
  521. * Receive data (in form of a pbuf) from a TCP netconn
  522. *
  523. * @param conn the netconn from which to receive data
  524. * @param new_buf pointer where a new pbuf is stored when received data
  525. * @return ERR_OK if data has been received, an error code otherwise (timeout,
  526. * memory error or another error)
  527. * ERR_ARG if conn is not a TCP netconn
  528. */
  529. err_t
  530. netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
  531. {
  532. LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
  533. NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
  534. return netconn_recv_data(conn, (void **)new_buf);
  535. }
  536. /**
  537. * @ingroup netconn_common
  538. * Receive data (in form of a netbuf containing a packet buffer) from a netconn
  539. *
  540. * @param conn the netconn from which to receive data
  541. * @param new_buf pointer where a new netbuf is stored when received data
  542. * @return ERR_OK if data has been received, an error code otherwise (timeout,
  543. * memory error or another error)
  544. */
  545. err_t
  546. netconn_recv(struct netconn *conn, struct netbuf **new_buf)
  547. {
  548. #if LWIP_TCP
  549. struct netbuf *buf = NULL;
  550. err_t err;
  551. #endif /* LWIP_TCP */
  552. LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
  553. *new_buf = NULL;
  554. LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
  555. #if LWIP_TCP
  556. #if (LWIP_UDP || LWIP_RAW)
  557. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  558. #endif /* (LWIP_UDP || LWIP_RAW) */
  559. {
  560. struct pbuf *p = NULL;
  561. /* This is not a listening netconn, since recvmbox is set */
  562. buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
  563. if (buf == NULL) {
  564. return ERR_MEM;
  565. }
  566. err = netconn_recv_data(conn, (void **)&p);
  567. if (err != ERR_OK) {
  568. memp_free(MEMP_NETBUF, buf);
  569. return err;
  570. }
  571. LWIP_ASSERT("p != NULL", p != NULL);
  572. buf->p = p;
  573. buf->ptr = p;
  574. buf->port = 0;
  575. ip_addr_set_zero(&buf->addr);
  576. *new_buf = buf;
  577. /* don't set conn->last_err: it's only ERR_OK, anyway */
  578. return ERR_OK;
  579. }
  580. #endif /* LWIP_TCP */
  581. #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
  582. else
  583. #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
  584. {
  585. #if (LWIP_UDP || LWIP_RAW)
  586. return netconn_recv_data(conn, (void **)new_buf);
  587. #endif /* (LWIP_UDP || LWIP_RAW) */
  588. }
  589. }
  590. /**
  591. * @ingroup netconn_udp
  592. * Send data (in form of a netbuf) to a specific remote IP address and port.
  593. * Only to be used for UDP and RAW netconns (not TCP).
  594. *
  595. * @param conn the netconn over which to send data
  596. * @param buf a netbuf containing the data to send
  597. * @param addr the remote IP address to which to send the data
  598. * @param port the remote port to which to send the data
  599. * @return ERR_OK if data was sent, any other err_t on error
  600. */
  601. err_t
  602. netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
  603. {
  604. if (buf != NULL) {
  605. ip_addr_set(&buf->addr, addr);
  606. buf->port = port;
  607. return netconn_send(conn, buf);
  608. }
  609. return ERR_VAL;
  610. }
  611. /**
  612. * @ingroup netconn_udp
  613. * Send data over a UDP or RAW netconn (that is already connected).
  614. *
  615. * @param conn the UDP or RAW netconn over which to send data
  616. * @param buf a netbuf containing the data to send
  617. * @return ERR_OK if data was sent, any other err_t on error
  618. */
  619. err_t
  620. netconn_send(struct netconn *conn, struct netbuf *buf)
  621. {
  622. API_MSG_VAR_DECLARE(msg);
  623. err_t err;
  624. LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
  625. LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
  626. API_MSG_VAR_ALLOC(msg);
  627. API_MSG_VAR_REF(msg).conn = conn;
  628. API_MSG_VAR_REF(msg).msg.b = buf;
  629. err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
  630. API_MSG_VAR_FREE(msg);
  631. return err;
  632. }
  633. /**
  634. * @ingroup netconn_tcp
  635. * Send data over a TCP netconn.
  636. *
  637. * @param conn the TCP netconn over which to send data
  638. * @param dataptr pointer to the application buffer that contains the data to send
  639. * @param size size of the application data to send
  640. * @param apiflags combination of following flags :
  641. * - NETCONN_COPY: data will be copied into memory belonging to the stack
  642. * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
  643. * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
  644. * @param bytes_written pointer to a location that receives the number of written bytes
  645. * @return ERR_OK if data was sent, any other err_t on error
  646. */
  647. err_t
  648. netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
  649. u8_t apiflags, size_t *bytes_written)
  650. {
  651. API_MSG_VAR_DECLARE(msg);
  652. err_t err;
  653. u8_t dontblock;
  654. LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
  655. LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;);
  656. if (size == 0) {
  657. return ERR_OK;
  658. }
  659. dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
  660. if (dontblock && !bytes_written) {
  661. /* This implies netconn_write() cannot be used for non-blocking send, since
  662. it has no way to return the number of bytes written. */
  663. return ERR_VAL;
  664. }
  665. API_MSG_VAR_ALLOC(msg);
  666. /* non-blocking write sends as much */
  667. API_MSG_VAR_REF(msg).conn = conn;
  668. API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr;
  669. API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
  670. API_MSG_VAR_REF(msg).msg.w.len = size;
  671. #if LWIP_SO_SNDTIMEO
  672. if (conn->send_timeout != 0) {
  673. /* get the time we started, which is later compared to
  674. sys_now() + conn->send_timeout */
  675. API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
  676. } else {
  677. API_MSG_VAR_REF(msg).msg.w.time_started = 0;
  678. }
  679. #endif /* LWIP_SO_SNDTIMEO */
  680. /* For locking the core: this _can_ be delayed on low memory/low send buffer,
  681. but if it is, this is done inside api_msg.c:do_write(), so we can use the
  682. non-blocking version here. */
  683. err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
  684. if ((err == ERR_OK) && (bytes_written != NULL)) {
  685. if (dontblock
  686. #if LWIP_SO_SNDTIMEO
  687. || (conn->send_timeout != 0)
  688. #endif /* LWIP_SO_SNDTIMEO */
  689. ) {
  690. /* nonblocking write: maybe the data has been sent partly */
  691. *bytes_written = API_MSG_VAR_REF(msg).msg.w.len;
  692. } else {
  693. /* blocking call succeeded: all data has been sent if it */
  694. *bytes_written = size;
  695. }
  696. }
  697. API_MSG_VAR_FREE(msg);
  698. return err;
  699. }
  700. /**
  701. * @ingroup netconn_tcp
  702. * Close or shutdown a TCP netconn (doesn't delete it).
  703. *
  704. * @param conn the TCP netconn to close or shutdown
  705. * @param how fully close or only shutdown one side?
  706. * @return ERR_OK if the netconn was closed, any other err_t on error
  707. */
  708. static err_t
  709. netconn_close_shutdown(struct netconn *conn, u8_t how)
  710. {
  711. API_MSG_VAR_DECLARE(msg);
  712. err_t err;
  713. LWIP_UNUSED_ARG(how);
  714. LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
  715. API_MSG_VAR_ALLOC(msg);
  716. API_MSG_VAR_REF(msg).conn = conn;
  717. #if LWIP_TCP
  718. /* shutting down both ends is the same as closing */
  719. API_MSG_VAR_REF(msg).msg.sd.shut = how;
  720. #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
  721. /* get the time we started, which is later compared to
  722. sys_now() + conn->send_timeout */
  723. API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
  724. #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
  725. API_MSG_VAR_REF(msg).msg.sd.polls_left =
  726. ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
  727. #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
  728. #endif /* LWIP_TCP */
  729. err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
  730. API_MSG_VAR_FREE(msg);
  731. return err;
  732. }
  733. /**
  734. * @ingroup netconn_tcp
  735. * Close a TCP netconn (doesn't delete it).
  736. *
  737. * @param conn the TCP netconn to close
  738. * @return ERR_OK if the netconn was closed, any other err_t on error
  739. */
  740. err_t
  741. netconn_close(struct netconn *conn)
  742. {
  743. /* shutting down both ends is the same as closing */
  744. return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
  745. }
  746. /**
  747. * @ingroup netconn_tcp
  748. * Shut down one or both sides of a TCP netconn (doesn't delete it).
  749. *
  750. * @param conn the TCP netconn to shut down
  751. * @param shut_rx shut down the RX side (no more read possible after this)
  752. * @param shut_tx shut down the TX side (no more write possible after this)
  753. * @return ERR_OK if the netconn was closed, any other err_t on error
  754. */
  755. err_t
  756. netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
  757. {
  758. return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
  759. }
  760. #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
  761. /**
  762. * @ingroup netconn_udp
  763. * Join multicast groups for UDP netconns.
  764. *
  765. * @param conn the UDP netconn for which to change multicast addresses
  766. * @param multiaddr IP address of the multicast group to join or leave
  767. * @param netif_addr the IP address of the network interface on which to send
  768. * the igmp message
  769. * @param join_or_leave flag whether to send a join- or leave-message
  770. * @return ERR_OK if the action was taken, any err_t on error
  771. */
  772. err_t
  773. netconn_join_leave_group(struct netconn *conn,
  774. const ip_addr_t *multiaddr,
  775. const ip_addr_t *netif_addr,
  776. enum netconn_igmp join_or_leave)
  777. {
  778. API_MSG_VAR_DECLARE(msg);
  779. err_t err;
  780. LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
  781. API_MSG_VAR_ALLOC(msg);
  782. /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
  783. if (multiaddr == NULL) {
  784. multiaddr = IP4_ADDR_ANY;
  785. }
  786. if (netif_addr == NULL) {
  787. netif_addr = IP4_ADDR_ANY;
  788. }
  789. API_MSG_VAR_REF(msg).conn = conn;
  790. API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
  791. API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
  792. API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
  793. err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
  794. API_MSG_VAR_FREE(msg);
  795. return err;
  796. }
  797. #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
  798. #if LWIP_DNS
  799. /**
  800. * @ingroup netconn_common
  801. * Execute a DNS query, only one IP address is returned
  802. *
  803. * @param name a string representation of the DNS host name to query
  804. * @param addr a preallocated ip_addr_t where to store the resolved IP address
  805. * @param dns_addrtype IP address type (IPv4 / IPv6)
  806. * @return ERR_OK: resolving succeeded
  807. * ERR_MEM: memory error, try again later
  808. * ERR_ARG: dns client not initialized or invalid hostname
  809. * ERR_VAL: dns server response was invalid
  810. */
  811. #if LWIP_IPV4 && LWIP_IPV6
  812. err_t
  813. netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
  814. #else
  815. err_t
  816. netconn_gethostbyname(const char *name, ip_addr_t *addr)
  817. #endif
  818. {
  819. API_VAR_DECLARE(struct dns_api_msg, msg);
  820. #if !LWIP_MPU_COMPATIBLE
  821. sys_sem_t sem;
  822. #endif /* LWIP_MPU_COMPATIBLE */
  823. err_t err;
  824. LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
  825. LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
  826. #if LWIP_MPU_COMPATIBLE
  827. if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
  828. return ERR_ARG;
  829. }
  830. #endif
  831. API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
  832. #if LWIP_MPU_COMPATIBLE
  833. strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1);
  834. API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0;
  835. #else /* LWIP_MPU_COMPATIBLE */
  836. msg.err = &err;
  837. msg.sem = &sem;
  838. API_VAR_REF(msg).addr = API_VAR_REF(addr);
  839. API_VAR_REF(msg).name = name;
  840. #endif /* LWIP_MPU_COMPATIBLE */
  841. #if LWIP_IPV4 && LWIP_IPV6
  842. API_VAR_REF(msg).dns_addrtype = dns_addrtype;
  843. #endif /* LWIP_IPV4 && LWIP_IPV6 */
  844. #if LWIP_NETCONN_SEM_PER_THREAD
  845. API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
  846. #else /* LWIP_NETCONN_SEM_PER_THREAD*/
  847. err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
  848. if (err != ERR_OK) {
  849. API_VAR_FREE(MEMP_DNS_API_MSG, msg);
  850. return err;
  851. }
  852. #endif /* LWIP_NETCONN_SEM_PER_THREAD */
  853. err = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
  854. if (err != ERR_OK) {
  855. #if !LWIP_NETCONN_SEM_PER_THREAD
  856. sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
  857. #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
  858. API_VAR_FREE(MEMP_DNS_API_MSG, msg);
  859. return err;
  860. }
  861. sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
  862. #if !LWIP_NETCONN_SEM_PER_THREAD
  863. sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
  864. #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
  865. #if LWIP_MPU_COMPATIBLE
  866. *addr = msg->addr;
  867. err = msg->err;
  868. #endif /* LWIP_MPU_COMPATIBLE */
  869. API_VAR_FREE(MEMP_DNS_API_MSG, msg);
  870. return err;
  871. }
  872. #endif /* LWIP_DNS*/
  873. #if LWIP_NETCONN_SEM_PER_THREAD
  874. void
  875. netconn_thread_init(void)
  876. {
  877. sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
  878. if ((sem == NULL) || !sys_sem_valid(sem)) {
  879. /* call alloc only once */
  880. LWIP_NETCONN_THREAD_SEM_ALLOC();
  881. LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
  882. }
  883. }
  884. void
  885. netconn_thread_cleanup(void)
  886. {
  887. sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
  888. if ((sem != NULL) && sys_sem_valid(sem)) {
  889. /* call free only once */
  890. LWIP_NETCONN_THREAD_SEM_FREE();
  891. }
  892. }
  893. #endif /* LWIP_NETCONN_SEM_PER_THREAD */
  894. #endif /* LWIP_NETCONN */