As announced in A.L.F.R.E.D. issue #202 (https://www.open-mesh.org/issues/202
I gave implementing server-to-server communication via TCP a spin.
The result is this - rather large - patch. I'd be glad for comments on the
implementation. Also, I might split this into more commits, but I think I need
ideas on how to properly separate the various parts - they mostly make sense
to me as a unit only.
A rough overview:
* struct tcp_connection is new, stores socket fd, pointer to data buffer,
a counter for data already read from socket (TCP is a stream and we can't
rely on self-contained datagrams), and list management
* struct interface is extended by a socket fd for the TCP socket and
a list of "tcp_connection"s
* struct globals is extended by a "requestproto" field that stores desired
* TCP operation is for now triggered by a command line flag "-t".
* for each interface, a TCP socket, bound/listening, is created and teared
down along with the UDP sockets
* a list of tcp_connection sockets is kept, managed and cleared alongside
* the sockets are incorporated into the fd_set management for select()
* process_alfred_request() gets another argument for a socket fd. It just
gets handed over to push_data() for sending the reply over the same
socket the request came from.
* recv_alfred_stream() is new and the analog function to recv_alfred_packet().
It manages the data buffer and will act on a received packet if and when
it is completely received.
ALFRED_REQUEST, ALFRED_PUSH_DATA and ALFRED_STATUS_TXEND packets are
handled for now.
* connect_tcp() function for setting up a new connection to a (TCP) server
* push_data() gets a new argument for a socket fd (c.f.
process_alfred_request() in recv.c). If said argument is >=0, the function
will operate on the socket rather than recvmsg() a datagram.
* sync_data() will act on requestproto configuration in globals struct and
opt to make the sync via TCP if configured to do so
* send_alfred_stream() will use connect_tcp() to create a new connection,
then send a packet analog to send_alfred_packet() and will then register
the socket to the list of "tcp_connection"s for the interface it is
currently operating upon. This way, the socket can receive a reply and
will be handled as long as it is not closed on the other end.
* check_if_socket() will tear down the TCP server and client sockets
along with the UDP sockets
* depending on the globals' requestproto setting, a REQUEST will be send
via TCP rather than UDP.
Testing has been only in an artificial virtual setup for now. I have some
hopes to get "mission clearance" for giving it a spin in our local
"Freifunk" setup. Even then TCP will most certainly only be used on a
handful of gateways since on the majority of nodes, reading values from
A.L.F.R.E.D. is not really needed (they are mostly push-only).
I'd be glad to hear some feedback.
Hans-Werner Hilse (1):
alfred: implement TCP support for server-to-server communication
alfred.h | 24 +++++++++-
main.c | 8 +++-
netsock.c | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
recv.c | 88 ++++++++++++++++++++++++++++++++++--
send.c | 119 +++++++++++++++++++++++++++++++++++++++++++-----
server.c | 11 +++++
unix_sock.c | 8 ++++
7 files changed, 389 insertions(+), 17 deletions(-)