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:
alfred.h: * 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 operation mode.
main.c: * TCP operation is for now triggered by a command line flag "-t".
netsock.c: * 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()
recv.c: * 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.
send.c: * 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.
server.c: * check_if_socket() will tear down the TCP server and client sockets along with the UDP sockets
unix_sock.c: * 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.
-hwh
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(-)