]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/lwIP_Demo_Rowley_ARM7/lwip-1.1.0/src/api/api_lib.c
Add FreeRTOS-Plus directory.
[freertos] / FreeRTOS / Demo / lwIP_Demo_Rowley_ARM7 / lwip-1.1.0 / src / api / api_lib.c
1 /*\r
2  * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
3  * All rights reserved. \r
4  * \r
5  * Redistribution and use in source and binary forms, with or without modification, \r
6  * are permitted provided that the following conditions are met:\r
7  *\r
8  * 1. Redistributions of source code must retain the above copyright notice,\r
9  *    this list of conditions and the following disclaimer.\r
10  * 2. Redistributions in binary form must reproduce the above copyright notice,\r
11  *    this list of conditions and the following disclaimer in the documentation\r
12  *    and/or other materials provided with the distribution.\r
13  * 3. The name of the author may not be used to endorse or promote products\r
14  *    derived from this software without specific prior written permission. \r
15  *\r
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
18  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
19  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
21  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
23  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
24  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
25  * OF SUCH DAMAGE.\r
26  *\r
27  * This file is part of the lwIP TCP/IP stack.\r
28  * \r
29  * Author: Adam Dunkels <adam@sics.se>\r
30  *\r
31  */\r
32 \r
33 /* This is the part of the API that is linked with\r
34    the application */\r
35 \r
36 #include "lwip/opt.h"\r
37 #include "lwip/api.h"\r
38 #include "lwip/api_msg.h"\r
39 #include "lwip/memp.h"\r
40 \r
41 \r
42 struct\r
43 netbuf *netbuf_new(void)\r
44 {\r
45   struct netbuf *buf;\r
46 \r
47   buf = memp_malloc(MEMP_NETBUF);\r
48   if (buf != NULL) {\r
49     buf->p = NULL;\r
50     buf->ptr = NULL;\r
51     return buf;\r
52   } else {\r
53     return NULL;\r
54   }\r
55 }\r
56 \r
57 void\r
58 netbuf_delete(struct netbuf *buf)\r
59 {\r
60   if (buf != NULL) {\r
61     if (buf->p != NULL) {\r
62       pbuf_free(buf->p);\r
63       buf->p = buf->ptr = NULL;\r
64     }\r
65     memp_free(MEMP_NETBUF, buf);\r
66   }\r
67 }\r
68 \r
69 void *\r
70 netbuf_alloc(struct netbuf *buf, u16_t size)\r
71 {\r
72   /* Deallocate any previously allocated memory. */\r
73   if (buf->p != NULL) {\r
74     pbuf_free(buf->p);\r
75   }\r
76   buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);\r
77   if (buf->p == NULL) {\r
78      return NULL;\r
79   }\r
80   buf->ptr = buf->p;\r
81   return buf->p->payload;\r
82 }\r
83 \r
84 void\r
85 netbuf_free(struct netbuf *buf)\r
86 {\r
87   if (buf->p != NULL) {\r
88     pbuf_free(buf->p);\r
89   }\r
90   buf->p = buf->ptr = NULL;\r
91 }\r
92 \r
93 void\r
94 netbuf_ref(struct netbuf *buf, void *dataptr, u16_t size)\r
95 {\r
96   if (buf->p != NULL) {\r
97     pbuf_free(buf->p);\r
98   }\r
99   buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);\r
100   buf->p->payload = dataptr;\r
101   buf->p->len = buf->p->tot_len = size;\r
102   buf->ptr = buf->p;\r
103 }\r
104 \r
105 void\r
106 netbuf_chain(struct netbuf *head, struct netbuf *tail)\r
107 {\r
108   pbuf_chain(head->p, tail->p);\r
109   head->ptr = head->p;\r
110   memp_free(MEMP_NETBUF, tail);\r
111 }\r
112 \r
113 u16_t\r
114 netbuf_len(struct netbuf *buf)\r
115 {\r
116   return buf->p->tot_len;\r
117 }\r
118 \r
119 err_t\r
120 netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)\r
121 {\r
122   if (buf->ptr == NULL) {\r
123     return ERR_BUF;\r
124   }\r
125   *dataptr = buf->ptr->payload;\r
126   *len = buf->ptr->len;\r
127   return ERR_OK;\r
128 }\r
129 \r
130 s8_t\r
131 netbuf_next(struct netbuf *buf)\r
132 {\r
133   if (buf->ptr->next == NULL) {\r
134     return -1;\r
135   }\r
136   buf->ptr = buf->ptr->next;\r
137   if (buf->ptr->next == NULL) {\r
138     return 1;\r
139   }\r
140   return 0;\r
141 }\r
142 \r
143 void\r
144 netbuf_first(struct netbuf *buf)\r
145 {\r
146   buf->ptr = buf->p;\r
147 }\r
148 \r
149 void\r
150 netbuf_copy_partial(struct netbuf *buf, void *dataptr, u16_t len, u16_t offset)\r
151 {\r
152   struct pbuf *p;\r
153   u16_t i, left;\r
154 \r
155   left = 0;\r
156 \r
157   if(buf == NULL || dataptr == NULL) {\r
158     return;\r
159   }\r
160   \r
161   /* This implementation is bad. It should use bcopy\r
162      instead. */\r
163   for(p = buf->p; left < len && p != NULL; p = p->next) {\r
164     if (offset != 0 && offset >= p->len) {\r
165       offset -= p->len;\r
166     } else {    \r
167       for(i = offset; i < p->len; ++i) {\r
168   ((char *)dataptr)[left] = ((char *)p->payload)[i];\r
169   if (++left >= len) {\r
170     return;\r
171   }\r
172       }\r
173       offset = 0;\r
174     }\r
175   }\r
176 }\r
177 \r
178 void\r
179 netbuf_copy(struct netbuf *buf, void *dataptr, u16_t len)\r
180 {\r
181   netbuf_copy_partial(buf, dataptr, len, 0);\r
182 }\r
183 \r
184 struct ip_addr *\r
185 netbuf_fromaddr(struct netbuf *buf)\r
186 {\r
187   return buf->fromaddr;\r
188 }\r
189 \r
190 u16_t\r
191 netbuf_fromport(struct netbuf *buf)\r
192 {\r
193   return buf->fromport;\r
194 }\r
195 \r
196 struct\r
197 netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u16_t proto,\r
198                                    void (*callback)(struct netconn *, enum netconn_evt, u16_t len))\r
199 {\r
200   struct netconn *conn;\r
201   struct api_msg *msg;\r
202 \r
203   conn = memp_malloc(MEMP_NETCONN);\r
204   if (conn == NULL) {\r
205     return NULL;\r
206   }\r
207   \r
208   conn->err = ERR_OK;\r
209   conn->type = t;\r
210   conn->pcb.tcp = NULL;\r
211 \r
212   if ((conn->mbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
213     memp_free(MEMP_NETCONN, conn);\r
214     return NULL;\r
215   }\r
216   conn->recvmbox = SYS_MBOX_NULL;\r
217   conn->acceptmbox = SYS_MBOX_NULL;\r
218   conn->sem = SYS_SEM_NULL;\r
219   conn->state = NETCONN_NONE;\r
220   conn->socket = 0;\r
221   conn->callback = callback;\r
222   conn->recv_avail = 0;\r
223 \r
224   if((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
225     memp_free(MEMP_NETCONN, conn);\r
226     return NULL;\r
227   }\r
228   \r
229   msg->type = API_MSG_NEWCONN;\r
230   msg->msg.msg.bc.port = proto; /* misusing the port field */\r
231   msg->msg.conn = conn;\r
232   api_msg_post(msg);  \r
233   sys_mbox_fetch(conn->mbox, NULL);\r
234   memp_free(MEMP_API_MSG, msg);\r
235 \r
236   if ( conn->err != ERR_OK ) {\r
237     memp_free(MEMP_NETCONN, conn);\r
238     return NULL;\r
239   }\r
240 \r
241   return conn;\r
242 }\r
243 \r
244 \r
245 struct\r
246 netconn *netconn_new(enum netconn_type t)\r
247 {\r
248   return netconn_new_with_proto_and_callback(t,0,NULL);\r
249 }\r
250 \r
251 struct\r
252 netconn *netconn_new_with_callback(enum netconn_type t,\r
253                                    void (*callback)(struct netconn *, enum netconn_evt, u16_t len))\r
254 {\r
255   return netconn_new_with_proto_and_callback(t,0,callback);\r
256 }\r
257 \r
258 \r
259 err_t\r
260 netconn_delete(struct netconn *conn)\r
261 {\r
262   struct api_msg *msg;\r
263   void *mem;\r
264   \r
265   if (conn == NULL) {\r
266     return ERR_OK;\r
267   }\r
268   \r
269   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
270     return ERR_MEM;\r
271   }\r
272   \r
273   msg->type = API_MSG_DELCONN;\r
274   msg->msg.conn = conn;\r
275   api_msg_post(msg);  \r
276   sys_mbox_fetch(conn->mbox, NULL);\r
277   memp_free(MEMP_API_MSG, msg);\r
278 \r
279   /* Drain the recvmbox. */\r
280   if (conn->recvmbox != SYS_MBOX_NULL) {\r
281     while (sys_arch_mbox_fetch(conn->recvmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {\r
282       if (conn->type == NETCONN_TCP) {\r
283         if(mem != NULL)\r
284           pbuf_free((struct pbuf *)mem);\r
285       } else {\r
286         netbuf_delete((struct netbuf *)mem);\r
287       }\r
288     }\r
289     sys_mbox_free(conn->recvmbox);\r
290     conn->recvmbox = SYS_MBOX_NULL;\r
291   }\r
292  \r
293 \r
294   /* Drain the acceptmbox. */\r
295   if (conn->acceptmbox != SYS_MBOX_NULL) {\r
296     while (sys_arch_mbox_fetch(conn->acceptmbox, &mem, 1) != SYS_ARCH_TIMEOUT) {\r
297       netconn_delete((struct netconn *)mem);\r
298     }\r
299     \r
300     sys_mbox_free(conn->acceptmbox);\r
301     conn->acceptmbox = SYS_MBOX_NULL;\r
302   }\r
303 \r
304   sys_mbox_free(conn->mbox);\r
305   conn->mbox = SYS_MBOX_NULL;\r
306   if (conn->sem != SYS_SEM_NULL) {\r
307     sys_sem_free(conn->sem);\r
308   }\r
309   /*  conn->sem = SYS_SEM_NULL;*/\r
310   memp_free(MEMP_NETCONN, conn);\r
311   return ERR_OK;\r
312 }\r
313 \r
314 enum netconn_type\r
315 netconn_type(struct netconn *conn)\r
316 {\r
317   return conn->type;\r
318 }\r
319 \r
320 err_t\r
321 netconn_peer(struct netconn *conn, struct ip_addr *addr,\r
322        u16_t *port)\r
323 {\r
324   switch (conn->type) {\r
325   case NETCONN_RAW:\r
326     /* return an error as connecting is only a helper for upper layers */\r
327     return ERR_CONN;\r
328   case NETCONN_UDPLITE:\r
329   case NETCONN_UDPNOCHKSUM:\r
330   case NETCONN_UDP:\r
331     if (conn->pcb.udp == NULL ||\r
332   ((conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0))\r
333      return ERR_CONN;\r
334     *addr = (conn->pcb.udp->remote_ip);\r
335     *port = conn->pcb.udp->remote_port;\r
336     break;\r
337   case NETCONN_TCP:\r
338     if (conn->pcb.tcp == NULL)\r
339       return ERR_CONN;\r
340     *addr = (conn->pcb.tcp->remote_ip);\r
341     *port = conn->pcb.tcp->remote_port;\r
342     break;\r
343   }\r
344   return (conn->err = ERR_OK);\r
345 }\r
346 \r
347 err_t\r
348 netconn_addr(struct netconn *conn, struct ip_addr **addr,\r
349        u16_t *port)\r
350 {\r
351   switch (conn->type) {\r
352   case NETCONN_RAW:\r
353     *addr = &(conn->pcb.raw->local_ip);\r
354     *port = conn->pcb.raw->protocol;\r
355     break;\r
356   case NETCONN_UDPLITE:\r
357   case NETCONN_UDPNOCHKSUM:\r
358   case NETCONN_UDP:\r
359     *addr = &(conn->pcb.udp->local_ip);\r
360     *port = conn->pcb.udp->local_port;\r
361     break;\r
362   case NETCONN_TCP:\r
363     *addr = &(conn->pcb.tcp->local_ip);\r
364     *port = conn->pcb.tcp->local_port;\r
365     break;\r
366   }\r
367   return (conn->err = ERR_OK);\r
368 }\r
369 \r
370 err_t\r
371 netconn_bind(struct netconn *conn, struct ip_addr *addr,\r
372       u16_t port)\r
373 {\r
374   struct api_msg *msg;\r
375 \r
376   if (conn == NULL) {\r
377     return ERR_VAL;\r
378   }\r
379 \r
380   if (conn->type != NETCONN_TCP &&\r
381      conn->recvmbox == SYS_MBOX_NULL) {\r
382     if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
383       return ERR_MEM;\r
384     }\r
385   }\r
386   \r
387   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
388     return (conn->err = ERR_MEM);\r
389   }\r
390   msg->type = API_MSG_BIND;\r
391   msg->msg.conn = conn;\r
392   msg->msg.msg.bc.ipaddr = addr;\r
393   msg->msg.msg.bc.port = port;\r
394   api_msg_post(msg);\r
395   sys_mbox_fetch(conn->mbox, NULL);\r
396   memp_free(MEMP_API_MSG, msg);\r
397   return conn->err;\r
398 }\r
399 \r
400 \r
401 err_t\r
402 netconn_connect(struct netconn *conn, struct ip_addr *addr,\r
403        u16_t port)\r
404 {\r
405   struct api_msg *msg;\r
406   \r
407   if (conn == NULL) {\r
408     return ERR_VAL;\r
409   }\r
410 \r
411 \r
412   if (conn->recvmbox == SYS_MBOX_NULL) {\r
413     if ((conn->recvmbox = sys_mbox_new()) == SYS_MBOX_NULL) {\r
414       return ERR_MEM;\r
415     }\r
416   }\r
417   \r
418   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
419     return ERR_MEM;\r
420   }\r
421   msg->type = API_MSG_CONNECT;\r
422   msg->msg.conn = conn;  \r
423   msg->msg.msg.bc.ipaddr = addr;\r
424   msg->msg.msg.bc.port = port;\r
425   api_msg_post(msg);\r
426   sys_mbox_fetch(conn->mbox, NULL);\r
427   memp_free(MEMP_API_MSG, msg);\r
428   return conn->err;\r
429 }\r
430 \r
431 err_t\r
432 netconn_disconnect(struct netconn *conn)\r
433 {\r
434   struct api_msg *msg;\r
435   \r
436   if (conn == NULL) {\r
437     return ERR_VAL;\r
438   }\r
439 \r
440   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
441     return ERR_MEM;\r
442   }\r
443   msg->type = API_MSG_DISCONNECT;\r
444   msg->msg.conn = conn;  \r
445   api_msg_post(msg);\r
446   sys_mbox_fetch(conn->mbox, NULL);\r
447   memp_free(MEMP_API_MSG, msg);\r
448   return conn->err;\r
449 \r
450 }\r
451 \r
452 err_t\r
453 netconn_listen(struct netconn *conn)\r
454 {\r
455   struct api_msg *msg;\r
456 \r
457   if (conn == NULL) {\r
458     return ERR_VAL;\r
459   }\r
460 \r
461   if (conn->acceptmbox == SYS_MBOX_NULL) {\r
462     conn->acceptmbox = sys_mbox_new();\r
463     if (conn->acceptmbox == SYS_MBOX_NULL) {\r
464       return ERR_MEM;\r
465     }\r
466   }\r
467   \r
468   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
469     return (conn->err = ERR_MEM);\r
470   }\r
471   msg->type = API_MSG_LISTEN;\r
472   msg->msg.conn = conn;\r
473   api_msg_post(msg);\r
474   sys_mbox_fetch(conn->mbox, NULL);\r
475   memp_free(MEMP_API_MSG, msg);\r
476   return conn->err;\r
477 }\r
478 \r
479 struct netconn *\r
480 netconn_accept(struct netconn *conn)\r
481 {\r
482   struct netconn *newconn;\r
483   \r
484   if (conn == NULL) {\r
485     return NULL;\r
486   }\r
487   \r
488   sys_mbox_fetch(conn->acceptmbox, (void **)&newconn);\r
489   /* Register event with callback */\r
490   if (conn->callback)\r
491       (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, 0);\r
492   \r
493   return newconn;\r
494 }\r
495 \r
496 struct netbuf *\r
497 netconn_recv(struct netconn *conn)\r
498 {\r
499   struct api_msg *msg;\r
500   struct netbuf *buf;\r
501   struct pbuf *p;\r
502   u16_t len;\r
503     \r
504   if (conn == NULL) {\r
505     return NULL;\r
506   }\r
507   \r
508   if (conn->recvmbox == SYS_MBOX_NULL) {\r
509     conn->err = ERR_CONN;\r
510     return NULL;\r
511   }\r
512 \r
513   if (conn->err != ERR_OK) {\r
514     return NULL;\r
515   }\r
516 \r
517   if (conn->type == NETCONN_TCP) {\r
518     if (conn->pcb.tcp->state == LISTEN) {\r
519       conn->err = ERR_CONN;\r
520       return NULL;\r
521     }\r
522 \r
523 \r
524     buf = memp_malloc(MEMP_NETBUF);\r
525 \r
526     if (buf == NULL) {\r
527       conn->err = ERR_MEM;\r
528       return NULL;\r
529     }\r
530     \r
531     sys_mbox_fetch(conn->recvmbox, (void **)&p);\r
532 \r
533     if (p != NULL)\r
534     {\r
535         len = p->tot_len;\r
536         conn->recv_avail -= len;\r
537     }\r
538     else\r
539         len = 0;\r
540     \r
541     /* Register event with callback */\r
542       if (conn->callback)\r
543         (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, len);\r
544 \r
545     /* If we are closed, we indicate that we no longer wish to receive\r
546        data by setting conn->recvmbox to SYS_MBOX_NULL. */\r
547     if (p == NULL) {\r
548       memp_free(MEMP_NETBUF, buf);\r
549       sys_mbox_free(conn->recvmbox);\r
550       conn->recvmbox = SYS_MBOX_NULL;\r
551       return NULL;\r
552     }\r
553 \r
554     buf->p = p;\r
555     buf->ptr = p;\r
556     buf->fromport = 0;\r
557     buf->fromaddr = NULL;\r
558 \r
559     /* Let the stack know that we have taken the data. */\r
560     if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
561       conn->err = ERR_MEM;\r
562       return buf;\r
563     }\r
564     msg->type = API_MSG_RECV;\r
565     msg->msg.conn = conn;\r
566     if (buf != NULL) {\r
567       msg->msg.msg.len = buf->p->tot_len;\r
568     } else {\r
569       msg->msg.msg.len = 1;\r
570     }\r
571     api_msg_post(msg);\r
572 \r
573     sys_mbox_fetch(conn->mbox, NULL);\r
574     memp_free(MEMP_API_MSG, msg);\r
575   } else {\r
576     sys_mbox_fetch(conn->recvmbox, (void **)&buf);\r
577   conn->recv_avail -= buf->p->tot_len;\r
578     /* Register event with callback */\r
579     if (conn->callback)\r
580         (*conn->callback)(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);\r
581   }\r
582 \r
583   \r
584 \r
585     \r
586   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));\r
587 \r
588 \r
589   return buf;\r
590 }\r
591 \r
592 err_t\r
593 netconn_send(struct netconn *conn, struct netbuf *buf)\r
594 {\r
595   struct api_msg *msg;\r
596 \r
597   if (conn == NULL) {\r
598     return ERR_VAL;\r
599   }\r
600 \r
601   if (conn->err != ERR_OK) {\r
602     return conn->err;\r
603   }\r
604 \r
605   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
606     return (conn->err = ERR_MEM);\r
607   }\r
608 \r
609   LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));\r
610   msg->type = API_MSG_SEND;\r
611   msg->msg.conn = conn;\r
612   msg->msg.msg.p = buf->p;\r
613   api_msg_post(msg);\r
614 \r
615   sys_mbox_fetch(conn->mbox, NULL);\r
616   memp_free(MEMP_API_MSG, msg);\r
617   return conn->err;\r
618 }\r
619 \r
620 err_t\r
621 netconn_write(struct netconn *conn, void *dataptr, u16_t size, u8_t copy)\r
622 {\r
623   struct api_msg *msg;\r
624   u16_t len;\r
625   \r
626   if (conn == NULL) {\r
627     return ERR_VAL;\r
628   }\r
629 \r
630   if (conn->err != ERR_OK) {\r
631     return conn->err;\r
632   }\r
633   \r
634   if (conn->sem == SYS_SEM_NULL) {\r
635     conn->sem = sys_sem_new(0);\r
636     if (conn->sem == SYS_SEM_NULL) {\r
637       return ERR_MEM;\r
638     }\r
639   }\r
640 \r
641   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
642     return (conn->err = ERR_MEM);\r
643   }\r
644   msg->type = API_MSG_WRITE;\r
645   msg->msg.conn = conn;\r
646         \r
647 \r
648   conn->state = NETCONN_WRITE;\r
649   while (conn->err == ERR_OK && size > 0) {\r
650     msg->msg.msg.w.dataptr = dataptr;\r
651     msg->msg.msg.w.copy = copy;\r
652     \r
653     if (conn->type == NETCONN_TCP) {\r
654       if (tcp_sndbuf(conn->pcb.tcp) == 0) {\r
655   sys_sem_wait(conn->sem);\r
656   if (conn->err != ERR_OK) {\r
657     goto ret;\r
658   }\r
659       }\r
660       if (size > tcp_sndbuf(conn->pcb.tcp)) {\r
661   /* We cannot send more than one send buffer's worth of data at a\r
662      time. */\r
663   len = tcp_sndbuf(conn->pcb.tcp);\r
664       } else {\r
665   len = size;\r
666       }\r
667     } else {\r
668       len = size;\r
669     }\r
670     \r
671     LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_write: writing %d bytes (%d)\n", len, copy));\r
672     msg->msg.msg.w.len = len;\r
673     api_msg_post(msg);\r
674     sys_mbox_fetch(conn->mbox, NULL);    \r
675     if (conn->err == ERR_OK) {\r
676       dataptr = (void *)((char *)dataptr + len);\r
677       size -= len;\r
678     } else if (conn->err == ERR_MEM) {\r
679       conn->err = ERR_OK;\r
680       sys_sem_wait(conn->sem);\r
681     } else {\r
682       goto ret;\r
683     }\r
684   }\r
685  ret:\r
686   memp_free(MEMP_API_MSG, msg);\r
687   conn->state = NETCONN_NONE;\r
688   if (conn->sem != SYS_SEM_NULL) {\r
689     sys_sem_free(conn->sem);\r
690     conn->sem = SYS_SEM_NULL;\r
691   }\r
692   \r
693   return conn->err;\r
694 }\r
695 \r
696 err_t\r
697 netconn_close(struct netconn *conn)\r
698 {\r
699   struct api_msg *msg;\r
700 \r
701   if (conn == NULL) {\r
702     return ERR_VAL;\r
703   }\r
704   if ((msg = memp_malloc(MEMP_API_MSG)) == NULL) {\r
705     return (conn->err = ERR_MEM);\r
706   }\r
707 \r
708   conn->state = NETCONN_CLOSE;\r
709  again:\r
710   msg->type = API_MSG_CLOSE;\r
711   msg->msg.conn = conn;\r
712   api_msg_post(msg);\r
713   sys_mbox_fetch(conn->mbox, NULL);\r
714   if (conn->err == ERR_MEM &&\r
715      conn->sem != SYS_SEM_NULL) {\r
716     sys_sem_wait(conn->sem);\r
717     goto again;\r
718   }\r
719   conn->state = NETCONN_NONE;\r
720   memp_free(MEMP_API_MSG, msg);\r
721   return conn->err;\r
722 }\r
723 \r
724 err_t\r
725 netconn_err(struct netconn *conn)\r
726 {\r
727   return conn->err;\r
728 }\r
729 \r