/[lwip]/lwip/src/core/tcp_out.c
ViewVC logotype

Diff of /lwip/src/core/tcp_out.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.8 by likewise, Wed Jan 8 14:35:02 2003 UTC revision 1.9 by likewise, Mon Jan 13 13:24:11 2003 UTC
# Line 76  tcp_send_ctrl(struct tcp_pcb *pcb, u8_t Line 76  tcp_send_ctrl(struct tcp_pcb *pcb, u8_t
76  err_t  err_t
77  tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)  tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t copy)
78  {  {
79      DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, arg=%p, len=%u, copy=%d)\n", pcb, arg, len, copy));
80    if(pcb->state == SYN_SENT ||    if(pcb->state == SYN_SENT ||
81       pcb->state == SYN_RCVD ||       pcb->state == SYN_RCVD ||
82       pcb->state == ESTABLISHED ||       pcb->state == ESTABLISHED ||
# Line 85  tcp_write(struct tcp_pcb *pcb, const voi Line 86  tcp_write(struct tcp_pcb *pcb, const voi
86      }      }
87      return ERR_OK;      return ERR_OK;
88    } else {    } else {
89        DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write() called in invalid state\n"));
90      return ERR_CONN;      return ERR_CONN;
91    }    }
92  }  }
# Line 101  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 103  tcp_enqueue(struct tcp_pcb *pcb, void *a
103    void *ptr;    void *ptr;
104    u8_t queuelen;    u8_t queuelen;
105    
106      DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%u, flags=%x, copy=%d)\n", pcb, arg, len, flags, copy));
107    left = len;    left = len;
108    ptr = arg;    ptr = arg;
109    /* fail on too much data */    /* fail on too much data */
# Line 110  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 113  tcp_enqueue(struct tcp_pcb *pcb, void *a
113    }    }
114    
115    /* seqno will be the sequence number of the first segment enqueued    /* seqno will be the sequence number of the first segment enqueued
116       by the call to this function. */    by the call to this function. */
117    seqno = pcb->snd_lbb;    seqno = pcb->snd_lbb;
118      
119    queue = NULL;      queue = NULL;
120    DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d\n", pcb->snd_queuelen));    DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %d\n", pcb->snd_queuelen));
121    
122    /* Check if the queue length exceeds the configured maximum queue    /* Check if the queue length exceeds the configured maximum queue
123       length. If so, we return an error. */    length. If so, we return an error. */
124    queuelen = pcb->snd_queuelen;    queuelen = pcb->snd_queuelen;
125    if(queuelen >= TCP_SND_QUEUELEN) {    if(queuelen >= TCP_SND_QUEUELEN) {
126      DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN));      DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: too long queue %d (max %d)\n", queuelen, TCP_SND_QUEUELEN));
127      goto memerr;      goto memerr;
128    }      }  
129      
130  #ifdef LWIP_DEBUG  #ifdef LWIP_DEBUG
131    if(pcb->snd_queuelen != 0) {    if(pcb->snd_queuelen != 0) {
132      ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||      ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
133             pcb->unsent != NULL);            pcb->unsent != NULL);      
134    }    }
135  #endif /* LWIP_DEBUG */  #endif /* LWIP_DEBUG */
136      
137    seg = NULL;    seg = NULL;
138    seglen = 0;    seglen = 0;
139    
140    /* First, break up the data into segments and tuck them together in    /* First, break up the data into segments and tuck them together in
141       the local "queue" variable. */    the local "queue" variable. */
142    while(queue == NULL || left > 0) {    while(queue == NULL || left > 0) {
143    
144      /* The segment length should be the MSS if the data to be enqueued      /* The segment length should be the MSS if the data to be enqueued
145         is larger than the MSS. */      is larger than the MSS. */
146      seglen = left > pcb->mss? pcb->mss: left;      seglen = left > pcb->mss? pcb->mss: left;
147        
148      /* Allocate memory for tcp_seg, and fill in fields. */      /* Allocate memory for tcp_seg, and fill in fields. */
149      seg = memp_malloc(MEMP_TCP_SEG);      seg = memp_malloc(MEMP_TCP_SEG);
150      if(seg == NULL) {      if(seg == NULL) {
# Line 150  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 153  tcp_enqueue(struct tcp_pcb *pcb, void *a
153      }      }
154      seg->next = NULL;      seg->next = NULL;
155      seg->p = NULL;      seg->p = NULL;
156        
157      if(queue == NULL) {      if(queue == NULL) {
158        queue = seg;        queue = seg;
159      } else {      }
160        else {
161        /* Attach the segment to the end of the queued segments. */        /* Attach the segment to the end of the queued segments. */
162        for(useg = queue; useg->next != NULL; useg = useg->next);        for(useg = queue; useg->next != NULL; useg = useg->next);
163        useg->next = seg;        useg->next = seg;
164      }      }
165          
166      /* If copy is set, memory should be allocated      /* If copy is set, memory should be allocated
167         and data copied into pbuf, otherwise data comes from      and data copied into pbuf, otherwise data comes from
168         ROM or other static memory, and need not be copied. If      ROM or other static memory, and need not be copied. If
169         optdata is != NULL, we have options instead of data. */      optdata is != NULL, we have options instead of data. */
170      if(optdata != NULL) {      if(optdata != NULL) {
171        if((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {        if((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {
172          goto memerr;          goto memerr;
173        }        }
174        ++queuelen;        ++queuelen;
175        seg->dataptr = seg->p->payload;        seg->dataptr = seg->p->payload;
176      } else if(copy) {      }
177        else if(copy) {
178        if((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {        if((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {
179          DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf copy\n"));              DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf copy size %u\n", seglen));    
180          goto memerr;          goto memerr;
181        }        }
182        ++queuelen;        ++queuelen;
183        if(arg != NULL) {        if(arg != NULL) {
184          memcpy(seg->p->payload, ptr, seglen);          memcpy(seg->p->payload, ptr, seglen);
185        }        }
186        seg->dataptr = seg->p->payload;        seg->dataptr = seg->p->payload;
187      } else {      }
188        else {
189        /* Do not copy the data. */        /* Do not copy the data. */
190    
191        /* First, allocate a pbuf for holding the data. */        /* First, allocate a pbuf for holding the data. */
192        if((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {        if((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {
193          DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf non-copy\n"));                          DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for pbuf non-copy\n"));                
194          goto memerr;          goto memerr;
195        }        }
196        ++queuelen;        ++queuelen;
197        p->payload = ptr;        p->payload = ptr;
# Line 193  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 199  tcp_enqueue(struct tcp_pcb *pcb, void *a
199    
200        /* Second, allocate a pbuf for the headers. */        /* Second, allocate a pbuf for the headers. */
201        if((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {        if((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {
202          /* If allocation fails, we have to deallocate the data pbuf as          /* If allocation fails, we have to deallocate the data pbuf as
203             well. */             well. */
204          pbuf_free(p);          pbuf_free(p);
205          DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for header pbuf\n"));                    DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: could not allocate memory for header pbuf\n"));          
206          goto memerr;          goto memerr;
207        }        }
208        ++queuelen;        ++queuelen;
209    
# Line 206  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 212  tcp_enqueue(struct tcp_pcb *pcb, void *a
212      }      }
213    
214      /* Now that there are more segments queued, we check again if the      /* Now that there are more segments queued, we check again if the
215         length of the queue exceeds the configured maximum. */      length of the queue exceeds the configured maximum. */
216      if(queuelen > TCP_SND_QUEUELEN) {      if(queuelen > TCP_SND_QUEUELEN) {
217        DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN));          DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queue too long %d (%d)\n", queuelen, TCP_SND_QUEUELEN));  
218        goto memerr;        goto memerr;
219      }      }
220          
221      seg->len = seglen;      seg->len = seglen;
222      /*    if((flags & TCP_SYN) || (flags & TCP_FIN)) {      /*    if((flags & TCP_SYN) || (flags & TCP_FIN)) {
223        ++seg->len;      ++seg->len;
224        }*/      }*/
225          
226      /* Build TCP header. */      /* Build TCP header. */
227      if(pbuf_header(seg->p, TCP_HLEN)) {      if(pbuf_header(seg->p, TCP_HLEN)) {
228            
229        DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: no room for TCP header in pbuf.\n"));        DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: no room for TCP header in pbuf.\n"));
230            
231  #ifdef TCP_STATS  #ifdef TCP_STATS
232        ++lwip_stats.tcp.err;        ++lwip_stats.tcp.err;
233  #endif /* TCP_STATS */  #endif /* TCP_STATS */
# Line 238  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 244  tcp_enqueue(struct tcp_pcb *pcb, void *a
244      /* Copy the options into the header, if they are present. */      /* Copy the options into the header, if they are present. */
245      if(optdata == NULL) {      if(optdata == NULL) {
246        TCPH_OFFSET_SET(seg->tcphdr, 5 << 4);        TCPH_OFFSET_SET(seg->tcphdr, 5 << 4);
247      } else {      }
248        else {
249        TCPH_OFFSET_SET(seg->tcphdr, (5 + optlen / 4) << 4);        TCPH_OFFSET_SET(seg->tcphdr, (5 + optlen / 4) << 4);
250        /* Copy options into data portion of segment.        /* Copy options into data portion of segment.
251           Options can thus only be sent in non data carrying         Options can thus only be sent in non data carrying
252           segments such as SYN|ACK. */         segments such as SYN|ACK. */
253        memcpy(seg->dataptr, optdata, optlen);        memcpy(seg->dataptr, optdata, optlen);
254      }      }
255      DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queueing %lu:%lu (0x%x)\n",      DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: queueing %lu:%lu (0x%x)\n",
256                                ntohl(seg->tcphdr->seqno),        ntohl(seg->tcphdr->seqno),
257                                ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),        ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),
258                                flags));        flags));
259    
260      left -= seglen;      left -= seglen;
261      seqno += seglen;      seqno += seglen;
262      ptr = (void *)((char *)ptr + seglen);      ptr = (void *)((char *)ptr + seglen);
263    }    }
264    
265        
266    /* Now that the data to be enqueued has been broken up into TCP    /* Now that the data to be enqueued has been broken up into TCP
267       segments in the queue variable, we add them to the end of the    segments in the queue variable, we add them to the end of the
268       pcb->unsent queue. */        pcb->unsent queue. */
269    if(pcb->unsent == NULL) {    if(pcb->unsent == NULL) {
270      useg = NULL;      useg = NULL;
271    } else {    }
272      else {
273      for(useg = pcb->unsent; useg->next != NULL; useg = useg->next);      for(useg = pcb->unsent; useg->next != NULL; useg = useg->next);
274    }    }
275        
276    /* If there is room in the last pbuf on the unsent queue,    /* If there is room in the last pbuf on the unsent queue,
277       chain the first pbuf on the queue together with that. */    chain the first pbuf on the queue together with that. */
278    if(useg != NULL &&    if(useg != NULL &&
279       TCP_TCPLEN(useg) != 0 &&      TCP_TCPLEN(useg) != 0 &&
280       !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&      !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&
281       !(flags & (TCP_SYN | TCP_FIN)) &&      !(flags & (TCP_SYN | TCP_FIN)) &&
282       useg->len + queue->len <= pcb->mss) {      useg->len + queue->len <= pcb->mss) {
283      /* Remove TCP header from first segment. */      /* Remove TCP header from first segment. */
284      pbuf_header(queue->p, -TCP_HLEN);      pbuf_header(queue->p, -TCP_HLEN);
285      pbuf_chain(useg->p, queue->p);      pbuf_chain(useg->p, queue->p);
286      useg->len += queue->len;      useg->len += queue->len;
287      useg->next = queue->next;      useg->next = queue->next;
288          
289      DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: chaining, new len %u\n", useg->len));      DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue: chaining, new len %u\n", useg->len));
290      if(seg == queue) {      if(seg == queue) {
291        seg = NULL;        seg = NULL;
292      }      }
293      memp_free(MEMP_TCP_SEG, queue);      memp_free(MEMP_TCP_SEG, queue);
294    } else {          }
295      else {      
296      if(useg == NULL) {      if(useg == NULL) {
297        pcb->unsent = queue;        pcb->unsent = queue;
298            
299      } else {      }
300        else {
301        useg->next = queue;        useg->next = queue;
302      }      }
303    }    }
# Line 301  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 311  tcp_enqueue(struct tcp_pcb *pcb, void *a
311  #ifdef LWIP_DEBUG  #ifdef LWIP_DEBUG
312    if(pcb->snd_queuelen != 0) {    if(pcb->snd_queuelen != 0) {
313      ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||      ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
314             pcb->unsent != NULL);        pcb->unsent != NULL);
315          
316    }    }
317  #endif /* LWIP_DEBUG */  #endif /* LWIP_DEBUG */
318        
319    /* Set the PSH flag in the last segment that we enqueued, but only    /* Set the PSH flag in the last segment that we enqueued, but only
320       if the segment has data (indicated by seglen > 0). */    if the segment has data (indicated by seglen > 0). */
321    if(seg != NULL && seglen > 0 && seg->tcphdr != NULL) {    if(seg != NULL && seglen > 0 && seg->tcphdr != NULL) {
322      TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_PSH);      TCPH_FLAGS_SET(seg->tcphdr, TCPH_FLAGS(seg->tcphdr) | TCP_PSH);
323    }    }
324      
325    return ERR_OK;    return ERR_OK;
326   memerr:    memerr:
327  #ifdef TCP_STATS  #ifdef TCP_STATS
328    ++lwip_stats.tcp.memerr;    ++lwip_stats.tcp.memerr;
329  #endif /* TCP_STATS */  #endif /* TCP_STATS */
# Line 324  tcp_enqueue(struct tcp_pcb *pcb, void *a Line 334  tcp_enqueue(struct tcp_pcb *pcb, void *a
334  #ifdef LWIP_DEBUG  #ifdef LWIP_DEBUG
335    if(pcb->snd_queuelen != 0) {    if(pcb->snd_queuelen != 0) {
336      ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||      ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||
337             pcb->unsent != NULL);        pcb->unsent != NULL);
338        
339    }    }
340  #endif /* LWIP_DEBUG */  #endif /* LWIP_DEBUG */
341    DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));    DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %d (with mem err)\n", pcb->snd_queuelen));
# Line 471  tcp_output_segment(struct tcp_seg *seg, Line 481  tcp_output_segment(struct tcp_seg *seg,
481    if(pcb->rcv_wnd < pcb->mss) {    if(pcb->rcv_wnd < pcb->mss) {
482      seg->tcphdr->wnd = 0;      seg->tcphdr->wnd = 0;
483    } else {    } else {
484        /* advertise our receive window size in this TCP segment */
485      seg->tcphdr->wnd = htons(pcb->rcv_wnd);      seg->tcphdr->wnd = htons(pcb->rcv_wnd);
486    }    }
487    

Legend:
Removed from v.1.8  
changed lines
  Added in v.1.9

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26