Genadi Zawidowski / lwip

Dependents:   IGLOO_board

Committer:
ua1arn
Date:
Tue Jul 24 17:26:58 2018 +0000
Revision:
0:c2ca3c5ded62
added lwip-1.4.1 (partial) from old projects

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ua1arn 0:c2ca3c5ded62 1 /**
ua1arn 0:c2ca3c5ded62 2 * @file
ua1arn 0:c2ca3c5ded62 3 * Sequential API Internal module
ua1arn 0:c2ca3c5ded62 4 *
ua1arn 0:c2ca3c5ded62 5 */
ua1arn 0:c2ca3c5ded62 6
ua1arn 0:c2ca3c5ded62 7 /*
ua1arn 0:c2ca3c5ded62 8 * Copyright (c) 2001-2004 Swedish Institute of Computer Science.
ua1arn 0:c2ca3c5ded62 9 * All rights reserved.
ua1arn 0:c2ca3c5ded62 10 *
ua1arn 0:c2ca3c5ded62 11 * Redistribution and use in source and binary forms, with or without modification,
ua1arn 0:c2ca3c5ded62 12 * are permitted provided that the following conditions are met:
ua1arn 0:c2ca3c5ded62 13 *
ua1arn 0:c2ca3c5ded62 14 * 1. Redistributions of source code must retain the above copyright notice,
ua1arn 0:c2ca3c5ded62 15 * this list of conditions and the following disclaimer.
ua1arn 0:c2ca3c5ded62 16 * 2. Redistributions in binary form must reproduce the above copyright notice,
ua1arn 0:c2ca3c5ded62 17 * this list of conditions and the following disclaimer in the documentation
ua1arn 0:c2ca3c5ded62 18 * and/or other materials provided with the distribution.
ua1arn 0:c2ca3c5ded62 19 * 3. The name of the author may not be used to endorse or promote products
ua1arn 0:c2ca3c5ded62 20 * derived from this software without specific prior written permission.
ua1arn 0:c2ca3c5ded62 21 *
ua1arn 0:c2ca3c5ded62 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
ua1arn 0:c2ca3c5ded62 23 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
ua1arn 0:c2ca3c5ded62 24 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
ua1arn 0:c2ca3c5ded62 25 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
ua1arn 0:c2ca3c5ded62 26 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
ua1arn 0:c2ca3c5ded62 27 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
ua1arn 0:c2ca3c5ded62 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
ua1arn 0:c2ca3c5ded62 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
ua1arn 0:c2ca3c5ded62 30 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
ua1arn 0:c2ca3c5ded62 31 * OF SUCH DAMAGE.
ua1arn 0:c2ca3c5ded62 32 *
ua1arn 0:c2ca3c5ded62 33 * This file is part of the lwIP TCP/IP stack.
ua1arn 0:c2ca3c5ded62 34 *
ua1arn 0:c2ca3c5ded62 35 * Author: Adam Dunkels <adam@sics.se>
ua1arn 0:c2ca3c5ded62 36 *
ua1arn 0:c2ca3c5ded62 37 */
ua1arn 0:c2ca3c5ded62 38
ua1arn 0:c2ca3c5ded62 39 #include "lwip/opt.h"
ua1arn 0:c2ca3c5ded62 40
ua1arn 0:c2ca3c5ded62 41 #if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
ua1arn 0:c2ca3c5ded62 42
ua1arn 0:c2ca3c5ded62 43 #include "lwip/api_msg.h"
ua1arn 0:c2ca3c5ded62 44
ua1arn 0:c2ca3c5ded62 45 #include "lwip/ip.h"
ua1arn 0:c2ca3c5ded62 46 #include "lwip/udp.h"
ua1arn 0:c2ca3c5ded62 47 #include "lwip/tcp.h"
ua1arn 0:c2ca3c5ded62 48 #include "lwip/raw.h"
ua1arn 0:c2ca3c5ded62 49
ua1arn 0:c2ca3c5ded62 50 #include "lwip/memp.h"
ua1arn 0:c2ca3c5ded62 51 #include "lwip/tcpip.h"
ua1arn 0:c2ca3c5ded62 52 #include "lwip/igmp.h"
ua1arn 0:c2ca3c5ded62 53 #include "lwip/dns.h"
ua1arn 0:c2ca3c5ded62 54
ua1arn 0:c2ca3c5ded62 55 #include <string.h>
ua1arn 0:c2ca3c5ded62 56
ua1arn 0:c2ca3c5ded62 57 #define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \
ua1arn 0:c2ca3c5ded62 58 (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \
ua1arn 0:c2ca3c5ded62 59 } else { \
ua1arn 0:c2ca3c5ded62 60 (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0)
ua1arn 0:c2ca3c5ded62 61 #define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0)
ua1arn 0:c2ca3c5ded62 62
ua1arn 0:c2ca3c5ded62 63 /* forward declarations */
ua1arn 0:c2ca3c5ded62 64 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 65 static err_t do_writemore(struct netconn *conn);
ua1arn 0:c2ca3c5ded62 66 static void do_close_internal(struct netconn *conn);
ua1arn 0:c2ca3c5ded62 67 #endif
ua1arn 0:c2ca3c5ded62 68
ua1arn 0:c2ca3c5ded62 69 #if LWIP_RAW
ua1arn 0:c2ca3c5ded62 70 /**
ua1arn 0:c2ca3c5ded62 71 * Receive callback function for RAW netconns.
ua1arn 0:c2ca3c5ded62 72 * Doesn't 'eat' the packet, only references it and sends it to
ua1arn 0:c2ca3c5ded62 73 * conn->recvmbox
ua1arn 0:c2ca3c5ded62 74 *
ua1arn 0:c2ca3c5ded62 75 * @see raw.h (struct raw_pcb.recv) for parameters and return value
ua1arn 0:c2ca3c5ded62 76 */
ua1arn 0:c2ca3c5ded62 77 static u8_t
ua1arn 0:c2ca3c5ded62 78 recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,
ua1arn 0:c2ca3c5ded62 79 ip_addr_t *addr)
ua1arn 0:c2ca3c5ded62 80 {
ua1arn 0:c2ca3c5ded62 81 struct pbuf *q;
ua1arn 0:c2ca3c5ded62 82 struct netbuf *buf;
ua1arn 0:c2ca3c5ded62 83 struct netconn *conn;
ua1arn 0:c2ca3c5ded62 84
ua1arn 0:c2ca3c5ded62 85 LWIP_UNUSED_ARG(addr);
ua1arn 0:c2ca3c5ded62 86 conn = (struct netconn *)arg;
ua1arn 0:c2ca3c5ded62 87
ua1arn 0:c2ca3c5ded62 88 if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) {
ua1arn 0:c2ca3c5ded62 89 #if LWIP_SO_RCVBUF
ua1arn 0:c2ca3c5ded62 90 int recv_avail;
ua1arn 0:c2ca3c5ded62 91 SYS_ARCH_GET(conn->recv_avail, recv_avail);
ua1arn 0:c2ca3c5ded62 92 if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) {
ua1arn 0:c2ca3c5ded62 93 return 0;
ua1arn 0:c2ca3c5ded62 94 }
ua1arn 0:c2ca3c5ded62 95 #endif /* LWIP_SO_RCVBUF */
ua1arn 0:c2ca3c5ded62 96 /* copy the whole packet into new pbufs */
ua1arn 0:c2ca3c5ded62 97 q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
ua1arn 0:c2ca3c5ded62 98 if(q != NULL) {
ua1arn 0:c2ca3c5ded62 99 if (pbuf_copy(q, p) != ERR_OK) {
ua1arn 0:c2ca3c5ded62 100 pbuf_free(q);
ua1arn 0:c2ca3c5ded62 101 q = NULL;
ua1arn 0:c2ca3c5ded62 102 }
ua1arn 0:c2ca3c5ded62 103 }
ua1arn 0:c2ca3c5ded62 104
ua1arn 0:c2ca3c5ded62 105 if (q != NULL) {
ua1arn 0:c2ca3c5ded62 106 u16_t len;
ua1arn 0:c2ca3c5ded62 107 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
ua1arn 0:c2ca3c5ded62 108 if (buf == NULL) {
ua1arn 0:c2ca3c5ded62 109 pbuf_free(q);
ua1arn 0:c2ca3c5ded62 110 return 0;
ua1arn 0:c2ca3c5ded62 111 }
ua1arn 0:c2ca3c5ded62 112
ua1arn 0:c2ca3c5ded62 113 buf->p = q;
ua1arn 0:c2ca3c5ded62 114 buf->ptr = q;
ua1arn 0:c2ca3c5ded62 115 ip_addr_copy(buf->addr, *ip_current_src_addr());
ua1arn 0:c2ca3c5ded62 116 buf->port = pcb->protocol;
ua1arn 0:c2ca3c5ded62 117
ua1arn 0:c2ca3c5ded62 118 len = q->tot_len;
ua1arn 0:c2ca3c5ded62 119 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
ua1arn 0:c2ca3c5ded62 120 netbuf_delete(buf);
ua1arn 0:c2ca3c5ded62 121 return 0;
ua1arn 0:c2ca3c5ded62 122 } else {
ua1arn 0:c2ca3c5ded62 123 #if LWIP_SO_RCVBUF
ua1arn 0:c2ca3c5ded62 124 SYS_ARCH_INC(conn->recv_avail, len);
ua1arn 0:c2ca3c5ded62 125 #endif /* LWIP_SO_RCVBUF */
ua1arn 0:c2ca3c5ded62 126 /* Register event with callback */
ua1arn 0:c2ca3c5ded62 127 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
ua1arn 0:c2ca3c5ded62 128 }
ua1arn 0:c2ca3c5ded62 129 }
ua1arn 0:c2ca3c5ded62 130 }
ua1arn 0:c2ca3c5ded62 131
ua1arn 0:c2ca3c5ded62 132 return 0; /* do not eat the packet */
ua1arn 0:c2ca3c5ded62 133 }
ua1arn 0:c2ca3c5ded62 134 #endif /* LWIP_RAW*/
ua1arn 0:c2ca3c5ded62 135
ua1arn 0:c2ca3c5ded62 136 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 137 /**
ua1arn 0:c2ca3c5ded62 138 * Receive callback function for UDP netconns.
ua1arn 0:c2ca3c5ded62 139 * Posts the packet to conn->recvmbox or deletes it on memory error.
ua1arn 0:c2ca3c5ded62 140 *
ua1arn 0:c2ca3c5ded62 141 * @see udp.h (struct udp_pcb.recv) for parameters
ua1arn 0:c2ca3c5ded62 142 */
ua1arn 0:c2ca3c5ded62 143 static void
ua1arn 0:c2ca3c5ded62 144 recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,
ua1arn 0:c2ca3c5ded62 145 ip_addr_t *addr, u16_t port)
ua1arn 0:c2ca3c5ded62 146 {
ua1arn 0:c2ca3c5ded62 147 struct netbuf *buf;
ua1arn 0:c2ca3c5ded62 148 struct netconn *conn;
ua1arn 0:c2ca3c5ded62 149 u16_t len;
ua1arn 0:c2ca3c5ded62 150 #if LWIP_SO_RCVBUF
ua1arn 0:c2ca3c5ded62 151 int recv_avail;
ua1arn 0:c2ca3c5ded62 152 #endif /* LWIP_SO_RCVBUF */
ua1arn 0:c2ca3c5ded62 153
ua1arn 0:c2ca3c5ded62 154 LWIP_UNUSED_ARG(pcb); /* only used for asserts... */
ua1arn 0:c2ca3c5ded62 155 LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);
ua1arn 0:c2ca3c5ded62 156 LWIP_ASSERT("recv_udp must have an argument", arg != NULL);
ua1arn 0:c2ca3c5ded62 157 conn = (struct netconn *)arg;
ua1arn 0:c2ca3c5ded62 158 LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);
ua1arn 0:c2ca3c5ded62 159
ua1arn 0:c2ca3c5ded62 160 #if LWIP_SO_RCVBUF
ua1arn 0:c2ca3c5ded62 161 SYS_ARCH_GET(conn->recv_avail, recv_avail);
ua1arn 0:c2ca3c5ded62 162 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) ||
ua1arn 0:c2ca3c5ded62 163 ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {
ua1arn 0:c2ca3c5ded62 164 #else /* LWIP_SO_RCVBUF */
ua1arn 0:c2ca3c5ded62 165 if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) {
ua1arn 0:c2ca3c5ded62 166 #endif /* LWIP_SO_RCVBUF */
ua1arn 0:c2ca3c5ded62 167 pbuf_free(p);
ua1arn 0:c2ca3c5ded62 168 return;
ua1arn 0:c2ca3c5ded62 169 }
ua1arn 0:c2ca3c5ded62 170
ua1arn 0:c2ca3c5ded62 171 buf = (struct netbuf *)memp_malloc(MEMP_NETBUF);
ua1arn 0:c2ca3c5ded62 172 if (buf == NULL) {
ua1arn 0:c2ca3c5ded62 173 pbuf_free(p);
ua1arn 0:c2ca3c5ded62 174 return;
ua1arn 0:c2ca3c5ded62 175 } else {
ua1arn 0:c2ca3c5ded62 176 buf->p = p;
ua1arn 0:c2ca3c5ded62 177 buf->ptr = p;
ua1arn 0:c2ca3c5ded62 178 ip_addr_set(&buf->addr, addr);
ua1arn 0:c2ca3c5ded62 179 buf->port = port;
ua1arn 0:c2ca3c5ded62 180 #if LWIP_NETBUF_RECVINFO
ua1arn 0:c2ca3c5ded62 181 {
ua1arn 0:c2ca3c5ded62 182 const struct ip_hdr* iphdr = ip_current_header();
ua1arn 0:c2ca3c5ded62 183 /* get the UDP header - always in the first pbuf, ensured by udp_input */
ua1arn 0:c2ca3c5ded62 184 const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr));
ua1arn 0:c2ca3c5ded62 185 #if LWIP_CHECKSUM_ON_COPY
ua1arn 0:c2ca3c5ded62 186 buf->flags = NETBUF_FLAG_DESTADDR;
ua1arn 0:c2ca3c5ded62 187 #endif /* LWIP_CHECKSUM_ON_COPY */
ua1arn 0:c2ca3c5ded62 188 ip_addr_set(&buf->toaddr, ip_current_dest_addr());
ua1arn 0:c2ca3c5ded62 189 buf->toport_chksum = udphdr->dest;
ua1arn 0:c2ca3c5ded62 190 }
ua1arn 0:c2ca3c5ded62 191 #endif /* LWIP_NETBUF_RECVINFO */
ua1arn 0:c2ca3c5ded62 192 }
ua1arn 0:c2ca3c5ded62 193
ua1arn 0:c2ca3c5ded62 194 len = p->tot_len;
ua1arn 0:c2ca3c5ded62 195 if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) {
ua1arn 0:c2ca3c5ded62 196 netbuf_delete(buf);
ua1arn 0:c2ca3c5ded62 197 return;
ua1arn 0:c2ca3c5ded62 198 } else {
ua1arn 0:c2ca3c5ded62 199 #if LWIP_SO_RCVBUF
ua1arn 0:c2ca3c5ded62 200 SYS_ARCH_INC(conn->recv_avail, len);
ua1arn 0:c2ca3c5ded62 201 #endif /* LWIP_SO_RCVBUF */
ua1arn 0:c2ca3c5ded62 202 /* Register event with callback */
ua1arn 0:c2ca3c5ded62 203 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
ua1arn 0:c2ca3c5ded62 204 }
ua1arn 0:c2ca3c5ded62 205 }
ua1arn 0:c2ca3c5ded62 206 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 207
ua1arn 0:c2ca3c5ded62 208 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 209 /**
ua1arn 0:c2ca3c5ded62 210 * Receive callback function for TCP netconns.
ua1arn 0:c2ca3c5ded62 211 * Posts the packet to conn->recvmbox, but doesn't delete it on errors.
ua1arn 0:c2ca3c5ded62 212 *
ua1arn 0:c2ca3c5ded62 213 * @see tcp.h (struct tcp_pcb.recv) for parameters and return value
ua1arn 0:c2ca3c5ded62 214 */
ua1arn 0:c2ca3c5ded62 215 static err_t
ua1arn 0:c2ca3c5ded62 216 recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
ua1arn 0:c2ca3c5ded62 217 {
ua1arn 0:c2ca3c5ded62 218 struct netconn *conn;
ua1arn 0:c2ca3c5ded62 219 u16_t len;
ua1arn 0:c2ca3c5ded62 220
ua1arn 0:c2ca3c5ded62 221 LWIP_UNUSED_ARG(pcb);
ua1arn 0:c2ca3c5ded62 222 LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);
ua1arn 0:c2ca3c5ded62 223 LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);
ua1arn 0:c2ca3c5ded62 224 conn = (struct netconn *)arg;
ua1arn 0:c2ca3c5ded62 225 LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);
ua1arn 0:c2ca3c5ded62 226
ua1arn 0:c2ca3c5ded62 227 if (conn == NULL) {
ua1arn 0:c2ca3c5ded62 228 return ERR_VAL;
ua1arn 0:c2ca3c5ded62 229 }
ua1arn 0:c2ca3c5ded62 230 if (!sys_mbox_valid(&conn->recvmbox)) {
ua1arn 0:c2ca3c5ded62 231 /* recvmbox already deleted */
ua1arn 0:c2ca3c5ded62 232 if (p != NULL) {
ua1arn 0:c2ca3c5ded62 233 tcp_recved(pcb, p->tot_len);
ua1arn 0:c2ca3c5ded62 234 pbuf_free(p);
ua1arn 0:c2ca3c5ded62 235 }
ua1arn 0:c2ca3c5ded62 236 return ERR_OK;
ua1arn 0:c2ca3c5ded62 237 }
ua1arn 0:c2ca3c5ded62 238 /* Unlike for UDP or RAW pcbs, don't check for available space
ua1arn 0:c2ca3c5ded62 239 using recv_avail since that could break the connection
ua1arn 0:c2ca3c5ded62 240 (data is already ACKed) */
ua1arn 0:c2ca3c5ded62 241
ua1arn 0:c2ca3c5ded62 242 /* don't overwrite fatal errors! */
ua1arn 0:c2ca3c5ded62 243 NETCONN_SET_SAFE_ERR(conn, err);
ua1arn 0:c2ca3c5ded62 244
ua1arn 0:c2ca3c5ded62 245 if (p != NULL) {
ua1arn 0:c2ca3c5ded62 246 len = p->tot_len;
ua1arn 0:c2ca3c5ded62 247 } else {
ua1arn 0:c2ca3c5ded62 248 len = 0;
ua1arn 0:c2ca3c5ded62 249 }
ua1arn 0:c2ca3c5ded62 250
ua1arn 0:c2ca3c5ded62 251 if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) {
ua1arn 0:c2ca3c5ded62 252 /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */
ua1arn 0:c2ca3c5ded62 253 return ERR_MEM;
ua1arn 0:c2ca3c5ded62 254 } else {
ua1arn 0:c2ca3c5ded62 255 #if LWIP_SO_RCVBUF
ua1arn 0:c2ca3c5ded62 256 SYS_ARCH_INC(conn->recv_avail, len);
ua1arn 0:c2ca3c5ded62 257 #endif /* LWIP_SO_RCVBUF */
ua1arn 0:c2ca3c5ded62 258 /* Register event with callback */
ua1arn 0:c2ca3c5ded62 259 API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);
ua1arn 0:c2ca3c5ded62 260 }
ua1arn 0:c2ca3c5ded62 261
ua1arn 0:c2ca3c5ded62 262 return ERR_OK;
ua1arn 0:c2ca3c5ded62 263 }
ua1arn 0:c2ca3c5ded62 264
ua1arn 0:c2ca3c5ded62 265 /**
ua1arn 0:c2ca3c5ded62 266 * Poll callback function for TCP netconns.
ua1arn 0:c2ca3c5ded62 267 * Wakes up an application thread that waits for a connection to close
ua1arn 0:c2ca3c5ded62 268 * or data to be sent. The application thread then takes the
ua1arn 0:c2ca3c5ded62 269 * appropriate action to go on.
ua1arn 0:c2ca3c5ded62 270 *
ua1arn 0:c2ca3c5ded62 271 * Signals the conn->sem.
ua1arn 0:c2ca3c5ded62 272 * netconn_close waits for conn->sem if closing failed.
ua1arn 0:c2ca3c5ded62 273 *
ua1arn 0:c2ca3c5ded62 274 * @see tcp.h (struct tcp_pcb.poll) for parameters and return value
ua1arn 0:c2ca3c5ded62 275 */
ua1arn 0:c2ca3c5ded62 276 static err_t
ua1arn 0:c2ca3c5ded62 277 poll_tcp(void *arg, struct tcp_pcb *pcb)
ua1arn 0:c2ca3c5ded62 278 {
ua1arn 0:c2ca3c5ded62 279 struct netconn *conn = (struct netconn *)arg;
ua1arn 0:c2ca3c5ded62 280
ua1arn 0:c2ca3c5ded62 281 LWIP_UNUSED_ARG(pcb);
ua1arn 0:c2ca3c5ded62 282 LWIP_ASSERT("conn != NULL", (conn != NULL));
ua1arn 0:c2ca3c5ded62 283
ua1arn 0:c2ca3c5ded62 284 if (conn->state == NETCONN_WRITE) {
ua1arn 0:c2ca3c5ded62 285 do_writemore(conn);
ua1arn 0:c2ca3c5ded62 286 } else if (conn->state == NETCONN_CLOSE) {
ua1arn 0:c2ca3c5ded62 287 do_close_internal(conn);
ua1arn 0:c2ca3c5ded62 288 }
ua1arn 0:c2ca3c5ded62 289 /* @todo: implement connect timeout here? */
ua1arn 0:c2ca3c5ded62 290
ua1arn 0:c2ca3c5ded62 291 /* Did a nonblocking write fail before? Then check available write-space. */
ua1arn 0:c2ca3c5ded62 292 if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) {
ua1arn 0:c2ca3c5ded62 293 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
ua1arn 0:c2ca3c5ded62 294 let select mark this pcb as writable again. */
ua1arn 0:c2ca3c5ded62 295 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
ua1arn 0:c2ca3c5ded62 296 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
ua1arn 0:c2ca3c5ded62 297 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
ua1arn 0:c2ca3c5ded62 298 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
ua1arn 0:c2ca3c5ded62 299 }
ua1arn 0:c2ca3c5ded62 300 }
ua1arn 0:c2ca3c5ded62 301
ua1arn 0:c2ca3c5ded62 302 return ERR_OK;
ua1arn 0:c2ca3c5ded62 303 }
ua1arn 0:c2ca3c5ded62 304
ua1arn 0:c2ca3c5ded62 305 /**
ua1arn 0:c2ca3c5ded62 306 * Sent callback function for TCP netconns.
ua1arn 0:c2ca3c5ded62 307 * Signals the conn->sem and calls API_EVENT.
ua1arn 0:c2ca3c5ded62 308 * netconn_write waits for conn->sem if send buffer is low.
ua1arn 0:c2ca3c5ded62 309 *
ua1arn 0:c2ca3c5ded62 310 * @see tcp.h (struct tcp_pcb.sent) for parameters and return value
ua1arn 0:c2ca3c5ded62 311 */
ua1arn 0:c2ca3c5ded62 312 static err_t
ua1arn 0:c2ca3c5ded62 313 sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)
ua1arn 0:c2ca3c5ded62 314 {
ua1arn 0:c2ca3c5ded62 315 struct netconn *conn = (struct netconn *)arg;
ua1arn 0:c2ca3c5ded62 316
ua1arn 0:c2ca3c5ded62 317 LWIP_UNUSED_ARG(pcb);
ua1arn 0:c2ca3c5ded62 318 LWIP_ASSERT("conn != NULL", (conn != NULL));
ua1arn 0:c2ca3c5ded62 319
ua1arn 0:c2ca3c5ded62 320 if (conn->state == NETCONN_WRITE) {
ua1arn 0:c2ca3c5ded62 321 do_writemore(conn);
ua1arn 0:c2ca3c5ded62 322 } else if (conn->state == NETCONN_CLOSE) {
ua1arn 0:c2ca3c5ded62 323 do_close_internal(conn);
ua1arn 0:c2ca3c5ded62 324 }
ua1arn 0:c2ca3c5ded62 325
ua1arn 0:c2ca3c5ded62 326 if (conn) {
ua1arn 0:c2ca3c5ded62 327 /* If the queued byte- or pbuf-count drops below the configured low-water limit,
ua1arn 0:c2ca3c5ded62 328 let select mark this pcb as writable again. */
ua1arn 0:c2ca3c5ded62 329 if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) &&
ua1arn 0:c2ca3c5ded62 330 (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) {
ua1arn 0:c2ca3c5ded62 331 conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE;
ua1arn 0:c2ca3c5ded62 332 API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);
ua1arn 0:c2ca3c5ded62 333 }
ua1arn 0:c2ca3c5ded62 334 }
ua1arn 0:c2ca3c5ded62 335
ua1arn 0:c2ca3c5ded62 336 return ERR_OK;
ua1arn 0:c2ca3c5ded62 337 }
ua1arn 0:c2ca3c5ded62 338
ua1arn 0:c2ca3c5ded62 339 /**
ua1arn 0:c2ca3c5ded62 340 * Error callback function for TCP netconns.
ua1arn 0:c2ca3c5ded62 341 * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.
ua1arn 0:c2ca3c5ded62 342 * The application thread has then to decide what to do.
ua1arn 0:c2ca3c5ded62 343 *
ua1arn 0:c2ca3c5ded62 344 * @see tcp.h (struct tcp_pcb.err) for parameters
ua1arn 0:c2ca3c5ded62 345 */
ua1arn 0:c2ca3c5ded62 346 static void
ua1arn 0:c2ca3c5ded62 347 err_tcp(void *arg, err_t err)
ua1arn 0:c2ca3c5ded62 348 {
ua1arn 0:c2ca3c5ded62 349 struct netconn *conn;
ua1arn 0:c2ca3c5ded62 350 enum netconn_state old_state;
ua1arn 0:c2ca3c5ded62 351 SYS_ARCH_DECL_PROTECT(lev);
ua1arn 0:c2ca3c5ded62 352
ua1arn 0:c2ca3c5ded62 353 conn = (struct netconn *)arg;
ua1arn 0:c2ca3c5ded62 354 LWIP_ASSERT("conn != NULL", (conn != NULL));
ua1arn 0:c2ca3c5ded62 355
ua1arn 0:c2ca3c5ded62 356 conn->pcb.tcp = NULL;
ua1arn 0:c2ca3c5ded62 357
ua1arn 0:c2ca3c5ded62 358 /* no check since this is always fatal! */
ua1arn 0:c2ca3c5ded62 359 SYS_ARCH_PROTECT(lev);
ua1arn 0:c2ca3c5ded62 360 conn->last_err = err;
ua1arn 0:c2ca3c5ded62 361 SYS_ARCH_UNPROTECT(lev);
ua1arn 0:c2ca3c5ded62 362
ua1arn 0:c2ca3c5ded62 363 /* reset conn->state now before waking up other threads */
ua1arn 0:c2ca3c5ded62 364 old_state = conn->state;
ua1arn 0:c2ca3c5ded62 365 conn->state = NETCONN_NONE;
ua1arn 0:c2ca3c5ded62 366
ua1arn 0:c2ca3c5ded62 367 /* Notify the user layer about a connection error. Used to signal
ua1arn 0:c2ca3c5ded62 368 select. */
ua1arn 0:c2ca3c5ded62 369 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
ua1arn 0:c2ca3c5ded62 370 /* Try to release selects pending on 'read' or 'write', too.
ua1arn 0:c2ca3c5ded62 371 They will get an error if they actually try to read or write. */
ua1arn 0:c2ca3c5ded62 372 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
ua1arn 0:c2ca3c5ded62 373 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
ua1arn 0:c2ca3c5ded62 374
ua1arn 0:c2ca3c5ded62 375 /* pass NULL-message to recvmbox to wake up pending recv */
ua1arn 0:c2ca3c5ded62 376 if (sys_mbox_valid(&conn->recvmbox)) {
ua1arn 0:c2ca3c5ded62 377 /* use trypost to prevent deadlock */
ua1arn 0:c2ca3c5ded62 378 sys_mbox_trypost(&conn->recvmbox, NULL);
ua1arn 0:c2ca3c5ded62 379 }
ua1arn 0:c2ca3c5ded62 380 /* pass NULL-message to acceptmbox to wake up pending accept */
ua1arn 0:c2ca3c5ded62 381 if (sys_mbox_valid(&conn->acceptmbox)) {
ua1arn 0:c2ca3c5ded62 382 /* use trypost to preven deadlock */
ua1arn 0:c2ca3c5ded62 383 sys_mbox_trypost(&conn->acceptmbox, NULL);
ua1arn 0:c2ca3c5ded62 384 }
ua1arn 0:c2ca3c5ded62 385
ua1arn 0:c2ca3c5ded62 386 if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) ||
ua1arn 0:c2ca3c5ded62 387 (old_state == NETCONN_CONNECT)) {
ua1arn 0:c2ca3c5ded62 388 /* calling do_writemore/do_close_internal is not necessary
ua1arn 0:c2ca3c5ded62 389 since the pcb has already been deleted! */
ua1arn 0:c2ca3c5ded62 390 int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn);
ua1arn 0:c2ca3c5ded62 391 SET_NONBLOCKING_CONNECT(conn, 0);
ua1arn 0:c2ca3c5ded62 392
ua1arn 0:c2ca3c5ded62 393 if (!was_nonblocking_connect) {
ua1arn 0:c2ca3c5ded62 394 /* set error return code */
ua1arn 0:c2ca3c5ded62 395 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
ua1arn 0:c2ca3c5ded62 396 conn->current_msg->err = err;
ua1arn 0:c2ca3c5ded62 397 conn->current_msg = NULL;
ua1arn 0:c2ca3c5ded62 398 /* wake up the waiting task */
ua1arn 0:c2ca3c5ded62 399 sys_sem_signal(&conn->op_completed);
ua1arn 0:c2ca3c5ded62 400 }
ua1arn 0:c2ca3c5ded62 401 } else {
ua1arn 0:c2ca3c5ded62 402 LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL);
ua1arn 0:c2ca3c5ded62 403 }
ua1arn 0:c2ca3c5ded62 404 }
ua1arn 0:c2ca3c5ded62 405
ua1arn 0:c2ca3c5ded62 406 /**
ua1arn 0:c2ca3c5ded62 407 * Setup a tcp_pcb with the correct callback function pointers
ua1arn 0:c2ca3c5ded62 408 * and their arguments.
ua1arn 0:c2ca3c5ded62 409 *
ua1arn 0:c2ca3c5ded62 410 * @param conn the TCP netconn to setup
ua1arn 0:c2ca3c5ded62 411 */
ua1arn 0:c2ca3c5ded62 412 static void
ua1arn 0:c2ca3c5ded62 413 setup_tcp(struct netconn *conn)
ua1arn 0:c2ca3c5ded62 414 {
ua1arn 0:c2ca3c5ded62 415 struct tcp_pcb *pcb;
ua1arn 0:c2ca3c5ded62 416
ua1arn 0:c2ca3c5ded62 417 pcb = conn->pcb.tcp;
ua1arn 0:c2ca3c5ded62 418 tcp_arg(pcb, conn);
ua1arn 0:c2ca3c5ded62 419 tcp_recv(pcb, recv_tcp);
ua1arn 0:c2ca3c5ded62 420 tcp_sent(pcb, sent_tcp);
ua1arn 0:c2ca3c5ded62 421 tcp_poll(pcb, poll_tcp, 4);
ua1arn 0:c2ca3c5ded62 422 tcp_err(pcb, err_tcp);
ua1arn 0:c2ca3c5ded62 423 }
ua1arn 0:c2ca3c5ded62 424
ua1arn 0:c2ca3c5ded62 425 /**
ua1arn 0:c2ca3c5ded62 426 * Accept callback function for TCP netconns.
ua1arn 0:c2ca3c5ded62 427 * Allocates a new netconn and posts that to conn->acceptmbox.
ua1arn 0:c2ca3c5ded62 428 *
ua1arn 0:c2ca3c5ded62 429 * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value
ua1arn 0:c2ca3c5ded62 430 */
ua1arn 0:c2ca3c5ded62 431 static err_t
ua1arn 0:c2ca3c5ded62 432 accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)
ua1arn 0:c2ca3c5ded62 433 {
ua1arn 0:c2ca3c5ded62 434 struct netconn *newconn;
ua1arn 0:c2ca3c5ded62 435 struct netconn *conn = (struct netconn *)arg;
ua1arn 0:c2ca3c5ded62 436
ua1arn 0:c2ca3c5ded62 437 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state)));
ua1arn 0:c2ca3c5ded62 438
ua1arn 0:c2ca3c5ded62 439 if (!sys_mbox_valid(&conn->acceptmbox)) {
ua1arn 0:c2ca3c5ded62 440 LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n"));
ua1arn 0:c2ca3c5ded62 441 return ERR_VAL;
ua1arn 0:c2ca3c5ded62 442 }
ua1arn 0:c2ca3c5ded62 443
ua1arn 0:c2ca3c5ded62 444 /* We have to set the callback here even though
ua1arn 0:c2ca3c5ded62 445 * the new socket is unknown. conn->socket is marked as -1. */
ua1arn 0:c2ca3c5ded62 446 newconn = netconn_alloc(conn->type, conn->callback);
ua1arn 0:c2ca3c5ded62 447 if (newconn == NULL) {
ua1arn 0:c2ca3c5ded62 448 return ERR_MEM;
ua1arn 0:c2ca3c5ded62 449 }
ua1arn 0:c2ca3c5ded62 450 newconn->pcb.tcp = newpcb;
ua1arn 0:c2ca3c5ded62 451 setup_tcp(newconn);
ua1arn 0:c2ca3c5ded62 452 /* no protection: when creating the pcb, the netconn is not yet known
ua1arn 0:c2ca3c5ded62 453 to the application thread */
ua1arn 0:c2ca3c5ded62 454 newconn->last_err = err;
ua1arn 0:c2ca3c5ded62 455
ua1arn 0:c2ca3c5ded62 456 if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) {
ua1arn 0:c2ca3c5ded62 457 /* When returning != ERR_OK, the pcb is aborted in tcp_process(),
ua1arn 0:c2ca3c5ded62 458 so do nothing here! */
ua1arn 0:c2ca3c5ded62 459 /* remove all references to this netconn from the pcb */
ua1arn 0:c2ca3c5ded62 460 struct tcp_pcb* pcb = newconn->pcb.tcp;
ua1arn 0:c2ca3c5ded62 461 tcp_arg(pcb, NULL);
ua1arn 0:c2ca3c5ded62 462 tcp_recv(pcb, NULL);
ua1arn 0:c2ca3c5ded62 463 tcp_sent(pcb, NULL);
ua1arn 0:c2ca3c5ded62 464 tcp_poll(pcb, NULL, 4);
ua1arn 0:c2ca3c5ded62 465 tcp_err(pcb, NULL);
ua1arn 0:c2ca3c5ded62 466 /* remove reference from to the pcb from this netconn */
ua1arn 0:c2ca3c5ded62 467 newconn->pcb.tcp = NULL;
ua1arn 0:c2ca3c5ded62 468 /* no need to drain since we know the recvmbox is empty. */
ua1arn 0:c2ca3c5ded62 469 sys_mbox_free(&newconn->recvmbox);
ua1arn 0:c2ca3c5ded62 470 sys_mbox_set_invalid(&newconn->recvmbox);
ua1arn 0:c2ca3c5ded62 471 netconn_free(newconn);
ua1arn 0:c2ca3c5ded62 472 return ERR_MEM;
ua1arn 0:c2ca3c5ded62 473 } else {
ua1arn 0:c2ca3c5ded62 474 /* Register event with callback */
ua1arn 0:c2ca3c5ded62 475 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
ua1arn 0:c2ca3c5ded62 476 }
ua1arn 0:c2ca3c5ded62 477
ua1arn 0:c2ca3c5ded62 478 return ERR_OK;
ua1arn 0:c2ca3c5ded62 479 }
ua1arn 0:c2ca3c5ded62 480 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 481
ua1arn 0:c2ca3c5ded62 482 /**
ua1arn 0:c2ca3c5ded62 483 * Create a new pcb of a specific type.
ua1arn 0:c2ca3c5ded62 484 * Called from do_newconn().
ua1arn 0:c2ca3c5ded62 485 *
ua1arn 0:c2ca3c5ded62 486 * @param msg the api_msg_msg describing the connection type
ua1arn 0:c2ca3c5ded62 487 * @return msg->conn->err, but the return value is currently ignored
ua1arn 0:c2ca3c5ded62 488 */
ua1arn 0:c2ca3c5ded62 489 static void
ua1arn 0:c2ca3c5ded62 490 pcb_new(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 491 {
ua1arn 0:c2ca3c5ded62 492 LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);
ua1arn 0:c2ca3c5ded62 493
ua1arn 0:c2ca3c5ded62 494 /* Allocate a PCB for this connection */
ua1arn 0:c2ca3c5ded62 495 switch(NETCONNTYPE_GROUP(msg->conn->type)) {
ua1arn 0:c2ca3c5ded62 496 #if LWIP_RAW
ua1arn 0:c2ca3c5ded62 497 case NETCONN_RAW:
ua1arn 0:c2ca3c5ded62 498 msg->conn->pcb.raw = raw_new(msg->msg.n.proto);
ua1arn 0:c2ca3c5ded62 499 if(msg->conn->pcb.raw == NULL) {
ua1arn 0:c2ca3c5ded62 500 msg->err = ERR_MEM;
ua1arn 0:c2ca3c5ded62 501 break;
ua1arn 0:c2ca3c5ded62 502 }
ua1arn 0:c2ca3c5ded62 503 raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);
ua1arn 0:c2ca3c5ded62 504 break;
ua1arn 0:c2ca3c5ded62 505 #endif /* LWIP_RAW */
ua1arn 0:c2ca3c5ded62 506 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 507 case NETCONN_UDP:
ua1arn 0:c2ca3c5ded62 508 msg->conn->pcb.udp = udp_new();
ua1arn 0:c2ca3c5ded62 509 if(msg->conn->pcb.udp == NULL) {
ua1arn 0:c2ca3c5ded62 510 msg->err = ERR_MEM;
ua1arn 0:c2ca3c5ded62 511 break;
ua1arn 0:c2ca3c5ded62 512 }
ua1arn 0:c2ca3c5ded62 513 #if LWIP_UDPLITE
ua1arn 0:c2ca3c5ded62 514 if (msg->conn->type==NETCONN_UDPLITE) {
ua1arn 0:c2ca3c5ded62 515 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);
ua1arn 0:c2ca3c5ded62 516 }
ua1arn 0:c2ca3c5ded62 517 #endif /* LWIP_UDPLITE */
ua1arn 0:c2ca3c5ded62 518 if (msg->conn->type==NETCONN_UDPNOCHKSUM) {
ua1arn 0:c2ca3c5ded62 519 udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);
ua1arn 0:c2ca3c5ded62 520 }
ua1arn 0:c2ca3c5ded62 521 udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);
ua1arn 0:c2ca3c5ded62 522 break;
ua1arn 0:c2ca3c5ded62 523 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 524 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 525 case NETCONN_TCP:
ua1arn 0:c2ca3c5ded62 526 msg->conn->pcb.tcp = tcp_new();
ua1arn 0:c2ca3c5ded62 527 if(msg->conn->pcb.tcp == NULL) {
ua1arn 0:c2ca3c5ded62 528 msg->err = ERR_MEM;
ua1arn 0:c2ca3c5ded62 529 break;
ua1arn 0:c2ca3c5ded62 530 }
ua1arn 0:c2ca3c5ded62 531 setup_tcp(msg->conn);
ua1arn 0:c2ca3c5ded62 532 break;
ua1arn 0:c2ca3c5ded62 533 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 534 default:
ua1arn 0:c2ca3c5ded62 535 /* Unsupported netconn type, e.g. protocol disabled */
ua1arn 0:c2ca3c5ded62 536 msg->err = ERR_VAL;
ua1arn 0:c2ca3c5ded62 537 break;
ua1arn 0:c2ca3c5ded62 538 }
ua1arn 0:c2ca3c5ded62 539 }
ua1arn 0:c2ca3c5ded62 540
ua1arn 0:c2ca3c5ded62 541 /**
ua1arn 0:c2ca3c5ded62 542 * Create a new pcb of a specific type inside a netconn.
ua1arn 0:c2ca3c5ded62 543 * Called from netconn_new_with_proto_and_callback.
ua1arn 0:c2ca3c5ded62 544 *
ua1arn 0:c2ca3c5ded62 545 * @param msg the api_msg_msg describing the connection type
ua1arn 0:c2ca3c5ded62 546 */
ua1arn 0:c2ca3c5ded62 547 void
ua1arn 0:c2ca3c5ded62 548 do_newconn(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 549 {
ua1arn 0:c2ca3c5ded62 550 msg->err = ERR_OK;
ua1arn 0:c2ca3c5ded62 551 if(msg->conn->pcb.tcp == NULL) {
ua1arn 0:c2ca3c5ded62 552 pcb_new(msg);
ua1arn 0:c2ca3c5ded62 553 }
ua1arn 0:c2ca3c5ded62 554 /* Else? This "new" connection already has a PCB allocated. */
ua1arn 0:c2ca3c5ded62 555 /* Is this an error condition? Should it be deleted? */
ua1arn 0:c2ca3c5ded62 556 /* We currently just are happy and return. */
ua1arn 0:c2ca3c5ded62 557
ua1arn 0:c2ca3c5ded62 558 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 559 }
ua1arn 0:c2ca3c5ded62 560
ua1arn 0:c2ca3c5ded62 561 /**
ua1arn 0:c2ca3c5ded62 562 * Create a new netconn (of a specific type) that has a callback function.
ua1arn 0:c2ca3c5ded62 563 * The corresponding pcb is NOT created!
ua1arn 0:c2ca3c5ded62 564 *
ua1arn 0:c2ca3c5ded62 565 * @param t the type of 'connection' to create (@see enum netconn_type)
ua1arn 0:c2ca3c5ded62 566 * @param proto the IP protocol for RAW IP pcbs
ua1arn 0:c2ca3c5ded62 567 * @param callback a function to call on status changes (RX available, TX'ed)
ua1arn 0:c2ca3c5ded62 568 * @return a newly allocated struct netconn or
ua1arn 0:c2ca3c5ded62 569 * NULL on memory error
ua1arn 0:c2ca3c5ded62 570 */
ua1arn 0:c2ca3c5ded62 571 struct netconn*
ua1arn 0:c2ca3c5ded62 572 netconn_alloc(enum netconn_type t, netconn_callback callback)
ua1arn 0:c2ca3c5ded62 573 {
ua1arn 0:c2ca3c5ded62 574 struct netconn *conn;
ua1arn 0:c2ca3c5ded62 575 int size;
ua1arn 0:c2ca3c5ded62 576
ua1arn 0:c2ca3c5ded62 577 conn = (struct netconn *)memp_malloc(MEMP_NETCONN);
ua1arn 0:c2ca3c5ded62 578 if (conn == NULL) {
ua1arn 0:c2ca3c5ded62 579 return NULL;
ua1arn 0:c2ca3c5ded62 580 }
ua1arn 0:c2ca3c5ded62 581
ua1arn 0:c2ca3c5ded62 582 conn->last_err = ERR_OK;
ua1arn 0:c2ca3c5ded62 583 conn->type = t;
ua1arn 0:c2ca3c5ded62 584 conn->pcb.tcp = NULL;
ua1arn 0:c2ca3c5ded62 585
ua1arn 0:c2ca3c5ded62 586 #if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \
ua1arn 0:c2ca3c5ded62 587 (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)
ua1arn 0:c2ca3c5ded62 588 size = DEFAULT_RAW_RECVMBOX_SIZE;
ua1arn 0:c2ca3c5ded62 589 #else
ua1arn 0:c2ca3c5ded62 590 switch(NETCONNTYPE_GROUP(t)) {
ua1arn 0:c2ca3c5ded62 591 #if LWIP_RAW
ua1arn 0:c2ca3c5ded62 592 case NETCONN_RAW:
ua1arn 0:c2ca3c5ded62 593 size = DEFAULT_RAW_RECVMBOX_SIZE;
ua1arn 0:c2ca3c5ded62 594 break;
ua1arn 0:c2ca3c5ded62 595 #endif /* LWIP_RAW */
ua1arn 0:c2ca3c5ded62 596 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 597 case NETCONN_UDP:
ua1arn 0:c2ca3c5ded62 598 size = DEFAULT_UDP_RECVMBOX_SIZE;
ua1arn 0:c2ca3c5ded62 599 break;
ua1arn 0:c2ca3c5ded62 600 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 601 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 602 case NETCONN_TCP:
ua1arn 0:c2ca3c5ded62 603 size = DEFAULT_TCP_RECVMBOX_SIZE;
ua1arn 0:c2ca3c5ded62 604 break;
ua1arn 0:c2ca3c5ded62 605 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 606 default:
ua1arn 0:c2ca3c5ded62 607 LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);
ua1arn 0:c2ca3c5ded62 608 goto free_and_return;
ua1arn 0:c2ca3c5ded62 609 }
ua1arn 0:c2ca3c5ded62 610 #endif
ua1arn 0:c2ca3c5ded62 611
ua1arn 0:c2ca3c5ded62 612 if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) {
ua1arn 0:c2ca3c5ded62 613 goto free_and_return;
ua1arn 0:c2ca3c5ded62 614 }
ua1arn 0:c2ca3c5ded62 615 if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) {
ua1arn 0:c2ca3c5ded62 616 sys_sem_free(&conn->op_completed);
ua1arn 0:c2ca3c5ded62 617 goto free_and_return;
ua1arn 0:c2ca3c5ded62 618 }
ua1arn 0:c2ca3c5ded62 619
ua1arn 0:c2ca3c5ded62 620 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 621 sys_mbox_set_invalid(&conn->acceptmbox);
ua1arn 0:c2ca3c5ded62 622 #endif
ua1arn 0:c2ca3c5ded62 623 conn->state = NETCONN_NONE;
ua1arn 0:c2ca3c5ded62 624 #if LWIP_SOCKET
ua1arn 0:c2ca3c5ded62 625 /* initialize socket to -1 since 0 is a valid socket */
ua1arn 0:c2ca3c5ded62 626 conn->socket = -1;
ua1arn 0:c2ca3c5ded62 627 #endif /* LWIP_SOCKET */
ua1arn 0:c2ca3c5ded62 628 conn->callback = callback;
ua1arn 0:c2ca3c5ded62 629 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 630 conn->current_msg = NULL;
ua1arn 0:c2ca3c5ded62 631 conn->write_offset = 0;
ua1arn 0:c2ca3c5ded62 632 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 633 #if LWIP_SO_SNDTIMEO
ua1arn 0:c2ca3c5ded62 634 conn->send_timeout = 0;
ua1arn 0:c2ca3c5ded62 635 #endif /* LWIP_SO_SNDTIMEO */
ua1arn 0:c2ca3c5ded62 636 #if LWIP_SO_RCVTIMEO
ua1arn 0:c2ca3c5ded62 637 conn->recv_timeout = 0;
ua1arn 0:c2ca3c5ded62 638 #endif /* LWIP_SO_RCVTIMEO */
ua1arn 0:c2ca3c5ded62 639 #if LWIP_SO_RCVBUF
ua1arn 0:c2ca3c5ded62 640 conn->recv_bufsize = RECV_BUFSIZE_DEFAULT;
ua1arn 0:c2ca3c5ded62 641 conn->recv_avail = 0;
ua1arn 0:c2ca3c5ded62 642 #endif /* LWIP_SO_RCVBUF */
ua1arn 0:c2ca3c5ded62 643 conn->flags = 0;
ua1arn 0:c2ca3c5ded62 644 return conn;
ua1arn 0:c2ca3c5ded62 645 free_and_return:
ua1arn 0:c2ca3c5ded62 646 memp_free(MEMP_NETCONN, conn);
ua1arn 0:c2ca3c5ded62 647 return NULL;
ua1arn 0:c2ca3c5ded62 648 }
ua1arn 0:c2ca3c5ded62 649
ua1arn 0:c2ca3c5ded62 650 /**
ua1arn 0:c2ca3c5ded62 651 * Delete a netconn and all its resources.
ua1arn 0:c2ca3c5ded62 652 * The pcb is NOT freed (since we might not be in the right thread context do this).
ua1arn 0:c2ca3c5ded62 653 *
ua1arn 0:c2ca3c5ded62 654 * @param conn the netconn to free
ua1arn 0:c2ca3c5ded62 655 */
ua1arn 0:c2ca3c5ded62 656 void
ua1arn 0:c2ca3c5ded62 657 netconn_free(struct netconn *conn)
ua1arn 0:c2ca3c5ded62 658 {
ua1arn 0:c2ca3c5ded62 659 LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);
ua1arn 0:c2ca3c5ded62 660 LWIP_ASSERT("recvmbox must be deallocated before calling this function",
ua1arn 0:c2ca3c5ded62 661 !sys_mbox_valid(&conn->recvmbox));
ua1arn 0:c2ca3c5ded62 662 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 663 LWIP_ASSERT("acceptmbox must be deallocated before calling this function",
ua1arn 0:c2ca3c5ded62 664 !sys_mbox_valid(&conn->acceptmbox));
ua1arn 0:c2ca3c5ded62 665 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 666
ua1arn 0:c2ca3c5ded62 667 sys_sem_free(&conn->op_completed);
ua1arn 0:c2ca3c5ded62 668 sys_sem_set_invalid(&conn->op_completed);
ua1arn 0:c2ca3c5ded62 669
ua1arn 0:c2ca3c5ded62 670 memp_free(MEMP_NETCONN, conn);
ua1arn 0:c2ca3c5ded62 671 }
ua1arn 0:c2ca3c5ded62 672
ua1arn 0:c2ca3c5ded62 673 /**
ua1arn 0:c2ca3c5ded62 674 * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in
ua1arn 0:c2ca3c5ded62 675 * these mboxes
ua1arn 0:c2ca3c5ded62 676 *
ua1arn 0:c2ca3c5ded62 677 * @param conn the netconn to free
ua1arn 0:c2ca3c5ded62 678 * @bytes_drained bytes drained from recvmbox
ua1arn 0:c2ca3c5ded62 679 * @accepts_drained pending connections drained from acceptmbox
ua1arn 0:c2ca3c5ded62 680 */
ua1arn 0:c2ca3c5ded62 681 static void
ua1arn 0:c2ca3c5ded62 682 netconn_drain(struct netconn *conn)
ua1arn 0:c2ca3c5ded62 683 {
ua1arn 0:c2ca3c5ded62 684 void *mem;
ua1arn 0:c2ca3c5ded62 685 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 686 struct pbuf *p;
ua1arn 0:c2ca3c5ded62 687 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 688
ua1arn 0:c2ca3c5ded62 689 /* This runs in tcpip_thread, so we don't need to lock against rx packets */
ua1arn 0:c2ca3c5ded62 690
ua1arn 0:c2ca3c5ded62 691 /* Delete and drain the recvmbox. */
ua1arn 0:c2ca3c5ded62 692 if (sys_mbox_valid(&conn->recvmbox)) {
ua1arn 0:c2ca3c5ded62 693 while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {
ua1arn 0:c2ca3c5ded62 694 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 695 if (conn->type == NETCONN_TCP) {
ua1arn 0:c2ca3c5ded62 696 if(mem != NULL) {
ua1arn 0:c2ca3c5ded62 697 p = (struct pbuf*)mem;
ua1arn 0:c2ca3c5ded62 698 /* pcb might be set to NULL already by err_tcp() */
ua1arn 0:c2ca3c5ded62 699 if (conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 700 tcp_recved(conn->pcb.tcp, p->tot_len);
ua1arn 0:c2ca3c5ded62 701 }
ua1arn 0:c2ca3c5ded62 702 pbuf_free(p);
ua1arn 0:c2ca3c5ded62 703 }
ua1arn 0:c2ca3c5ded62 704 } else
ua1arn 0:c2ca3c5ded62 705 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 706 {
ua1arn 0:c2ca3c5ded62 707 netbuf_delete((struct netbuf *)mem);
ua1arn 0:c2ca3c5ded62 708 }
ua1arn 0:c2ca3c5ded62 709 }
ua1arn 0:c2ca3c5ded62 710 sys_mbox_free(&conn->recvmbox);
ua1arn 0:c2ca3c5ded62 711 sys_mbox_set_invalid(&conn->recvmbox);
ua1arn 0:c2ca3c5ded62 712 }
ua1arn 0:c2ca3c5ded62 713
ua1arn 0:c2ca3c5ded62 714 /* Delete and drain the acceptmbox. */
ua1arn 0:c2ca3c5ded62 715 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 716 if (sys_mbox_valid(&conn->acceptmbox)) {
ua1arn 0:c2ca3c5ded62 717 while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {
ua1arn 0:c2ca3c5ded62 718 struct netconn *newconn = (struct netconn *)mem;
ua1arn 0:c2ca3c5ded62 719 /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */
ua1arn 0:c2ca3c5ded62 720 /* pcb might be set to NULL already by err_tcp() */
ua1arn 0:c2ca3c5ded62 721 if (conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 722 tcp_accepted(conn->pcb.tcp);
ua1arn 0:c2ca3c5ded62 723 }
ua1arn 0:c2ca3c5ded62 724 /* drain recvmbox */
ua1arn 0:c2ca3c5ded62 725 netconn_drain(newconn);
ua1arn 0:c2ca3c5ded62 726 if (newconn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 727 tcp_abort(newconn->pcb.tcp);
ua1arn 0:c2ca3c5ded62 728 newconn->pcb.tcp = NULL;
ua1arn 0:c2ca3c5ded62 729 }
ua1arn 0:c2ca3c5ded62 730 netconn_free(newconn);
ua1arn 0:c2ca3c5ded62 731 }
ua1arn 0:c2ca3c5ded62 732 sys_mbox_free(&conn->acceptmbox);
ua1arn 0:c2ca3c5ded62 733 sys_mbox_set_invalid(&conn->acceptmbox);
ua1arn 0:c2ca3c5ded62 734 }
ua1arn 0:c2ca3c5ded62 735 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 736 }
ua1arn 0:c2ca3c5ded62 737
ua1arn 0:c2ca3c5ded62 738 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 739 /**
ua1arn 0:c2ca3c5ded62 740 * Internal helper function to close a TCP netconn: since this sometimes
ua1arn 0:c2ca3c5ded62 741 * doesn't work at the first attempt, this function is called from multiple
ua1arn 0:c2ca3c5ded62 742 * places.
ua1arn 0:c2ca3c5ded62 743 *
ua1arn 0:c2ca3c5ded62 744 * @param conn the TCP netconn to close
ua1arn 0:c2ca3c5ded62 745 */
ua1arn 0:c2ca3c5ded62 746 static void
ua1arn 0:c2ca3c5ded62 747 do_close_internal(struct netconn *conn)
ua1arn 0:c2ca3c5ded62 748 {
ua1arn 0:c2ca3c5ded62 749 err_t err;
ua1arn 0:c2ca3c5ded62 750 u8_t shut, shut_rx, shut_tx, close;
ua1arn 0:c2ca3c5ded62 751
ua1arn 0:c2ca3c5ded62 752 LWIP_ASSERT("invalid conn", (conn != NULL));
ua1arn 0:c2ca3c5ded62 753 LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
ua1arn 0:c2ca3c5ded62 754 LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
ua1arn 0:c2ca3c5ded62 755 LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
ua1arn 0:c2ca3c5ded62 756 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
ua1arn 0:c2ca3c5ded62 757
ua1arn 0:c2ca3c5ded62 758 shut = conn->current_msg->msg.sd.shut;
ua1arn 0:c2ca3c5ded62 759 shut_rx = shut & NETCONN_SHUT_RD;
ua1arn 0:c2ca3c5ded62 760 shut_tx = shut & NETCONN_SHUT_WR;
ua1arn 0:c2ca3c5ded62 761 /* shutting down both ends is the same as closing */
ua1arn 0:c2ca3c5ded62 762 close = shut == NETCONN_SHUT_RDWR;
ua1arn 0:c2ca3c5ded62 763
ua1arn 0:c2ca3c5ded62 764 /* Set back some callback pointers */
ua1arn 0:c2ca3c5ded62 765 if (close) {
ua1arn 0:c2ca3c5ded62 766 tcp_arg(conn->pcb.tcp, NULL);
ua1arn 0:c2ca3c5ded62 767 }
ua1arn 0:c2ca3c5ded62 768 if (conn->pcb.tcp->state == LISTEN) {
ua1arn 0:c2ca3c5ded62 769 tcp_accept(conn->pcb.tcp, NULL);
ua1arn 0:c2ca3c5ded62 770 } else {
ua1arn 0:c2ca3c5ded62 771 /* some callbacks have to be reset if tcp_close is not successful */
ua1arn 0:c2ca3c5ded62 772 if (shut_rx) {
ua1arn 0:c2ca3c5ded62 773 tcp_recv(conn->pcb.tcp, NULL);
ua1arn 0:c2ca3c5ded62 774 tcp_accept(conn->pcb.tcp, NULL);
ua1arn 0:c2ca3c5ded62 775 }
ua1arn 0:c2ca3c5ded62 776 if (shut_tx) {
ua1arn 0:c2ca3c5ded62 777 tcp_sent(conn->pcb.tcp, NULL);
ua1arn 0:c2ca3c5ded62 778 }
ua1arn 0:c2ca3c5ded62 779 if (close) {
ua1arn 0:c2ca3c5ded62 780 tcp_poll(conn->pcb.tcp, NULL, 4);
ua1arn 0:c2ca3c5ded62 781 tcp_err(conn->pcb.tcp, NULL);
ua1arn 0:c2ca3c5ded62 782 }
ua1arn 0:c2ca3c5ded62 783 }
ua1arn 0:c2ca3c5ded62 784 /* Try to close the connection */
ua1arn 0:c2ca3c5ded62 785 if (close) {
ua1arn 0:c2ca3c5ded62 786 err = tcp_close(conn->pcb.tcp);
ua1arn 0:c2ca3c5ded62 787 } else {
ua1arn 0:c2ca3c5ded62 788 err = tcp_shutdown(conn->pcb.tcp, shut_rx, shut_tx);
ua1arn 0:c2ca3c5ded62 789 }
ua1arn 0:c2ca3c5ded62 790 if (err == ERR_OK) {
ua1arn 0:c2ca3c5ded62 791 /* Closing succeeded */
ua1arn 0:c2ca3c5ded62 792 conn->current_msg->err = ERR_OK;
ua1arn 0:c2ca3c5ded62 793 conn->current_msg = NULL;
ua1arn 0:c2ca3c5ded62 794 conn->state = NETCONN_NONE;
ua1arn 0:c2ca3c5ded62 795 if (close) {
ua1arn 0:c2ca3c5ded62 796 /* Set back some callback pointers as conn is going away */
ua1arn 0:c2ca3c5ded62 797 conn->pcb.tcp = NULL;
ua1arn 0:c2ca3c5ded62 798 /* Trigger select() in socket layer. Make sure everybody notices activity
ua1arn 0:c2ca3c5ded62 799 on the connection, error first! */
ua1arn 0:c2ca3c5ded62 800 API_EVENT(conn, NETCONN_EVT_ERROR, 0);
ua1arn 0:c2ca3c5ded62 801 }
ua1arn 0:c2ca3c5ded62 802 if (shut_rx) {
ua1arn 0:c2ca3c5ded62 803 API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);
ua1arn 0:c2ca3c5ded62 804 }
ua1arn 0:c2ca3c5ded62 805 if (shut_tx) {
ua1arn 0:c2ca3c5ded62 806 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
ua1arn 0:c2ca3c5ded62 807 }
ua1arn 0:c2ca3c5ded62 808 /* wake up the application task */
ua1arn 0:c2ca3c5ded62 809 sys_sem_signal(&conn->op_completed);
ua1arn 0:c2ca3c5ded62 810 } else {
ua1arn 0:c2ca3c5ded62 811 /* Closing failed, restore some of the callbacks */
ua1arn 0:c2ca3c5ded62 812 /* Closing of listen pcb will never fail! */
ua1arn 0:c2ca3c5ded62 813 LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN));
ua1arn 0:c2ca3c5ded62 814 tcp_sent(conn->pcb.tcp, sent_tcp);
ua1arn 0:c2ca3c5ded62 815 tcp_poll(conn->pcb.tcp, poll_tcp, 4);
ua1arn 0:c2ca3c5ded62 816 tcp_err(conn->pcb.tcp, err_tcp);
ua1arn 0:c2ca3c5ded62 817 tcp_arg(conn->pcb.tcp, conn);
ua1arn 0:c2ca3c5ded62 818 /* don't restore recv callback: we don't want to receive any more data */
ua1arn 0:c2ca3c5ded62 819 }
ua1arn 0:c2ca3c5ded62 820 /* If closing didn't succeed, we get called again either
ua1arn 0:c2ca3c5ded62 821 from poll_tcp or from sent_tcp */
ua1arn 0:c2ca3c5ded62 822 }
ua1arn 0:c2ca3c5ded62 823 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 824
ua1arn 0:c2ca3c5ded62 825 /**
ua1arn 0:c2ca3c5ded62 826 * Delete the pcb inside a netconn.
ua1arn 0:c2ca3c5ded62 827 * Called from netconn_delete.
ua1arn 0:c2ca3c5ded62 828 *
ua1arn 0:c2ca3c5ded62 829 * @param msg the api_msg_msg pointing to the connection
ua1arn 0:c2ca3c5ded62 830 */
ua1arn 0:c2ca3c5ded62 831 void
ua1arn 0:c2ca3c5ded62 832 do_delconn(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 833 {
ua1arn 0:c2ca3c5ded62 834 /* @todo TCP: abort running write/connect? */
ua1arn 0:c2ca3c5ded62 835 if ((msg->conn->state != NETCONN_NONE) &&
ua1arn 0:c2ca3c5ded62 836 (msg->conn->state != NETCONN_LISTEN) &&
ua1arn 0:c2ca3c5ded62 837 (msg->conn->state != NETCONN_CONNECT)) {
ua1arn 0:c2ca3c5ded62 838 /* this only happens for TCP netconns */
ua1arn 0:c2ca3c5ded62 839 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
ua1arn 0:c2ca3c5ded62 840 msg->err = ERR_INPROGRESS;
ua1arn 0:c2ca3c5ded62 841 } else {
ua1arn 0:c2ca3c5ded62 842 LWIP_ASSERT("blocking connect in progress",
ua1arn 0:c2ca3c5ded62 843 (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn));
ua1arn 0:c2ca3c5ded62 844 /* Drain and delete mboxes */
ua1arn 0:c2ca3c5ded62 845 netconn_drain(msg->conn);
ua1arn 0:c2ca3c5ded62 846
ua1arn 0:c2ca3c5ded62 847 if (msg->conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 848
ua1arn 0:c2ca3c5ded62 849 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
ua1arn 0:c2ca3c5ded62 850 #if LWIP_RAW
ua1arn 0:c2ca3c5ded62 851 case NETCONN_RAW:
ua1arn 0:c2ca3c5ded62 852 raw_remove(msg->conn->pcb.raw);
ua1arn 0:c2ca3c5ded62 853 break;
ua1arn 0:c2ca3c5ded62 854 #endif /* LWIP_RAW */
ua1arn 0:c2ca3c5ded62 855 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 856 case NETCONN_UDP:
ua1arn 0:c2ca3c5ded62 857 msg->conn->pcb.udp->recv_arg = NULL;
ua1arn 0:c2ca3c5ded62 858 udp_remove(msg->conn->pcb.udp);
ua1arn 0:c2ca3c5ded62 859 break;
ua1arn 0:c2ca3c5ded62 860 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 861 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 862 case NETCONN_TCP:
ua1arn 0:c2ca3c5ded62 863 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
ua1arn 0:c2ca3c5ded62 864 msg->conn->write_offset == 0);
ua1arn 0:c2ca3c5ded62 865 msg->conn->state = NETCONN_CLOSE;
ua1arn 0:c2ca3c5ded62 866 msg->msg.sd.shut = NETCONN_SHUT_RDWR;
ua1arn 0:c2ca3c5ded62 867 msg->conn->current_msg = msg;
ua1arn 0:c2ca3c5ded62 868 do_close_internal(msg->conn);
ua1arn 0:c2ca3c5ded62 869 /* API_EVENT is called inside do_close_internal, before releasing
ua1arn 0:c2ca3c5ded62 870 the application thread, so we can return at this point! */
ua1arn 0:c2ca3c5ded62 871 return;
ua1arn 0:c2ca3c5ded62 872 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 873 default:
ua1arn 0:c2ca3c5ded62 874 break;
ua1arn 0:c2ca3c5ded62 875 }
ua1arn 0:c2ca3c5ded62 876 msg->conn->pcb.tcp = NULL;
ua1arn 0:c2ca3c5ded62 877 }
ua1arn 0:c2ca3c5ded62 878 /* tcp netconns don't come here! */
ua1arn 0:c2ca3c5ded62 879
ua1arn 0:c2ca3c5ded62 880 /* @todo: this lets select make the socket readable and writable,
ua1arn 0:c2ca3c5ded62 881 which is wrong! errfd instead? */
ua1arn 0:c2ca3c5ded62 882 API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);
ua1arn 0:c2ca3c5ded62 883 API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);
ua1arn 0:c2ca3c5ded62 884 }
ua1arn 0:c2ca3c5ded62 885 if (sys_sem_valid(&msg->conn->op_completed)) {
ua1arn 0:c2ca3c5ded62 886 sys_sem_signal(&msg->conn->op_completed);
ua1arn 0:c2ca3c5ded62 887 }
ua1arn 0:c2ca3c5ded62 888 }
ua1arn 0:c2ca3c5ded62 889
ua1arn 0:c2ca3c5ded62 890 /**
ua1arn 0:c2ca3c5ded62 891 * Bind a pcb contained in a netconn
ua1arn 0:c2ca3c5ded62 892 * Called from netconn_bind.
ua1arn 0:c2ca3c5ded62 893 *
ua1arn 0:c2ca3c5ded62 894 * @param msg the api_msg_msg pointing to the connection and containing
ua1arn 0:c2ca3c5ded62 895 * the IP address and port to bind to
ua1arn 0:c2ca3c5ded62 896 */
ua1arn 0:c2ca3c5ded62 897 void
ua1arn 0:c2ca3c5ded62 898 do_bind(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 899 {
ua1arn 0:c2ca3c5ded62 900 if (ERR_IS_FATAL(msg->conn->last_err)) {
ua1arn 0:c2ca3c5ded62 901 msg->err = msg->conn->last_err;
ua1arn 0:c2ca3c5ded62 902 } else {
ua1arn 0:c2ca3c5ded62 903 msg->err = ERR_VAL;
ua1arn 0:c2ca3c5ded62 904 if (msg->conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 905 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
ua1arn 0:c2ca3c5ded62 906 #if LWIP_RAW
ua1arn 0:c2ca3c5ded62 907 case NETCONN_RAW:
ua1arn 0:c2ca3c5ded62 908 msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
ua1arn 0:c2ca3c5ded62 909 break;
ua1arn 0:c2ca3c5ded62 910 #endif /* LWIP_RAW */
ua1arn 0:c2ca3c5ded62 911 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 912 case NETCONN_UDP:
ua1arn 0:c2ca3c5ded62 913 msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
ua1arn 0:c2ca3c5ded62 914 break;
ua1arn 0:c2ca3c5ded62 915 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 916 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 917 case NETCONN_TCP:
ua1arn 0:c2ca3c5ded62 918 msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);
ua1arn 0:c2ca3c5ded62 919 break;
ua1arn 0:c2ca3c5ded62 920 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 921 default:
ua1arn 0:c2ca3c5ded62 922 break;
ua1arn 0:c2ca3c5ded62 923 }
ua1arn 0:c2ca3c5ded62 924 }
ua1arn 0:c2ca3c5ded62 925 }
ua1arn 0:c2ca3c5ded62 926 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 927 }
ua1arn 0:c2ca3c5ded62 928
ua1arn 0:c2ca3c5ded62 929 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 930 /**
ua1arn 0:c2ca3c5ded62 931 * TCP callback function if a connection (opened by tcp_connect/do_connect) has
ua1arn 0:c2ca3c5ded62 932 * been established (or reset by the remote host).
ua1arn 0:c2ca3c5ded62 933 *
ua1arn 0:c2ca3c5ded62 934 * @see tcp.h (struct tcp_pcb.connected) for parameters and return values
ua1arn 0:c2ca3c5ded62 935 */
ua1arn 0:c2ca3c5ded62 936 static err_t
ua1arn 0:c2ca3c5ded62 937 do_connected(void *arg, struct tcp_pcb *pcb, err_t err)
ua1arn 0:c2ca3c5ded62 938 {
ua1arn 0:c2ca3c5ded62 939 struct netconn *conn;
ua1arn 0:c2ca3c5ded62 940 int was_blocking;
ua1arn 0:c2ca3c5ded62 941
ua1arn 0:c2ca3c5ded62 942 LWIP_UNUSED_ARG(pcb);
ua1arn 0:c2ca3c5ded62 943
ua1arn 0:c2ca3c5ded62 944 conn = (struct netconn *)arg;
ua1arn 0:c2ca3c5ded62 945
ua1arn 0:c2ca3c5ded62 946 if (conn == NULL) {
ua1arn 0:c2ca3c5ded62 947 return ERR_VAL;
ua1arn 0:c2ca3c5ded62 948 }
ua1arn 0:c2ca3c5ded62 949
ua1arn 0:c2ca3c5ded62 950 LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT);
ua1arn 0:c2ca3c5ded62 951 LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect",
ua1arn 0:c2ca3c5ded62 952 (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn));
ua1arn 0:c2ca3c5ded62 953
ua1arn 0:c2ca3c5ded62 954 if (conn->current_msg != NULL) {
ua1arn 0:c2ca3c5ded62 955 conn->current_msg->err = err;
ua1arn 0:c2ca3c5ded62 956 }
ua1arn 0:c2ca3c5ded62 957 if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {
ua1arn 0:c2ca3c5ded62 958 setup_tcp(conn);
ua1arn 0:c2ca3c5ded62 959 }
ua1arn 0:c2ca3c5ded62 960 was_blocking = !IN_NONBLOCKING_CONNECT(conn);
ua1arn 0:c2ca3c5ded62 961 SET_NONBLOCKING_CONNECT(conn, 0);
ua1arn 0:c2ca3c5ded62 962 conn->current_msg = NULL;
ua1arn 0:c2ca3c5ded62 963 conn->state = NETCONN_NONE;
ua1arn 0:c2ca3c5ded62 964 if (!was_blocking) {
ua1arn 0:c2ca3c5ded62 965 NETCONN_SET_SAFE_ERR(conn, ERR_OK);
ua1arn 0:c2ca3c5ded62 966 }
ua1arn 0:c2ca3c5ded62 967 API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);
ua1arn 0:c2ca3c5ded62 968
ua1arn 0:c2ca3c5ded62 969 if (was_blocking) {
ua1arn 0:c2ca3c5ded62 970 sys_sem_signal(&conn->op_completed);
ua1arn 0:c2ca3c5ded62 971 }
ua1arn 0:c2ca3c5ded62 972 return ERR_OK;
ua1arn 0:c2ca3c5ded62 973 }
ua1arn 0:c2ca3c5ded62 974 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 975
ua1arn 0:c2ca3c5ded62 976 /**
ua1arn 0:c2ca3c5ded62 977 * Connect a pcb contained inside a netconn
ua1arn 0:c2ca3c5ded62 978 * Called from netconn_connect.
ua1arn 0:c2ca3c5ded62 979 *
ua1arn 0:c2ca3c5ded62 980 * @param msg the api_msg_msg pointing to the connection and containing
ua1arn 0:c2ca3c5ded62 981 * the IP address and port to connect to
ua1arn 0:c2ca3c5ded62 982 */
ua1arn 0:c2ca3c5ded62 983 void
ua1arn 0:c2ca3c5ded62 984 do_connect(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 985 {
ua1arn 0:c2ca3c5ded62 986 if (msg->conn->pcb.tcp == NULL) {
ua1arn 0:c2ca3c5ded62 987 /* This may happen when calling netconn_connect() a second time */
ua1arn 0:c2ca3c5ded62 988 msg->err = ERR_CLSD;
ua1arn 0:c2ca3c5ded62 989 } else {
ua1arn 0:c2ca3c5ded62 990 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
ua1arn 0:c2ca3c5ded62 991 #if LWIP_RAW
ua1arn 0:c2ca3c5ded62 992 case NETCONN_RAW:
ua1arn 0:c2ca3c5ded62 993 msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);
ua1arn 0:c2ca3c5ded62 994 break;
ua1arn 0:c2ca3c5ded62 995 #endif /* LWIP_RAW */
ua1arn 0:c2ca3c5ded62 996 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 997 case NETCONN_UDP:
ua1arn 0:c2ca3c5ded62 998 msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);
ua1arn 0:c2ca3c5ded62 999 break;
ua1arn 0:c2ca3c5ded62 1000 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 1001 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 1002 case NETCONN_TCP:
ua1arn 0:c2ca3c5ded62 1003 /* Prevent connect while doing any other action. */
ua1arn 0:c2ca3c5ded62 1004 if (msg->conn->state != NETCONN_NONE) {
ua1arn 0:c2ca3c5ded62 1005 msg->err = ERR_ISCONN;
ua1arn 0:c2ca3c5ded62 1006 } else {
ua1arn 0:c2ca3c5ded62 1007 setup_tcp(msg->conn);
ua1arn 0:c2ca3c5ded62 1008 msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr,
ua1arn 0:c2ca3c5ded62 1009 msg->msg.bc.port, do_connected);
ua1arn 0:c2ca3c5ded62 1010 if (msg->err == ERR_OK) {
ua1arn 0:c2ca3c5ded62 1011 u8_t non_blocking = netconn_is_nonblocking(msg->conn);
ua1arn 0:c2ca3c5ded62 1012 msg->conn->state = NETCONN_CONNECT;
ua1arn 0:c2ca3c5ded62 1013 SET_NONBLOCKING_CONNECT(msg->conn, non_blocking);
ua1arn 0:c2ca3c5ded62 1014 if (non_blocking) {
ua1arn 0:c2ca3c5ded62 1015 msg->err = ERR_INPROGRESS;
ua1arn 0:c2ca3c5ded62 1016 } else {
ua1arn 0:c2ca3c5ded62 1017 msg->conn->current_msg = msg;
ua1arn 0:c2ca3c5ded62 1018 /* sys_sem_signal() is called from do_connected (or err_tcp()),
ua1arn 0:c2ca3c5ded62 1019 * when the connection is established! */
ua1arn 0:c2ca3c5ded62 1020 return;
ua1arn 0:c2ca3c5ded62 1021 }
ua1arn 0:c2ca3c5ded62 1022 }
ua1arn 0:c2ca3c5ded62 1023 }
ua1arn 0:c2ca3c5ded62 1024 break;
ua1arn 0:c2ca3c5ded62 1025 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 1026 default:
ua1arn 0:c2ca3c5ded62 1027 LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0));
ua1arn 0:c2ca3c5ded62 1028 break;
ua1arn 0:c2ca3c5ded62 1029 }
ua1arn 0:c2ca3c5ded62 1030 }
ua1arn 0:c2ca3c5ded62 1031 sys_sem_signal(&msg->conn->op_completed);
ua1arn 0:c2ca3c5ded62 1032 }
ua1arn 0:c2ca3c5ded62 1033
ua1arn 0:c2ca3c5ded62 1034 /**
ua1arn 0:c2ca3c5ded62 1035 * Connect a pcb contained inside a netconn
ua1arn 0:c2ca3c5ded62 1036 * Only used for UDP netconns.
ua1arn 0:c2ca3c5ded62 1037 * Called from netconn_disconnect.
ua1arn 0:c2ca3c5ded62 1038 *
ua1arn 0:c2ca3c5ded62 1039 * @param msg the api_msg_msg pointing to the connection to disconnect
ua1arn 0:c2ca3c5ded62 1040 */
ua1arn 0:c2ca3c5ded62 1041 void
ua1arn 0:c2ca3c5ded62 1042 do_disconnect(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 1043 {
ua1arn 0:c2ca3c5ded62 1044 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 1045 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
ua1arn 0:c2ca3c5ded62 1046 udp_disconnect(msg->conn->pcb.udp);
ua1arn 0:c2ca3c5ded62 1047 msg->err = ERR_OK;
ua1arn 0:c2ca3c5ded62 1048 } else
ua1arn 0:c2ca3c5ded62 1049 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 1050 {
ua1arn 0:c2ca3c5ded62 1051 msg->err = ERR_VAL;
ua1arn 0:c2ca3c5ded62 1052 }
ua1arn 0:c2ca3c5ded62 1053 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 1054 }
ua1arn 0:c2ca3c5ded62 1055
ua1arn 0:c2ca3c5ded62 1056 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 1057 /**
ua1arn 0:c2ca3c5ded62 1058 * Set a TCP pcb contained in a netconn into listen mode
ua1arn 0:c2ca3c5ded62 1059 * Called from netconn_listen.
ua1arn 0:c2ca3c5ded62 1060 *
ua1arn 0:c2ca3c5ded62 1061 * @param msg the api_msg_msg pointing to the connection
ua1arn 0:c2ca3c5ded62 1062 */
ua1arn 0:c2ca3c5ded62 1063 void
ua1arn 0:c2ca3c5ded62 1064 do_listen(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 1065 {
ua1arn 0:c2ca3c5ded62 1066 if (ERR_IS_FATAL(msg->conn->last_err)) {
ua1arn 0:c2ca3c5ded62 1067 msg->err = msg->conn->last_err;
ua1arn 0:c2ca3c5ded62 1068 } else {
ua1arn 0:c2ca3c5ded62 1069 msg->err = ERR_CONN;
ua1arn 0:c2ca3c5ded62 1070 if (msg->conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 1071 if (msg->conn->type == NETCONN_TCP) {
ua1arn 0:c2ca3c5ded62 1072 if (msg->conn->state == NETCONN_NONE) {
ua1arn 0:c2ca3c5ded62 1073 #if TCP_LISTEN_BACKLOG
ua1arn 0:c2ca3c5ded62 1074 struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);
ua1arn 0:c2ca3c5ded62 1075 #else /* TCP_LISTEN_BACKLOG */
ua1arn 0:c2ca3c5ded62 1076 struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);
ua1arn 0:c2ca3c5ded62 1077 #endif /* TCP_LISTEN_BACKLOG */
ua1arn 0:c2ca3c5ded62 1078 if (lpcb == NULL) {
ua1arn 0:c2ca3c5ded62 1079 /* in this case, the old pcb is still allocated */
ua1arn 0:c2ca3c5ded62 1080 msg->err = ERR_MEM;
ua1arn 0:c2ca3c5ded62 1081 } else {
ua1arn 0:c2ca3c5ded62 1082 /* delete the recvmbox and allocate the acceptmbox */
ua1arn 0:c2ca3c5ded62 1083 if (sys_mbox_valid(&msg->conn->recvmbox)) {
ua1arn 0:c2ca3c5ded62 1084 /** @todo: should we drain the recvmbox here? */
ua1arn 0:c2ca3c5ded62 1085 sys_mbox_free(&msg->conn->recvmbox);
ua1arn 0:c2ca3c5ded62 1086 sys_mbox_set_invalid(&msg->conn->recvmbox);
ua1arn 0:c2ca3c5ded62 1087 }
ua1arn 0:c2ca3c5ded62 1088 msg->err = ERR_OK;
ua1arn 0:c2ca3c5ded62 1089 if (!sys_mbox_valid(&msg->conn->acceptmbox)) {
ua1arn 0:c2ca3c5ded62 1090 msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE);
ua1arn 0:c2ca3c5ded62 1091 }
ua1arn 0:c2ca3c5ded62 1092 if (msg->err == ERR_OK) {
ua1arn 0:c2ca3c5ded62 1093 msg->conn->state = NETCONN_LISTEN;
ua1arn 0:c2ca3c5ded62 1094 msg->conn->pcb.tcp = lpcb;
ua1arn 0:c2ca3c5ded62 1095 tcp_arg(msg->conn->pcb.tcp, msg->conn);
ua1arn 0:c2ca3c5ded62 1096 tcp_accept(msg->conn->pcb.tcp, accept_function);
ua1arn 0:c2ca3c5ded62 1097 } else {
ua1arn 0:c2ca3c5ded62 1098 /* since the old pcb is already deallocated, free lpcb now */
ua1arn 0:c2ca3c5ded62 1099 tcp_close(lpcb);
ua1arn 0:c2ca3c5ded62 1100 msg->conn->pcb.tcp = NULL;
ua1arn 0:c2ca3c5ded62 1101 }
ua1arn 0:c2ca3c5ded62 1102 }
ua1arn 0:c2ca3c5ded62 1103 }
ua1arn 0:c2ca3c5ded62 1104 } else {
ua1arn 0:c2ca3c5ded62 1105 msg->err = ERR_ARG;
ua1arn 0:c2ca3c5ded62 1106 }
ua1arn 0:c2ca3c5ded62 1107 }
ua1arn 0:c2ca3c5ded62 1108 }
ua1arn 0:c2ca3c5ded62 1109 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 1110 }
ua1arn 0:c2ca3c5ded62 1111 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 1112
ua1arn 0:c2ca3c5ded62 1113 /**
ua1arn 0:c2ca3c5ded62 1114 * Send some data on a RAW or UDP pcb contained in a netconn
ua1arn 0:c2ca3c5ded62 1115 * Called from netconn_send
ua1arn 0:c2ca3c5ded62 1116 *
ua1arn 0:c2ca3c5ded62 1117 * @param msg the api_msg_msg pointing to the connection
ua1arn 0:c2ca3c5ded62 1118 */
ua1arn 0:c2ca3c5ded62 1119 void
ua1arn 0:c2ca3c5ded62 1120 do_send(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 1121 {
ua1arn 0:c2ca3c5ded62 1122 if (ERR_IS_FATAL(msg->conn->last_err)) {
ua1arn 0:c2ca3c5ded62 1123 msg->err = msg->conn->last_err;
ua1arn 0:c2ca3c5ded62 1124 } else {
ua1arn 0:c2ca3c5ded62 1125 msg->err = ERR_CONN;
ua1arn 0:c2ca3c5ded62 1126 if (msg->conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 1127 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
ua1arn 0:c2ca3c5ded62 1128 #if LWIP_RAW
ua1arn 0:c2ca3c5ded62 1129 case NETCONN_RAW:
ua1arn 0:c2ca3c5ded62 1130 if (ip_addr_isany(&msg->msg.b->addr)) {
ua1arn 0:c2ca3c5ded62 1131 msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);
ua1arn 0:c2ca3c5ded62 1132 } else {
ua1arn 0:c2ca3c5ded62 1133 msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr);
ua1arn 0:c2ca3c5ded62 1134 }
ua1arn 0:c2ca3c5ded62 1135 break;
ua1arn 0:c2ca3c5ded62 1136 #endif
ua1arn 0:c2ca3c5ded62 1137 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 1138 case NETCONN_UDP:
ua1arn 0:c2ca3c5ded62 1139 #if LWIP_CHECKSUM_ON_COPY
ua1arn 0:c2ca3c5ded62 1140 if (ip_addr_isany(&msg->msg.b->addr)) {
ua1arn 0:c2ca3c5ded62 1141 msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p,
ua1arn 0:c2ca3c5ded62 1142 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
ua1arn 0:c2ca3c5ded62 1143 } else {
ua1arn 0:c2ca3c5ded62 1144 msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p,
ua1arn 0:c2ca3c5ded62 1145 &msg->msg.b->addr, msg->msg.b->port,
ua1arn 0:c2ca3c5ded62 1146 msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum);
ua1arn 0:c2ca3c5ded62 1147 }
ua1arn 0:c2ca3c5ded62 1148 #else /* LWIP_CHECKSUM_ON_COPY */
ua1arn 0:c2ca3c5ded62 1149 if (ip_addr_isany(&msg->msg.b->addr)) {
ua1arn 0:c2ca3c5ded62 1150 msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);
ua1arn 0:c2ca3c5ded62 1151 } else {
ua1arn 0:c2ca3c5ded62 1152 msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port);
ua1arn 0:c2ca3c5ded62 1153 }
ua1arn 0:c2ca3c5ded62 1154 #endif /* LWIP_CHECKSUM_ON_COPY */
ua1arn 0:c2ca3c5ded62 1155 break;
ua1arn 0:c2ca3c5ded62 1156 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 1157 default:
ua1arn 0:c2ca3c5ded62 1158 break;
ua1arn 0:c2ca3c5ded62 1159 }
ua1arn 0:c2ca3c5ded62 1160 }
ua1arn 0:c2ca3c5ded62 1161 }
ua1arn 0:c2ca3c5ded62 1162 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 1163 }
ua1arn 0:c2ca3c5ded62 1164
ua1arn 0:c2ca3c5ded62 1165 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 1166 /**
ua1arn 0:c2ca3c5ded62 1167 * Indicate data has been received from a TCP pcb contained in a netconn
ua1arn 0:c2ca3c5ded62 1168 * Called from netconn_recv
ua1arn 0:c2ca3c5ded62 1169 *
ua1arn 0:c2ca3c5ded62 1170 * @param msg the api_msg_msg pointing to the connection
ua1arn 0:c2ca3c5ded62 1171 */
ua1arn 0:c2ca3c5ded62 1172 void
ua1arn 0:c2ca3c5ded62 1173 do_recv(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 1174 {
ua1arn 0:c2ca3c5ded62 1175 msg->err = ERR_OK;
ua1arn 0:c2ca3c5ded62 1176 if (msg->conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 1177 if (msg->conn->type == NETCONN_TCP) {
ua1arn 0:c2ca3c5ded62 1178 #if TCP_LISTEN_BACKLOG
ua1arn 0:c2ca3c5ded62 1179 if (msg->conn->pcb.tcp->state == LISTEN) {
ua1arn 0:c2ca3c5ded62 1180 tcp_accepted(msg->conn->pcb.tcp);
ua1arn 0:c2ca3c5ded62 1181 } else
ua1arn 0:c2ca3c5ded62 1182 #endif /* TCP_LISTEN_BACKLOG */
ua1arn 0:c2ca3c5ded62 1183 {
ua1arn 0:c2ca3c5ded62 1184 u32_t remaining = msg->msg.r.len;
ua1arn 0:c2ca3c5ded62 1185 do {
ua1arn 0:c2ca3c5ded62 1186 u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining;
ua1arn 0:c2ca3c5ded62 1187 tcp_recved(msg->conn->pcb.tcp, recved);
ua1arn 0:c2ca3c5ded62 1188 remaining -= recved;
ua1arn 0:c2ca3c5ded62 1189 }while(remaining != 0);
ua1arn 0:c2ca3c5ded62 1190 }
ua1arn 0:c2ca3c5ded62 1191 }
ua1arn 0:c2ca3c5ded62 1192 }
ua1arn 0:c2ca3c5ded62 1193 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 1194 }
ua1arn 0:c2ca3c5ded62 1195
ua1arn 0:c2ca3c5ded62 1196 /**
ua1arn 0:c2ca3c5ded62 1197 * See if more data needs to be written from a previous call to netconn_write.
ua1arn 0:c2ca3c5ded62 1198 * Called initially from do_write. If the first call can't send all data
ua1arn 0:c2ca3c5ded62 1199 * (because of low memory or empty send-buffer), this function is called again
ua1arn 0:c2ca3c5ded62 1200 * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the
ua1arn 0:c2ca3c5ded62 1201 * blocking application thread (waiting in netconn_write) is released.
ua1arn 0:c2ca3c5ded62 1202 *
ua1arn 0:c2ca3c5ded62 1203 * @param conn netconn (that is currently in state NETCONN_WRITE) to process
ua1arn 0:c2ca3c5ded62 1204 * @return ERR_OK
ua1arn 0:c2ca3c5ded62 1205 * ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished
ua1arn 0:c2ca3c5ded62 1206 */
ua1arn 0:c2ca3c5ded62 1207 static err_t
ua1arn 0:c2ca3c5ded62 1208 do_writemore(struct netconn *conn)
ua1arn 0:c2ca3c5ded62 1209 {
ua1arn 0:c2ca3c5ded62 1210 err_t err;
ua1arn 0:c2ca3c5ded62 1211 void *dataptr;
ua1arn 0:c2ca3c5ded62 1212 u16_t len, available;
ua1arn 0:c2ca3c5ded62 1213 u8_t write_finished = 0;
ua1arn 0:c2ca3c5ded62 1214 size_t diff;
ua1arn 0:c2ca3c5ded62 1215 u8_t dontblock = netconn_is_nonblocking(conn) ||
ua1arn 0:c2ca3c5ded62 1216 (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK);
ua1arn 0:c2ca3c5ded62 1217 u8_t apiflags = conn->current_msg->msg.w.apiflags;
ua1arn 0:c2ca3c5ded62 1218
ua1arn 0:c2ca3c5ded62 1219 LWIP_ASSERT("conn != NULL", conn != NULL);
ua1arn 0:c2ca3c5ded62 1220 LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));
ua1arn 0:c2ca3c5ded62 1221 LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL);
ua1arn 0:c2ca3c5ded62 1222 LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);
ua1arn 0:c2ca3c5ded62 1223 LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len",
ua1arn 0:c2ca3c5ded62 1224 conn->write_offset < conn->current_msg->msg.w.len);
ua1arn 0:c2ca3c5ded62 1225
ua1arn 0:c2ca3c5ded62 1226 #if LWIP_SO_SNDTIMEO
ua1arn 0:c2ca3c5ded62 1227 if ((conn->send_timeout != 0) &&
ua1arn 0:c2ca3c5ded62 1228 ((s32_t)(sys_now() - conn->current_msg->msg.w.time_started) >= conn->send_timeout)) {
ua1arn 0:c2ca3c5ded62 1229 write_finished = 1;
ua1arn 0:c2ca3c5ded62 1230 if (conn->write_offset == 0) {
ua1arn 0:c2ca3c5ded62 1231 /* nothing has been written */
ua1arn 0:c2ca3c5ded62 1232 err = ERR_WOULDBLOCK;
ua1arn 0:c2ca3c5ded62 1233 conn->current_msg->msg.w.len = 0;
ua1arn 0:c2ca3c5ded62 1234 } else {
ua1arn 0:c2ca3c5ded62 1235 /* partial write */
ua1arn 0:c2ca3c5ded62 1236 err = ERR_OK;
ua1arn 0:c2ca3c5ded62 1237 conn->current_msg->msg.w.len = conn->write_offset;
ua1arn 0:c2ca3c5ded62 1238 }
ua1arn 0:c2ca3c5ded62 1239 } else
ua1arn 0:c2ca3c5ded62 1240 #endif /* LWIP_SO_SNDTIMEO */
ua1arn 0:c2ca3c5ded62 1241 {
ua1arn 0:c2ca3c5ded62 1242 dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset;
ua1arn 0:c2ca3c5ded62 1243 diff = conn->current_msg->msg.w.len - conn->write_offset;
ua1arn 0:c2ca3c5ded62 1244 if (diff > 0xffffUL) { /* max_u16_t */
ua1arn 0:c2ca3c5ded62 1245 len = 0xffff;
ua1arn 0:c2ca3c5ded62 1246 #if LWIP_TCPIP_CORE_LOCKING
ua1arn 0:c2ca3c5ded62 1247 conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
ua1arn 0:c2ca3c5ded62 1248 #endif
ua1arn 0:c2ca3c5ded62 1249 apiflags |= TCP_WRITE_FLAG_MORE;
ua1arn 0:c2ca3c5ded62 1250 } else {
ua1arn 0:c2ca3c5ded62 1251 len = (u16_t)diff;
ua1arn 0:c2ca3c5ded62 1252 }
ua1arn 0:c2ca3c5ded62 1253 available = tcp_sndbuf(conn->pcb.tcp);
ua1arn 0:c2ca3c5ded62 1254 if (available < len) {
ua1arn 0:c2ca3c5ded62 1255 /* don't try to write more than sendbuf */
ua1arn 0:c2ca3c5ded62 1256 len = available;
ua1arn 0:c2ca3c5ded62 1257 if (dontblock){
ua1arn 0:c2ca3c5ded62 1258 if (!len) {
ua1arn 0:c2ca3c5ded62 1259 err = ERR_WOULDBLOCK;
ua1arn 0:c2ca3c5ded62 1260 goto err_mem;
ua1arn 0:c2ca3c5ded62 1261 }
ua1arn 0:c2ca3c5ded62 1262 } else {
ua1arn 0:c2ca3c5ded62 1263 #if LWIP_TCPIP_CORE_LOCKING
ua1arn 0:c2ca3c5ded62 1264 conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
ua1arn 0:c2ca3c5ded62 1265 #endif
ua1arn 0:c2ca3c5ded62 1266 apiflags |= TCP_WRITE_FLAG_MORE;
ua1arn 0:c2ca3c5ded62 1267 }
ua1arn 0:c2ca3c5ded62 1268 }
ua1arn 0:c2ca3c5ded62 1269 LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len));
ua1arn 0:c2ca3c5ded62 1270 err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags);
ua1arn 0:c2ca3c5ded62 1271 /* if OK or memory error, check available space */
ua1arn 0:c2ca3c5ded62 1272 if ((err == ERR_OK) || (err == ERR_MEM)) {
ua1arn 0:c2ca3c5ded62 1273 err_mem:
ua1arn 0:c2ca3c5ded62 1274 if (dontblock && (len < conn->current_msg->msg.w.len)) {
ua1arn 0:c2ca3c5ded62 1275 /* non-blocking write did not write everything: mark the pcb non-writable
ua1arn 0:c2ca3c5ded62 1276 and let poll_tcp check writable space to mark the pcb writable again */
ua1arn 0:c2ca3c5ded62 1277 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
ua1arn 0:c2ca3c5ded62 1278 conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE;
ua1arn 0:c2ca3c5ded62 1279 } else if ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) ||
ua1arn 0:c2ca3c5ded62 1280 (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT)) {
ua1arn 0:c2ca3c5ded62 1281 /* The queued byte- or pbuf-count exceeds the configured low-water limit,
ua1arn 0:c2ca3c5ded62 1282 let select mark this pcb as non-writable. */
ua1arn 0:c2ca3c5ded62 1283 API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);
ua1arn 0:c2ca3c5ded62 1284 }
ua1arn 0:c2ca3c5ded62 1285 }
ua1arn 0:c2ca3c5ded62 1286
ua1arn 0:c2ca3c5ded62 1287 if (err == ERR_OK) {
ua1arn 0:c2ca3c5ded62 1288 conn->write_offset += len;
ua1arn 0:c2ca3c5ded62 1289 if ((conn->write_offset == conn->current_msg->msg.w.len) || dontblock) {
ua1arn 0:c2ca3c5ded62 1290 /* return sent length */
ua1arn 0:c2ca3c5ded62 1291 conn->current_msg->msg.w.len = conn->write_offset;
ua1arn 0:c2ca3c5ded62 1292 /* everything was written */
ua1arn 0:c2ca3c5ded62 1293 write_finished = 1;
ua1arn 0:c2ca3c5ded62 1294 conn->write_offset = 0;
ua1arn 0:c2ca3c5ded62 1295 }
ua1arn 0:c2ca3c5ded62 1296 tcp_output(conn->pcb.tcp);
ua1arn 0:c2ca3c5ded62 1297 } else if ((err == ERR_MEM) && !dontblock) {
ua1arn 0:c2ca3c5ded62 1298 /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called
ua1arn 0:c2ca3c5ded62 1299 we do NOT return to the application thread, since ERR_MEM is
ua1arn 0:c2ca3c5ded62 1300 only a temporary error! */
ua1arn 0:c2ca3c5ded62 1301
ua1arn 0:c2ca3c5ded62 1302 /* tcp_write returned ERR_MEM, try tcp_output anyway */
ua1arn 0:c2ca3c5ded62 1303 tcp_output(conn->pcb.tcp);
ua1arn 0:c2ca3c5ded62 1304
ua1arn 0:c2ca3c5ded62 1305 #if LWIP_TCPIP_CORE_LOCKING
ua1arn 0:c2ca3c5ded62 1306 conn->flags |= NETCONN_FLAG_WRITE_DELAYED;
ua1arn 0:c2ca3c5ded62 1307 #endif
ua1arn 0:c2ca3c5ded62 1308 } else {
ua1arn 0:c2ca3c5ded62 1309 /* On errors != ERR_MEM, we don't try writing any more but return
ua1arn 0:c2ca3c5ded62 1310 the error to the application thread. */
ua1arn 0:c2ca3c5ded62 1311 write_finished = 1;
ua1arn 0:c2ca3c5ded62 1312 conn->current_msg->msg.w.len = 0;
ua1arn 0:c2ca3c5ded62 1313 }
ua1arn 0:c2ca3c5ded62 1314 }
ua1arn 0:c2ca3c5ded62 1315 if (write_finished) {
ua1arn 0:c2ca3c5ded62 1316 /* everything was written: set back connection state
ua1arn 0:c2ca3c5ded62 1317 and back to application task */
ua1arn 0:c2ca3c5ded62 1318 conn->current_msg->err = err;
ua1arn 0:c2ca3c5ded62 1319 conn->current_msg = NULL;
ua1arn 0:c2ca3c5ded62 1320 conn->state = NETCONN_NONE;
ua1arn 0:c2ca3c5ded62 1321 #if LWIP_TCPIP_CORE_LOCKING
ua1arn 0:c2ca3c5ded62 1322 if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0)
ua1arn 0:c2ca3c5ded62 1323 #endif
ua1arn 0:c2ca3c5ded62 1324 {
ua1arn 0:c2ca3c5ded62 1325 sys_sem_signal(&conn->op_completed);
ua1arn 0:c2ca3c5ded62 1326 }
ua1arn 0:c2ca3c5ded62 1327 }
ua1arn 0:c2ca3c5ded62 1328 #if LWIP_TCPIP_CORE_LOCKING
ua1arn 0:c2ca3c5ded62 1329 else
ua1arn 0:c2ca3c5ded62 1330 return ERR_MEM;
ua1arn 0:c2ca3c5ded62 1331 #endif
ua1arn 0:c2ca3c5ded62 1332 return ERR_OK;
ua1arn 0:c2ca3c5ded62 1333 }
ua1arn 0:c2ca3c5ded62 1334 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 1335
ua1arn 0:c2ca3c5ded62 1336 /**
ua1arn 0:c2ca3c5ded62 1337 * Send some data on a TCP pcb contained in a netconn
ua1arn 0:c2ca3c5ded62 1338 * Called from netconn_write
ua1arn 0:c2ca3c5ded62 1339 *
ua1arn 0:c2ca3c5ded62 1340 * @param msg the api_msg_msg pointing to the connection
ua1arn 0:c2ca3c5ded62 1341 */
ua1arn 0:c2ca3c5ded62 1342 void
ua1arn 0:c2ca3c5ded62 1343 do_write(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 1344 {
ua1arn 0:c2ca3c5ded62 1345 if (ERR_IS_FATAL(msg->conn->last_err)) {
ua1arn 0:c2ca3c5ded62 1346 msg->err = msg->conn->last_err;
ua1arn 0:c2ca3c5ded62 1347 } else {
ua1arn 0:c2ca3c5ded62 1348 if (msg->conn->type == NETCONN_TCP) {
ua1arn 0:c2ca3c5ded62 1349 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 1350 if (msg->conn->state != NETCONN_NONE) {
ua1arn 0:c2ca3c5ded62 1351 /* netconn is connecting, closing or in blocking write */
ua1arn 0:c2ca3c5ded62 1352 msg->err = ERR_INPROGRESS;
ua1arn 0:c2ca3c5ded62 1353 } else if (msg->conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 1354 msg->conn->state = NETCONN_WRITE;
ua1arn 0:c2ca3c5ded62 1355 /* set all the variables used by do_writemore */
ua1arn 0:c2ca3c5ded62 1356 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
ua1arn 0:c2ca3c5ded62 1357 msg->conn->write_offset == 0);
ua1arn 0:c2ca3c5ded62 1358 LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0);
ua1arn 0:c2ca3c5ded62 1359 msg->conn->current_msg = msg;
ua1arn 0:c2ca3c5ded62 1360 msg->conn->write_offset = 0;
ua1arn 0:c2ca3c5ded62 1361 #if LWIP_TCPIP_CORE_LOCKING
ua1arn 0:c2ca3c5ded62 1362 msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED;
ua1arn 0:c2ca3c5ded62 1363 if (do_writemore(msg->conn) != ERR_OK) {
ua1arn 0:c2ca3c5ded62 1364 LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);
ua1arn 0:c2ca3c5ded62 1365 UNLOCK_TCPIP_CORE();
ua1arn 0:c2ca3c5ded62 1366 sys_arch_sem_wait(&msg->conn->op_completed, 0);
ua1arn 0:c2ca3c5ded62 1367 LOCK_TCPIP_CORE();
ua1arn 0:c2ca3c5ded62 1368 LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);
ua1arn 0:c2ca3c5ded62 1369 }
ua1arn 0:c2ca3c5ded62 1370 #else /* LWIP_TCPIP_CORE_LOCKING */
ua1arn 0:c2ca3c5ded62 1371 do_writemore(msg->conn);
ua1arn 0:c2ca3c5ded62 1372 #endif /* LWIP_TCPIP_CORE_LOCKING */
ua1arn 0:c2ca3c5ded62 1373 /* for both cases: if do_writemore was called, don't ACK the APIMSG
ua1arn 0:c2ca3c5ded62 1374 since do_writemore ACKs it! */
ua1arn 0:c2ca3c5ded62 1375 return;
ua1arn 0:c2ca3c5ded62 1376 } else {
ua1arn 0:c2ca3c5ded62 1377 msg->err = ERR_CONN;
ua1arn 0:c2ca3c5ded62 1378 }
ua1arn 0:c2ca3c5ded62 1379 #else /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 1380 msg->err = ERR_VAL;
ua1arn 0:c2ca3c5ded62 1381 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 1382 #if (LWIP_UDP || LWIP_RAW)
ua1arn 0:c2ca3c5ded62 1383 } else {
ua1arn 0:c2ca3c5ded62 1384 msg->err = ERR_VAL;
ua1arn 0:c2ca3c5ded62 1385 #endif /* (LWIP_UDP || LWIP_RAW) */
ua1arn 0:c2ca3c5ded62 1386 }
ua1arn 0:c2ca3c5ded62 1387 }
ua1arn 0:c2ca3c5ded62 1388 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 1389 }
ua1arn 0:c2ca3c5ded62 1390
ua1arn 0:c2ca3c5ded62 1391 /**
ua1arn 0:c2ca3c5ded62 1392 * Return a connection's local or remote address
ua1arn 0:c2ca3c5ded62 1393 * Called from netconn_getaddr
ua1arn 0:c2ca3c5ded62 1394 *
ua1arn 0:c2ca3c5ded62 1395 * @param msg the api_msg_msg pointing to the connection
ua1arn 0:c2ca3c5ded62 1396 */
ua1arn 0:c2ca3c5ded62 1397 void
ua1arn 0:c2ca3c5ded62 1398 do_getaddr(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 1399 {
ua1arn 0:c2ca3c5ded62 1400 if (msg->conn->pcb.ip != NULL) {
ua1arn 0:c2ca3c5ded62 1401 *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip :
ua1arn 0:c2ca3c5ded62 1402 msg->conn->pcb.ip->remote_ip);
ua1arn 0:c2ca3c5ded62 1403
ua1arn 0:c2ca3c5ded62 1404 msg->err = ERR_OK;
ua1arn 0:c2ca3c5ded62 1405 switch (NETCONNTYPE_GROUP(msg->conn->type)) {
ua1arn 0:c2ca3c5ded62 1406 #if LWIP_RAW
ua1arn 0:c2ca3c5ded62 1407 case NETCONN_RAW:
ua1arn 0:c2ca3c5ded62 1408 if (msg->msg.ad.local) {
ua1arn 0:c2ca3c5ded62 1409 *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;
ua1arn 0:c2ca3c5ded62 1410 } else {
ua1arn 0:c2ca3c5ded62 1411 /* return an error as connecting is only a helper for upper layers */
ua1arn 0:c2ca3c5ded62 1412 msg->err = ERR_CONN;
ua1arn 0:c2ca3c5ded62 1413 }
ua1arn 0:c2ca3c5ded62 1414 break;
ua1arn 0:c2ca3c5ded62 1415 #endif /* LWIP_RAW */
ua1arn 0:c2ca3c5ded62 1416 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 1417 case NETCONN_UDP:
ua1arn 0:c2ca3c5ded62 1418 if (msg->msg.ad.local) {
ua1arn 0:c2ca3c5ded62 1419 *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;
ua1arn 0:c2ca3c5ded62 1420 } else {
ua1arn 0:c2ca3c5ded62 1421 if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {
ua1arn 0:c2ca3c5ded62 1422 msg->err = ERR_CONN;
ua1arn 0:c2ca3c5ded62 1423 } else {
ua1arn 0:c2ca3c5ded62 1424 *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;
ua1arn 0:c2ca3c5ded62 1425 }
ua1arn 0:c2ca3c5ded62 1426 }
ua1arn 0:c2ca3c5ded62 1427 break;
ua1arn 0:c2ca3c5ded62 1428 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 1429 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 1430 case NETCONN_TCP:
ua1arn 0:c2ca3c5ded62 1431 *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);
ua1arn 0:c2ca3c5ded62 1432 break;
ua1arn 0:c2ca3c5ded62 1433 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 1434 default:
ua1arn 0:c2ca3c5ded62 1435 LWIP_ASSERT("invalid netconn_type", 0);
ua1arn 0:c2ca3c5ded62 1436 break;
ua1arn 0:c2ca3c5ded62 1437 }
ua1arn 0:c2ca3c5ded62 1438 } else {
ua1arn 0:c2ca3c5ded62 1439 msg->err = ERR_CONN;
ua1arn 0:c2ca3c5ded62 1440 }
ua1arn 0:c2ca3c5ded62 1441 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 1442 }
ua1arn 0:c2ca3c5ded62 1443
ua1arn 0:c2ca3c5ded62 1444 /**
ua1arn 0:c2ca3c5ded62 1445 * Close a TCP pcb contained in a netconn
ua1arn 0:c2ca3c5ded62 1446 * Called from netconn_close
ua1arn 0:c2ca3c5ded62 1447 *
ua1arn 0:c2ca3c5ded62 1448 * @param msg the api_msg_msg pointing to the connection
ua1arn 0:c2ca3c5ded62 1449 */
ua1arn 0:c2ca3c5ded62 1450 void
ua1arn 0:c2ca3c5ded62 1451 do_close(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 1452 {
ua1arn 0:c2ca3c5ded62 1453 #if LWIP_TCP
ua1arn 0:c2ca3c5ded62 1454 /* @todo: abort running write/connect? */
ua1arn 0:c2ca3c5ded62 1455 if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) {
ua1arn 0:c2ca3c5ded62 1456 /* this only happens for TCP netconns */
ua1arn 0:c2ca3c5ded62 1457 LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP);
ua1arn 0:c2ca3c5ded62 1458 msg->err = ERR_INPROGRESS;
ua1arn 0:c2ca3c5ded62 1459 } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
ua1arn 0:c2ca3c5ded62 1460 if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) {
ua1arn 0:c2ca3c5ded62 1461 /* LISTEN doesn't support half shutdown */
ua1arn 0:c2ca3c5ded62 1462 msg->err = ERR_CONN;
ua1arn 0:c2ca3c5ded62 1463 } else {
ua1arn 0:c2ca3c5ded62 1464 if (msg->msg.sd.shut & NETCONN_SHUT_RD) {
ua1arn 0:c2ca3c5ded62 1465 /* Drain and delete mboxes */
ua1arn 0:c2ca3c5ded62 1466 netconn_drain(msg->conn);
ua1arn 0:c2ca3c5ded62 1467 }
ua1arn 0:c2ca3c5ded62 1468 LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL &&
ua1arn 0:c2ca3c5ded62 1469 msg->conn->write_offset == 0);
ua1arn 0:c2ca3c5ded62 1470 msg->conn->state = NETCONN_CLOSE;
ua1arn 0:c2ca3c5ded62 1471 msg->conn->current_msg = msg;
ua1arn 0:c2ca3c5ded62 1472 do_close_internal(msg->conn);
ua1arn 0:c2ca3c5ded62 1473 /* for tcp netconns, do_close_internal ACKs the message */
ua1arn 0:c2ca3c5ded62 1474 return;
ua1arn 0:c2ca3c5ded62 1475 }
ua1arn 0:c2ca3c5ded62 1476 } else
ua1arn 0:c2ca3c5ded62 1477 #endif /* LWIP_TCP */
ua1arn 0:c2ca3c5ded62 1478 {
ua1arn 0:c2ca3c5ded62 1479 msg->err = ERR_VAL;
ua1arn 0:c2ca3c5ded62 1480 }
ua1arn 0:c2ca3c5ded62 1481 sys_sem_signal(&msg->conn->op_completed);
ua1arn 0:c2ca3c5ded62 1482 }
ua1arn 0:c2ca3c5ded62 1483
ua1arn 0:c2ca3c5ded62 1484 #if LWIP_IGMP
ua1arn 0:c2ca3c5ded62 1485 /**
ua1arn 0:c2ca3c5ded62 1486 * Join multicast groups for UDP netconns.
ua1arn 0:c2ca3c5ded62 1487 * Called from netconn_join_leave_group
ua1arn 0:c2ca3c5ded62 1488 *
ua1arn 0:c2ca3c5ded62 1489 * @param msg the api_msg_msg pointing to the connection
ua1arn 0:c2ca3c5ded62 1490 */
ua1arn 0:c2ca3c5ded62 1491 void
ua1arn 0:c2ca3c5ded62 1492 do_join_leave_group(struct api_msg_msg *msg)
ua1arn 0:c2ca3c5ded62 1493 {
ua1arn 0:c2ca3c5ded62 1494 if (ERR_IS_FATAL(msg->conn->last_err)) {
ua1arn 0:c2ca3c5ded62 1495 msg->err = msg->conn->last_err;
ua1arn 0:c2ca3c5ded62 1496 } else {
ua1arn 0:c2ca3c5ded62 1497 if (msg->conn->pcb.tcp != NULL) {
ua1arn 0:c2ca3c5ded62 1498 if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {
ua1arn 0:c2ca3c5ded62 1499 #if LWIP_UDP
ua1arn 0:c2ca3c5ded62 1500 if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {
ua1arn 0:c2ca3c5ded62 1501 msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
ua1arn 0:c2ca3c5ded62 1502 } else {
ua1arn 0:c2ca3c5ded62 1503 msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr);
ua1arn 0:c2ca3c5ded62 1504 }
ua1arn 0:c2ca3c5ded62 1505 #endif /* LWIP_UDP */
ua1arn 0:c2ca3c5ded62 1506 #if (LWIP_TCP || LWIP_RAW)
ua1arn 0:c2ca3c5ded62 1507 } else {
ua1arn 0:c2ca3c5ded62 1508 msg->err = ERR_VAL;
ua1arn 0:c2ca3c5ded62 1509 #endif /* (LWIP_TCP || LWIP_RAW) */
ua1arn 0:c2ca3c5ded62 1510 }
ua1arn 0:c2ca3c5ded62 1511 } else {
ua1arn 0:c2ca3c5ded62 1512 msg->err = ERR_CONN;
ua1arn 0:c2ca3c5ded62 1513 }
ua1arn 0:c2ca3c5ded62 1514 }
ua1arn 0:c2ca3c5ded62 1515 TCPIP_APIMSG_ACK(msg);
ua1arn 0:c2ca3c5ded62 1516 }
ua1arn 0:c2ca3c5ded62 1517 #endif /* LWIP_IGMP */
ua1arn 0:c2ca3c5ded62 1518
ua1arn 0:c2ca3c5ded62 1519 #if LWIP_DNS
ua1arn 0:c2ca3c5ded62 1520 /**
ua1arn 0:c2ca3c5ded62 1521 * Callback function that is called when DNS name is resolved
ua1arn 0:c2ca3c5ded62 1522 * (or on timeout). A waiting application thread is waked up by
ua1arn 0:c2ca3c5ded62 1523 * signaling the semaphore.
ua1arn 0:c2ca3c5ded62 1524 */
ua1arn 0:c2ca3c5ded62 1525 static void
ua1arn 0:c2ca3c5ded62 1526 do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg)
ua1arn 0:c2ca3c5ded62 1527 {
ua1arn 0:c2ca3c5ded62 1528 struct dns_api_msg *msg = (struct dns_api_msg*)arg;
ua1arn 0:c2ca3c5ded62 1529
ua1arn 0:c2ca3c5ded62 1530 LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);
ua1arn 0:c2ca3c5ded62 1531 LWIP_UNUSED_ARG(name);
ua1arn 0:c2ca3c5ded62 1532
ua1arn 0:c2ca3c5ded62 1533 if (ipaddr == NULL) {
ua1arn 0:c2ca3c5ded62 1534 /* timeout or memory error */
ua1arn 0:c2ca3c5ded62 1535 *msg->err = ERR_VAL;
ua1arn 0:c2ca3c5ded62 1536 } else {
ua1arn 0:c2ca3c5ded62 1537 /* address was resolved */
ua1arn 0:c2ca3c5ded62 1538 *msg->err = ERR_OK;
ua1arn 0:c2ca3c5ded62 1539 *msg->addr = *ipaddr;
ua1arn 0:c2ca3c5ded62 1540 }
ua1arn 0:c2ca3c5ded62 1541 /* wake up the application task waiting in netconn_gethostbyname */
ua1arn 0:c2ca3c5ded62 1542 sys_sem_signal(msg->sem);
ua1arn 0:c2ca3c5ded62 1543 }
ua1arn 0:c2ca3c5ded62 1544
ua1arn 0:c2ca3c5ded62 1545 /**
ua1arn 0:c2ca3c5ded62 1546 * Execute a DNS query
ua1arn 0:c2ca3c5ded62 1547 * Called from netconn_gethostbyname
ua1arn 0:c2ca3c5ded62 1548 *
ua1arn 0:c2ca3c5ded62 1549 * @param arg the dns_api_msg pointing to the query
ua1arn 0:c2ca3c5ded62 1550 */
ua1arn 0:c2ca3c5ded62 1551 void
ua1arn 0:c2ca3c5ded62 1552 do_gethostbyname(void *arg)
ua1arn 0:c2ca3c5ded62 1553 {
ua1arn 0:c2ca3c5ded62 1554 struct dns_api_msg *msg = (struct dns_api_msg*)arg;
ua1arn 0:c2ca3c5ded62 1555
ua1arn 0:c2ca3c5ded62 1556 *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);
ua1arn 0:c2ca3c5ded62 1557 if (*msg->err != ERR_INPROGRESS) {
ua1arn 0:c2ca3c5ded62 1558 /* on error or immediate success, wake up the application
ua1arn 0:c2ca3c5ded62 1559 * task waiting in netconn_gethostbyname */
ua1arn 0:c2ca3c5ded62 1560 sys_sem_signal(msg->sem);
ua1arn 0:c2ca3c5ded62 1561 }
ua1arn 0:c2ca3c5ded62 1562 }
ua1arn 0:c2ca3c5ded62 1563 #endif /* LWIP_DNS */
ua1arn 0:c2ca3c5ded62 1564
ua1arn 0:c2ca3c5ded62 1565 #endif /* LWIP_NETCONN */