1
0

api_lib.c 31 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010
  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_TCP
  160. #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
  161. /* get the time we started, which is later compared to
  162. sys_now() + conn->send_timeout */
  163. API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
  164. #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
  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. #if LWIP_IPV4
  229. /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
  230. if (addr == NULL) {
  231. addr = IP4_ADDR_ANY;
  232. }
  233. #endif /* LWIP_IPV4 */
  234. #if LWIP_IPV4 && LWIP_IPV6
  235. /* "Socket API like" dual-stack support: If IP to bind to is IP6_ADDR_ANY,
  236. * and NETCONN_FLAG_IPV6_V6ONLY is 0, use IP_ANY_TYPE to bind
  237. */
  238. if ((netconn_get_ipv6only(conn) == 0) &&
  239. ip_addr_cmp(addr, IP6_ADDR_ANY)) {
  240. addr = IP_ANY_TYPE;
  241. }
  242. #endif /* LWIP_IPV4 && LWIP_IPV6 */
  243. API_MSG_VAR_ALLOC(msg);
  244. API_MSG_VAR_REF(msg).conn = conn;
  245. API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
  246. API_MSG_VAR_REF(msg).msg.bc.port = port;
  247. err = netconn_apimsg(lwip_netconn_do_bind, &API_MSG_VAR_REF(msg));
  248. API_MSG_VAR_FREE(msg);
  249. return err;
  250. }
  251. /**
  252. * @ingroup netconn_common
  253. * Connect a netconn to a specific remote IP address and port.
  254. *
  255. * @param conn the netconn to connect
  256. * @param addr the remote IP address to connect to
  257. * @param port the remote port to connect to (no used for RAW)
  258. * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
  259. */
  260. err_t
  261. netconn_connect(struct netconn *conn, const ip_addr_t *addr, u16_t port)
  262. {
  263. API_MSG_VAR_DECLARE(msg);
  264. err_t err;
  265. LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
  266. #if LWIP_IPV4
  267. /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
  268. if (addr == NULL) {
  269. addr = IP4_ADDR_ANY;
  270. }
  271. #endif /* LWIP_IPV4 */
  272. API_MSG_VAR_ALLOC(msg);
  273. API_MSG_VAR_REF(msg).conn = conn;
  274. API_MSG_VAR_REF(msg).msg.bc.ipaddr = API_MSG_VAR_REF(addr);
  275. API_MSG_VAR_REF(msg).msg.bc.port = port;
  276. err = netconn_apimsg(lwip_netconn_do_connect, &API_MSG_VAR_REF(msg));
  277. API_MSG_VAR_FREE(msg);
  278. return err;
  279. }
  280. /**
  281. * @ingroup netconn_udp
  282. * Disconnect a netconn from its current peer (only valid for UDP netconns).
  283. *
  284. * @param conn the netconn to disconnect
  285. * @return See @ref err_t
  286. */
  287. err_t
  288. netconn_disconnect(struct netconn *conn)
  289. {
  290. API_MSG_VAR_DECLARE(msg);
  291. err_t err;
  292. LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
  293. API_MSG_VAR_ALLOC(msg);
  294. API_MSG_VAR_REF(msg).conn = conn;
  295. err = netconn_apimsg(lwip_netconn_do_disconnect, &API_MSG_VAR_REF(msg));
  296. API_MSG_VAR_FREE(msg);
  297. return err;
  298. }
  299. /**
  300. * @ingroup netconn_tcp
  301. * Set a TCP netconn into listen mode
  302. *
  303. * @param conn the tcp netconn to set to listen mode
  304. * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
  305. * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
  306. * don't return any error (yet?))
  307. */
  308. err_t
  309. netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
  310. {
  311. #if LWIP_TCP
  312. API_MSG_VAR_DECLARE(msg);
  313. err_t err;
  314. /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
  315. LWIP_UNUSED_ARG(backlog);
  316. LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
  317. API_MSG_VAR_ALLOC(msg);
  318. API_MSG_VAR_REF(msg).conn = conn;
  319. #if TCP_LISTEN_BACKLOG
  320. API_MSG_VAR_REF(msg).msg.lb.backlog = backlog;
  321. #endif /* TCP_LISTEN_BACKLOG */
  322. err = netconn_apimsg(lwip_netconn_do_listen, &API_MSG_VAR_REF(msg));
  323. API_MSG_VAR_FREE(msg);
  324. return err;
  325. #else /* LWIP_TCP */
  326. LWIP_UNUSED_ARG(conn);
  327. LWIP_UNUSED_ARG(backlog);
  328. return ERR_ARG;
  329. #endif /* LWIP_TCP */
  330. }
  331. /**
  332. * @ingroup netconn_tcp
  333. * Accept a new connection on a TCP listening netconn.
  334. *
  335. * @param conn the TCP listen netconn
  336. * @param new_conn pointer where the new connection is stored
  337. * @return ERR_OK if a new connection has been received or an error
  338. * code otherwise
  339. */
  340. err_t
  341. netconn_accept(struct netconn *conn, struct netconn **new_conn)
  342. {
  343. #if LWIP_TCP
  344. void *accept_ptr;
  345. struct netconn *newconn;
  346. #if TCP_LISTEN_BACKLOG
  347. API_MSG_VAR_DECLARE(msg);
  348. #endif /* TCP_LISTEN_BACKLOG */
  349. LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;);
  350. *new_conn = NULL;
  351. LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;);
  352. if (ERR_IS_FATAL(conn->last_err)) {
  353. /* don't recv on fatal errors: this might block the application task
  354. waiting on acceptmbox forever! */
  355. return conn->last_err;
  356. }
  357. if (!sys_mbox_valid(&conn->acceptmbox)) {
  358. return ERR_CLSD;
  359. }
  360. #if TCP_LISTEN_BACKLOG
  361. API_MSG_VAR_ALLOC(msg);
  362. #endif /* TCP_LISTEN_BACKLOG */
  363. #if LWIP_SO_RCVTIMEO
  364. if (sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
  365. #if TCP_LISTEN_BACKLOG
  366. API_MSG_VAR_FREE(msg);
  367. #endif /* TCP_LISTEN_BACKLOG */
  368. return ERR_TIMEOUT;
  369. }
  370. #else
  371. sys_arch_mbox_fetch(&conn->acceptmbox, &accept_ptr, 0);
  372. #endif /* LWIP_SO_RCVTIMEO*/
  373. newconn = (struct netconn *)accept_ptr;
  374. /* Register event with callback */
  375. API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
  376. if (accept_ptr == &netconn_aborted) {
  377. /* a connection has been aborted: out of pcbs or out of netconns during accept */
  378. /* @todo: set netconn error, but this would be fatal and thus block further accepts */
  379. #if TCP_LISTEN_BACKLOG
  380. API_MSG_VAR_FREE(msg);
  381. #endif /* TCP_LISTEN_BACKLOG */
  382. return ERR_ABRT;
  383. }
  384. if (newconn == NULL) {
  385. /* connection has been aborted */
  386. /* in this special case, we set the netconn error from application thread, as
  387. on a ready-to-accept listening netconn, there should not be anything running
  388. in tcpip_thread */
  389. NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
  390. #if TCP_LISTEN_BACKLOG
  391. API_MSG_VAR_FREE(msg);
  392. #endif /* TCP_LISTEN_BACKLOG */
  393. return ERR_CLSD;
  394. }
  395. #if TCP_LISTEN_BACKLOG
  396. /* Let the stack know that we have accepted the connection. */
  397. API_MSG_VAR_REF(msg).conn = newconn;
  398. /* don't care for the return value of lwip_netconn_do_recv */
  399. netconn_apimsg(lwip_netconn_do_accepted, &API_MSG_VAR_REF(msg));
  400. API_MSG_VAR_FREE(msg);
  401. #endif /* TCP_LISTEN_BACKLOG */
  402. *new_conn = newconn;
  403. /* don't set conn->last_err: it's only ERR_OK, anyway */
  404. return ERR_OK;
  405. #else /* LWIP_TCP */
  406. LWIP_UNUSED_ARG(conn);
  407. LWIP_UNUSED_ARG(new_conn);
  408. return ERR_ARG;
  409. #endif /* LWIP_TCP */
  410. }
  411. /**
  412. * @ingroup netconn_common
  413. * Receive data: actual implementation that doesn't care whether pbuf or netbuf
  414. * is received
  415. *
  416. * @param conn the netconn from which to receive data
  417. * @param new_buf pointer where a new pbuf/netbuf is stored when received data
  418. * @return ERR_OK if data has been received, an error code otherwise (timeout,
  419. * memory error or another error)
  420. */
  421. static err_t
  422. netconn_recv_data(struct netconn *conn, void **new_buf)
  423. {
  424. void *buf = NULL;
  425. u16_t len;
  426. #if LWIP_TCP
  427. API_MSG_VAR_DECLARE(msg);
  428. #if LWIP_MPU_COMPATIBLE
  429. msg = NULL;
  430. #endif
  431. #endif /* LWIP_TCP */
  432. LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
  433. *new_buf = NULL;
  434. LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
  435. #if LWIP_TCP
  436. #if (LWIP_UDP || LWIP_RAW)
  437. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  438. #endif /* (LWIP_UDP || LWIP_RAW) */
  439. {
  440. if (!sys_mbox_valid(&conn->recvmbox)) {
  441. /* This happens when calling this function after receiving FIN */
  442. return sys_mbox_valid(&conn->acceptmbox) ? ERR_CONN : ERR_CLSD;
  443. }
  444. }
  445. #endif /* LWIP_TCP */
  446. LWIP_ERROR("netconn_recv: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
  447. if (ERR_IS_FATAL(conn->last_err)) {
  448. /* don't recv on fatal errors: this might block the application task
  449. waiting on recvmbox forever! */
  450. /* @todo: this does not allow us to fetch data that has been put into recvmbox
  451. before the fatal error occurred - is that a problem? */
  452. return conn->last_err;
  453. }
  454. #if LWIP_TCP
  455. #if (LWIP_UDP || LWIP_RAW)
  456. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  457. #endif /* (LWIP_UDP || LWIP_RAW) */
  458. {
  459. API_MSG_VAR_ALLOC(msg);
  460. }
  461. #endif /* LWIP_TCP */
  462. #if LWIP_SO_RCVTIMEO
  463. if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
  464. #if LWIP_TCP
  465. #if (LWIP_UDP || LWIP_RAW)
  466. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  467. #endif /* (LWIP_UDP || LWIP_RAW) */
  468. {
  469. API_MSG_VAR_FREE(msg);
  470. }
  471. #endif /* LWIP_TCP */
  472. return ERR_TIMEOUT;
  473. }
  474. #else
  475. sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
  476. #endif /* LWIP_SO_RCVTIMEO*/
  477. #if LWIP_TCP
  478. #if (LWIP_UDP || LWIP_RAW)
  479. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  480. #endif /* (LWIP_UDP || LWIP_RAW) */
  481. {
  482. /* Let the stack know that we have taken the data. */
  483. /* @todo: Speedup: Don't block and wait for the answer here
  484. (to prevent multiple thread-switches). */
  485. API_MSG_VAR_REF(msg).conn = conn;
  486. if (buf != NULL) {
  487. API_MSG_VAR_REF(msg).msg.r.len = ((struct pbuf *)buf)->tot_len;
  488. } else {
  489. API_MSG_VAR_REF(msg).msg.r.len = 1;
  490. }
  491. /* don't care for the return value of lwip_netconn_do_recv */
  492. netconn_apimsg(lwip_netconn_do_recv, &API_MSG_VAR_REF(msg));
  493. API_MSG_VAR_FREE(msg);
  494. /* If we are closed, we indicate that we no longer wish to use the socket */
  495. if (buf == NULL) {
  496. API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
  497. if (conn->pcb.ip == NULL) {
  498. /* race condition: RST during recv */
  499. return conn->last_err == ERR_OK ? ERR_RST : conn->last_err;
  500. }
  501. /* RX side is closed, so deallocate the recvmbox */
  502. netconn_close_shutdown(conn, NETCONN_SHUT_RD);
  503. /* Don' store ERR_CLSD as conn->err since we are only half-closed */
  504. return ERR_CLSD;
  505. }
  506. len = ((struct pbuf *)buf)->tot_len;
  507. }
  508. #endif /* LWIP_TCP */
  509. #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
  510. else
  511. #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
  512. #if (LWIP_UDP || LWIP_RAW)
  513. {
  514. LWIP_ASSERT("buf != NULL", buf != NULL);
  515. len = netbuf_len((struct netbuf*)buf);
  516. }
  517. #endif /* (LWIP_UDP || LWIP_RAW) */
  518. #if LWIP_SO_RCVBUF
  519. SYS_ARCH_DEC(conn->recv_avail, len);
  520. #endif /* LWIP_SO_RCVBUF */
  521. /* Register event with callback */
  522. API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
  523. LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
  524. *new_buf = buf;
  525. /* don't set conn->last_err: it's only ERR_OK, anyway */
  526. return ERR_OK;
  527. }
  528. /**
  529. * @ingroup netconn_tcp
  530. * Receive data (in form of a pbuf) from a TCP netconn
  531. *
  532. * @param conn the netconn from which to receive data
  533. * @param new_buf pointer where a new pbuf is stored when received data
  534. * @return ERR_OK if data has been received, an error code otherwise (timeout,
  535. * memory error or another error)
  536. * ERR_ARG if conn is not a TCP netconn
  537. */
  538. err_t
  539. netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
  540. {
  541. LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
  542. NETCONNTYPE_GROUP(netconn_type(conn)) == NETCONN_TCP, return ERR_ARG;);
  543. return netconn_recv_data(conn, (void **)new_buf);
  544. }
  545. /**
  546. * @ingroup netconn_common
  547. * Receive data (in form of a netbuf containing a packet buffer) from a netconn
  548. *
  549. * @param conn the netconn from which to receive data
  550. * @param new_buf pointer where a new netbuf is stored when received data
  551. * @return ERR_OK if data has been received, an error code otherwise (timeout,
  552. * memory error or another error)
  553. */
  554. err_t
  555. netconn_recv(struct netconn *conn, struct netbuf **new_buf)
  556. {
  557. #if LWIP_TCP
  558. struct netbuf *buf = NULL;
  559. err_t err;
  560. #endif /* LWIP_TCP */
  561. LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
  562. *new_buf = NULL;
  563. LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;);
  564. #if LWIP_TCP
  565. #if (LWIP_UDP || LWIP_RAW)
  566. if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP)
  567. #endif /* (LWIP_UDP || LWIP_RAW) */
  568. {
  569. struct pbuf *p = NULL;
  570. /* This is not a listening netconn, since recvmbox is set */
  571. buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
  572. if (buf == NULL) {
  573. return ERR_MEM;
  574. }
  575. err = netconn_recv_data(conn, (void **)&p);
  576. if (err != ERR_OK) {
  577. memp_free(MEMP_NETBUF, buf);
  578. return err;
  579. }
  580. LWIP_ASSERT("p != NULL", p != NULL);
  581. buf->p = p;
  582. buf->ptr = p;
  583. buf->port = 0;
  584. ip_addr_set_zero(&buf->addr);
  585. *new_buf = buf;
  586. /* don't set conn->last_err: it's only ERR_OK, anyway */
  587. return ERR_OK;
  588. }
  589. #endif /* LWIP_TCP */
  590. #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
  591. else
  592. #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
  593. {
  594. #if (LWIP_UDP || LWIP_RAW)
  595. return netconn_recv_data(conn, (void **)new_buf);
  596. #endif /* (LWIP_UDP || LWIP_RAW) */
  597. }
  598. }
  599. /**
  600. * @ingroup netconn_udp
  601. * Send data (in form of a netbuf) to a specific remote IP address and port.
  602. * Only to be used for UDP and RAW netconns (not TCP).
  603. *
  604. * @param conn the netconn over which to send data
  605. * @param buf a netbuf containing the data to send
  606. * @param addr the remote IP address to which to send the data
  607. * @param port the remote port to which to send the data
  608. * @return ERR_OK if data was sent, any other err_t on error
  609. */
  610. err_t
  611. netconn_sendto(struct netconn *conn, struct netbuf *buf, const ip_addr_t *addr, u16_t port)
  612. {
  613. if (buf != NULL) {
  614. ip_addr_set(&buf->addr, addr);
  615. buf->port = port;
  616. return netconn_send(conn, buf);
  617. }
  618. return ERR_VAL;
  619. }
  620. /**
  621. * @ingroup netconn_udp
  622. * Send data over a UDP or RAW netconn (that is already connected).
  623. *
  624. * @param conn the UDP or RAW netconn over which to send data
  625. * @param buf a netbuf containing the data to send
  626. * @return ERR_OK if data was sent, any other err_t on error
  627. */
  628. err_t
  629. netconn_send(struct netconn *conn, struct netbuf *buf)
  630. {
  631. API_MSG_VAR_DECLARE(msg);
  632. err_t err;
  633. LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;);
  634. LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
  635. API_MSG_VAR_ALLOC(msg);
  636. API_MSG_VAR_REF(msg).conn = conn;
  637. API_MSG_VAR_REF(msg).msg.b = buf;
  638. err = netconn_apimsg(lwip_netconn_do_send, &API_MSG_VAR_REF(msg));
  639. API_MSG_VAR_FREE(msg);
  640. return err;
  641. }
  642. /**
  643. * @ingroup netconn_tcp
  644. * Send data over a TCP netconn.
  645. *
  646. * @param conn the TCP netconn over which to send data
  647. * @param dataptr pointer to the application buffer that contains the data to send
  648. * @param size size of the application data to send
  649. * @param apiflags combination of following flags :
  650. * - NETCONN_COPY: data will be copied into memory belonging to the stack
  651. * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
  652. * - NETCONN_DONTBLOCK: only write the data if all data can be written at once
  653. * @param bytes_written pointer to a location that receives the number of written bytes
  654. * @return ERR_OK if data was sent, any other err_t on error
  655. */
  656. err_t
  657. netconn_write_partly(struct netconn *conn, const void *dataptr, size_t size,
  658. u8_t apiflags, size_t *bytes_written)
  659. {
  660. API_MSG_VAR_DECLARE(msg);
  661. err_t err;
  662. u8_t dontblock;
  663. LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;);
  664. LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(conn->type)== NETCONN_TCP), return ERR_VAL;);
  665. if (size == 0) {
  666. return ERR_OK;
  667. }
  668. dontblock = netconn_is_nonblocking(conn) || (apiflags & NETCONN_DONTBLOCK);
  669. #if LWIP_SO_SNDTIMEO
  670. if (conn->send_timeout != 0) {
  671. dontblock = 1;
  672. }
  673. #endif /* LWIP_SO_SNDTIMEO */
  674. if (dontblock && !bytes_written) {
  675. /* This implies netconn_write() cannot be used for non-blocking send, since
  676. it has no way to return the number of bytes written. */
  677. return ERR_VAL;
  678. }
  679. API_MSG_VAR_ALLOC(msg);
  680. /* non-blocking write sends as much */
  681. API_MSG_VAR_REF(msg).conn = conn;
  682. API_MSG_VAR_REF(msg).msg.w.dataptr = dataptr;
  683. API_MSG_VAR_REF(msg).msg.w.apiflags = apiflags;
  684. API_MSG_VAR_REF(msg).msg.w.len = size;
  685. #if LWIP_SO_SNDTIMEO
  686. if (conn->send_timeout != 0) {
  687. /* get the time we started, which is later compared to
  688. sys_now() + conn->send_timeout */
  689. API_MSG_VAR_REF(msg).msg.w.time_started = sys_now();
  690. } else {
  691. API_MSG_VAR_REF(msg).msg.w.time_started = 0;
  692. }
  693. #endif /* LWIP_SO_SNDTIMEO */
  694. /* For locking the core: this _can_ be delayed on low memory/low send buffer,
  695. but if it is, this is done inside api_msg.c:do_write(), so we can use the
  696. non-blocking version here. */
  697. err = netconn_apimsg(lwip_netconn_do_write, &API_MSG_VAR_REF(msg));
  698. if ((err == ERR_OK) && (bytes_written != NULL)) {
  699. if (dontblock) {
  700. /* nonblocking write: maybe the data has been sent partly */
  701. *bytes_written = API_MSG_VAR_REF(msg).msg.w.len;
  702. } else {
  703. /* blocking call succeeded: all data has been sent if it */
  704. *bytes_written = size;
  705. }
  706. }
  707. API_MSG_VAR_FREE(msg);
  708. return err;
  709. }
  710. /**
  711. * @ingroup netconn_tcp
  712. * Close or shutdown a TCP netconn (doesn't delete it).
  713. *
  714. * @param conn the TCP netconn to close or shutdown
  715. * @param how fully close or only shutdown one side?
  716. * @return ERR_OK if the netconn was closed, any other err_t on error
  717. */
  718. static err_t
  719. netconn_close_shutdown(struct netconn *conn, u8_t how)
  720. {
  721. API_MSG_VAR_DECLARE(msg);
  722. err_t err;
  723. LWIP_UNUSED_ARG(how);
  724. LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
  725. API_MSG_VAR_ALLOC(msg);
  726. API_MSG_VAR_REF(msg).conn = conn;
  727. #if LWIP_TCP
  728. /* shutting down both ends is the same as closing */
  729. API_MSG_VAR_REF(msg).msg.sd.shut = how;
  730. #if LWIP_SO_SNDTIMEO || LWIP_SO_LINGER
  731. /* get the time we started, which is later compared to
  732. sys_now() + conn->send_timeout */
  733. API_MSG_VAR_REF(msg).msg.sd.time_started = sys_now();
  734. #else /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
  735. API_MSG_VAR_REF(msg).msg.sd.polls_left =
  736. ((LWIP_TCP_CLOSE_TIMEOUT_MS_DEFAULT + TCP_SLOW_INTERVAL - 1) / TCP_SLOW_INTERVAL) + 1;
  737. #endif /* LWIP_SO_SNDTIMEO || LWIP_SO_LINGER */
  738. #endif /* LWIP_TCP */
  739. err = netconn_apimsg(lwip_netconn_do_close, &API_MSG_VAR_REF(msg));
  740. API_MSG_VAR_FREE(msg);
  741. return err;
  742. }
  743. /**
  744. * @ingroup netconn_tcp
  745. * Close a TCP netconn (doesn't delete it).
  746. *
  747. * @param conn the TCP netconn to close
  748. * @return ERR_OK if the netconn was closed, any other err_t on error
  749. */
  750. err_t
  751. netconn_close(struct netconn *conn)
  752. {
  753. /* shutting down both ends is the same as closing */
  754. return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
  755. }
  756. /**
  757. * @ingroup netconn_tcp
  758. * Shut down one or both sides of a TCP netconn (doesn't delete it).
  759. *
  760. * @param conn the TCP netconn to shut down
  761. * @param shut_rx shut down the RX side (no more read possible after this)
  762. * @param shut_tx shut down the TX side (no more write possible after this)
  763. * @return ERR_OK if the netconn was closed, any other err_t on error
  764. */
  765. err_t
  766. netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
  767. {
  768. return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
  769. }
  770. #if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
  771. /**
  772. * @ingroup netconn_udp
  773. * Join multicast groups for UDP netconns.
  774. *
  775. * @param conn the UDP netconn for which to change multicast addresses
  776. * @param multiaddr IP address of the multicast group to join or leave
  777. * @param netif_addr the IP address of the network interface on which to send
  778. * the igmp message
  779. * @param join_or_leave flag whether to send a join- or leave-message
  780. * @return ERR_OK if the action was taken, any err_t on error
  781. */
  782. err_t
  783. netconn_join_leave_group(struct netconn *conn,
  784. const ip_addr_t *multiaddr,
  785. const ip_addr_t *netif_addr,
  786. enum netconn_igmp join_or_leave)
  787. {
  788. API_MSG_VAR_DECLARE(msg);
  789. err_t err;
  790. LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;);
  791. API_MSG_VAR_ALLOC(msg);
  792. #if LWIP_IPV4
  793. /* Don't propagate NULL pointer (IP_ADDR_ANY alias) to subsequent functions */
  794. if (multiaddr == NULL) {
  795. multiaddr = IP4_ADDR_ANY;
  796. }
  797. if (netif_addr == NULL) {
  798. netif_addr = IP4_ADDR_ANY;
  799. }
  800. #endif /* LWIP_IPV4 */
  801. API_MSG_VAR_REF(msg).conn = conn;
  802. API_MSG_VAR_REF(msg).msg.jl.multiaddr = API_MSG_VAR_REF(multiaddr);
  803. API_MSG_VAR_REF(msg).msg.jl.netif_addr = API_MSG_VAR_REF(netif_addr);
  804. API_MSG_VAR_REF(msg).msg.jl.join_or_leave = join_or_leave;
  805. err = netconn_apimsg(lwip_netconn_do_join_leave_group, &API_MSG_VAR_REF(msg));
  806. API_MSG_VAR_FREE(msg);
  807. return err;
  808. }
  809. #endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
  810. #if LWIP_DNS
  811. /**
  812. * @ingroup netconn_common
  813. * Execute a DNS query, only one IP address is returned
  814. *
  815. * @param name a string representation of the DNS host name to query
  816. * @param addr a preallocated ip_addr_t where to store the resolved IP address
  817. * @param dns_addrtype IP address type (IPv4 / IPv6)
  818. * @return ERR_OK: resolving succeeded
  819. * ERR_MEM: memory error, try again later
  820. * ERR_ARG: dns client not initialized or invalid hostname
  821. * ERR_VAL: dns server response was invalid
  822. */
  823. #if LWIP_IPV4 && LWIP_IPV6
  824. err_t
  825. netconn_gethostbyname_addrtype(const char *name, ip_addr_t *addr, u8_t dns_addrtype)
  826. #else
  827. err_t
  828. netconn_gethostbyname(const char *name, ip_addr_t *addr)
  829. #endif
  830. {
  831. API_VAR_DECLARE(struct dns_api_msg, msg);
  832. #if !LWIP_MPU_COMPATIBLE
  833. sys_sem_t sem;
  834. #endif /* LWIP_MPU_COMPATIBLE */
  835. err_t err;
  836. err_t cberr;
  837. LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
  838. LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
  839. #if LWIP_MPU_COMPATIBLE
  840. if (strlen(name) >= DNS_MAX_NAME_LENGTH) {
  841. return ERR_ARG;
  842. }
  843. #endif
  844. API_VAR_ALLOC(struct dns_api_msg, MEMP_DNS_API_MSG, msg, ERR_MEM);
  845. #if LWIP_MPU_COMPATIBLE
  846. strncpy(API_VAR_REF(msg).name, name, DNS_MAX_NAME_LENGTH-1);
  847. API_VAR_REF(msg).name[DNS_MAX_NAME_LENGTH-1] = 0;
  848. #else /* LWIP_MPU_COMPATIBLE */
  849. msg.err = &err;
  850. msg.sem = &sem;
  851. API_VAR_REF(msg).addr = API_VAR_REF(addr);
  852. API_VAR_REF(msg).name = name;
  853. #endif /* LWIP_MPU_COMPATIBLE */
  854. #if LWIP_IPV4 && LWIP_IPV6
  855. API_VAR_REF(msg).dns_addrtype = dns_addrtype;
  856. #endif /* LWIP_IPV4 && LWIP_IPV6 */
  857. #if LWIP_NETCONN_SEM_PER_THREAD
  858. API_VAR_REF(msg).sem = LWIP_NETCONN_THREAD_SEM_GET();
  859. #else /* LWIP_NETCONN_SEM_PER_THREAD*/
  860. err = sys_sem_new(API_EXPR_REF(API_VAR_REF(msg).sem), 0);
  861. if (err != ERR_OK) {
  862. API_VAR_FREE(MEMP_DNS_API_MSG, msg);
  863. return err;
  864. }
  865. #endif /* LWIP_NETCONN_SEM_PER_THREAD */
  866. cberr = tcpip_callback(lwip_netconn_do_gethostbyname, &API_VAR_REF(msg));
  867. if (cberr != ERR_OK) {
  868. #if !LWIP_NETCONN_SEM_PER_THREAD
  869. sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
  870. #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
  871. API_VAR_FREE(MEMP_DNS_API_MSG, msg);
  872. return cberr;
  873. }
  874. sys_sem_wait(API_EXPR_REF_SEM(API_VAR_REF(msg).sem));
  875. #if !LWIP_NETCONN_SEM_PER_THREAD
  876. sys_sem_free(API_EXPR_REF(API_VAR_REF(msg).sem));
  877. #endif /* !LWIP_NETCONN_SEM_PER_THREAD */
  878. #if LWIP_MPU_COMPATIBLE
  879. *addr = msg->addr;
  880. err = msg->err;
  881. #endif /* LWIP_MPU_COMPATIBLE */
  882. API_VAR_FREE(MEMP_DNS_API_MSG, msg);
  883. return err;
  884. }
  885. #endif /* LWIP_DNS*/
  886. #if LWIP_NETCONN_SEM_PER_THREAD
  887. void
  888. netconn_thread_init(void)
  889. {
  890. sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
  891. if ((sem == NULL) || !sys_sem_valid(sem)) {
  892. /* call alloc only once */
  893. LWIP_NETCONN_THREAD_SEM_ALLOC();
  894. LWIP_ASSERT("LWIP_NETCONN_THREAD_SEM_ALLOC() failed", sys_sem_valid(LWIP_NETCONN_THREAD_SEM_GET()));
  895. }
  896. }
  897. void
  898. netconn_thread_cleanup(void)
  899. {
  900. sys_sem_t *sem = LWIP_NETCONN_THREAD_SEM_GET();
  901. if ((sem != NULL) && sys_sem_valid(sem)) {
  902. /* call free only once */
  903. LWIP_NETCONN_THREAD_SEM_FREE();
  904. }
  905. }
  906. #endif /* LWIP_NETCONN_SEM_PER_THREAD */
  907. #endif /* LWIP_NETCONN */