if ((rx_len > 0) )
{
//read rx_len bytes from the buffer and send over ethernet
rx_len = serial_receive(i, buf, rx_len);
if (rx_len > 0)
{
if (write(ethser_port[i].client_fd, buf, rx_len) <0)
{
//something went wrong. Close the client socket
dbg_printf("EthSer Closing client idx: %d fd: %d", i, ethser_port[i].client_fd);
close(ethser_port[i].client_fd);
ethser_port[i].client_fd = -1;
continue; //break from the for-loop early
}
ethser_port[i].rx_count += rx_len;
}
}
//socket ready for writing
if(FD_ISSET(new_sd, &write_flags)) {
//printf("\nSocket ready for write");
FD_CLR(new_sd, &write_flags);
send(new_sd, out, 255, 0);
memset(&out, 0, 255);
} //end if
int
lwip_write(int s, const void *data, size_t size)
{
return lwip_send(s, data, size, 0);
}
But a much better way would be some kind of a queue_space() function for lwip_send(). I would call it before reading the UART rx buffer and read out of that buffer the lesser figure.
Surprisingly (this function is all over the place) I can't find a definition what this returns but from what you say it sounds like it returns #bytes actually written and the rest it discarded. Is that right?
I may be able to work with that, with a bit of a hack, because the "discarded" data has already been read out of the UART rx buffer so I can't just dump it; I have to call lwip_write again and repeat until it has all gone.
But a much better way would be some kind of a queue_space() function for lwip_send(). I would call it before reading the UART rx buffer and read out of that buffer the lesser figure.
if ((rx_len > 0) && (force_rx == true))
{
//read rx_len bytes from the buffer and send over ethernet
rx_len = serial_receive(i, buf, rx_len);
if (rx_len > 0)
{
int tmp_len;
bool fail = false;
// This returns # bytes actually written (if a positive value)
tmp_len = write(ethser_port[i].client_fd, buf, rx_len);
if (tmp_len<0) fail=true;
// Process the case where not all rx_len bytes were written (by the NON blocking socket)
// This can cause a wait here if the other end is slow in consuming the data.
if ( (tmp_len<rx_len) && !fail )
{
int offset = 0;
do
{
rx_len -= tmp_len;
offset += tmp_len;
tmp_len = write(ethser_port[i].client_fd, &buf[offset], rx_len);
if (tmp_len<0) fail=true;
}
while ( ( tmp_len>0 ) && !fail );
}
if ( fail )
{
//something went wrong. Close the client socket
dbg_printf("EthSer Closing client idx: %d fd: %d", i, ethser_port[i].client_fd);
close(ethser_port[i].client_fd);
ethser_port[i].client_fd = -1;
continue; //break from the for-loop early
}
}
}
The very first call to write() returns -1, which is strange.
if ((rx_len > 0) && (force_rx == true))
{
//read rx_len bytes from the serial port buffer
rx_len = KDE_serial_receive(i, buf, rx_len);
// and send them over ethernet
if (rx_len > 0)
{
//dbg_printf("rx_len: %d", rx_len); //Debug to show how (well) the buffering works
int written;
bool fail = false;
// This returns # bytes actually written (if a positive value)
written = write(ethser_port[i].client_fd, buf, rx_len);
if (written<0)
{
fail=true; // error condition
}
else
{
ethser_port[i].rx_count += written;
}
// Process the case where not all rx_len bytes were written (by the NON blocking socket)
// This can cause a wait here if the other end is slow in consuming the data.
if ( (written<rx_len) && !fail )
{
int offset = 0;
do
{
rx_len -= written;
offset += written;
written = write(ethser_port[i].client_fd, &buf[offset], rx_len);
if (written<0)
{
fail=true; // error condition
}
else
{
ethser_port[i].rx_count += rx_len;
}
}
while ( ( written<rx_len ) && !fail );
}
/*
* This code crashes the task somehow
if ( fail )
{
//something went wrong. Close the client socket
dbg_printf("EthSer Closing client idx: %d fd: %d", i, ethser_port[i].client_fd);
close(ethser_port[i].client_fd);
ethser_port[i].client_fd = -1;
continue; //break from the for-loop early
}
*/
}
}
The more I read LWIP sources and understand its internal architecture, the less I like it. Then again, I haven't designed an embedded TCP/IP stack myself, so who am I to judge?
I can't find errnoto.
// Also omitted: check that ethser_port[i].client_fd != -1, before rx_len = KDE_serial_receive(i, buf, rx_len);
size_t tx_len = 0;
while (tx_len < rx_len) {
ssize_t written;
errno = 0;
written = write(ethser_port[i].client_fd, buf + tx_len, rx_len - tx_len);
if (written > 0) {
tx_len += n;
continue;
} else
if (errno == ERR_VAL) {
// yield()? sleep()? For one half of TCP send timeout interval?
continue;
} else {
// Something went wrong. 'errno' should contain the error code.
shutdown(ethser_port[i].client_fd, SHUT_RDWR);
close(ethser_port[i].client_fd);
ethser_port[i].client_fd = -1;
break;
}
}
//read data from TCP connection for transmit
int tx_len = serial_get_opqspace(i);
if (tx_len > sizeof(buf)) tx_len = sizeof(buf);
//tx_len contains the maximum number of characters the UART buffer can hold. IOW
//tx_len has the maximum number of characters we can read from the socket.
if (tx_len > 0)
{
tx_len = read(ethser_port[i].client_fd, buf, tx_len);
//Now tx_len is either >0 when data has arrived, 0 when the remote side
//closed the socket or -1 to indicate no data or an error.
if (tx_len > 0)
{
//we have data, send it to the UART
serial_transmit(i, buf, tx_len);
ethser_port[i].tx_count += tx_len;
}
//Check socket closed or an error occured (except for when the socket
//return no data in which case errno is set to EWOULDBLOCK).
if ((tx_len <= 0) && (errno != EWOULDBLOCK))
{
//Something went wrong or remote closed. Close the client socket
dbg_printf("EthSer Closing client idx: %d fd: %d", i, ethser_port[i].client_fd);
close(ethser_port[i].client_fd);
ethser_port[i].client_fd = -1;
continue; //break from the for-loop early; no need to continue with this socket
}
}
Yes; that aspect I am aware of (serial comms has been my day job for 40 years).
However, what I did was a software hack at the RH end, whereby the data is just dumped, so the output UART baud rate is not limiting the flow. In that situation, no data should be lost, because flow control should work along the preceeding sections.
Curiously, I am never seeing short writes to the socket.
Don't be offended
If all downstream buffers are a multiple of 512 bytes in size, and the TCP MTU is large enough to never split 512 byte packets, then this is to be expected: either the buffer is full, or it has room for a multiple of 512 bytes, all down the buffer chain.
there are two 512 byte buffers, but in addition there are a few k MTU-sized buffers (1500 + a bit). I tried it with the 512 byte buffers much bigger than the MTU and still didn't see a short write. But this could be for any reason at all. TCP/IP is incredibly complex.
But as far as free code goes, there probably isn't anything better.
An interesting point relating to this is whether LWIP (or how much of it) is zero-copy.