_______________________________________________
lwip-users mailing list
lwip-...@nongnu.org
https://lists.nongnu.org/mailman/listinfo/lwip-users
1) First call tcp_new()
2) Then set up the callbacks needed (e.g. by calling tcp_err() to
specific the error callback, and so on)
3) Then call tcp_connect()
- this will either succeed and call the connected callback passed to
tcp_connect, or fail and call the error callback specified by tcp_err()
- if the error callback is called because of a timeout I think you
could immediately call tcp_connect() again, but I haven't checked this.
4) When you've finished with a connection, call tcp_close(). After this
returns success you can't touch the pcb struct again, and must call
tcp_new() to get another (i.e. back to step 1).
Hope that helps. This is all taken from lwip/doc/rawapi.txt, and there
is more detail there.
Kieran
Simon
I'm basically trying to account for 4 situations:
1 - A connection is established from lwip to some code on another
machine, and then I ctrl-C the code listening on the other machine. I
want lwip to recognize this and try to reconnect, to be ready whenever
I restart the listener on B.
2 - I attempt to connect but the cable is not plugged in between the machines.
3 - I attempt to connect and the cable is plugged in, but nothing is
listening to the socket yet to accept the connection on the other
machine.
4 - I have connected successfully, and I then unplug the cable. My
code that uses lwip periodically sends a ping packet, and if it
doesn't get a response in time, it should close the connection and try
to reconnect.
So for which of these do I have to call tcp_close(), which can I
recall tcp_new() or should I reuse the old tcp_pcb, and what do I need
to monitor before I call either of these or call tcp_connect() again?
Do I need to be checking the state of the pcb or something else?
thanks,
RB
It will (eventually) time out.
> and everything
> will get messed up if you just try and tcp_connect again.
It shouldn't get messed up. If it does, that's a bug. Can you give
more details?
> I've had
> problems where if you call tcp_new() or tcp_connect() at the wrong
> time, it will overwrite the current connection and repush it on to
> tcp_active_pcbs which causes pcb->next to point to itself. This causes
> lots of the lwip timers and functions to loop forever and freeze the
> code.
Can you describe your threading model? It sounds like you might have
two threads racing here and modifying state in the core of lwIP, which
isn't supported and would cause exactly the sort of problem you
describe.
> Other times, even if the other computer is still connected and
> the closing is completely acked and everything, when you try and
> tcp_connect again on the same connection, it no longer seems to get
> any response from the other computer. It seems like even though the
> connection makes it all the way to the CLOSED state, the other
> computer isn't completely aware that the connection is done and wont
> accept another request from the same connection.
If you can get a packet capture of this I'll take a look. by
"tcp_connect again on the same connection" are you trying to use the
same pcb after calling tcp_close()? This isn't allowed: once
tcp_close() has returned success, you must not touch the pcb structure
as it could have been freed.
> I'm basically trying to account for 4 situations:
> 1 - A connection is established from lwip to some code on another
> machine, and then I ctrl-C the code listening on the other machine. I
> want lwip to recognize this and try to reconnect, to be ready whenever
> I restart the listener on B.
This rather depends on what happens with you ctrl-C the code on the
other machine:
1) if it closes the connection (with a FIN) then lwIP will notify the
application by calling the recv callback with zero length.
2) if it aborts the connection (with a RST) then lwIP will notify the
application by either the recv callback or the err callback (I can't
remember which off the top of my head).
3) if it doesn't send us anything, or the packet it sends it lost, then
lwIP will only notice next time it tries to send to the other side,
which will then likely cause it to send us a RST. This could take some
time. There is a feature in TCP called keep-alive which probes the
connection at regular intervals to see if it is still up to help deal
with the case where an idle connection is no longer being handled by the
other end.
> 2 - I attempt to connect but the cable is not plugged in between the machines.
This should time out, but it may take some time. TCP is very tolerant
and keeps re-trying for a while.
> 3 - I attempt to connect and the cable is plugged in, but nothing is
> listening to the socket yet to accept the connection on the other
> machine.
This should fail quickly, as the other end will reply to our connection
attempt. Your application can then wait a while and attempt to connect
again. I would avoid putting this in a tight loop though, as it would
be rather antisocial to flood the network with repeated connection
attempts.
> 4 - I have connected successfully, and I then unplug the cable. My
> code that uses lwip periodically sends a ping packet, and if it
> doesn't get a response in time, it should close the connection and try
> to reconnect.
TCP is very tolerant of broken links and will keep trying to send your
pings for a long time before it gives up and closes the connection.
There is nothing to stop you doing as you describe and having a much
more strict time-out in your application if it doesn't receive a reply.
Just call tcp_close() and try and open a new one (although as before, be
careful you don't flood the network with connection attempts).
> So for which of these do I have to call tcp_close().
Call tcp_close() if you want to close a connection. It is probably
safest and simplest to do this in all cases you describe, then create a
new PCB, then call tcp_connect() again.
> which can I
> recall tcp_new() or should I reuse the old tcp_pcb
No, after you've called tcp_close(), don't touch the PCB again.
> and what do I need
> to monitor before I call either of these or call tcp_connect() again?
See above.
> Do I need to be checking the state of the pcb or something else?
You should get all the notifications you need via the RAW api callbacks.
It shouldn't be necessary to look into the PCB internals
Kieran
fsm->datapcb = tcp_new();
if (fsm->datapcb == NULL)
{
printf ("create data pcb fail \r\n");
}
if ( ERR_USE == tcp_bind(fsm->datapcb, &pcb->local_ip, 20))
{
printf(" port 20 is in used \r\n");
}
tcp_arg(fsm->datapcb, fsm->datafs);
if ( ERR_OK != tcp_connect(fsm->datapcb, &fsm->dataip, fsm->dataport, ftpd_dataconnected))
{
return 1;
The callback is only called when the connection is fully established and
acknowledged by the server. If you not getting the callback in that
situation, then something is wrong.
Kieran
Because connections start out as closed until you connect them. Can you
get a packet capture?
A screenshot of the packet capture? If you have the packet capture,
please send that instead of a screenshot, as it has so much more useful
information.
Let me summarise what I think the situation is, please correct me if I'm
wrong:
- You have an FTP server running on your lwIP device.
- You use an FTP client on windows to try to connect to it
- It connects successfully and you can log in.
- You've called tcp_connect() on your lwIP device to open a data
connection.
- We see the SYN for this new connection in the packet capture, but
Windows seems to ignore it.
- You don't see the connected callback invoked (which makes sense, as it
is not connected)
I would guess that this is nothing to do with lwIP at all. It's
probably the common problem of Active FTP and firewalls, where you
windows PC is not allowing the data connection to be opened. Please
check that.
Clearing the memory would not help: it might already be re-allocated and thus have a valid state. Plus "CLOSED" is 0, I think...
[..] In addition, the state the struct returns to is identical to the state of a brand new tcp_pcb, "CLOSED". This caused me to believe that I could tcp_connect() again on the same tcp_pcb. As you've said, this is not actually ok. After tcp_close returns, lwip no longer knows about your tcp_pcb struct, and although the memory isn't cleared, lwip has designated that memory space as free so the next time you create a connection with tcp_new() it may place it there and overwrite your old tcp_pcb.
So my four situations:
1) I ctrl-C the listener on the other machine.
This will send some sort of packet to your lwip machine telling you the connection is closing. Lwip will move tcp_pcb into the CLOSE_WAIT state, and will call the recv_callback with a NULL argument. In the recv_callback you should then check that this packet is coming from your currently opened connection. If it isn't, it must be from an old connection that you already attempted to close, so you can ignore it.
If it is, then you must call tcp_close() yourself. This then completes some more acking with the other machine and eventually places the tcp_pcb into the CLOSED state, and then calls the err_callback with ERR_ABRT.
At this point, the tcp_pcb is "freed" and should not be touched again.
A new tcp_pcb should be tcp_new()'d and then you can tcp_connect() again.
2) I try to connect from lwip but no cable is plugged in.Lwip will try and send a SYN packet and wait for an ack. Until it gets the ack, a counter is being incremented until it times out. When it times out, it calls the err_callback with ERR_ABRT. It is not clear to me if the tcp_pcb is CLOSED at this point, but it looks like the memory is freed anyway.
Should I have to call tcp_close() here? Once the memory is freed in lwip you can again tcp_new() and tcp_connect().
3) I try to connect from lwip and the cable is plugged in, but nothing is listening.The other machine should immediately send Lwip back a rst packet. Lwip will then call the err_callback with ERR_RST. I noted though that at this point when the error callback is called, the old tcp_pcb is not yet closed nor freed.
It's always good to hear how lwIP is being used. If you'd like to add a
brief description to the wiki that would be great:
http://lwip.wikia.com/wiki/Projects_that_use_lwIP
Kieran