Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of lwip by
api_lib.c
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 00057 /** 00058 * Create a new netconn (of a specific type) that has a callback function. 00059 * The corresponding pcb is also created. 00060 * 00061 * @param t the type of 'connection' to create (@see enum netconn_type) 00062 * @param proto the IP protocol for RAW IP pcbs 00063 * @param callback a function to call on status changes (RX available, TX'ed) 00064 * @return a newly allocated struct netconn or 00065 * NULL on memory error 00066 */ 00067 struct netconn* 00068 netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) 00069 { 00070 struct netconn *conn; 00071 struct api_msg msg; 00072 00073 conn = netconn_alloc(t, callback); 00074 if (conn != NULL ) { 00075 msg.function = do_newconn; 00076 msg.msg.msg.n.proto = proto; 00077 msg.msg.conn = conn; 00078 TCPIP_APIMSG(&msg); 00079 00080 if (conn->err != ERR_OK) { 00081 LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); 00082 LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL); 00083 LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL); 00084 LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL); 00085 sys_sem_free(conn->op_completed); 00086 sys_mbox_free(conn->recvmbox); 00087 memp_free(MEMP_NETCONN, conn); 00088 return NULL; 00089 } 00090 } 00091 return conn; 00092 } 00093 00094 /** 00095 * Close a netconn 'connection' and free its resources. 00096 * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate 00097 * after this returns. 00098 * 00099 * @param conn the netconn to delete 00100 * @return ERR_OK if the connection was deleted 00101 */ 00102 err_t 00103 netconn_delete(struct netconn *conn) 00104 { 00105 struct api_msg msg; 00106 00107 /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ 00108 if (conn == NULL) { 00109 return ERR_OK; 00110 } 00111 00112 msg.function = do_delconn; 00113 msg.msg.conn = conn; 00114 tcpip_apimsg(&msg); 00115 00116 conn->pcb.tcp = NULL; 00117 netconn_free(conn); 00118 00119 return ERR_OK; 00120 } 00121 00122 /** 00123 * Get the type of a netconn (as enum netconn_type). 00124 * 00125 * @param conn the netconn of which to get the type 00126 * @return the netconn_type of conn 00127 */ 00128 enum netconn_type 00129 netconn_type(struct netconn *conn) 00130 { 00131 LWIP_ERROR("netconn_type: invalid conn", (conn != NULL), return NETCONN_INVALID;); 00132 return conn->type; 00133 } 00134 00135 /** 00136 * Get the local or remote IP address and port of a netconn. 00137 * For RAW netconns, this returns the protocol instead of a port! 00138 * 00139 * @param conn the netconn to query 00140 * @param addr a pointer to which to save the IP address 00141 * @param port a pointer to which to save the port (or protocol for RAW) 00142 * @param local 1 to get the local IP address, 0 to get the remote one 00143 * @return ERR_CONN for invalid connections 00144 * ERR_OK if the information was retrieved 00145 */ 00146 err_t 00147 netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local) 00148 { 00149 struct api_msg msg; 00150 00151 LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); 00152 LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); 00153 LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); 00154 00155 msg.function = do_getaddr; 00156 msg.msg.conn = conn; 00157 msg.msg.msg.ad.ipaddr = addr; 00158 msg.msg.msg.ad.port = port; 00159 msg.msg.msg.ad.local = local; 00160 TCPIP_APIMSG(&msg); 00161 00162 return conn->err; 00163 } 00164 00165 /** 00166 * Bind a netconn to a specific local IP address and port. 00167 * Binding one netconn twice might not always be checked correctly! 00168 * 00169 * @param conn the netconn to bind 00170 * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY 00171 * to bind to all addresses) 00172 * @param port the local port to bind the netconn to (not used for RAW) 00173 * @return ERR_OK if bound, any other err_t on failure 00174 */ 00175 err_t 00176 netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port) 00177 { 00178 struct api_msg msg; 00179 00180 LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); 00181 00182 msg.function = do_bind; 00183 msg.msg.conn = conn; 00184 msg.msg.msg.bc.ipaddr = addr; 00185 msg.msg.msg.bc.port = port; 00186 TCPIP_APIMSG(&msg); 00187 return conn->err; 00188 } 00189 00190 /** 00191 * Connect a netconn to a specific remote IP address and port. 00192 * 00193 * @param conn the netconn to connect 00194 * @param addr the remote IP address to connect to 00195 * @param port the remote port to connect to (no used for RAW) 00196 * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise 00197 */ 00198 err_t 00199 netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port) 00200 { 00201 struct api_msg msg; 00202 00203 LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); 00204 00205 msg.function = do_connect; 00206 msg.msg.conn = conn; 00207 msg.msg.msg.bc.ipaddr = addr; 00208 msg.msg.msg.bc.port = port; 00209 /* This is the only function which need to not block tcpip_thread */ 00210 tcpip_apimsg(&msg); 00211 return conn->err; 00212 } 00213 00214 /** 00215 * Disconnect a netconn from its current peer (only valid for UDP netconns). 00216 * 00217 * @param conn the netconn to disconnect 00218 * @return TODO: return value is not set here... 00219 */ 00220 err_t 00221 netconn_disconnect(struct netconn *conn) 00222 { 00223 struct api_msg msg; 00224 00225 LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); 00226 00227 msg.function = do_disconnect; 00228 msg.msg.conn = conn; 00229 TCPIP_APIMSG(&msg); 00230 return conn->err; 00231 } 00232 00233 /** 00234 * Set a TCP netconn into listen mode 00235 * 00236 * @param conn the tcp netconn to set to listen mode 00237 * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 00238 * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns 00239 * don't return any error (yet?)) 00240 */ 00241 err_t 00242 netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) 00243 { 00244 struct api_msg msg; 00245 00246 /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ 00247 LWIP_UNUSED_ARG(backlog); 00248 00249 LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); 00250 00251 msg.function = do_listen; 00252 msg.msg.conn = conn; 00253 #if TCP_LISTEN_BACKLOG 00254 msg.msg.msg.lb.backlog = backlog; 00255 #endif /* TCP_LISTEN_BACKLOG */ 00256 TCPIP_APIMSG(&msg); 00257 return conn->err; 00258 } 00259 00260 /** 00261 * Accept a new connection on a TCP listening netconn. 00262 * 00263 * @param conn the TCP listen netconn 00264 * @return the newly accepted netconn or NULL on timeout 00265 */ 00266 struct netconn * 00267 netconn_accept(struct netconn *conn) 00268 { 00269 struct netconn *newconn; 00270 00271 LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return NULL;); 00272 LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;); 00273 00274 #if LWIP_SO_RCVTIMEO 00275 if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { 00276 newconn = NULL; 00277 } else 00278 #else 00279 sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0); 00280 #endif /* LWIP_SO_RCVTIMEO*/ 00281 { 00282 /* Register event with callback */ 00283 API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); 00284 00285 #if TCP_LISTEN_BACKLOG 00286 if (newconn != NULL) { 00287 /* Let the stack know that we have accepted the connection. */ 00288 struct api_msg msg; 00289 msg.function = do_recv; 00290 msg.msg.conn = conn; 00291 TCPIP_APIMSG(&msg); 00292 } 00293 #endif /* TCP_LISTEN_BACKLOG */ 00294 } 00295 00296 return newconn; 00297 } 00298 00299 /** 00300 * Receive data (in form of a netbuf containing a packet buffer) from a netconn 00301 * 00302 * @param conn the netconn from which to receive data 00303 * @return a new netbuf containing received data or NULL on memory error or timeout 00304 */ 00305 struct netbuf * 00306 netconn_recv(struct netconn *conn) 00307 { 00308 struct api_msg msg; 00309 struct netbuf *buf = NULL; 00310 struct pbuf *p; 00311 u16_t len; 00312 00313 LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return NULL;); 00314 00315 if (conn->recvmbox == SYS_MBOX_NULL) { 00316 /* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */ 00317 /* TCP listen conns don't have a recvmbox! */ 00318 conn->err = ERR_CONN; 00319 return NULL; 00320 } 00321 00322 if (ERR_IS_FATAL(conn->err)) { 00323 return NULL; 00324 } 00325 00326 if (conn->type == NETCONN_TCP) { 00327 #if LWIP_TCP 00328 if (conn->state == NETCONN_LISTEN) { 00329 /* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */ 00330 conn->err = ERR_CONN; 00331 return NULL; 00332 } 00333 00334 buf = memp_malloc(MEMP_NETBUF); 00335 00336 if (buf == NULL) { 00337 conn->err = ERR_MEM; 00338 return NULL; 00339 } 00340 00341 #if LWIP_SO_RCVTIMEO 00342 if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { 00343 conn->err = ERR_TIMEOUT; 00344 p = NULL; 00345 } 00346 #else 00347 sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0); 00348 #endif /* LWIP_SO_RCVTIMEO*/ 00349 00350 if (p != NULL) { 00351 len = p->tot_len; 00352 SYS_ARCH_DEC(conn->recv_avail, len); 00353 } else { 00354 len = 0; 00355 } 00356 00357 /* Register event with callback */ 00358 API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); 00359 00360 /* If we are closed, we indicate that we no longer wish to use the socket */ 00361 if (p == NULL) { 00362 memp_free(MEMP_NETBUF, buf); 00363 /* Avoid to lose any previous error code */ 00364 if (conn->err == ERR_OK) { 00365 conn->err = ERR_CLSD; 00366 } 00367 return NULL; 00368 } 00369 00370 buf->p = p; 00371 buf->ptr = p; 00372 buf->port = 0; 00373 buf->addr = NULL; 00374 00375 /* Let the stack know that we have taken the data. */ 00376 msg.function = do_recv; 00377 msg.msg.conn = conn; 00378 if (buf != NULL) { 00379 msg.msg.msg.r.len = buf->p->tot_len; 00380 } else { 00381 msg.msg.msg.r.len = 1; 00382 } 00383 TCPIP_APIMSG(&msg); 00384 #endif /* LWIP_TCP */ 00385 } else { 00386 #if (LWIP_UDP || LWIP_RAW) 00387 #if LWIP_SO_RCVTIMEO 00388 if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { 00389 buf = NULL; 00390 } 00391 #else 00392 sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0); 00393 #endif /* LWIP_SO_RCVTIMEO*/ 00394 if (buf!=NULL) { 00395 SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len); 00396 /* Register event with callback */ 00397 API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len); 00398 } 00399 #endif /* (LWIP_UDP || LWIP_RAW) */ 00400 } 00401 00402 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err)); 00403 00404 return buf; 00405 } 00406 00407 /** 00408 * Send data (in form of a netbuf) to a specific remote IP address and port. 00409 * Only to be used for UDP and RAW netconns (not TCP). 00410 * 00411 * @param conn the netconn over which to send data 00412 * @param buf a netbuf containing the data to send 00413 * @param addr the remote IP address to which to send the data 00414 * @param port the remote port to which to send the data 00415 * @return ERR_OK if data was sent, any other err_t on error 00416 */ 00417 err_t 00418 netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port) 00419 { 00420 if (buf != NULL) { 00421 buf->addr = addr; 00422 buf->port = port; 00423 return netconn_send(conn, buf); 00424 } 00425 return ERR_VAL; 00426 } 00427 00428 /** 00429 * Send data over a UDP or RAW netconn (that is already connected). 00430 * 00431 * @param conn the UDP or RAW netconn over which to send data 00432 * @param buf a netbuf containing the data to send 00433 * @return ERR_OK if data was sent, any other err_t on error 00434 */ 00435 err_t 00436 netconn_send(struct netconn *conn, struct netbuf *buf) 00437 { 00438 struct api_msg msg; 00439 00440 LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); 00441 00442 LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len)); 00443 msg.function = do_send; 00444 msg.msg.conn = conn; 00445 msg.msg.msg.b = buf; 00446 TCPIP_APIMSG(&msg); 00447 return conn->err; 00448 } 00449 00450 /** 00451 * Send data over a TCP netconn. 00452 * 00453 * @param conn the TCP netconn over which to send data 00454 * @param dataptr pointer to the application buffer that contains the data to send 00455 * @param size size of the application data to send 00456 * @param apiflags combination of following flags : 00457 * - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack 00458 * - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent 00459 * @return ERR_OK if data was sent, any other err_t on error 00460 */ 00461 err_t 00462 netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags) 00463 { 00464 struct api_msg msg; 00465 00466 LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); 00467 LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;); 00468 00469 msg.function = do_write; 00470 msg.msg.conn = conn; 00471 msg.msg.msg.w.dataptr = dataptr; 00472 msg.msg.msg.w.apiflags = apiflags; 00473 msg.msg.msg.w.len = size; 00474 /* For locking the core: this _can_ be delayed on low memory/low send buffer, 00475 but if it is, this is done inside api_msg.c:do_write(), so we can use the 00476 non-blocking version here. */ 00477 TCPIP_APIMSG(&msg); 00478 return conn->err; 00479 } 00480 00481 /** 00482 * Close a TCP netconn (doesn't delete it). 00483 * 00484 * @param conn the TCP netconn to close 00485 * @return ERR_OK if the netconn was closed, any other err_t on error 00486 */ 00487 err_t 00488 netconn_close(struct netconn *conn) 00489 { 00490 struct api_msg msg; 00491 00492 LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); 00493 00494 msg.function = do_close; 00495 msg.msg.conn = conn; 00496 tcpip_apimsg(&msg); 00497 return conn->err; 00498 } 00499 00500 #if LWIP_IGMP 00501 /** 00502 * Join multicast groups for UDP netconns. 00503 * 00504 * @param conn the UDP netconn for which to change multicast addresses 00505 * @param multiaddr IP address of the multicast group to join or leave 00506 * @param interface the IP address of the network interface on which to send 00507 * the igmp message 00508 * @param join_or_leave flag whether to send a join- or leave-message 00509 * @return ERR_OK if the action was taken, any err_t on error 00510 */ 00511 err_t 00512 netconn_join_leave_group(struct netconn *conn, 00513 struct ip_addr *multiaddr, 00514 struct ip_addr *interface, 00515 enum netconn_igmp join_or_leave) 00516 { 00517 struct api_msg msg; 00518 00519 LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); 00520 00521 msg.function = do_join_leave_group; 00522 msg.msg.conn = conn; 00523 msg.msg.msg.jl.multiaddr = multiaddr; 00524 msg.msg.msg.jl.interface = interface; 00525 msg.msg.msg.jl.join_or_leave = join_or_leave; 00526 TCPIP_APIMSG(&msg); 00527 return conn->err; 00528 } 00529 #endif /* LWIP_IGMP */ 00530 00531 #if LWIP_DNS 00532 /** 00533 * Execute a DNS query, only one IP address is returned 00534 * 00535 * @param name a string representation of the DNS host name to query 00536 * @param addr a preallocated struct ip_addr where to store the resolved IP address 00537 * @return ERR_OK: resolving succeeded 00538 * ERR_MEM: memory error, try again later 00539 * ERR_ARG: dns client not initialized or invalid hostname 00540 * ERR_VAL: dns server response was invalid 00541 */ 00542 err_t 00543 netconn_gethostbyname(const char *name, struct ip_addr *addr) 00544 { 00545 struct dns_api_msg msg; 00546 err_t err; 00547 sys_sem_t sem; 00548 00549 LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); 00550 LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); 00551 00552 sem = sys_sem_new(0); 00553 if (sem == SYS_SEM_NULL) { 00554 return ERR_MEM; 00555 } 00556 00557 msg.name = name; 00558 msg.addr = addr; 00559 msg.err = &err; 00560 msg.sem = sem; 00561 00562 tcpip_callback(do_gethostbyname, &msg); 00563 sys_sem_wait(sem); 00564 sys_sem_free(sem); 00565 00566 return err; 00567 } 00568 #endif /* LWIP_DNS*/ 00569 00570 #endif /* LWIP_NETCONN */
Generated on Tue Jul 12 2022 16:07:00 by
1.7.2
