Index: api/api_lib.c
===================================================================
RCS file: /sources/lwip/lwip/src/api/api_lib.c,v
retrieving revision 1.57
diff -u -r1.57 api_lib.c
--- api/api_lib.c	29 Jun 2007 13:37:33 -0000	1.57
+++ api/api_lib.c	1 Jul 2007 15:58:35 -0000
@@ -314,12 +314,6 @@
   }
   conn->recvmbox = SYS_MBOX_NULL;
   conn->acceptmbox = SYS_MBOX_NULL;
-  conn->sem = sys_sem_new(0);
-  if (conn->sem == SYS_SEM_NULL) {
-    sys_mbox_free(conn->mbox);
-    memp_free(MEMP_NETCONN, conn);
-    return NULL;
-  }
   conn->state        = NETCONN_NONE;
   conn->socket       = 0;
   conn->callback     = callback;
@@ -334,7 +328,6 @@
   TCPIP_APIMSG(&msg);
 
   if (conn->err != ERR_OK) {
-    sys_sem_free(conn->sem);
     sys_mbox_free(conn->mbox);
     memp_free(MEMP_NETCONN, conn);
     return NULL;
@@ -364,7 +357,7 @@
 
   msg.function = do_delconn;
   msg.msg.conn = conn;
-  TCPIP_APIMSG(&msg);
+  tcpip_apimsg(&msg);
 
   /* Drain the recvmbox. */
   if (conn->recvmbox != SYS_MBOX_NULL) {
@@ -392,11 +385,6 @@
   sys_mbox_free(conn->mbox);
   conn->mbox = SYS_MBOX_NULL;
 
-  if (conn->sem != SYS_SEM_NULL) {
-    sys_sem_free(conn->sem);
-    /* conn->sem = SYS_SEM_NULL; */
-  }
-
   memp_free(MEMP_NETCONN, conn);
   return ERR_OK;
 }
@@ -812,16 +800,15 @@
 
   LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);
 
-  conn->state = NETCONN_CLOSE;
- again:
+  /* We don't have to wait here since the standard behaviour for TCP
+   * connections is sending unsent data in the background.
+   * See http://www.opengroup.org/onlinepubs/000095399/functions/close.html
+   * and http://www.opengroup.org/onlinepubs/009695399/functions/setsockopt.html
+   * for explanations why not to wait.
+   */
   msg.function = do_close;
   msg.msg.conn = conn;
-  TCPIP_APIMSG(&msg);
-  if (conn->err == ERR_MEM && conn->sem != SYS_SEM_NULL) {
-    sys_sem_wait(conn->sem);
-    goto again;
-  }
-  conn->state = NETCONN_NONE;
+  tcpip_apimsg(&msg);
   return conn->err;
 }
 
Index: api/api_msg.c
===================================================================
RCS file: /sources/lwip/lwip/src/api/api_msg.c,v
retrieving revision 1.56
diff -u -r1.56 api_msg.c
--- api/api_msg.c	22 Jun 2007 20:50:21 -0000	1.56
+++ api/api_msg.c	1 Jul 2007 15:58:20 -0000
@@ -43,6 +43,7 @@
 /* forward declarations */
 #if LWIP_TCP
 static err_t do_writemore(struct netconn *conn);
+static void do_close_internal(struct netconn *conn);
 #endif
 
 #if LWIP_RAW
@@ -188,8 +189,8 @@
 
   if (conn->state == NETCONN_WRITE) {
     do_writemore(conn);
-  } else if ((conn->state == NETCONN_CLOSE) && (conn->sem != SYS_SEM_NULL)) {
-    sys_sem_signal(conn->sem);
+  } else if (conn->state == NETCONN_CLOSE) {
+    do_close_internal(conn);
   }
 
   return ERR_OK;
@@ -212,8 +213,8 @@
 
   if (conn->state == NETCONN_WRITE) {
     do_writemore(conn);
-  } else if ((conn->state == NETCONN_CLOSE) && (conn->sem != SYS_SEM_NULL)) {
-    sys_sem_signal(conn->sem);
+  } else if (conn->state == NETCONN_CLOSE) {
+    do_close_internal(conn);
   }
 
   if (conn && conn->callback)
@@ -257,17 +258,13 @@
       (*conn->callback)(conn, NETCONN_EVT_RCVPLUS, 0);
     sys_mbox_post(conn->acceptmbox, NULL);
   }
-  if (conn->state == NETCONN_WRITE) {
-    /* calling do_writemore is not necessary
+  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {
+    /* calling do_writemore/do_close_internal is not necessary
        since the pcb has already been deleted! */
     conn->state = NETCONN_NONE;
     /* wake up the waiting task */
     sys_mbox_post(conn->mbox, NULL);
-  } else
-    if ((conn->sem != SYS_SEM_NULL) &&
-      (conn->state == NETCONN_CLOSE)) {
-      sys_sem_signal(conn->sem);
-    }
+  }
 }
 
 /**
@@ -326,13 +323,6 @@
     memp_free(MEMP_NETCONN, newconn);
     return ERR_MEM;
   }
-  newconn->sem = sys_sem_new(0);
-  if (newconn->sem == SYS_SEM_NULL) {
-    sys_mbox_free(newconn->mbox);
-    sys_mbox_free(newconn->recvmbox);
-    memp_free(MEMP_NETCONN, newconn);
-    return ERR_MEM;
-  }
   /* Allocations were OK, setup the PCB etc */
   newconn->type = NETCONN_TCP;
   newconn->pcb.tcp = newpcb;
@@ -433,6 +423,60 @@
    TCPIP_APIMSG_ACK(msg);
 }
 
+static void
+do_close_internal(struct netconn *conn)
+{
+  LWIP_ASSERT("invalid conn", (conn != NULL));
+  LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));
+  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));
+  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));
+
+  if (conn->pcb.tcp->state == LISTEN) {
+    tcp_arg(conn->pcb.tcp, NULL);
+    tcp_accept(conn->pcb.tcp, NULL);
+    /* for state==LISTEN, tcp_close can't fail */
+    tcp_close(conn->pcb.tcp);
+    conn->state = NETCONN_NONE;
+    conn->pcb.tcp = NULL;
+    conn->err = ERR_OK;
+    sys_mbox_post(conn->mbox, NULL);
+  } else {
+    err_t err;
+    enum tcp_state old_state = conn->pcb.tcp->state;
+    if ((old_state == SYN_RCVD) || (old_state == ESTABLISHED) ||
+      (old_state == CLOSE_WAIT)) {
+      tcp_arg(conn->pcb.tcp, NULL);
+      tcp_sent(conn->pcb.tcp, NULL);
+      tcp_recv(conn->pcb.tcp, NULL);
+      tcp_poll(conn->pcb.tcp, NULL, 0);
+      tcp_err(conn->pcb.tcp, NULL);
+      err = tcp_close(conn->pcb.tcp);
+      switch (err) {
+        default:
+          /* any other error: abort! */
+          tcp_abort(conn->pcb.tcp);
+          /* fall through */
+        case (ERR_OK):
+          /* ERR_OK: fall through */
+        case (ERR_BUF):
+          /* ERR_BUF: tcp_output failed,
+             will be called again by internal tcp timers */
+          conn->state = NETCONN_NONE;
+          conn->pcb.tcp = NULL;
+          conn->err = err;
+          /* wake up the application task */
+          sys_mbox_post(conn->mbox, NULL);
+          break;
+        case (ERR_MEM):
+          /* ERR_MEM: error sending FIN?
+             try again in sent_tcp or poll_tcp */
+          /* stay in state NETCONN_CLOSE */
+          break;
+      }
+    }
+  }
+}
+
 /**
  * Delete the pcb inside a netconn.
  * Called from netconn_delete.
@@ -457,20 +501,8 @@
 #endif /* LWIP_UDP */
 #if LWIP_TCP
     case NETCONN_TCP:
-      if (msg->conn->pcb.tcp->state == LISTEN) {
-        tcp_arg(msg->conn->pcb.tcp, NULL);
-        tcp_accept(msg->conn->pcb.tcp, NULL);
-        tcp_close(msg->conn->pcb.tcp);
-      } else {
-        tcp_arg(msg->conn->pcb.tcp, NULL);
-        tcp_sent(msg->conn->pcb.tcp, NULL);
-        tcp_recv(msg->conn->pcb.tcp, NULL);
-        tcp_poll(msg->conn->pcb.tcp, NULL, 0);
-        tcp_err(msg->conn->pcb.tcp, NULL);
-        if (tcp_close(msg->conn->pcb.tcp) != ERR_OK) {
-          tcp_abort(msg->conn->pcb.tcp);
-        }
-      }
+      msg->conn->state = NETCONN_CLOSE;
+      do_close_internal(msg->conn);
       break;
 #endif /* LWIP_TCP */
     default:
@@ -483,7 +515,14 @@
       (*msg->conn->callback)(msg->conn, NETCONN_EVT_SENDPLUS, 0);
   }
 
-  if (msg->conn->mbox != SYS_MBOX_NULL) {
+  if ((msg->conn->mbox != SYS_MBOX_NULL)
+#if LWIP_TCP
+     /* for tcp netconns, do_close_internal ACKs the message */
+     && (NETCONNTYPE_GROUP(msg->conn->type) != NETCONN_TCP))
+#else
+    )
+#endif
+  {
     TCPIP_APIMSG_ACK(msg);
   }
 }
@@ -748,7 +787,52 @@
     conn->write_delayed = 1;
 #endif
   }
-
+  if (conn->pcb.tcp->unsent) {
+    u32_t avail2;
+    u32_t tmp1 = ntohl(conn->pcb.tcp->unsent->tcphdr->seqno);
+    u32_t tmp2 = tmp1 - conn->pcb.tcp->lastack;
+    avail2 = conn->pcb.tcp->snd_wnd - tmp2;
+    if (avail2 < len) {
+      /* don't try to write more than send-window */
+      len = (avail2 > 0xffff) ? (u16_t)(avail2 & 0xffff) : 0xffff;
+  #if LWIP_TCPIP_CORE_LOCKING
+      conn->write_delayed = 1;
+  #endif
+    }
+    avail2 = conn->pcb.tcp->cwnd - tmp2;
+    if (avail2 < len) {
+      /* don't try to write more than congestion-window */
+      len = (avail2 > 0xffff) ? (u16_t)(avail2 & 0xffff) : 0xffff;
+  #if LWIP_TCPIP_CORE_LOCKING
+      conn->write_delayed = 1;
+  #endif
+    }
+  }
+  if (conn->pcb.tcp->unacked) {
+    u32_t avail2;
+    u32_t tmp1 = ntohl(conn->pcb.tcp->unacked->tcphdr->seqno);
+    u32_t tmp2 = tmp1 - conn->pcb.tcp->lastack;
+    struct tcp_seg *seg;
+    for (seg = conn->pcb.tcp->unacked; seg != NULL; seg = seg->next) {
+      tmp2 += seg->len;
+    }
+    avail2 = conn->pcb.tcp->snd_wnd - tmp2;
+    if (avail2 < len) {
+      /* don't try to write more than send-window */
+      len = (avail2 > 0xffff) ? (u16_t)(avail2 & 0xffff) : 0xffff;
+  #if LWIP_TCPIP_CORE_LOCKING
+      conn->write_delayed = 1;
+  #endif
+    }
+    avail2 = conn->pcb.tcp->cwnd - tmp2;
+    if (avail2 < len) {
+      /* don't try to write more than congestion-window */
+      len = (avail2 > 0xffff) ? (u16_t)(avail2 & 0xffff) : 0xffff;
+  #if LWIP_TCPIP_CORE_LOCKING
+      conn->write_delayed = 1;
+  #endif
+    }
+  }
   err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.copy);
   LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len));
   if (err == ERR_OK) {
@@ -766,6 +850,7 @@
       (*conn->callback)(conn, NETCONN_EVT_SENDMINUS, len);
     }
   } else if (err == ERR_MEM) {
+    tcp_output_nagle(conn->pcb.tcp);
 #if LWIP_TCPIP_CORE_LOCKING
     conn->write_delayed = 1;
 #endif
@@ -846,17 +931,16 @@
 do_close(struct api_msg_msg *msg)
 {
 #if LWIP_TCP
-  if (msg->conn->pcb.tcp != NULL) {
-    if (msg->conn->type == NETCONN_TCP) {
-      if (msg->conn->pcb.tcp->state == LISTEN) {
-        msg->conn->err = tcp_close(msg->conn->pcb.tcp);
-      } else if (msg->conn->pcb.tcp->state == CLOSE_WAIT) {
-        msg->conn->err = tcp_output(msg->conn->pcb.tcp);
-      }
-    }
-  }
+  if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {
+      msg->conn->state = NETCONN_CLOSE;
+      do_close_internal(msg->conn);
+      /* for tcp netconns, do_close_internal ACKs the message */
+  } else
 #endif /* LWIP_TCP */
-  TCPIP_APIMSG_ACK(msg);
+  {
+    msg->conn->err = ERR_VAL;
+    TCPIP_APIMSG_ACK(msg);
+  }
 }
 
 #if LWIP_IGMP
Index: include/lwip/api.h
===================================================================
RCS file: /sources/lwip/lwip/src/include/lwip/api.h,v
retrieving revision 1.24
diff -u -r1.24 api.h
--- include/lwip/api.h	21 Jun 2007 19:32:31 -0000	1.24
+++ include/lwip/api.h	1 Jul 2007 15:58:28 -0000
@@ -112,7 +112,6 @@
   sys_mbox_t mbox;
   sys_mbox_t recvmbox;
   sys_mbox_t acceptmbox;
-  sys_sem_t sem;
   int socket;
 #if LWIP_SO_RCVTIMEO
   int recv_timeout;
