* @ingroup tcp_raw * Write data for sending (but does not send it immediately). * * It waits in the expectation of more data being sent soon (as * it can send them more efficiently by combining them together). * To prompt the system to send data now, call tcp_output() after * calling tcp_write(). * * This function enqueues the data pointed to by the argument dataptr. The length of * the
| 387 | * @return ERR_OK if enqueued, another err_t on error |
| 388 | */ |
| 389 | err_t |
| 390 | tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) |
| 391 | { |
| 392 | struct pbuf *concat_p = NULL; |
| 393 | struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; |
| 394 | u16_t pos = 0; /* position in 'arg' data */ |
| 395 | u16_t queuelen; |
| 396 | u8_t optlen; |
| 397 | u8_t optflags = 0; |
| 398 | #if TCP_OVERSIZE |
| 399 | u16_t oversize = 0; |
| 400 | u16_t oversize_used = 0; |
| 401 | #if TCP_OVERSIZE_DBGCHECK |
| 402 | u16_t oversize_add = 0; |
| 403 | #endif /* TCP_OVERSIZE_DBGCHECK*/ |
| 404 | #endif /* TCP_OVERSIZE */ |
| 405 | u16_t extendlen = 0; |
| 406 | #if TCP_CHECKSUM_ON_COPY |
| 407 | u16_t concat_chksum = 0; |
| 408 | u8_t concat_chksum_swapped = 0; |
| 409 | u16_t concat_chksummed = 0; |
| 410 | #endif /* TCP_CHECKSUM_ON_COPY */ |
| 411 | err_t err; |
| 412 | u16_t mss_local; |
| 413 | |
| 414 | LWIP_ERROR("tcp_write: invalid pcb", pcb != NULL, return ERR_ARG); |
| 415 | |
| 416 | /* don't allocate segments bigger than half the maximum window we ever received */ |
| 417 | mss_local = LWIP_MIN(pcb->mss, TCPWND_MIN16(pcb->snd_wnd_max / 2)); |
| 418 | mss_local = mss_local ? mss_local : pcb->mss; |
| 419 | |
| 420 | LWIP_ASSERT_CORE_LOCKED(); |
| 421 | |
| 422 | #if LWIP_NETIF_TX_SINGLE_PBUF |
| 423 | /* Always copy to try to create single pbufs for TX */ |
| 424 | apiflags |= TCP_WRITE_FLAG_COPY; |
| 425 | #endif /* LWIP_NETIF_TX_SINGLE_PBUF */ |
| 426 | |
| 427 | LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", |
| 428 | (void *)pcb, arg, len, (u16_t)apiflags)); |
| 429 | LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", |
| 430 | arg != NULL, return ERR_ARG;); |
| 431 | |
| 432 | err = tcp_write_checks(pcb, len); |
| 433 | if (err != ERR_OK) { |
| 434 | return err; |
| 435 | } |
| 436 | queuelen = pcb->snd_queuelen; |
| 437 | |
| 438 | #if LWIP_TCP_TIMESTAMPS |
| 439 | if ((pcb->flags & TF_TIMESTAMP)) { |
| 440 | /* Make sure the timestamp option is only included in data segments if we |
| 441 | agreed about it with the remote host. */ |
| 442 | optflags = TF_SEG_OPTS_TS; |
| 443 | optlen = LWIP_TCP_OPT_LENGTH_SEGMENT(TF_SEG_OPTS_TS, pcb); |
| 444 | /* ensure that segments can hold at least one data byte... */ |
| 445 | mss_local = LWIP_MAX(mss_local, LWIP_TCP_OPT_LEN_TS + 1); |
| 446 | } else |