Marcelo Rebonatto / lwip

Dependents:   EthernetInterface

Fork of lwip by mbed official

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers api_lib.c Source File

api_lib.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * Sequential API External module
00004  *
00005  */
00006  
00007 /*
00008  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
00009  * All rights reserved. 
00010  * 
00011  * Redistribution and use in source and binary forms, with or without modification, 
00012  * are permitted provided that the following conditions are met:
00013  *
00014  * 1. Redistributions of source code must retain the above copyright notice,
00015  *    this list of conditions and the following disclaimer.
00016  * 2. Redistributions in binary form must reproduce the above copyright notice,
00017  *    this list of conditions and the following disclaimer in the documentation
00018  *    and/or other materials provided with the distribution.
00019  * 3. The name of the author may not be used to endorse or promote products
00020  *    derived from this software without specific prior written permission. 
00021  *
00022  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00023  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00024  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00025  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00026  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00027  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00028  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00029  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00030  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00031  * OF SUCH DAMAGE.
00032  *
00033  * This file is part of the lwIP TCP/IP stack.
00034  * 
00035  * Author: Adam Dunkels <adam@sics.se>
00036  *
00037  */
00038 
00039 /* This is the part of the API that is linked with
00040    the application */
00041 
00042 #include "lwip/opt.h"
00043 
00044 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
00045 
00046 #include "lwip/api.h"
00047 #include "lwip/tcpip.h"
00048 #include "lwip/memp.h"
00049 
00050 #include "lwip/ip.h"
00051 #include "lwip/raw.h"
00052 #include "lwip/udp.h"
00053 #include "lwip/tcp.h"
00054 
00055 #include <string.h>
00056 #include <stdio.h>
00057 
00058 /**
00059  * Create a new netconn (of a specific type) that has a callback function.
00060  * The corresponding pcb is also created.
00061  *
00062  * @param t the type of 'connection' to create (@see enum netconn_type)
00063  * @param proto the IP protocol for RAW IP pcbs
00064  * @param callback a function to call on status changes (RX available, TX'ed)
00065  * @return a newly allocated struct netconn or
00066  *         NULL on memory error
00067  */
00068 struct netconn*
00069 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)
00070 {
00071   struct netconn *conn;
00072   struct api_msg msg;
00073 
00074   conn = netconn_alloc(t, callback);
00075   if (conn != NULL) {
00076     msg.function = do_newconn;
00077     msg.msg.msg.n.proto = proto;
00078     msg.msg.conn = conn;
00079     if (TCPIP_APIMSG(&msg) != ERR_OK) {
00080       LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);
00081       LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed));
00082       LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox));
00083 #if LWIP_TCP
00084       LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox));
00085 #endif /* LWIP_TCP */
00086       sys_sem_free(&conn->op_completed);
00087       sys_mbox_free(&conn->recvmbox);
00088       memp_free(MEMP_NETCONN, conn);
00089       return NULL;
00090     }
00091   }
00092   return conn;
00093 }
00094 
00095 /**
00096  * Close a netconn 'connection' and free its resources.
00097  * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate
00098  * after this returns.
00099  *
00100  * @param conn the netconn to delete
00101  * @return ERR_OK if the connection was deleted
00102  */
00103 err_t
00104 netconn_delete(struct netconn *conn)
00105 {
00106   struct api_msg msg;
00107 
00108   /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */
00109   if (conn == NULL) {
00110     return ERR_OK;
00111   }
00112 
00113   msg.function = do_delconn;
00114   msg.msg.conn = conn;
00115   tcpip_apimsg(&msg);
00116 
00117   netconn_free(conn);
00118 
00119   /* don't care for return value of do_delconn since it only calls void functions */
00120 
00121   return ERR_OK;
00122 }
00123 
00124 /**
00125  * Get the local or remote IP address and port of a netconn.
00126  * For RAW netconns, this returns the protocol instead of a port!
00127  *
00128  * @param conn the netconn to query
00129  * @param addr a pointer to which to save the IP address
00130  * @param port a pointer to which to save the port (or protocol for RAW)
00131  * @param local 1 to get the local IP address, 0 to get the remote one
00132  * @return ERR_CONN for invalid connections
00133  *         ERR_OK if the information was retrieved
00134  */
00135 err_t
00136 netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
00137 {
00138   struct api_msg msg;
00139   err_t err;
00140 
00141   LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
00142   LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
00143   LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
00144 
00145   msg.function = do_getaddr;
00146   msg.msg.conn = conn;
00147   msg.msg.msg.ad.ipaddr = addr;
00148   msg.msg.msg.ad.port = port;
00149   msg.msg.msg.ad.local = local;
00150   err = TCPIP_APIMSG(&msg);
00151 
00152   NETCONN_SET_SAFE_ERR(conn, err);
00153   return err;
00154 }
00155 
00156 /**
00157  * Bind a netconn to a specific local IP address and port.
00158  * Binding one netconn twice might not always be checked correctly!
00159  *
00160  * @param conn the netconn to bind
00161  * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY
00162  *             to bind to all addresses)
00163  * @param port the local port to bind the netconn to (not used for RAW)
00164  * @return ERR_OK if bound, any other err_t on failure
00165  */
00166 err_t
00167 netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port)
00168 {
00169   struct api_msg msg;
00170   err_t err;
00171 
00172   LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);
00173 
00174   msg.function = do_bind;
00175   msg.msg.conn = conn;
00176   msg.msg.msg.bc.ipaddr = addr;
00177   msg.msg.msg.bc.port = port;
00178   err = TCPIP_APIMSG(&msg);
00179 
00180   NETCONN_SET_SAFE_ERR(conn, err);
00181   return err;
00182 }
00183 
00184 /**
00185  * Connect a netconn to a specific remote IP address and port.
00186  *
00187  * @param conn the netconn to connect
00188  * @param addr the remote IP address to connect to
00189  * @param port the remote port to connect to (no used for RAW)
00190  * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise
00191  */
00192 err_t
00193 netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port)
00194 {
00195   struct api_msg msg;
00196   err_t err;
00197 
00198   LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);
00199   msg.function = do_connect;
00200   msg.msg.conn = conn;
00201   msg.msg.msg.bc.ipaddr = addr;
00202   msg.msg.msg.bc.port = port;
00203   /* This is the only function which need to not block tcpip_thread */
00204   err = tcpip_apimsg(&msg);
00205   if(err != 0)
00206     printf("Pau em tcpip_apimsg\n");
00207  
00208   NETCONN_SET_SAFE_ERR(conn, err);
00209   return err;
00210 }
00211 
00212 /**
00213  * Disconnect a netconn from its current peer (only valid for UDP netconns).
00214  *
00215  * @param conn the netconn to disconnect
00216  * @return TODO: return value is not set here...
00217  */
00218 err_t
00219 netconn_disconnect(struct netconn *conn)
00220 {
00221   struct api_msg msg;
00222   err_t err;
00223 
00224   LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);
00225 
00226   msg.function = do_disconnect;
00227   msg.msg.conn = conn;
00228   err = TCPIP_APIMSG(&msg);
00229 
00230   NETCONN_SET_SAFE_ERR(conn, err);
00231   return err;
00232 }
00233 
00234 /**
00235  * Set a TCP netconn into listen mode
00236  *
00237  * @param conn the tcp netconn to set to listen mode
00238  * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1
00239  * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns
00240  *         don't return any error (yet?))
00241  */
00242 err_t
00243 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)
00244 {
00245 #if LWIP_TCP
00246   struct api_msg msg;
00247   err_t err;
00248 
00249   /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */
00250   LWIP_UNUSED_ARG(backlog);
00251 
00252   LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);
00253 
00254   msg.function = do_listen;
00255   msg.msg.conn = conn;
00256 #if TCP_LISTEN_BACKLOG
00257   msg.msg.msg.lb.backlog = backlog;
00258 #endif /* TCP_LISTEN_BACKLOG */
00259   err = TCPIP_APIMSG(&msg);
00260 
00261   NETCONN_SET_SAFE_ERR(conn, err);
00262   return err;
00263 #else /* LWIP_TCP */
00264   LWIP_UNUSED_ARG(conn);
00265   LWIP_UNUSED_ARG(backlog);
00266   return ERR_ARG;
00267 #endif /* LWIP_TCP */
00268 }
00269 
00270 /**
00271  * Accept a new connection on a TCP listening netconn.
00272  *
00273  * @param conn the TCP listen netconn
00274  * @param new_conn pointer where the new connection is stored
00275  * @return ERR_OK if a new connection has been received or an error
00276  *                code otherwise
00277  */
00278 err_t
00279 netconn_accept(struct netconn *conn, struct netconn **new_conn)
00280 {
00281 #if LWIP_TCP
00282   struct netconn *newconn;
00283   err_t err;
00284 #if TCP_LISTEN_BACKLOG
00285   struct api_msg msg;
00286 #endif /* TCP_LISTEN_BACKLOG */
00287 
00288   LWIP_ERROR("netconn_accept: invalid pointer",    (new_conn != NULL),                  return ERR_ARG;);
00289   *new_conn = NULL;
00290   LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return ERR_ARG;);
00291   LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox),   return ERR_ARG;);
00292 
00293   err = conn->last_err;
00294   if (ERR_IS_FATAL(err)) {
00295     /* don't recv on fatal errors: this might block the application task
00296        waiting on acceptmbox forever! */
00297     return err;
00298   }
00299 
00300 #if LWIP_SO_RCVTIMEO
00301   if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
00302     NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
00303     return ERR_TIMEOUT;
00304   }
00305 #else
00306   sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0);
00307 #endif /* LWIP_SO_RCVTIMEO*/
00308   /* Register event with callback */
00309   API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
00310 
00311   if (newconn == NULL) {
00312     /* connection has been aborted */
00313     NETCONN_SET_SAFE_ERR(conn, ERR_ABRT);
00314     return ERR_ABRT;
00315   }
00316 #if TCP_LISTEN_BACKLOG
00317   /* Let the stack know that we have accepted the connection. */
00318   msg.function = do_recv;
00319   msg.msg.conn = conn;
00320   /* don't care for the return value of do_recv */
00321   TCPIP_APIMSG(&msg);
00322 #endif /* TCP_LISTEN_BACKLOG */
00323 
00324   *new_conn = newconn;
00325   /* don't set conn->last_err: it's only ERR_OK, anyway */
00326   return ERR_OK;
00327 #else /* LWIP_TCP */
00328   LWIP_UNUSED_ARG(conn);
00329   LWIP_UNUSED_ARG(new_conn);
00330   return ERR_ARG;
00331 #endif /* LWIP_TCP */
00332 }
00333 
00334 /**
00335  * Receive data: actual implementation that doesn't care whether pbuf or netbuf
00336  * is received
00337  *
00338  * @param conn the netconn from which to receive data
00339  * @param new_buf pointer where a new pbuf/netbuf is stored when received data
00340  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00341  *                memory error or another error)
00342  */
00343 static err_t
00344 netconn_recv_data(struct netconn *conn, void **new_buf)
00345 {
00346   void *buf = NULL;
00347   u16_t len;
00348   err_t err;
00349 #if LWIP_TCP
00350   struct api_msg msg;
00351 #endif /* LWIP_TCP */
00352 
00353   LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
00354   *new_buf = NULL;
00355   LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
00356   LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
00357 
00358   err = conn->last_err;
00359   if (ERR_IS_FATAL(err)) {
00360     /* don't recv on fatal errors: this might block the application task
00361        waiting on recvmbox forever! */
00362     /* @todo: this does not allow us to fetch data that has been put into recvmbox
00363        before the fatal error occurred - is that a problem? */
00364     return err;
00365   }
00366 
00367 #if LWIP_SO_RCVTIMEO
00368   if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
00369     NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT);
00370     return ERR_TIMEOUT;
00371   }
00372 #else
00373   sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0);
00374 #endif /* LWIP_SO_RCVTIMEO*/
00375 
00376 #if LWIP_TCP
00377   if (conn->type == NETCONN_TCP) {
00378     if (!netconn_get_noautorecved(conn) || (buf == NULL)) {
00379       /* Let the stack know that we have taken the data. */
00380       /* TODO: Speedup: Don't block and wait for the answer here
00381          (to prevent multiple thread-switches). */
00382       msg.function = do_recv;
00383       msg.msg.conn = conn;
00384       if (buf != NULL) {
00385         msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len;
00386       } else {
00387         msg.msg.msg.r.len = 1;
00388       }
00389       /* don't care for the return value of do_recv */
00390       TCPIP_APIMSG(&msg);
00391     }
00392 
00393     /* If we are closed, we indicate that we no longer wish to use the socket */
00394     if (buf == NULL) {
00395       API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
00396       /* Avoid to lose any previous error code */
00397       NETCONN_SET_SAFE_ERR(conn, ERR_CLSD);
00398       return ERR_CLSD;
00399     }
00400     len = ((struct pbuf *)buf)->tot_len;
00401   }
00402 #endif /* LWIP_TCP */
00403 #if LWIP_TCP && (LWIP_UDP || LWIP_RAW)
00404   else
00405 #endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */
00406 #if (LWIP_UDP || LWIP_RAW)
00407   {
00408     LWIP_ASSERT("buf != NULL", buf != NULL);
00409     len = netbuf_len((struct netbuf *)buf);
00410   }
00411 #endif /* (LWIP_UDP || LWIP_RAW) */
00412 
00413 #if LWIP_SO_RCVBUF
00414   SYS_ARCH_DEC(conn->recv_avail, len);
00415 #endif /* LWIP_SO_RCVBUF */
00416   /* Register event with callback */
00417   API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
00418 
00419   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
00420 
00421   *new_buf = buf;
00422   /* don't set conn->last_err: it's only ERR_OK, anyway */
00423   return ERR_OK;
00424 }
00425 
00426 /**
00427  * Receive data (in form of a pbuf) from a TCP netconn
00428  *
00429  * @param conn the netconn from which to receive data
00430  * @param new_buf pointer where a new pbuf is stored when received data
00431  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00432  *                memory error or another error)
00433  *         ERR_ARG if conn is not a TCP netconn
00434  */
00435 err_t
00436 netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf)
00437 {
00438   LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) &&
00439              netconn_type(conn) == NETCONN_TCP, return ERR_ARG;);
00440 
00441   return netconn_recv_data(conn, (void **)new_buf);
00442 }
00443 
00444 /**
00445  * Receive data (in form of a netbuf containing a packet buffer) from a netconn
00446  *
00447  * @param conn the netconn from which to receive data
00448  * @param new_buf pointer where a new netbuf is stored when received data
00449  * @return ERR_OK if data has been received, an error code otherwise (timeout,
00450  *                memory error or another error)
00451  */
00452 err_t
00453 netconn_recv(struct netconn *conn, struct netbuf **new_buf)
00454 {
00455 #if LWIP_TCP
00456   struct netbuf *buf = NULL;
00457   err_t err;
00458 #endif /* LWIP_TCP */
00459 
00460   LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;);
00461   *new_buf = NULL;
00462   LWIP_ERROR("netconn_recv: invalid conn",    (conn != NULL),    return ERR_ARG;);
00463   LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;);
00464 
00465 #if LWIP_TCP
00466   if (conn->type == NETCONN_TCP) {
00467     struct pbuf *p = NULL;
00468     /* This is not a listening netconn, since recvmbox is set */
00469 
00470     buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
00471     if (buf == NULL) {
00472       NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
00473       return ERR_MEM;
00474     }
00475 
00476     err = netconn_recv_data(conn, (void **)&p);
00477     if (err != ERR_OK) {
00478       memp_free(MEMP_NETBUF, buf);
00479       return err;
00480     }
00481     LWIP_ASSERT("p != NULL", p != NULL);
00482 
00483     buf->p = p;
00484     buf->ptr = p;
00485     buf->port = 0;
00486     ip_addr_set_any(&buf->addr);
00487     *new_buf = buf;
00488     /* don't set conn->last_err: it's only ERR_OK, anyway */
00489     return ERR_OK;
00490   } else
00491 #endif /* LWIP_TCP */
00492   {
00493 #if (LWIP_UDP || LWIP_RAW)
00494     return netconn_recv_data(conn, (void **)new_buf);
00495 #endif /* (LWIP_UDP || LWIP_RAW) */
00496   }
00497 }
00498 
00499 /**
00500  * TCP: update the receive window: by calling this, the application
00501  * tells the stack that it has processed data and is able to accept
00502  * new data.
00503  * ATTENTION: use with care, this is mainly used for sockets!
00504  * Can only be used when calling netconn_set_noautorecved(conn, 1) before.
00505  *
00506  * @param conn the netconn for which to update the receive window
00507  * @param length amount of data processed (ATTENTION: this must be accurate!)
00508  */
00509 void
00510 netconn_recved(struct netconn *conn, u32_t length)
00511 {
00512 #if LWIP_TCP
00513   if ((conn != NULL) && (conn->type == NETCONN_TCP) &&
00514       (netconn_get_noautorecved(conn))) {
00515     struct api_msg msg;
00516     /* Let the stack know that we have taken the data. */
00517     /* TODO: Speedup: Don't block and wait for the answer here
00518        (to prevent multiple thread-switches). */
00519     msg.function = do_recv;
00520     msg.msg.conn = conn;
00521     msg.msg.msg.r.len = length;
00522     /* don't care for the return value of do_recv */
00523     TCPIP_APIMSG(&msg);
00524   }
00525 #else /* LWIP_TCP */
00526   LWIP_UNUSED_ARG(conn);
00527   LWIP_UNUSED_ARG(length);
00528 #endif /* LWIP_TCP */
00529 }
00530 
00531 /**
00532  * Send data (in form of a netbuf) to a specific remote IP address and port.
00533  * Only to be used for UDP and RAW netconns (not TCP).
00534  *
00535  * @param conn the netconn over which to send data
00536  * @param buf a netbuf containing the data to send
00537  * @param addr the remote IP address to which to send the data
00538  * @param port the remote port to which to send the data
00539  * @return ERR_OK if data was sent, any other err_t on error
00540  */
00541 err_t
00542 netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port)
00543 {
00544   if (buf != NULL) {
00545     ip_addr_set(&buf->addr, addr);
00546     buf->port = port;
00547     return netconn_send(conn, buf);
00548   }
00549   return ERR_VAL;
00550 }
00551 
00552 /**
00553  * Send data over a UDP or RAW netconn (that is already connected).
00554  *
00555  * @param conn the UDP or RAW netconn over which to send data
00556  * @param buf a netbuf containing the data to send
00557  * @return ERR_OK if data was sent, any other err_t on error
00558  */
00559 err_t
00560 netconn_send(struct netconn *conn, struct netbuf *buf)
00561 {
00562   struct api_msg msg;
00563   err_t err;
00564 
00565   LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);
00566 
00567   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
00568   msg.function = do_send;
00569   msg.msg.conn = conn;
00570   msg.msg.msg.b = buf;
00571   err = TCPIP_APIMSG(&msg);
00572 
00573   NETCONN_SET_SAFE_ERR(conn, err);
00574   return err;
00575 }
00576 
00577 /**
00578  * Send data over a TCP netconn.
00579  *
00580  * @param conn the TCP netconn over which to send data
00581  * @param dataptr pointer to the application buffer that contains the data to send
00582  * @param size size of the application data to send
00583  * @param apiflags combination of following flags :
00584  * - NETCONN_COPY: data will be copied into memory belonging to the stack
00585  * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent
00586  * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once
00587  * @return ERR_OK if data was sent, any other err_t on error
00588  */
00589 err_t
00590 netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags)
00591 {
00592   struct api_msg msg;
00593   err_t err;
00594 
00595   LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);
00596   LWIP_ERROR("netconn_write: invalid conn->type",  (conn->type == NETCONN_TCP), return ERR_VAL;);
00597   if (size == 0) {
00598     return ERR_OK;
00599   }
00600 
00601   /* @todo: for non-blocking write, check if 'size' would ever fit into
00602             snd_queue or snd_buf */
00603   msg.function = do_write;
00604   msg.msg.conn = conn;
00605   msg.msg.msg.w.dataptr = dataptr;
00606   msg.msg.msg.w.apiflags = apiflags;
00607   msg.msg.msg.w.len = size;
00608   /* For locking the core: this _can_ be delayed on low memory/low send buffer,
00609      but if it is, this is done inside api_msg.c:do_write(), so we can use the
00610      non-blocking version here. */
00611   err = TCPIP_APIMSG(&msg);
00612 
00613   NETCONN_SET_SAFE_ERR(conn, err);
00614   return err;
00615 }
00616 
00617 /**
00618  * Close ot shutdown a TCP netconn (doesn't delete it).
00619  *
00620  * @param conn the TCP netconn to close or shutdown
00621  * @param how fully close or only shutdown one side?
00622  * @return ERR_OK if the netconn was closed, any other err_t on error
00623  */
00624 static err_t
00625 netconn_close_shutdown(struct netconn *conn, u8_t how)
00626 {
00627   struct api_msg msg;
00628   err_t err;
00629 
00630   LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);
00631 
00632   msg.function = do_close;
00633   msg.msg.conn = conn;
00634   /* shutting down both ends is the same as closing */
00635   msg.msg.msg.sd.shut = how;
00636   /* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close,
00637      don't use TCPIP_APIMSG here */
00638   err = tcpip_apimsg(&msg);
00639 
00640   NETCONN_SET_SAFE_ERR(conn, err);
00641   return err;
00642 }
00643 
00644 /**
00645  * Close a TCP netconn (doesn't delete it).
00646  *
00647  * @param conn the TCP netconn to close
00648  * @return ERR_OK if the netconn was closed, any other err_t on error
00649  */
00650 err_t
00651 netconn_close(struct netconn *conn)
00652 {
00653   /* shutting down both ends is the same as closing */
00654   return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
00655 }
00656 
00657 /**
00658  * Shut down one or both sides of a TCP netconn (doesn't delete it).
00659  *
00660  * @param conn the TCP netconn to shut down
00661  * @return ERR_OK if the netconn was closed, any other err_t on error
00662  */
00663 err_t
00664 netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx)
00665 {
00666   return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0));
00667 }
00668 
00669 #if LWIP_IGMP
00670 /**
00671  * Join multicast groups for UDP netconns.
00672  *
00673  * @param conn the UDP netconn for which to change multicast addresses
00674  * @param multiaddr IP address of the multicast group to join or leave
00675  * @param netif_addr the IP address of the network interface on which to send
00676  *                  the igmp message
00677  * @param join_or_leave flag whether to send a join- or leave-message
00678  * @return ERR_OK if the action was taken, any err_t on error
00679  */
00680 err_t
00681 netconn_join_leave_group(struct netconn *conn,
00682                          ip_addr_t *multiaddr,
00683                          ip_addr_t *netif_addr,
00684                          enum netconn_igmp join_or_leave)
00685 {
00686   struct api_msg msg;
00687   err_t err;
00688 
00689   LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);
00690 
00691   msg.function = do_join_leave_group;
00692   msg.msg.conn = conn;
00693   msg.msg.msg.jl.multiaddr = multiaddr;
00694   msg.msg.msg.jl.netif_addr = netif_addr;
00695   msg.msg.msg.jl.join_or_leave = join_or_leave;
00696   err = TCPIP_APIMSG(&msg);
00697 
00698   NETCONN_SET_SAFE_ERR(conn, err);
00699   return err;
00700 }
00701 #endif /* LWIP_IGMP */
00702 
00703 #if LWIP_DNS
00704 /**
00705  * Execute a DNS query, only one IP address is returned
00706  *
00707  * @param name a string representation of the DNS host name to query
00708  * @param addr a preallocated ip_addr_t where to store the resolved IP address
00709  * @return ERR_OK: resolving succeeded
00710  *         ERR_MEM: memory error, try again later
00711  *         ERR_ARG: dns client not initialized or invalid hostname
00712  *         ERR_VAL: dns server response was invalid
00713  */
00714 err_t
00715 netconn_gethostbyname(const char *name, ip_addr_t *addr)
00716 {
00717   struct dns_api_msg msg;
00718   err_t err;
00719   sys_sem_t sem;
00720 
00721   LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);
00722   LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);
00723 
00724   err = sys_sem_new(&sem, 0);
00725   if (err != ERR_OK) {
00726     return err;
00727   }
00728 
00729   msg.name = name;
00730   msg.addr = addr;
00731   msg.err = &err;
00732   msg.sem = &sem;
00733 
00734   tcpip_callback(do_gethostbyname, &msg);
00735   sys_sem_wait(&sem);
00736   sys_sem_free(&sem);
00737 
00738   return err;
00739 }
00740 #endif /* LWIP_DNS*/
00741 
00742 #endif /* LWIP_NETCONN */