From db7f68afd7fcd0693e18370de91ea55369e9c870 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Thu, 28 Nov 2013 16:53:12 +1030 Subject: [PATCH 01/18] Initial msp library implementation with connection state tracking --- commandline.c | 5 + dataformats.c | 10 + dataformats.h | 5 + directory_service.c | 1 + fdqueue.c | 4 +- headerfiles.mk | 1 + mdp_client.h | 3 - msp_client.c | 534 ++++++++++++++++++++++++++++++++++++++++++++ msp_client.h | 63 ++++++ msp_proxy.c | 356 +++++++++++++++++++++++++++++ overlay_mdp.c | 17 +- serval.h | 1 + sourcefiles.mk | 2 + tests/msp | 60 +++++ 14 files changed, 1053 insertions(+), 9 deletions(-) create mode 100644 msp_client.c create mode 100644 msp_client.h create mode 100644 msp_proxy.c create mode 100755 tests/msp diff --git a/commandline.c b/commandline.c index 8fd9303a..820ab451 100644 --- a/commandline.c +++ b/commandline.c @@ -2261,6 +2261,7 @@ static int app_keyring_set_tag(const struct cli_parsed *parsed, struct cli_conte return r; } +// returns -1 on error, -2 on timeout, packet length on success. ssize_t mdp_poll_recv(int mdp_sock, time_ms_t timeout, struct mdp_header *rev_header, unsigned char *payload, size_t buffer_size) { time_ms_t now = gettime_ms(); @@ -3055,6 +3056,10 @@ struct cli_schema command_line_options[]={ "Run byte order handling test"}, {app_slip_test,{"test","slip","[--seed=]","[--duration=|--iterations=]",NULL}, 0, "Run serial encapsulation test"}, + {app_msp_connection,{"msp", "listen", "", NULL}, 0, + "Listen for incoming connections"}, + {app_msp_connection,{"msp", "connect", "", "", NULL}, 0, + "Connect to a remote party"}, #ifdef HAVE_VOIPTEST {app_pa_phone,{"phone",NULL}, 0, "Run phone test application"}, diff --git a/dataformats.c b/dataformats.c index 95b59762..8d26393c 100644 --- a/dataformats.c +++ b/dataformats.c @@ -239,3 +239,13 @@ uint16_t read_uint16(const unsigned char *o) for(i=0;i<2;i++) v=(v<<8)|o[2-1-i]; return v; } + +int compare_wrapped_uint8(uint8_t one, uint8_t two) +{ + return (int8_t)(one - two); +} + +int compare_wrapped_uint16(uint16_t one, uint16_t two) +{ + return (int16_t)(one - two); +} diff --git a/dataformats.h b/dataformats.h index 26c9fb7c..2770a111 100644 --- a/dataformats.h +++ b/dataformats.h @@ -42,4 +42,9 @@ uint64_t read_uint64(const unsigned char *o); uint32_t read_uint32(const unsigned char *o); uint16_t read_uint16(const unsigned char *o); +// compare sequence numbers that wrap +// returns <0 if one is before two, 0 if they are the same, else >0 +int compare_wrapped_uint8(uint8_t one, uint8_t two); +int compare_wrapped_uint16(uint16_t one, uint16_t two); + #endif //__SERVAL_DNA___DATA_FORMATS_H diff --git a/directory_service.c b/directory_service.c index ebad7542..311c1951 100644 --- a/directory_service.c +++ b/directory_service.c @@ -23,6 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include #include "constants.h" +#include "serval.h" #include "mdp_client.h" #include "str.h" diff --git a/fdqueue.c b/fdqueue.c index de18178b..a78967f6 100644 --- a/fdqueue.c +++ b/fdqueue.c @@ -204,7 +204,9 @@ int _watch(struct __sourceloc __whence, struct sched_ent *alarm) WARN("watch() called without supplying an alarm name"); if (!alarm->function) - return WHY("Can't watch if you haven't set the function pointer"); + FATAL("Can't watch if you haven't set the function pointer"); + if (!alarm->poll.events) + FATAL("Can't watch if you haven't set any poll flags"); if (alarm->_poll_index>=0 && fd_callbacks[alarm->_poll_index]==alarm){ // updating event flags diff --git a/headerfiles.mk b/headerfiles.mk index fc9ae543..ff362454 100644 --- a/headerfiles.mk +++ b/headerfiles.mk @@ -28,5 +28,6 @@ HDRS= fifo.h \ constants.h \ monitor-client.h \ mdp_client.h \ + msp_client.h \ radio_link.h \ sqlite-amalgamation-3070900/sqlite3.h diff --git a/mdp_client.h b/mdp_client.h index a93e0a3c..4b820d59 100644 --- a/mdp_client.h +++ b/mdp_client.h @@ -19,8 +19,6 @@ #ifndef __SERVAL_DNA__MDP_CLIENT_H #define __SERVAL_DNA__MDP_CLIENT_H -#include "serval.h" - // define 3rd party mdp API without any structure padding #pragma pack(push, 1) @@ -95,7 +93,6 @@ ssize_t mdp_recv(int socket, struct mdp_header *header, uint8_t *payload, ssize_ int mdp_poll(int socket, time_ms_t timeout_ms); - /* Client-side MDP function */ int overlay_mdp_client_socket(void); int overlay_mdp_client_close(int mdp_sockfd); diff --git a/msp_client.c b/msp_client.c new file mode 100644 index 00000000..f5f36874 --- /dev/null +++ b/msp_client.c @@ -0,0 +1,534 @@ + +#include +#include "serval.h" +#include "mdp_client.h" +#include "msp_client.h" +#include "str.h" +#include "dataformats.h" +#include "socket.h" +#include "log.h" + +#define FLAG_SHUTDOWN (1<<0) + +struct msp_packet{ + struct msp_packet *_next; + uint16_t seq; + uint8_t flags; + time_ms_t added; + time_ms_t sent; + const uint8_t *payload; + size_t len; +}; + +#define MAX_WINDOW_SIZE 64 +struct msp_window{ + int packet_count; + uint32_t base_rtt; + uint32_t rtt; + uint16_t next_seq; // seq of next expected TX or RX packet. + struct msp_packet *_head, *_tail; +}; + +struct msp_sock{ + struct msp_sock *_next; + struct msp_sock *_prev; + int mdp_sock; + msp_state_t state; + struct msp_window tx; + struct msp_window rx; + uint16_t previous_ack; + int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context); + void *context; + struct mdp_header header; + time_ms_t last_rx; + time_ms_t timeout; + time_ms_t next_action; +}; + +struct msp_sock *root=NULL; + +struct msp_sock * msp_socket(int mdp_sock) +{ + struct msp_sock *ret = emalloc_zero(sizeof(struct msp_sock)); + ret->mdp_sock = mdp_sock; + ret->state = MSP_STATE_UNINITIALISED; + ret->_next = root; + // TODO set base rtt to ensure that we send the first packet a few times before giving up + ret->tx.base_rtt = ret->tx.rtt = 0xFFFFFFFF; + if (root) + root->_prev=ret; + root = ret; + return ret; +} + +static void free_all_packets(struct msp_window *window) +{ + struct msp_packet *p = window->_head; + while(p){ + struct msp_packet *free_me=p; + p=p->_next; + free((void *)free_me->payload); + free(free_me); + } +} + +static void free_acked_packets(struct msp_window *window, uint16_t seq) +{ + struct msp_packet *p = window->_head; + uint32_t rtt=0; + time_ms_t now = gettime_ms(); + + while(p && compare_wrapped_uint16(p->seq, seq)<=0){ + if (p->sent) + rtt = now - p->sent; + struct msp_packet *free_me=p; + p=p->_next; + free((void *)free_me->payload); + free(free_me); + window->packet_count--; + } + window->_head = p; + if (rtt){ + window->rtt = rtt; + if (window->base_rtt > rtt) + window->base_rtt = rtt; + } + if (!p) + window->_tail = NULL; +} + +void msp_close(struct msp_sock *sock) +{ + sock->state |= MSP_STATE_CLOSED; + + // last chance to free other resources + if (sock->handler) + sock->handler(sock, sock->state, NULL, 0, sock->context); + + if (sock->_prev) + sock->_prev->_next = sock->_next; + else + root=sock->_next; + if (sock->_next) + sock->_next->_prev = sock->_prev; + + free_all_packets(&sock->tx); + free_all_packets(&sock->rx); + + free(sock); +} + +int msp_set_handler(struct msp_sock *sock, + int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context), + void *context) +{ + sock->handler = handler; + sock->context = context; + return 0; +} + +msp_state_t msp_get_state(struct msp_sock *sock) +{ + return sock->state; +} + +void msp_set_watch(struct msp_sock *sock, msp_state_t flags) +{ + assert(flags & ~(MSP_STATE_POLLIN|MSP_STATE_POLLOUT)); + // clear any existing poll bits, and set the requested ones + sock->state &= ~(MSP_STATE_POLLIN|MSP_STATE_POLLOUT); + sock->state |= flags; +} + +int msp_set_local(struct msp_sock *sock, struct mdp_sockaddr local) +{ + assert(sock->state == MSP_STATE_UNINITIALISED); + sock->header.local = local; + return 0; +} + +int msp_set_remote(struct msp_sock *sock, struct mdp_sockaddr remote) +{ + assert(sock->state == MSP_STATE_UNINITIALISED); + sock->header.remote = remote; + return 0; +} + +int msp_listen(struct msp_sock *sock) +{ + assert(sock->state == MSP_STATE_UNINITIALISED); + assert(sock->header.local.port); + + sock->state |= MSP_STATE_LISTENING; + sock->header.flags |= MDP_FLAG_BIND; + mdp_send(sock->mdp_sock, &sock->header, NULL, 0); + + return 0; +} + +int msp_get_remote_adr(struct msp_sock *sock, struct mdp_sockaddr *remote) +{ + *remote = sock->header.remote; + return 0; +} + +static int add_packet(struct msp_window *window, uint16_t seq, uint8_t flags, + const uint8_t *payload, size_t len) +{ + struct msp_packet *packet = emalloc_zero(sizeof(struct msp_packet)); + if (!packet) + return -1; + + if (!window->_head){ + window->_head = window->_tail = packet; + }else{ + if (window->_tail->seq == seq){ + // ignore duplicate packets + free(packet); + return 0; + }else if (compare_wrapped_uint16(window->_tail->seq, seq)<0){ + if (compare_wrapped_uint16(window->_head->seq, seq)>0){ + // this is ambiguous + free(packet); + return WHYF("%04x is both < tail (%04x) and > head (%04x)", seq, window->_tail->seq, window->_head->seq); + } + + window->_tail->_next = packet; + window->_tail = packet; + }else{ + struct msp_packet **pos = &window->_head; + while(compare_wrapped_uint16((*pos)->seq, seq)<0){ + if ((*pos)->seq == seq){ + // ignore duplicate packets + free(packet); + return 0; + } + pos = &(*pos)->_next; + } + (*pos)->_next = packet; + packet->_next = (*pos); + *pos = packet; + } + } + + packet->added = gettime_ms(); + packet->seq = seq; + packet->flags = flags; + packet->len = len; + + if (payload && len){ + uint8_t *p = emalloc(len); + if (!p){ + free(packet); + return -1; + } + packet->payload = p; + bcopy(payload, p, len); + } + window->packet_count++; + return 0; +} + +struct socket_address daemon_addr={.addrlen=0,}; + +static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet) +{ + if (daemon_addr.addrlen == 0){ + if (make_local_sockaddr(&daemon_addr, "mdp.2.socket") == -1) + return -1; + } + + uint8_t msp_header[5]; + + msp_header[0]=packet->flags; + write_uint16(&msp_header[1], sock->rx.next_seq); + write_uint16(&msp_header[3], packet->seq); + sock->previous_ack = sock->rx.next_seq; + + DEBUGF("Sending packet flags %d, ack %d, seq %d", packet->flags, sock->rx.next_seq, packet->seq); + struct fragmented_data data={ + .fragment_count=3, + .iov={ + { + .iov_base = (void*)&sock->header, + .iov_len = sizeof(struct mdp_header) + }, + { + .iov_base = &msp_header, + .iov_len = sizeof(msp_header) + }, + { + .iov_base = (void*)packet->payload, + .iov_len = packet->len + } + } + }; + + // allow for sending an empty payload body + if (!(packet->payload && packet->len)) + data.fragment_count --; + + ssize_t r = send_message(sock->mdp_sock, &daemon_addr, &data); + if (r==-1) + return -1; + packet->sent = gettime_ms(); + if (!sock->timeout) + sock->timeout = packet->sent + 10000; + return 0; +} + +static int send_ack(struct msp_sock *sock) +{ + D; + if (daemon_addr.addrlen == 0){ + if (make_local_sockaddr(&daemon_addr, "mdp.2.socket") == -1) + return -1; + } + + uint8_t msp_header[3]; + + msp_header[0]=0; + write_uint16(&msp_header[1], sock->rx.next_seq); + sock->previous_ack = sock->rx.next_seq; + + struct fragmented_data data={ + .fragment_count=2, + .iov={ + { + .iov_base = (void*)&sock->header, + .iov_len = sizeof(struct mdp_header) + }, + { + .iov_base = &msp_header, + .iov_len = sizeof(msp_header) + } + } + }; + + ssize_t r = send_message(sock->mdp_sock, &daemon_addr, &data); + return r<0?-1:0; +} + +// add a packet to the transmit buffer +int msp_send(struct msp_sock *sock, const uint8_t *payload, size_t len) +{ + assert(sock->header.remote.port); + assert((sock->state & MSP_STATE_SHUTDOWN_LOCAL)==0); + + if (sock->tx.packet_count > MAX_WINDOW_SIZE) + return -1; + + if (add_packet(&sock->tx, sock->tx.next_seq, 0, payload, len)==-1) + return -1; + + sock->tx.next_seq++; + + // make sure we attempt to process packets from this sock soon + // TODO calculate based on congestion window + sock->next_action = gettime_ms(); + + return 0; +} + +int msp_shutdown(struct msp_sock *sock) +{ + if (sock->tx._tail && sock->tx._tail->sent==0){ + sock->tx._tail->flags |= FLAG_SHUTDOWN; + }else{ + if (add_packet(&sock->tx, sock->tx.next_seq, FLAG_SHUTDOWN, NULL, 0)==-1) + return -1; + sock->tx.next_seq++; + } + sock->state|=MSP_STATE_SHUTDOWN_LOCAL; + return 0; +} + +static int process_sock(struct msp_sock *sock) +{ + time_ms_t now = gettime_ms(); + + if (sock->timeout && sock->timeout < now){ + msp_close(sock); + return -1; + } + + sock->next_action = sock->timeout; + struct msp_packet *p; + + // deliver packets that have now arrived in order + p = sock->rx._head; + if (p) + DEBUGF("Seq %d vs %d", p->seq, sock->rx.next_seq); + + // TODO ... ? (sock->state & MSP_STATE_POLLIN) + while(p && p->seq == sock->rx.next_seq){ + struct msp_packet *packet=p; + + // process packet flags when we have delivered the packet + if (packet->flags & FLAG_SHUTDOWN) + sock->state|=MSP_STATE_SHUTDOWN_REMOTE; + + if (sock->handler + && sock->handler(sock, sock->state, packet->payload, packet->len, sock->context)==-1){ + // keep the packet if the handler refused to accept it. + break; + } + + p=p->_next; + sock->rx.next_seq++; + } + free_acked_packets(&sock->rx, sock->rx.next_seq -1); + + // transmit packets that can now be sent + p = sock->tx._head; + while(p){ + if (p->sent==0 || p->sent + sock->tx.rtt*2 < now){ + + if (!(sock->state & (MSP_STATE_CONNECTING|MSP_STATE_CONNECTED))){ + sock->state |= MSP_STATE_CONNECTING; + sock->header.flags |= MDP_FLAG_BIND; + + }else if (!sock->header.local.port){ + // wait until we have heard back from the daemon with our port number before sending another packet. + break; + } + if (msp_send_packet(sock, p)==-1) + return -1; + } + if (sock->next_action > p->sent + sock->tx.rtt*2) + sock->next_action = p->sent + sock->tx.rtt*2; + p=p->_next; + } + + // should we send an ack now without sending a payload? + if (sock->previous_ack != sock->rx.next_seq){ + if (send_ack(sock)) + return -1; + } + + if ((sock->state & (MSP_STATE_SHUTDOWN_LOCAL|MSP_STATE_SHUTDOWN_REMOTE)) == (MSP_STATE_SHUTDOWN_LOCAL|MSP_STATE_SHUTDOWN_REMOTE) + && sock->tx.packet_count == 0 + && sock->rx.packet_count == 0){ + msp_close(sock); + return -1; + } + + return 0; +} + +int msp_processing(time_ms_t *next_action) +{ + *next_action=0; + struct msp_sock *sock = root; + time_ms_t now = gettime_ms(); + while(sock){ + struct msp_sock *s=sock; + sock = s->_next; + + if (s->next_action && s->next_action <= now){ + // this might cause the socket to be closed. + if (process_sock(s)==0){ + // remember the time of the next thing we need to do. + if (s->next_action!=0 && s->next_action < *next_action) + *next_action=s->next_action; + } + } + } + return 0; +} + +static struct msp_sock * find_connection(int mdp_sock, struct mdp_header *header) +{ + struct msp_sock *s=root; + struct msp_sock *listen=NULL; + while(s){ + if (s->mdp_sock == mdp_sock ){ + if ((s->header.flags & MDP_FLAG_BIND) && (header->flags & MDP_FLAG_BIND)){ + // bind response from the daemon + s->header.local = header->local; + s->header.flags &= ~MDP_FLAG_BIND; + DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(header->local.sid), header->local.port); + return NULL; + } + + if (s->state & MSP_STATE_LISTENING){ + // remember any matching listen socket so we can create a connection on first use + if (s->header.local.port == header->local.port + && (is_sid_t_any(s->header.local.sid) + || memcmp(&s->header.local.sid, &header->local.sid, SID_SIZE)==0)) + listen=s; + }else if (memcmp(&s->header.remote, &header->remote, sizeof header->remote)==0 + && memcmp(&s->header.local, &header->local, sizeof header->local)==0){ + // if the addresses match, we found it. + return s; + } + } + s = s->_next; + } + + if (listen){ + // create socket for incoming connection + s = msp_socket(listen->mdp_sock); + s->header = *header; + // use the same handler initially + s->handler = listen->handler; + s->context = listen->context; + return s; + } + + WARNF("Unexpected packet from %s:%d", alloca_tohex_sid_t(header->remote.sid), header->remote.port); + return NULL; +} + +static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t *payload, size_t len) +{ + DEBUGF("packet from %s:%d", alloca_tohex_sid_t(header->remote.sid), header->remote.port); + // find or create mdp_sock... + struct msp_sock *sock=find_connection(mdp_sock, header); + + if (!sock) + return 0; + + if (len<3) + return WHY("Expected at least 3 bytes"); + + sock->state |= MSP_STATE_CONNECTED; + sock->last_rx = gettime_ms(); + sock->timeout = sock->last_rx + 10000; + + uint8_t flags = payload[0]; + + uint16_t ack_seq = read_uint16(&payload[1]); + + // release acknowledged packets + free_acked_packets(&sock->tx, ack_seq); + + // TODO if their ack seq has not advanced, we may need to hurry up and retransmit a packet + + + // make sure we attempt to process packets from this sock soon + // TODO calculate based on congestion window + sock->next_action = gettime_ms(); + + if (len<5) + return 0; + + uint16_t seq = read_uint16(&payload[3]); + + add_packet(&sock->rx, seq, flags, &payload[5], len - 5); + return 0; +} + +int msp_recv(int mdp_sock) +{ + + struct mdp_header header; + uint8_t payload[1200]; + + ssize_t len = mdp_recv(mdp_sock, &header, payload, sizeof(payload)); + if (len<0) + return -1; + + return process_packet(mdp_sock, &header, payload, len); +} + diff --git a/msp_client.h b/msp_client.h new file mode 100644 index 00000000..56ff6589 --- /dev/null +++ b/msp_client.h @@ -0,0 +1,63 @@ +#ifndef __SERVALD_MSP_CLIENT_H +#define __SERVALD_MSP_CLIENT_H + +#define MSP_STATE_UNINITIALISED 0 +#define MSP_STATE_LISTENING (1<<0) + +#define MSP_STATE_CONNECTING (1<<1) +#define MSP_STATE_CONNECTED (1<<2) + +#define MSP_STATE_SHUTDOWN_LOCAL (1<<3) +#define MSP_STATE_SHUTDOWN_REMOTE (1<<4) + +// this connection is about to be free'd, release any other resources or references to the state +#define MSP_STATE_CLOSED (1<<5) + +// something has gone wrong somewhere and the connection will be closed +#define MSP_STATE_ERROR (1<<6) + +// does the client want to be interupted to reading data? +#define MSP_STATE_POLLIN (1<<7) +// does the client want to know when data can be written? +#define MSP_STATE_POLLOUT (1<<8) + +// is there some data to read? +#define MSP_STATE_DATAIN (1<<9) +// is there space for sending more data? +#define MSP_STATE_DATAOUT (1<<10) + + +struct msp_sock; +typedef uint16_t msp_state_t; + +// allocate a new socket +struct msp_sock * msp_socket(int mdp_sock); +void msp_close(struct msp_sock *sock); + +int msp_set_handler(struct msp_sock *sock, + int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context), + void *context); + +// the local address is only set when calling msp_listen or msp_send +int msp_set_local(struct msp_sock *sock, struct mdp_sockaddr local); +int msp_set_remote(struct msp_sock *sock, struct mdp_sockaddr remote); + +int msp_listen(struct msp_sock *sock); + +int msp_get_remote_adr(struct msp_sock *sock, struct mdp_sockaddr *remote); +msp_state_t msp_get_state(struct msp_sock *sock); + +// which events are you interested in handling? +void msp_set_watch(struct msp_sock *sock, msp_state_t flags); + +// bind, send data, and potentially shutdown this end of the connection +int msp_send(struct msp_sock *sock, const uint8_t *payload, size_t len); +int msp_shutdown(struct msp_sock *sock); + +// receive and process an incoming packet +int msp_recv(int mdp_sock); + +// next_action indicates the next time that msp_processing should be called +int msp_processing(time_ms_t *next_action); + +#endif \ No newline at end of file diff --git a/msp_proxy.c b/msp_proxy.c new file mode 100644 index 00000000..5fc51ab9 --- /dev/null +++ b/msp_proxy.c @@ -0,0 +1,356 @@ + +#include "serval.h" +#include "str.h" +#include "dataformats.h" +#include "mdp_client.h" +#include "msp_client.h" + +struct buffer{ + size_t position; + size_t limit; + size_t capacity; + uint8_t bytes[]; +}; + +struct connection{ + struct msp_sock *sock; + struct buffer *in; + struct buffer *out; +}; + +struct connection *stdio_connection=NULL; +struct msp_sock *listener=NULL; + +static void msp_poll(struct sched_ent *alarm); +static void stdin_poll(struct sched_ent *alarm); +static void stdout_poll(struct sched_ent *alarm); + +struct profile_total mdp_sock_stats={ + .name="msp_poll" +}; +struct sched_ent mdp_sock={ + .function = msp_poll, + .stats = &mdp_sock_stats, +}; + +struct profile_total stdin_stats={ + .name="stdin_poll" +}; +struct sched_ent stdin_alarm={ + .function = stdin_poll, + .stats = &stdin_stats, +}; + +struct profile_total stdout_stats={ + .name="stdout_poll" +}; +struct sched_ent stdout_alarm={ + .function = stdout_poll, + .stats = &stdout_stats, +}; + +static struct connection *alloc_connection() +{ + struct connection *conn = emalloc_zero(sizeof(struct connection)); + if (!conn) + return NULL; + conn->in = emalloc(1024 + sizeof(struct buffer)); + if (!conn->in){ + free(conn); + return NULL; + } + conn->out = emalloc(1024 + sizeof(struct buffer)); + if (!conn->out){ + free(conn->in); + free(conn); + return NULL; + } + conn->in->position = conn->out->position = 0; + conn->in->limit = conn->out->limit = 0; + conn->in->capacity = conn->out->capacity = 1024; + return conn; +} + +static void free_connection(struct connection *conn) +{ + if (!conn) + return; + if (conn->in) + free(conn->in); + if (conn->out) + free(conn->out); + free(conn); +} + +static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context) +{ + struct connection *conn = context; + DEBUGF("Handler, state %d, payload len %zd", state, len); + + if (payload && len){ + dump("incoming payload", payload, len); + if (conn->out->capacity < len + conn->out->limit){ + DEBUGF("Insufficient space len %zd, capacity %zd, limit %zd", len, conn->out->capacity, conn->out->limit); + return -1; + } + if (conn->out->limit==0){ + watch(&stdout_alarm); + INFOF("Watching stdout"); + } + bcopy(payload, &conn->out->bytes[conn->out->limit], len); + conn->out->limit+=len; + } + + if (state & MSP_STATE_CLOSED){ + struct mdp_sockaddr remote; + msp_get_remote_adr(sock, &remote); + INFOF(" - Connection with %s:%d closed", alloca_tohex_sid_t(remote.sid), remote.port); + + if (conn == stdio_connection){ + stdio_connection->sock=NULL; + }else{ + free_connection(conn); + } + + unschedule(&mdp_sock); + + if (mdp_sock.poll.events){ + unwatch(&mdp_sock); + mdp_sock.poll.events=0; + INFOF("Unwatching mdp socket"); + } + mdp_close(mdp_sock.poll.fd); + mdp_sock.poll.fd=-1; + return 0; + } + + if (state & MSP_STATE_SHUTDOWN_REMOTE){ + struct mdp_sockaddr remote; + msp_get_remote_adr(sock, &remote); + INFOF(" - Connection with %s:%d remote shutdown", alloca_tohex_sid_t(remote.sid), remote.port); + } + + return 0; +} + +static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *UNUSED(context)) +{ + struct mdp_sockaddr remote; + msp_get_remote_adr(sock, &remote); + INFOF(" - New connection from %s:%d", alloca_tohex_sid_t(remote.sid), remote.port); + + struct connection *conn = alloc_connection(); + if (!conn) + return -1; + conn->sock = sock; + if (!stdio_connection){ + stdio_connection=conn; + watch(&stdin_alarm); + INFOF("Watching stdin"); + } + msp_set_handler(sock, msp_handler, conn); + if (payload) + return msp_handler(sock, state, payload, len, conn); + + // stop listening after an incoming connection + msp_close(listener); + + return 0; +} + +static void msp_poll(struct sched_ent *alarm) +{ + if (alarm->poll.revents & POLLIN) + // process incoming data packet + msp_recv(alarm->poll.fd); + + // do any timed actions that need to be done, either in response to receiving or due to a timed alarm. + msp_processing(&alarm->alarm); + if (alarm->alarm){ + time_ms_t now = gettime_ms(); + if (alarm->alarm < now) + alarm->alarm = now; + alarm->deadline = alarm->alarm +10; + unschedule(alarm); + schedule(alarm); + } +} + +static void stdin_poll(struct sched_ent *alarm) +{ + INFOF("Poll stdin, %d", alarm->poll.revents); + if (alarm->poll.revents & POLLIN) { + if (!stdio_connection){ + unwatch(alarm); + INFOF("Unwatching stdin"); + return; + } + + size_t remaining = stdio_connection->in->capacity - stdio_connection->in->limit; + if (remaining>0){ + ssize_t r = read(alarm->poll.fd, + stdio_connection->in->bytes + stdio_connection->in->limit, + remaining); + INFOF("Read %zd from stdin %d, %d", r, alarm->poll.revents, errno); + if (r>0){ + dump("stdin",stdio_connection->in->bytes + stdio_connection->in->limit, r); + + stdio_connection->in->limit+=r; + + if (msp_send(stdio_connection->sock, stdio_connection->in->bytes, stdio_connection->in->limit)!=-1){ + // if this packet was acceptted, clear the read buffer + stdio_connection->in->limit = stdio_connection->in->position = 0; + // attempt to process this socket asap + mdp_sock.alarm = gettime_ms(); + mdp_sock.deadline = mdp_sock.alarm+10; + unschedule(&mdp_sock); + schedule(&mdp_sock); + } + + // stop reading input when the buffer is full + if (stdio_connection->in->limit==stdio_connection->in->capacity){ + unwatch(alarm); + INFOF("Unwatching stdin"); + } + }else{ + // EOF, just trigger our error handler + alarm->poll.revents|=POLLERR; + } + } + } + + if (alarm->poll.revents & (POLLHUP | POLLERR)) { + // input has closed? + struct mdp_sockaddr remote; + msp_get_remote_adr(stdio_connection->sock, &remote); + msp_shutdown(stdio_connection->sock); + unwatch(alarm); + INFOF(" - Connection with %s:%d local shutdown", alloca_tohex_sid_t(remote.sid), remote.port); + // attempt to process this socket asap + mdp_sock.alarm = gettime_ms(); + mdp_sock.deadline = mdp_sock.alarm+10; + unschedule(&mdp_sock); + schedule(&mdp_sock); + } +} + +static void stdout_poll(struct sched_ent *alarm) +{ + if (alarm->poll.revents & POLLOUT) { + if (!stdio_connection){ + unwatch(alarm); + INFOF("Unwatching stdout"); + return; + } + // try to write some data + size_t data = stdio_connection->out->limit-stdio_connection->out->position; + if (data>0){ + ssize_t r = write(alarm->poll.fd, + stdio_connection->out->bytes+stdio_connection->out->position, + data); + INFOF("Wrote %zd to stdout", r); + if (r > 0) + stdio_connection->out->position+=r; + } + + // if the buffer is empty now, reset it and unwatch the handle + if (stdio_connection->out->position==stdio_connection->out->limit){ + stdio_connection->out->limit=0; + stdio_connection->out->position=0; + unwatch(alarm); + INFOF("Unwatching stdout"); + } + + if (stdio_connection->out->limit < stdio_connection->out->capacity){ + // TODO try to get more data from the socket + } + } + + if (alarm->poll.revents & (POLLHUP | POLLERR)) { + unwatch(alarm); + INFOF("Unwatching stdout"); + // Um, quit? + } +} + +int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) +{ + const char *sidhex, *port_string; + + if (cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, NULL) == -1) + return -1; + if (cli_arg(parsed, "port", &port_string, cli_uint, NULL) == -1) + return -1; + + struct mdp_sockaddr addr; + bzero(&addr, sizeof addr); + + addr.port = atoi(port_string); + + if (sidhex && *sidhex){ + if (str_to_sid_t(&addr.sid, sidhex) == -1) + return WHY("str_to_sid_t() failed"); + } + + int ret=-1; + struct msp_sock *sock = NULL; + + mdp_sock.poll.fd = mdp_socket(); + if (mdp_sock.poll.fd==-1) + goto end; + mdp_sock.poll.events = POLLIN; + watch(&mdp_sock); + INFOF("Watching mdp socket"); + + set_nonblock(STDIN_FILENO); + set_nonblock(STDOUT_FILENO); + + stdin_alarm.poll.fd=STDIN_FILENO; + stdin_alarm.poll.events=POLLIN; + + stdout_alarm.poll.fd=STDOUT_FILENO; + stdout_alarm.poll.events=POLLOUT; + + sock = msp_socket(mdp_sock.poll.fd); + if (sidhex && *sidhex){ + stdio_connection = alloc_connection(); + if (!stdio_connection) + return -1; + stdio_connection->sock = sock; + msp_set_handler(sock, msp_handler, stdio_connection); + msp_set_remote(sock, addr); + INFOF("Set remote %s:%d", alloca_tohex_sid_t(addr.sid), addr.port); + + // note we only watch these stdio handles when we have space / bytes in our buffers + watch(&stdin_alarm); + INFOF("Watching stdin"); + }else{ + msp_set_handler(sock, msp_listener, NULL); + msp_set_local(sock, addr); + msp_listen(sock); + listener=sock; + INFOF(" - Listening on port %d", addr.port); + } + sock=NULL; + + while(fd_poll()){ + ; + } + ret=0; + +end: + if (sock) + msp_close(sock); + if (mdp_sock.poll.fd>=0){ + if (mdp_sock.poll.events){ + unwatch(&mdp_sock); + INFOF("Unwatching mdp socket"); + } + mdp_close(mdp_sock.poll.fd); + } + unschedule(&mdp_sock); + free_connection(stdio_connection); + stdio_connection=NULL; + return ret; +} + diff --git a/overlay_mdp.c b/overlay_mdp.c index b9cd1f8d..b0624e42 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -495,7 +495,7 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame */ if (config.debug.mdprequests) - DEBUGF("Received packet with listener (MDP ports: src=%s*:%"PRImdp_port_t", dst=%"PRImdp_port_t")", + DEBUGF("Received packet (MDP ports: src=%s*:%"PRImdp_port_t", dst=%"PRImdp_port_t")", alloca_tohex_sid_t_trunc(mdp->out.src.sid, 14), mdp->out.src.port, mdp->out.dst.port); @@ -530,6 +530,8 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame if (len < 0) RETURN(WHY("unsupported MDP packet type")); struct socket_address *client = &mdp_bindings[match].client; + if (config.debug.mdprequests) + DEBUGF("Forwarding packet to client %s", alloca_socket_address(client)); ssize_t r = sendto(mdp_sock.poll.fd,mdp,len,0, &client->addr, client->addrlen); if (r == -1){ WHYF_perror("sendto(fd=%d,len=%zu,addr=%s)", mdp_sock.poll.fd, (size_t)len, alloca_socket_address(client)); @@ -546,6 +548,7 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame } case 1: { + struct socket_address *client = &mdp_bindings[match].client; struct mdp_header header; header.local.sid=mdp->out.dst.sid; header.local.port=mdp->out.dst.port; @@ -562,7 +565,9 @@ static int overlay_saw_mdp_frame(struct overlay_frame *frame, overlay_mdp_frame if (mdp_bindings[match].internal) RETURN(mdp_bindings[match].internal(&header, mdp->out.payload, mdp->out.payload_length)); - RETURN(mdp_send2(&mdp_bindings[match].client, &header, mdp->out.payload, mdp->out.payload_length)); + if (config.debug.mdprequests) + DEBUGF("Forwarding packet to client v2 %s", alloca_socket_address(client)); + RETURN(mdp_send2(client, &header, mdp->out.payload, mdp->out.payload_length)); } } } else { @@ -740,6 +745,11 @@ static int overlay_send_frame( if (!source) return WHYF("No source specified"); + if (config.debug.mdprequests) + DEBUGF("Attempting to queue mdp packet from %s:%d to %s:%d", + alloca_tohex_sid_t(source->sid), src_port, + destination?alloca_tohex_sid_t(destination->sid):"broadcast", dst_port); + /* Prepare the overlay frame for dispatch */ struct overlay_frame *frame = emalloc_zero(sizeof(struct overlay_frame)); if (!frame) @@ -1406,9 +1416,6 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header overlay_saw_mdp_frame(NULL, &mdp); } - if (config.debug.mdprequests) - DEBUGF("Attempting to queue mdp packet"); - // construct, encrypt, sign and queue the packet if (overlay_send_frame( source, header->local.port, diff --git a/serval.h b/serval.h index c8465336..2a7794e5 100644 --- a/serval.h +++ b/serval.h @@ -602,6 +602,7 @@ int app_meshms_conversations(const struct cli_parsed *parsed, struct cli_context int app_meshms_send_message(const struct cli_parsed *parsed, struct cli_context *context); int app_meshms_list_messages(const struct cli_parsed *parsed, struct cli_context *context); int app_meshms_mark_read(const struct cli_parsed *parsed, struct cli_context *context); +int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *context); int monitor_get_fds(struct pollfd *fds,int *fdcount,int fdmax); diff --git a/sourcefiles.mk b/sourcefiles.mk index 4894d7cc..976771d1 100644 --- a/sourcefiles.mk +++ b/sourcefiles.mk @@ -24,6 +24,8 @@ SERVAL_SOURCES = \ $(SERVAL_BASE)meshms.c \ $(SERVAL_BASE)mdp_client.c \ $(SERVAL_BASE)mdp_net.c \ + $(SERVAL_BASE)msp_client.c \ + $(SERVAL_BASE)msp_proxy.c \ $(SERVAL_BASE)os.c \ $(SERVAL_BASE)mem.c \ $(SERVAL_BASE)instance.c \ diff --git a/tests/msp b/tests/msp new file mode 100755 index 00000000..fd106c7b --- /dev/null +++ b/tests/msp @@ -0,0 +1,60 @@ +#!/bin/bash + +# Tests for stream connections +# +# Copyright 2012 Serval Project, Inc. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + +source "${0%/*}/../testframework.sh" +source "${0%/*}/../testdefs.sh" + +teardown() { + stop_all_servald_servers + kill_all_servald_processes + assert_no_servald_processes + report_all_servald_servers +} + +doc_hello="Simple Hello World" +setup_hello() { + setup_servald + assert_no_servald_processes + foreach_instance +A +B create_single_identity + foreach_instance +A +B \ + executeOk_servald config \ + set debug.mdprequests on \ + set log.console.level DEBUG \ + set log.console.show_time on + start_servald_instances +A +B + set_instance +A +} +test_hello() { + fork executeOk_servald --timeout=5 msp listen 512 < Date: Thu, 5 Dec 2013 11:25:47 +1030 Subject: [PATCH 02/18] Improve msp failure handling --- msp_client.c | 186 +++++++++++++++++++++++++++++++-------------------- msp_client.h | 7 +- msp_proxy.c | 15 +++-- tests/msp | 16 +++-- 4 files changed, 135 insertions(+), 89 deletions(-) diff --git a/msp_client.c b/msp_client.c index f5f36874..dfda78cc 100644 --- a/msp_client.c +++ b/msp_client.c @@ -9,6 +9,7 @@ #include "log.h" #define FLAG_SHUTDOWN (1<<0) +#define FLAG_ACK (1<<1) struct msp_packet{ struct msp_packet *_next; @@ -26,6 +27,7 @@ struct msp_window{ uint32_t base_rtt; uint32_t rtt; uint16_t next_seq; // seq of next expected TX or RX packet. + time_ms_t last_activity; struct msp_packet *_head, *_tail; }; @@ -40,7 +42,6 @@ struct msp_sock{ int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context); void *context; struct mdp_header header; - time_ms_t last_rx; time_ms_t timeout; time_ms_t next_action; }; @@ -55,6 +56,9 @@ struct msp_sock * msp_socket(int mdp_sock) ret->_next = root; // TODO set base rtt to ensure that we send the first packet a few times before giving up ret->tx.base_rtt = ret->tx.rtt = 0xFFFFFFFF; + ret->tx.last_activity = TIME_NEVER_HAS; + ret->rx.last_activity = TIME_NEVER_HAS; + ret->timeout = gettime_ms() + 10000; if (root) root->_prev=ret; root = ret; @@ -118,6 +122,18 @@ void msp_close(struct msp_sock *sock) free(sock); } +void msp_close_all(int mdp_sock) +{ + struct msp_sock **p = &root; + while(*p){ + if ((*p)->mdp_sock == mdp_sock){ + msp_close(*p); + }else{ + p=&(*p)->_next; + } + } +} + int msp_set_handler(struct msp_sock *sock, int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context), void *context) @@ -161,8 +177,14 @@ int msp_listen(struct msp_sock *sock) sock->state |= MSP_STATE_LISTENING; sock->header.flags |= MDP_FLAG_BIND; - mdp_send(sock->mdp_sock, &sock->header, NULL, 0); + if (mdp_send(sock->mdp_sock, &sock->header, NULL, 0)==-1){ + sock->state|=MSP_STATE_ERROR; + msp_close(sock); + return -1; + } + + sock->timeout = TIME_NEVER_WILL; return 0; } @@ -241,6 +263,11 @@ static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet) uint8_t msp_header[5]; msp_header[0]=packet->flags; + + // only set the ack flag if we've received a sequenced packet + if (sock->state & MSP_STATE_RECEIVED_DATA) + msp_header[0]|=FLAG_ACK; + write_uint16(&msp_header[1], sock->rx.next_seq); write_uint16(&msp_header[3], packet->seq); sock->previous_ack = sock->rx.next_seq; @@ -269,17 +296,16 @@ static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet) data.fragment_count --; ssize_t r = send_message(sock->mdp_sock, &daemon_addr, &data); - if (r==-1) + if (r==-1){ + msp_close_all(sock->mdp_sock); return -1; - packet->sent = gettime_ms(); - if (!sock->timeout) - sock->timeout = packet->sent + 10000; + } + sock->tx.last_activity = packet->sent = gettime_ms(); return 0; } static int send_ack(struct msp_sock *sock) { - D; if (daemon_addr.addrlen == 0){ if (make_local_sockaddr(&daemon_addr, "mdp.2.socket") == -1) return -1; @@ -288,6 +314,11 @@ static int send_ack(struct msp_sock *sock) uint8_t msp_header[3]; msp_header[0]=0; + // if we haven't heard a sequence number, we can't ack data + // (but we can indicate the existence of the connection) + if (sock->state & MSP_STATE_RECEIVED_DATA) + msp_header[0]|=FLAG_ACK; + write_uint16(&msp_header[1], sock->rx.next_seq); sock->previous_ack = sock->rx.next_seq; @@ -306,7 +337,12 @@ static int send_ack(struct msp_sock *sock) }; ssize_t r = send_message(sock->mdp_sock, &daemon_addr, &data); - return r<0?-1:0; + if (r==-1){ + msp_close_all(sock->mdp_sock); + return -1; + } + sock->tx.last_activity = gettime_ms(); + return 0; } // add a packet to the transmit buffer @@ -347,7 +383,7 @@ static int process_sock(struct msp_sock *sock) { time_ms_t now = gettime_ms(); - if (sock->timeout && sock->timeout < now){ + if (sock->timeout < now){ msp_close(sock); return -1; } @@ -383,14 +419,11 @@ static int process_sock(struct msp_sock *sock) p = sock->tx._head; while(p){ if (p->sent==0 || p->sent + sock->tx.rtt*2 < now){ - - if (!(sock->state & (MSP_STATE_CONNECTING|MSP_STATE_CONNECTED))){ - sock->state |= MSP_STATE_CONNECTING; + if (!sock->header.local.port){ + if (sock->header.flags & MDP_FLAG_BIND) + // wait until we have heard back from the daemon with our port number before sending another packet. + break; sock->header.flags |= MDP_FLAG_BIND; - - }else if (!sock->header.local.port){ - // wait until we have heard back from the daemon with our port number before sending another packet. - break; } if (msp_send_packet(sock, p)==-1) return -1; @@ -437,82 +470,89 @@ int msp_processing(time_ms_t *next_action) return 0; } -static struct msp_sock * find_connection(int mdp_sock, struct mdp_header *header) -{ - struct msp_sock *s=root; - struct msp_sock *listen=NULL; - while(s){ - if (s->mdp_sock == mdp_sock ){ - if ((s->header.flags & MDP_FLAG_BIND) && (header->flags & MDP_FLAG_BIND)){ - // bind response from the daemon - s->header.local = header->local; - s->header.flags &= ~MDP_FLAG_BIND; - DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(header->local.sid), header->local.port); - return NULL; - } - - if (s->state & MSP_STATE_LISTENING){ - // remember any matching listen socket so we can create a connection on first use - if (s->header.local.port == header->local.port - && (is_sid_t_any(s->header.local.sid) - || memcmp(&s->header.local.sid, &header->local.sid, SID_SIZE)==0)) - listen=s; - }else if (memcmp(&s->header.remote, &header->remote, sizeof header->remote)==0 - && memcmp(&s->header.local, &header->local, sizeof header->local)==0){ - // if the addresses match, we found it. - return s; - } - } - s = s->_next; - } - - if (listen){ - // create socket for incoming connection - s = msp_socket(listen->mdp_sock); - s->header = *header; - // use the same handler initially - s->handler = listen->handler; - s->context = listen->context; - return s; - } - - WARNF("Unexpected packet from %s:%d", alloca_tohex_sid_t(header->remote.sid), header->remote.port); - return NULL; -} - static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t *payload, size_t len) { DEBUGF("packet from %s:%d", alloca_tohex_sid_t(header->remote.sid), header->remote.port); - // find or create mdp_sock... - struct msp_sock *sock=find_connection(mdp_sock, header); - - if (!sock) + + // any kind of error reported by the daemon, close all related msp connections + if (header->flags & MDP_FLAG_ERROR){ + msp_close_all(mdp_sock); return 0; + } + + // find or create mdp_sock... + struct msp_sock *sock=NULL; + { + struct msp_sock *s=root; + struct msp_sock *listen=NULL; + while(s){ + if (s->mdp_sock == mdp_sock ){ + + if ((s->header.flags & MDP_FLAG_BIND) && (header->flags & MDP_FLAG_BIND)){ + // process bind response from the daemon + s->header.local = header->local; + s->header.flags &= ~MDP_FLAG_BIND; + DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(header->local.sid), header->local.port); + return 0; + } + + if (s->state & MSP_STATE_LISTENING){ + // remember any matching listen socket so we can create a connection on first use + if (s->header.local.port == header->local.port + && (is_sid_t_any(s->header.local.sid) + || memcmp(&s->header.local.sid, &header->local.sid, SID_SIZE)==0)) + listen=s; + }else if (memcmp(&s->header.remote, &header->remote, sizeof header->remote)==0 + && memcmp(&s->header.local, &header->local, sizeof header->local)==0){ + // if the addresses match, we found it. + sock=s; + break; + } + } + s = s->_next; + } + + if (listen && !sock){ + // create a new socket for the incoming connection + sock = msp_socket(listen->mdp_sock); + sock->header = *header; + // use the same handler initially + sock->handler = listen->handler; + sock->context = listen->context; + } + + if (!sock){ + WARNF("Unexpected packet from %s:%d", alloca_tohex_sid_t(header->remote.sid), header->remote.port); + // TODO reply with shutdown ack to forcefully break the connection? + return 0; + } + } if (len<3) return WHY("Expected at least 3 bytes"); - sock->state |= MSP_STATE_CONNECTED; - sock->last_rx = gettime_ms(); - sock->timeout = sock->last_rx + 10000; + sock->rx.last_activity = gettime_ms(); + sock->timeout = sock->rx.last_activity + 10000; uint8_t flags = payload[0]; - uint16_t ack_seq = read_uint16(&payload[1]); - - // release acknowledged packets - free_acked_packets(&sock->tx, ack_seq); - - // TODO if their ack seq has not advanced, we may need to hurry up and retransmit a packet - + if (flags & FLAG_ACK){ + uint16_t ack_seq = read_uint16(&payload[1]); + // release acknowledged packets + free_acked_packets(&sock->tx, ack_seq); + // TODO if their ack seq has not advanced, we may need to hurry up and retransmit a packet + } // make sure we attempt to process packets from this sock soon // TODO calculate based on congestion window + sock->state |= MSP_STATE_RECEIVED_PACKET; + sock->next_action = gettime_ms(); if (len<5) return 0; + sock->state |= MSP_STATE_RECEIVED_DATA; uint16_t seq = read_uint16(&payload[3]); add_packet(&sock->rx, seq, flags, &payload[5], len - 5); diff --git a/msp_client.h b/msp_client.h index 56ff6589..40750f3b 100644 --- a/msp_client.h +++ b/msp_client.h @@ -4,8 +4,8 @@ #define MSP_STATE_UNINITIALISED 0 #define MSP_STATE_LISTENING (1<<0) -#define MSP_STATE_CONNECTING (1<<1) -#define MSP_STATE_CONNECTED (1<<2) +#define MSP_STATE_RECEIVED_DATA (1<<1) +#define MSP_STATE_RECEIVED_PACKET (1<<2) #define MSP_STATE_SHUTDOWN_LOCAL (1<<3) #define MSP_STATE_SHUTDOWN_REMOTE (1<<4) @@ -13,7 +13,7 @@ // this connection is about to be free'd, release any other resources or references to the state #define MSP_STATE_CLOSED (1<<5) -// something has gone wrong somewhere and the connection will be closed +// something has gone wrong somewhere #define MSP_STATE_ERROR (1<<6) // does the client want to be interupted to reading data? @@ -33,6 +33,7 @@ typedef uint16_t msp_state_t; // allocate a new socket struct msp_sock * msp_socket(int mdp_sock); void msp_close(struct msp_sock *sock); +void msp_close_all(int mdp_sock); int msp_set_handler(struct msp_sock *sock, int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context), diff --git a/msp_proxy.c b/msp_proxy.c index 5fc51ab9..e1a20429 100644 --- a/msp_proxy.c +++ b/msp_proxy.c @@ -152,7 +152,7 @@ static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t if (payload) return msp_handler(sock, state, payload, len, conn); - // stop listening after an incoming connection + // stop listening after the first incoming connection msp_close(listener); return 0; @@ -315,7 +315,7 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS if (sidhex && *sidhex){ stdio_connection = alloc_connection(); if (!stdio_connection) - return -1; + goto end; stdio_connection->sock = sock; msp_set_handler(sock, msp_handler, stdio_connection); msp_set_remote(sock, addr); @@ -327,11 +327,14 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS }else{ msp_set_handler(sock, msp_listener, NULL); msp_set_local(sock, addr); - msp_listen(sock); + + // sock will be closed if listen fails + if (msp_listen(sock)==-1) + goto end; + listener=sock; INFOF(" - Listening on port %d", addr.port); } - sock=NULL; while(fd_poll()){ ; @@ -339,9 +342,9 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS ret=0; end: - if (sock) - msp_close(sock); + listener=NULL; if (mdp_sock.poll.fd>=0){ + msp_close_all(mdp_sock.poll.fd); if (mdp_sock.poll.events){ unwatch(&mdp_sock); INFOF("Unwatching mdp socket"); diff --git a/tests/msp b/tests/msp index fd106c7b..cc77fbd3 100755 --- a/tests/msp +++ b/tests/msp @@ -40,21 +40,23 @@ setup_hello() { set log.console.level DEBUG \ set log.console.show_time on start_servald_instances +A +B - set_instance +A } -test_hello() { - fork executeOk_servald --timeout=5 msp listen 512 < Date: Thu, 5 Dec 2013 16:37:19 +1030 Subject: [PATCH 03/18] Pipe file contents across msp connection --- msp_client.c | 183 +++++++++++++++++++++++++++++++------------------- msp_client.h | 12 +--- msp_proxy.c | 119 +++++++++++++++++--------------- overlay_mdp.c | 3 +- tests/msp | 62 ++++++++++++++++- 5 files changed, 240 insertions(+), 139 deletions(-) diff --git a/msp_client.c b/msp_client.c index dfda78cc..1902f9be 100644 --- a/msp_client.c +++ b/msp_client.c @@ -21,7 +21,7 @@ struct msp_packet{ size_t len; }; -#define MAX_WINDOW_SIZE 64 +#define MAX_WINDOW_SIZE 4 struct msp_window{ int packet_count; uint32_t base_rtt; @@ -58,7 +58,9 @@ struct msp_sock * msp_socket(int mdp_sock) ret->tx.base_rtt = ret->tx.rtt = 0xFFFFFFFF; ret->tx.last_activity = TIME_NEVER_HAS; ret->rx.last_activity = TIME_NEVER_HAS; + ret->next_action = TIME_NEVER_WILL; ret->timeout = gettime_ms() + 10000; + ret->previous_ack = 0xFFFF; if (root) root->_prev=ret; root = ret; @@ -71,14 +73,19 @@ static void free_all_packets(struct msp_window *window) while(p){ struct msp_packet *free_me=p; p=p->_next; - free((void *)free_me->payload); + if (free_me->payload) + free((void *)free_me->payload); free(free_me); } } static void free_acked_packets(struct msp_window *window, uint16_t seq) { + if (!window->_head) + return; + struct msp_packet *p = window->_head; + uint32_t rtt=0; time_ms_t now = gettime_ms(); @@ -87,7 +94,8 @@ static void free_acked_packets(struct msp_window *window, uint16_t seq) rtt = now - p->sent; struct msp_packet *free_me=p; p=p->_next; - free((void *)free_me->payload); + if (free_me->payload) + free((void *)free_me->payload); free(free_me); window->packet_count--; } @@ -96,12 +104,13 @@ static void free_acked_packets(struct msp_window *window, uint16_t seq) window->rtt = rtt; if (window->base_rtt > rtt) window->base_rtt = rtt; + DEBUGF("RTT %u, base %u", rtt, window->base_rtt); } if (!p) window->_tail = NULL; } -void msp_close(struct msp_sock *sock) +static void msp_free(struct msp_sock *sock) { sock->state |= MSP_STATE_CLOSED; @@ -115,22 +124,26 @@ void msp_close(struct msp_sock *sock) root=sock->_next; if (sock->_next) sock->_next->_prev = sock->_prev; - + free_all_packets(&sock->tx); free_all_packets(&sock->rx); free(sock); } +void msp_close(struct msp_sock *sock) +{ + sock->state |= MSP_STATE_CLOSED; +} + void msp_close_all(int mdp_sock) { - struct msp_sock **p = &root; - while(*p){ - if ((*p)->mdp_sock == mdp_sock){ - msp_close(*p); - }else{ - p=&(*p)->_next; - } + struct msp_sock *p = root; + while(p){ + struct msp_sock *sock=p; + p=p->_next; + if (sock->mdp_sock == mdp_sock) + msp_free(sock); } } @@ -148,14 +161,6 @@ msp_state_t msp_get_state(struct msp_sock *sock) return sock->state; } -void msp_set_watch(struct msp_sock *sock, msp_state_t flags) -{ - assert(flags & ~(MSP_STATE_POLLIN|MSP_STATE_POLLOUT)); - // clear any existing poll bits, and set the requested ones - sock->state &= ~(MSP_STATE_POLLIN|MSP_STATE_POLLOUT); - sock->state |= flags; -} - int msp_set_local(struct msp_sock *sock, struct mdp_sockaddr local) { assert(sock->state == MSP_STATE_UNINITIALISED); @@ -167,6 +172,9 @@ int msp_set_remote(struct msp_sock *sock, struct mdp_sockaddr remote) { assert(sock->state == MSP_STATE_UNINITIALISED); sock->header.remote = remote; + sock->state|=MSP_STATE_DATAOUT; + // make sure we send a packet soon + sock->next_action = gettime_ms()+10; return 0; } @@ -179,8 +187,7 @@ int msp_listen(struct msp_sock *sock) sock->header.flags |= MDP_FLAG_BIND; if (mdp_send(sock->mdp_sock, &sock->header, NULL, 0)==-1){ - sock->state|=MSP_STATE_ERROR; - msp_close(sock); + sock->state|=MSP_STATE_ERROR|MSP_STATE_CLOSED; return -1; } @@ -197,42 +204,40 @@ int msp_get_remote_adr(struct msp_sock *sock, struct mdp_sockaddr *remote) static int add_packet(struct msp_window *window, uint16_t seq, uint8_t flags, const uint8_t *payload, size_t len) { - struct msp_packet *packet = emalloc_zero(sizeof(struct msp_packet)); - if (!packet) - return -1; + + struct msp_packet **insert_pos=NULL; if (!window->_head){ - window->_head = window->_tail = packet; + insert_pos = &window->_head; }else{ if (window->_tail->seq == seq){ // ignore duplicate packets - free(packet); return 0; }else if (compare_wrapped_uint16(window->_tail->seq, seq)<0){ if (compare_wrapped_uint16(window->_head->seq, seq)>0){ // this is ambiguous - free(packet); return WHYF("%04x is both < tail (%04x) and > head (%04x)", seq, window->_tail->seq, window->_head->seq); } - - window->_tail->_next = packet; - window->_tail = packet; + insert_pos = &window->_tail->_next; }else{ - struct msp_packet **pos = &window->_head; - while(compare_wrapped_uint16((*pos)->seq, seq)<0){ - if ((*pos)->seq == seq){ - // ignore duplicate packets - free(packet); - return 0; - } - pos = &(*pos)->_next; + insert_pos = &window->_head; + while(compare_wrapped_uint16((*insert_pos)->seq, seq)<0) + insert_pos = &(*insert_pos)->_next; + if ((*insert_pos)->seq == seq){ + // ignore duplicate packets + return 0; } - (*pos)->_next = packet; - packet->_next = (*pos); - *pos = packet; } } + struct msp_packet *packet = emalloc_zero(sizeof(struct msp_packet)); + if (!packet) + return -1; + + packet->_next = (*insert_pos); + *insert_pos = packet; + if (!packet->_next) + window->_tail = packet; packet->added = gettime_ms(); packet->seq = seq; packet->flags = flags; @@ -272,7 +277,6 @@ static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet) write_uint16(&msp_header[3], packet->seq); sock->previous_ack = sock->rx.next_seq; - DEBUGF("Sending packet flags %d, ack %d, seq %d", packet->flags, sock->rx.next_seq, packet->seq); struct fragmented_data data={ .fragment_count=3, .iov={ @@ -297,9 +301,12 @@ static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet) ssize_t r = send_message(sock->mdp_sock, &daemon_addr, &data); if (r==-1){ + if (errno==11) + return 1; msp_close_all(sock->mdp_sock); return -1; } + DEBUGF("Sent packet seq %02x len %zd (acked %02x)", packet->seq, packet->len, sock->rx.next_seq); sock->tx.last_activity = packet->sent = gettime_ms(); return 0; } @@ -338,9 +345,11 @@ static int send_ack(struct msp_sock *sock) ssize_t r = send_message(sock->mdp_sock, &daemon_addr, &data); if (r==-1){ - msp_close_all(sock->mdp_sock); + if (errno!=11) + msp_close_all(sock->mdp_sock); return -1; } + DEBUGF("Sent packet (acked %02x)", sock->rx.next_seq); sock->tx.last_activity = gettime_ms(); return 0; } @@ -358,7 +367,8 @@ int msp_send(struct msp_sock *sock, const uint8_t *payload, size_t len) return -1; sock->tx.next_seq++; - + if (sock->tx.packet_count>=MAX_WINDOW_SIZE) + sock->state&=~MSP_STATE_DATAOUT; // make sure we attempt to process packets from this sock soon // TODO calculate based on congestion window sock->next_action = gettime_ms(); @@ -376,6 +386,9 @@ int msp_shutdown(struct msp_sock *sock) sock->tx.next_seq++; } sock->state|=MSP_STATE_SHUTDOWN_LOCAL; + sock->state&=~MSP_STATE_DATAOUT; + // make sure we send a packet soon + sock->next_action = gettime_ms(); return 0; } @@ -384,17 +397,16 @@ static int process_sock(struct msp_sock *sock) time_ms_t now = gettime_ms(); if (sock->timeout < now){ - msp_close(sock); + sock->state |= MSP_STATE_CLOSED; return -1; } sock->next_action = sock->timeout; + struct msp_packet *p; // deliver packets that have now arrived in order p = sock->rx._head; - if (p) - DEBUGF("Seq %d vs %d", p->seq, sock->rx.next_seq); // TODO ... ? (sock->state & MSP_STATE_POLLIN) while(p && p->seq == sock->rx.next_seq){ @@ -404,10 +416,17 @@ static int process_sock(struct msp_sock *sock) if (packet->flags & FLAG_SHUTDOWN) sock->state|=MSP_STATE_SHUTDOWN_REMOTE; - if (sock->handler - && sock->handler(sock, sock->state, packet->payload, packet->len, sock->context)==-1){ + if (sock->handler && packet->payload){ + int r = sock->handler(sock, sock->state, packet->payload, packet->len, sock->context); + if (r==-1){ + sock->state |= MSP_STATE_CLOSED; + return -1; + } // keep the packet if the handler refused to accept it. - break; + if (r){ + sock->next_action=gettime_ms()+1; + break; + } } p=p->_next; @@ -418,31 +437,42 @@ static int process_sock(struct msp_sock *sock) // transmit packets that can now be sent p = sock->tx._head; while(p){ - if (p->sent==0 || p->sent + sock->tx.rtt*2 < now){ + if (p->sent==0 || p->sent + 1500 < now){ if (!sock->header.local.port){ if (sock->header.flags & MDP_FLAG_BIND) // wait until we have heard back from the daemon with our port number before sending another packet. break; sock->header.flags |= MDP_FLAG_BIND; } - if (msp_send_packet(sock, p)==-1) + int r = msp_send_packet(sock, p); + if (r==-1) return -1; + if (r) + break; } - if (sock->next_action > p->sent + sock->tx.rtt*2) - sock->next_action = p->sent + sock->tx.rtt*2; + if (sock->next_action > p->sent + 1500) + sock->next_action = p->sent + 1500; p=p->_next; } + time_ms_t next_packet = sock->tx.last_activity + sock->tx.rtt*2; + // should we send an ack now without sending a payload? - if (sock->previous_ack != sock->rx.next_seq){ - if (send_ack(sock)) + if (sock->previous_ack != sock->rx.next_seq || now > next_packet){ + int r = send_ack(sock); + if (r==-1) return -1; + next_packet = sock->tx.last_activity + sock->tx.rtt*2; } - if ((sock->state & (MSP_STATE_SHUTDOWN_LOCAL|MSP_STATE_SHUTDOWN_REMOTE)) == (MSP_STATE_SHUTDOWN_LOCAL|MSP_STATE_SHUTDOWN_REMOTE) + if (sock->next_action > next_packet) + sock->next_action = next_packet; + + if (sock->state & MSP_STATE_SHUTDOWN_LOCAL + && sock->state & MSP_STATE_SHUTDOWN_REMOTE && sock->tx.packet_count == 0 && sock->rx.packet_count == 0){ - msp_close(sock); + sock->state |= MSP_STATE_CLOSED; return -1; } @@ -451,33 +481,36 @@ static int process_sock(struct msp_sock *sock) int msp_processing(time_ms_t *next_action) { - *next_action=0; + *next_action=TIME_NEVER_WILL; struct msp_sock *sock = root; time_ms_t now = gettime_ms(); while(sock){ - struct msp_sock *s=sock; - sock = s->_next; - - if (s->next_action && s->next_action <= now){ + if (!(sock->state & MSP_STATE_CLOSED) + && sock->next_action <= now){ // this might cause the socket to be closed. - if (process_sock(s)==0){ + if (process_sock(sock)==0){ // remember the time of the next thing we need to do. - if (s->next_action!=0 && s->next_action < *next_action) - *next_action=s->next_action; + if (sock->next_action < *next_action) + *next_action=sock->next_action; } } + if (sock->state & MSP_STATE_CLOSED){ + struct msp_sock *s = sock->_next; + msp_free(sock); + sock=s; + }else{ + sock = sock->_next; + } } return 0; } static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t *payload, size_t len) { - DEBUGF("packet from %s:%d", alloca_tohex_sid_t(header->remote.sid), header->remote.port); - // any kind of error reported by the daemon, close all related msp connections if (header->flags & MDP_FLAG_ERROR){ msp_close_all(mdp_sock); - return 0; + return -1; } // find or create mdp_sock... @@ -493,6 +526,7 @@ static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t s->header.local = header->local; s->header.flags &= ~MDP_FLAG_BIND; DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(header->local.sid), header->local.port); + s->next_action = gettime_ms(); return 0; } @@ -540,9 +574,18 @@ static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t uint16_t ack_seq = read_uint16(&payload[1]); // release acknowledged packets free_acked_packets(&sock->tx, ack_seq); + // TODO if their ack seq has not advanced, we may need to hurry up and retransmit a packet } + if (sock->tx.packet_count < MAX_WINDOW_SIZE + && !(sock->state & MSP_STATE_DATAOUT) + && !(sock->state & MSP_STATE_SHUTDOWN_LOCAL)){ + sock->state|=MSP_STATE_DATAOUT; + if (sock->handler) + sock->handler(sock, sock->state, NULL, 0, sock->context); + } + // make sure we attempt to process packets from this sock soon // TODO calculate based on congestion window sock->state |= MSP_STATE_RECEIVED_PACKET; diff --git a/msp_client.h b/msp_client.h index 40750f3b..bf68d284 100644 --- a/msp_client.h +++ b/msp_client.h @@ -16,15 +16,8 @@ // something has gone wrong somewhere #define MSP_STATE_ERROR (1<<6) -// does the client want to be interupted to reading data? -#define MSP_STATE_POLLIN (1<<7) -// does the client want to know when data can be written? -#define MSP_STATE_POLLOUT (1<<8) - -// is there some data to read? -#define MSP_STATE_DATAIN (1<<9) // is there space for sending more data? -#define MSP_STATE_DATAOUT (1<<10) +#define MSP_STATE_DATAOUT (1<<7) struct msp_sock; @@ -48,9 +41,6 @@ int msp_listen(struct msp_sock *sock); int msp_get_remote_adr(struct msp_sock *sock, struct mdp_sockaddr *remote); msp_state_t msp_get_state(struct msp_sock *sock); -// which events are you interested in handling? -void msp_set_watch(struct msp_sock *sock, msp_state_t flags); - // bind, send data, and potentially shutdown this end of the connection int msp_send(struct msp_sock *sock, const uint8_t *payload, size_t len); int msp_shutdown(struct msp_sock *sock); diff --git a/msp_proxy.c b/msp_proxy.c index e1a20429..bd98f976 100644 --- a/msp_proxy.c +++ b/msp_proxy.c @@ -21,6 +21,7 @@ struct connection{ struct connection *stdio_connection=NULL; struct msp_sock *listener=NULL; +static int try_send(); static void msp_poll(struct sched_ent *alarm); static void stdin_poll(struct sched_ent *alarm); static void stdout_poll(struct sched_ent *alarm); @@ -85,20 +86,24 @@ static void free_connection(struct connection *conn) static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context) { struct connection *conn = context; - DEBUGF("Handler, state %d, payload len %zd", state, len); if (payload && len){ - dump("incoming payload", payload, len); - if (conn->out->capacity < len + conn->out->limit){ - DEBUGF("Insufficient space len %zd, capacity %zd, limit %zd", len, conn->out->capacity, conn->out->limit); - return -1; - } - if (conn->out->limit==0){ - watch(&stdout_alarm); - INFOF("Watching stdout"); + if (conn->out->limit){ + // attempt to write immediately + stdout_alarm.poll.revents=POLLOUT; + stdout_poll(&stdout_alarm); } + if (conn->out->capacity < len + conn->out->limit) + return 1; + bcopy(payload, &conn->out->bytes[conn->out->limit], len); conn->out->limit+=len; + // attempt to write immediately + if (!is_watching(&stdout_alarm)) + watch(&stdout_alarm); + + stdout_alarm.poll.revents=POLLOUT; + stdout_poll(&stdout_alarm); } if (state & MSP_STATE_CLOSED){ @@ -106,35 +111,31 @@ static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t * msp_get_remote_adr(sock, &remote); INFOF(" - Connection with %s:%d closed", alloca_tohex_sid_t(remote.sid), remote.port); - if (conn == stdio_connection){ - stdio_connection->sock=NULL; - }else{ + conn->sock = NULL; + + if (conn != stdio_connection) free_connection(conn); - } unschedule(&mdp_sock); - if (mdp_sock.poll.events){ + if (is_watching(&mdp_sock)) unwatch(&mdp_sock); - mdp_sock.poll.events=0; - INFOF("Unwatching mdp socket"); - } - mdp_close(mdp_sock.poll.fd); - mdp_sock.poll.fd=-1; return 0; } - if (state & MSP_STATE_SHUTDOWN_REMOTE){ - struct mdp_sockaddr remote; - msp_get_remote_adr(sock, &remote); - INFOF(" - Connection with %s:%d remote shutdown", alloca_tohex_sid_t(remote.sid), remote.port); + if (state&MSP_STATE_DATAOUT){ + try_send(); + if (stdio_connection->in->limitin->capacity && !is_watching(&stdin_alarm)) + watch(&stdin_alarm); } - return 0; } static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *UNUSED(context)) { + if (state & MSP_STATE_CLOSED) + return 0; + struct mdp_sockaddr remote; msp_get_remote_adr(sock, &remote); INFOF(" - New connection from %s:%d", alloca_tohex_sid_t(remote.sid), remote.port); @@ -146,7 +147,6 @@ static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t if (!stdio_connection){ stdio_connection=conn; watch(&stdin_alarm); - INFOF("Watching stdin"); } msp_set_handler(sock, msp_handler, conn); if (payload) @@ -176,13 +176,24 @@ static void msp_poll(struct sched_ent *alarm) } } +static int try_send() +{ + if (!stdio_connection->in->limit) + return 0; + if (msp_send(stdio_connection->sock, stdio_connection->in->bytes, stdio_connection->in->limit)==-1) + return 0; + + // if this packet was acceptted, clear the read buffer + stdio_connection->in->limit = stdio_connection->in->position = 0; + + return 1; +} + static void stdin_poll(struct sched_ent *alarm) { - INFOF("Poll stdin, %d", alarm->poll.revents); if (alarm->poll.revents & POLLIN) { if (!stdio_connection){ unwatch(alarm); - INFOF("Unwatching stdin"); return; } @@ -191,30 +202,25 @@ static void stdin_poll(struct sched_ent *alarm) ssize_t r = read(alarm->poll.fd, stdio_connection->in->bytes + stdio_connection->in->limit, remaining); - INFOF("Read %zd from stdin %d, %d", r, alarm->poll.revents, errno); if (r>0){ - dump("stdin",stdio_connection->in->bytes + stdio_connection->in->limit, r); - stdio_connection->in->limit+=r; - - if (msp_send(stdio_connection->sock, stdio_connection->in->bytes, stdio_connection->in->limit)!=-1){ - // if this packet was acceptted, clear the read buffer - stdio_connection->in->limit = stdio_connection->in->position = 0; + if (try_send()){ // attempt to process this socket asap mdp_sock.alarm = gettime_ms(); mdp_sock.deadline = mdp_sock.alarm+10; unschedule(&mdp_sock); schedule(&mdp_sock); } - // stop reading input when the buffer is full if (stdio_connection->in->limit==stdio_connection->in->capacity){ unwatch(alarm); - INFOF("Unwatching stdin"); } }else{ - // EOF, just trigger our error handler - alarm->poll.revents|=POLLERR; + if (stdio_connection->in->limit) + unwatch(alarm); + else + // EOF and no data in the buffer, just trigger our error handler + alarm->poll.revents|=POLLERR; } } } @@ -224,7 +230,8 @@ static void stdin_poll(struct sched_ent *alarm) struct mdp_sockaddr remote; msp_get_remote_adr(stdio_connection->sock, &remote); msp_shutdown(stdio_connection->sock); - unwatch(alarm); + if (is_watching(alarm)) + unwatch(alarm); INFOF(" - Connection with %s:%d local shutdown", alloca_tohex_sid_t(remote.sid), remote.port); // attempt to process this socket asap mdp_sock.alarm = gettime_ms(); @@ -238,8 +245,8 @@ static void stdout_poll(struct sched_ent *alarm) { if (alarm->poll.revents & POLLOUT) { if (!stdio_connection){ - unwatch(alarm); - INFOF("Unwatching stdout"); + if (is_watching(alarm)) + unwatch(alarm); return; } // try to write some data @@ -248,7 +255,6 @@ static void stdout_poll(struct sched_ent *alarm) ssize_t r = write(alarm->poll.fd, stdio_connection->out->bytes+stdio_connection->out->position, data); - INFOF("Wrote %zd to stdout", r); if (r > 0) stdio_connection->out->position+=r; } @@ -257,19 +263,22 @@ static void stdout_poll(struct sched_ent *alarm) if (stdio_connection->out->position==stdio_connection->out->limit){ stdio_connection->out->limit=0; stdio_connection->out->position=0; - unwatch(alarm); - INFOF("Unwatching stdout"); + if (is_watching(alarm)) + unwatch(alarm); } if (stdio_connection->out->limit < stdio_connection->out->capacity){ - // TODO try to get more data from the socket + // make sure we try to process this socket soon for more data + mdp_sock.alarm = gettime_ms(); + mdp_sock.deadline = mdp_sock.alarm+10; + unschedule(&mdp_sock); + schedule(&mdp_sock); } } if (alarm->poll.revents & (POLLHUP | POLLERR)) { - unwatch(alarm); - INFOF("Unwatching stdout"); - // Um, quit? + if (is_watching(alarm)) + unwatch(alarm); } } @@ -300,7 +309,6 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS goto end; mdp_sock.poll.events = POLLIN; watch(&mdp_sock); - INFOF("Watching mdp socket"); set_nonblock(STDIN_FILENO); set_nonblock(STDOUT_FILENO); @@ -319,11 +327,10 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS stdio_connection->sock = sock; msp_set_handler(sock, msp_handler, stdio_connection); msp_set_remote(sock, addr); - INFOF("Set remote %s:%d", alloca_tohex_sid_t(addr.sid), addr.port); + INFOF("- Connecting to %s:%d", alloca_tohex_sid_t(addr.sid), addr.port); // note we only watch these stdio handles when we have space / bytes in our buffers watch(&stdin_alarm); - INFOF("Watching stdin"); }else{ msp_set_handler(sock, msp_listener, NULL); msp_set_local(sock, addr); @@ -336,6 +343,10 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS INFOF(" - Listening on port %d", addr.port); } + // run msp_processing once to init alarm timer + mdp_sock.poll.revents=0; + msp_poll(&mdp_sock); + while(fd_poll()){ ; } @@ -343,12 +354,10 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS end: listener=NULL; + if (is_watching(&mdp_sock)) + unwatch(&mdp_sock); if (mdp_sock.poll.fd>=0){ msp_close_all(mdp_sock.poll.fd); - if (mdp_sock.poll.events){ - unwatch(&mdp_sock); - INFOF("Unwatching mdp socket"); - } mdp_close(mdp_sock.poll.fd); } unschedule(&mdp_sock); diff --git a/overlay_mdp.c b/overlay_mdp.c index b0624e42..299e976c 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -784,7 +784,8 @@ static int overlay_send_frame( } if (config.debug.mdprequests) { DEBUGF("Send frame %zu bytes", ob_position(plaintext)); - dump("Frame plaintext", ob_ptr(plaintext), ob_position(plaintext)); + if (config.debug.verbose) + dump("Frame plaintext", ob_ptr(plaintext), ob_position(plaintext)); } /* Work out the disposition of the frame-> For now we are only worried diff --git a/tests/msp b/tests/msp index cc77fbd3..8df12950 100755 --- a/tests/msp +++ b/tests/msp @@ -42,7 +42,7 @@ setup_hello() { start_servald_instances +A +B } server_hello() { - executeOk_servald --timeout=5 msp listen 512 < Date: Mon, 9 Dec 2013 11:21:26 +1030 Subject: [PATCH 04/18] Test connection keep alive and timeouts --- msp_client.c | 32 ++++++++++++++++++++------------ msp_proxy.c | 8 +++++++- tests/msp | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 76 insertions(+), 13 deletions(-) diff --git a/msp_client.c b/msp_client.c index 1902f9be..bb95f091 100644 --- a/msp_client.c +++ b/msp_client.c @@ -39,6 +39,7 @@ struct msp_sock{ struct msp_window tx; struct msp_window rx; uint16_t previous_ack; + time_ms_t next_ack; int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context); void *context; struct mdp_header header; @@ -60,7 +61,7 @@ struct msp_sock * msp_socket(int mdp_sock) ret->rx.last_activity = TIME_NEVER_HAS; ret->next_action = TIME_NEVER_WILL; ret->timeout = gettime_ms() + 10000; - ret->previous_ack = 0xFFFF; + ret->previous_ack = 0x7FFF; if (root) root->_prev=ret; root = ret; @@ -253,13 +254,14 @@ static int add_packet(struct msp_window *window, uint16_t seq, uint8_t flags, bcopy(payload, p, len); } window->packet_count++; - return 0; + return 1; } struct socket_address daemon_addr={.addrlen=0,}; static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet) { + assert(sock->header.remote.port); if (daemon_addr.addrlen == 0){ if (make_local_sockaddr(&daemon_addr, "mdp.2.socket") == -1) return -1; @@ -308,11 +310,13 @@ static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet) } DEBUGF("Sent packet seq %02x len %zd (acked %02x)", packet->seq, packet->len, sock->rx.next_seq); sock->tx.last_activity = packet->sent = gettime_ms(); + sock->next_ack = packet->sent + 1500; return 0; } static int send_ack(struct msp_sock *sock) { + assert(sock->header.remote.port); if (daemon_addr.addrlen == 0){ if (make_local_sockaddr(&daemon_addr, "mdp.2.socket") == -1) return -1; @@ -327,7 +331,6 @@ static int send_ack(struct msp_sock *sock) msp_header[0]|=FLAG_ACK; write_uint16(&msp_header[1], sock->rx.next_seq); - sock->previous_ack = sock->rx.next_seq; struct fragmented_data data={ .fragment_count=2, @@ -350,7 +353,9 @@ static int send_ack(struct msp_sock *sock) return -1; } DEBUGF("Sent packet (acked %02x)", sock->rx.next_seq); + sock->previous_ack = sock->rx.next_seq; sock->tx.last_activity = gettime_ms(); + sock->next_ack = sock->tx.last_activity + 1500; return 0; } @@ -397,12 +402,16 @@ static int process_sock(struct msp_sock *sock) time_ms_t now = gettime_ms(); if (sock->timeout < now){ - sock->state |= MSP_STATE_CLOSED; + WHY("MSP socket timed out"); + sock->state |= (MSP_STATE_CLOSED|MSP_STATE_ERROR); return -1; } sock->next_action = sock->timeout; + if (sock->state & MSP_STATE_LISTENING) + return 0; + struct msp_packet *p; // deliver packets that have now arrived in order @@ -455,23 +464,21 @@ static int process_sock(struct msp_sock *sock) p=p->_next; } - time_ms_t next_packet = sock->tx.last_activity + sock->tx.rtt*2; - // should we send an ack now without sending a payload? - if (sock->previous_ack != sock->rx.next_seq || now > next_packet){ + if (now > sock->next_ack){ int r = send_ack(sock); if (r==-1) return -1; - next_packet = sock->tx.last_activity + sock->tx.rtt*2; } - if (sock->next_action > next_packet) - sock->next_action = next_packet; + if (sock->next_action > sock->next_ack) + sock->next_action = sock->next_ack; if (sock->state & MSP_STATE_SHUTDOWN_LOCAL && sock->state & MSP_STATE_SHUTDOWN_REMOTE && sock->tx.packet_count == 0 - && sock->rx.packet_count == 0){ + && sock->rx.packet_count == 0 + && sock->previous_ack == sock->rx.next_seq){ sock->state |= MSP_STATE_CLOSED; return -1; } @@ -598,7 +605,8 @@ static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t sock->state |= MSP_STATE_RECEIVED_DATA; uint16_t seq = read_uint16(&payload[3]); - add_packet(&sock->rx, seq, flags, &payload[5], len - 5); + if (add_packet(&sock->rx, seq, flags, &payload[5], len - 5)==1) + sock->next_ack = gettime_ms(); return 0; } diff --git a/msp_proxy.c b/msp_proxy.c index bd98f976..595cf59c 100644 --- a/msp_proxy.c +++ b/msp_proxy.c @@ -16,6 +16,7 @@ struct connection{ struct msp_sock *sock; struct buffer *in; struct buffer *out; + int last_state; }; struct connection *stdio_connection=NULL; @@ -86,6 +87,7 @@ static void free_connection(struct connection *conn) static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context) { struct connection *conn = context; + conn->last_state=state; if (payload && len){ if (conn->out->limit){ @@ -350,7 +352,11 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS while(fd_poll()){ ; } - ret=0; + + if (stdio_connection && stdio_connection->last_state & MSP_STATE_ERROR) + ret = 1; + else + ret = 0; end: listener=NULL; diff --git a/tests/msp b/tests/msp index 8df12950..efecd154 100755 --- a/tests/msp +++ b/tests/msp @@ -29,6 +29,26 @@ teardown() { report_all_servald_servers } +doc_connect_fail="Timeout when the connection isn't reachable" +setup_connect_fail() { + setup_servald + assert_no_servald_processes + foreach_instance +A +B create_single_identity + foreach_instance +A +B \ + executeOk_servald config \ + set debug.mdprequests on \ + set log.console.level DEBUG \ + set log.console.show_time on + start_servald_instances +A +} +test_connect_fail() { + set_instance +A + execute --exit-status=1 --timeout=20 $servald msp connect $SIDB 512 < Date: Mon, 9 Dec 2013 17:45:47 +1030 Subject: [PATCH 05/18] Refactor interface addresses to use new socket_address struct --- directory_service.c | 1 + headerfiles.mk | 1 + keyring.c | 1 + lsif.c | 54 +++++++--- mdp_client.c | 21 +--- overlay.c | 1 + overlay_address.c | 5 +- overlay_address.h | 3 +- overlay_interface.c | 218 ++++++++++++++++------------------------ overlay_interface.h | 145 ++++++++++++++++++++++++++ overlay_link.c | 77 +++++++------- overlay_mdp.c | 28 +++--- overlay_olsr.c | 1 + overlay_packet.h | 2 +- overlay_packetformats.c | 9 +- overlay_packetradio.c | 3 +- overlay_queue.c | 1 + performance_timing.c | 3 - radio_link.c | 1 + rhizome.h | 7 +- rhizome_direct_http.c | 33 +++--- rhizome_fetch.c | 64 +++++------- rhizome_http.c | 1 + rhizome_packetformats.c | 9 +- route_link.c | 29 +++--- serval.h | 195 +---------------------------------- server.c | 1 + socket.c | 20 ++++ socket.h | 1 + 29 files changed, 444 insertions(+), 491 deletions(-) create mode 100644 overlay_interface.h diff --git a/directory_service.c b/directory_service.c index 311c1951..b0f84c6e 100644 --- a/directory_service.c +++ b/directory_service.c @@ -22,6 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #endif #include #include +#include #include "constants.h" #include "serval.h" #include "mdp_client.h" diff --git a/headerfiles.mk b/headerfiles.mk index ff362454..8c329cfc 100644 --- a/headerfiles.mk +++ b/headerfiles.mk @@ -3,6 +3,7 @@ HDRS= fifo.h \ overlay_buffer.h \ overlay_address.h \ overlay_packet.h \ + overlay_interface.h \ rhizome.h \ serval.h \ keyring.h \ diff --git a/keyring.c b/keyring.c index 411a5fca..ab36d636 100644 --- a/keyring.c +++ b/keyring.c @@ -30,6 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "nacl.h" #include "overlay_address.h" #include "crypto.h" +#include "overlay_interface.h" #include "overlay_packet.h" #include "keyring.h" #include "dataformats.h" diff --git a/lsif.c b/lsif.c index e549f1ab..73374bef 100644 --- a/lsif.c +++ b/lsif.c @@ -26,9 +26,6 @@ * */ -#include "serval.h" -#include "conf.h" - #include #include #include @@ -61,6 +58,9 @@ #include #endif +#include "conf.h" +#include "overlay_interface.h" + /* On platforms that have variable length ifreq use the old fixed length interface instead */ #ifdef OSIOCGIFCONF @@ -97,12 +97,22 @@ int scrapeProcNetRoute() line[0] = '\0'; if (fgets(line,1024,f) == NULL) return WHYF_perror("fgets(%p,1024,\"/proc/net/route\")", line); + + struct socket_address addr, broadcast; + bzero(&addr, sizeof(addr)); + bzero(&broadcast, sizeof(broadcast)); + addr.addrlen = sizeof(addr.inet); + addr.inet.sin_family = AF_INET; + broadcast.addrlen = sizeof(addr.inet); + broadcast.inet.sin_family = AF_INET; + while(line[0]) { int r; if ((r=sscanf(line,"%s %s %*s %*s %*s %*s %*s %s",name,dest,mask))==3) { - struct in_addr addr = {.s_addr=strtol(dest,NULL,16)}; + addr.inet.sin_addr.s_addr=strtol(dest,NULL,16); struct in_addr netmask = {.s_addr=strtol(mask,NULL,16)}; - overlay_interface_register(name,addr,netmask); + broadcast.inet.sin_addr.s_addr=addr.inet.sin_addr.s_addr | ~netmask.s_addr; + overlay_interface_register(name,&addr,&broadcast); } line[0] = '\0'; if (fgets(line,1024,f) == NULL) @@ -126,8 +136,11 @@ lsif(void) { struct ifconf ifc; int sck; struct ifreq *ifr; - struct in_addr addr, netmask; - + struct in_addr netmask; + struct socket_address addr, broadcast; + bzero(&addr, sizeof(addr)); + bzero(&broadcast, sizeof(broadcast)); + if (config.debug.overlayinterfaces) DEBUG("called"); /* Get a socket handle. */ @@ -146,6 +159,9 @@ lsif(void) { return 1; } + broadcast.addrlen = sizeof(addr.inet); + broadcast.inet.sin_family = AF_INET; + /* Iterate through the list of interfaces. */ unsigned nInterfaces = 0; unsigned ofs = 0; @@ -158,8 +174,9 @@ lsif(void) { if (config.debug.overlayinterfaces) DEBUGF("Skipping non-AF_INET address on %s", ifr->ifr_name); continue; } - - addr = ((struct sockaddr_in *)&ifr->ifr_ifru.ifru_addr)->sin_addr; + + addr.addrlen = sizeof(addr.inet); + bcopy(&ifr->ifr_ifru.ifru_addr, &addr.addr, addr.addrlen); /* Get interface flags */ if (ioctl(sck, SIOCGIFFLAGS, ifr) == -1) @@ -178,7 +195,9 @@ lsif(void) { } netmask = ((struct sockaddr_in *)&ifr->ifr_ifru.ifru_addr)->sin_addr; - overlay_interface_register(ifr->ifr_name, addr, netmask); + broadcast.inet.sin_addr.s_addr=addr.inet.sin_addr.s_addr | ~netmask.s_addr; + + overlay_interface_register(ifr->ifr_name, &addr, &broadcast); nInterfaces++; } @@ -195,13 +214,19 @@ int doifaddrs(void) { struct ifaddrs *ifaddr, *ifa; char *name; - struct in_addr addr, netmask; + struct socket_address addr, broadcast; + struct in_addr netmask; + bzero(&addr, sizeof(addr)); + bzero(&broadcast, sizeof(broadcast)); if (config.debug.overlayinterfaces) DEBUGF("called"); if (getifaddrs(&ifaddr) == -1) return WHY_perror("getifaddr()"); + broadcast.addrlen = sizeof(addr.inet); + broadcast.inet.sin_family = AF_INET; + for (ifa = ifaddr; ifa != NULL ; ifa = ifa->ifa_next) { if (!ifa->ifa_addr || !ifa->ifa_netmask) continue; @@ -219,10 +244,13 @@ doifaddrs(void) { } name = ifa->ifa_name; - addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; + addr.addrlen = sizeof(addr.inet); + bcopy(ifa->ifa_addr, &addr.addr, addr.addrlen); + netmask = ((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; + broadcast.inet.sin_addr.s_addr=addr.inet.sin_addr.s_addr | ~netmask.s_addr; - overlay_interface_register(name, addr, netmask); + overlay_interface_register(name, &addr, &broadcast); } freeifaddrs(ifaddr); diff --git a/mdp_client.c b/mdp_client.c index bc02fb20..cdc28eba 100644 --- a/mdp_client.c +++ b/mdp_client.c @@ -26,6 +26,7 @@ #include "strbuf_helpers.h" #include "overlay_buffer.h" #include "overlay_address.h" +#include "overlay_interface.h" #include "overlay_packet.h" #include "mdp_client.h" #include "socket.h" @@ -36,22 +37,6 @@ int mdp_socket(void) return overlay_mdp_client_socket(); } -static void mdp_unlink(int mdp_sock) -{ - // get the socket name and unlink it from the filesystem if not abstract - struct socket_address addr; - addr.addrlen = sizeof addr.store; - if (getsockname(mdp_sock, &addr.addr, &addr.addrlen)) - WHYF_perror("getsockname(%d)", mdp_sock); - else if (addr.addr.sa_family==AF_UNIX - && addr.addrlen > sizeof addr.local.sun_family - && addr.addrlen <= sizeof addr.local && addr.local.sun_path[0] != '\0') { - if (unlink(addr.local.sun_path) == -1) - WARNF_perror("unlink(%s)", alloca_str_toprint(addr.local.sun_path)); - } - close(mdp_sock); -} - int mdp_close(int socket) { // tell the daemon to drop all bindings @@ -63,7 +48,7 @@ int mdp_close(int socket) mdp_send(socket, &header, NULL, 0); // remove socket - mdp_unlink(socket); + socket_unlink_close(socket); return 0; } @@ -229,7 +214,7 @@ int overlay_mdp_client_close(int mdp_sockfd) mdp.packetTypeAndFlags = MDP_GOODBYE; overlay_mdp_send(mdp_sockfd, &mdp, 0, 0); - mdp_unlink(mdp_sockfd); + socket_unlink_close(mdp_sockfd); return 0; } diff --git a/overlay.c b/overlay.c index ca4b043b..5dbf8533 100644 --- a/overlay.c +++ b/overlay.c @@ -73,6 +73,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "rhizome.h" #include "strbuf.h" #include "keyring.h" +#include "overlay_interface.h" int overlayMode=0; diff --git a/overlay_address.c b/overlay_address.c index c8463764..cf8635b8 100644 --- a/overlay_address.c +++ b/overlay_address.c @@ -27,13 +27,14 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include +#include #include "serval.h" #include "conf.h" #include "str.h" #include "overlay_address.h" #include "overlay_buffer.h" +#include "overlay_interface.h" #include "overlay_packet.h" -#include #define MAX_BPIS 1024 #define BPI_MASK 0x3ff @@ -476,7 +477,7 @@ int send_please_explain(struct decode_context *context, struct subscriber *sourc frame->destination = destination; frame->destinations[frame->destination_count++].destination=add_destination_ref(context->interface->destination); - struct network_destination *dest = create_unicast_destination(context->addr, context->interface); + struct network_destination *dest = create_unicast_destination(&context->addr, context->interface); if (dest) frame->destinations[frame->destination_count++].destination=dest; diff --git a/overlay_address.h b/overlay_address.h index 82a9b3fa..44dba661 100644 --- a/overlay_address.h +++ b/overlay_address.h @@ -21,6 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define __SERVAL_DNA__OVERLAY_ADDRESS_H #include "constants.h" +#include "socket.h" // not reachable #define REACHABLE_NONE 0 @@ -94,7 +95,7 @@ struct decode_context{ int sender_interface; int packet_version; int encapsulation; - struct sockaddr_in addr; + struct socket_address addr; union{ // only valid while decoding int invalid_addresses; diff --git a/overlay_interface.c b/overlay_interface.c index 5a6c821d..c7e53bda 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conf.h" #include "net.h" #include "socket.h" +#include "overlay_interface.h" #include "strbuf.h" #include "strbuf_helpers.h" #include "overlay_buffer.h" @@ -46,17 +47,16 @@ int overlay_last_interface_number=-1; struct profile_total interface_poll_stats; struct sched_ent sock_any; -struct sockaddr_in sock_any_addr; +struct socket_address sock_any_addr; struct profile_total sock_any_stats; static void overlay_interface_poll(struct sched_ent *alarm); -static int re_init_socket(int interface_index); static void overlay_interface_close(overlay_interface *interface){ link_interface_down(interface); INFOF("Interface %s addr %s is down", - interface->name, inet_ntoa(interface->address.sin_addr)); + interface->name, alloca_socket_address(&interface->address)); unschedule(&interface->alarm); unwatch(&interface->alarm); close(interface->alarm.poll.fd); @@ -97,12 +97,9 @@ void interface_state_html(struct strbuf *b, struct overlay_interface *interface) break; case SOCK_DGRAM: { - char addrtxt[INET_ADDRSTRLEN]; strbuf_puts(b, "Socket: DGram
"); - if (inet_ntop(AF_INET, (const void *)&interface->address.sin_addr, addrtxt, INET_ADDRSTRLEN)) - strbuf_sprintf(b, "Address: %s:%d
", addrtxt, ntohs(interface->address.sin_port)); - if (inet_ntop(AF_INET, (const void *)&interface->destination->address.sin_addr, addrtxt, INET_ADDRSTRLEN)) - strbuf_sprintf(b, "Broadcast Address: %s:%d
", addrtxt, ntohs(interface->destination->address.sin_port)); + strbuf_sprintf(b, "Address: %s
", alloca_socket_address(&interface->address)); + strbuf_sprintf(b, "Broadcast Address: %s
", alloca_socket_address(&interface->destination->address)); } break; case SOCK_FILE: @@ -115,16 +112,26 @@ void interface_state_html(struct strbuf *b, struct overlay_interface *interface) // create a socket with options common to all our UDP sockets static int -overlay_bind_socket(const struct sockaddr *addr, size_t addr_size, char *interface_name){ +overlay_bind_socket(const struct socket_address *addr){ int fd; int reuseP = 1; int broadcastP = 1; + int protocol; - fd = socket(PF_INET,SOCK_DGRAM,0); - if (fd < 0) { - WHY_perror("Error creating socket"); - return -1; - } + switch(addr->addr.sa_family){ + case AF_INET: + protocol = PF_INET; + break; + case AF_UNIX: + protocol = PF_UNIX; + break; + default: + return WHYF("Unsupported address %s", alloca_socket_address(addr)); + } + + fd = socket(protocol, SOCK_DGRAM, 0); + if (fd < 0) + return WHY_perror("Error creating socket"); if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseP, sizeof(reuseP)) < 0) { WHY_perror("setsockopt(SO_REUSEADR)"); @@ -154,18 +161,7 @@ overlay_bind_socket(const struct sockaddr *addr, size_t addr_size, char *interfa #endif ); -#ifdef SO_BINDTODEVICE - /* - Limit incoming and outgoing packets to this interface, no matter what the routing table says. - This should allow for a device with multiple interfaces on the same subnet. - Don't abort if this fails, I believe it requires root, just log it. - */ - if (interface_name && setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, interface_name, strlen(interface_name)+1) < 0) { - WHY_perror("setsockopt(SO_BINDTODEVICE)"); - } -#endif - - if (bind(fd, addr, addr_size)) { + if (bind(fd, &addr->addr, addr->addrlen)) { WHY_perror("Bind failed"); goto error; } @@ -187,7 +183,7 @@ overlay_interface * overlay_interface_get_default(){ return NULL; } -// find an interface that can send a packet to this address +// find an interface that can send a packet to this IPv4 address overlay_interface * overlay_interface_find(struct in_addr addr, int return_default){ int i; overlay_interface *ret = NULL; @@ -195,7 +191,8 @@ overlay_interface * overlay_interface_find(struct in_addr addr, int return_defau if (overlay_interfaces[i].state!=INTERFACE_STATE_UP) continue; - if ((overlay_interfaces[i].netmask.s_addr & addr.s_addr) == (overlay_interfaces[i].netmask.s_addr & overlay_interfaces[i].address.sin_addr.s_addr)){ + if (overlay_interfaces[i].address.addr.sa_family == AF_INET + && (overlay_interfaces[i].netmask.s_addr & addr.s_addr) == (overlay_interfaces[i].netmask.s_addr & overlay_interfaces[i].address.inet.sin_addr.s_addr)){ return &overlay_interfaces[i]; } @@ -296,25 +293,23 @@ overlay_interface_read_any(struct sched_ent *alarm) // for now, we don't have a graceful close for this interface but it should go away when the process dies static int overlay_interface_init_any(int port) { - struct sockaddr_in addr; - if (sock_any.poll.fd>0){ // Check the port number matches - if (sock_any_addr.sin_port != htons(port)) - return WHYF("Unable to listen to broadcast packets for ports %d & %d", port, ntohs(sock_any_addr.sin_port)); + if (sock_any_addr.inet.sin_port != htons(port)) + return WHYF("Unable to listen to broadcast packets for ports %d & %d", + port, ntohs(sock_any_addr.inet.sin_port)); return 0; } - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - addr.sin_addr.s_addr = INADDR_ANY; + sock_any_addr.addrlen = sizeof(sock_any_addr.inet); + sock_any_addr.inet.sin_family = AF_INET; + sock_any_addr.inet.sin_port = htons(port); + sock_any_addr.inet.sin_addr.s_addr = INADDR_ANY; - sock_any.poll.fd = overlay_bind_socket((const struct sockaddr *)&addr, sizeof(addr), NULL); + sock_any.poll.fd = overlay_bind_socket(&sock_any_addr); if (sock_any.poll.fd<0) return -1; - sock_any_addr = addr; - sock_any.poll.events=POLLIN; sock_any.function = overlay_interface_read_any; @@ -344,20 +339,15 @@ overlay_interface_init_socket(int interface_index) overlay_interface_init_any(interface->port); - interface->alarm.poll.fd = overlay_bind_socket( - (const struct sockaddr *)&interface->address, - sizeof(interface->address), interface->name); + interface->alarm.poll.fd = overlay_bind_socket(&interface->address); if (interface->alarm.poll.fd<0){ interface->state=INTERFACE_STATE_DOWN; return WHYF("Failed to bind interface %s", interface->name); } - if (config.debug.packetrx || config.debug.io) { - char srctxt[INET_ADDRSTRLEN]; - if (inet_ntop(AF_INET, (const void *)&interface->address.sin_addr, srctxt, INET_ADDRSTRLEN)) - DEBUGF("Bound to %s:%d", srctxt, ntohs(interface->address.sin_port)); - } + if (config.debug.packetrx || config.debug.io) + DEBUGF("Bound to %s", alloca_socket_address(&interface->address)); interface->alarm.poll.events=POLLIN; watch(&interface->alarm); @@ -365,29 +355,13 @@ overlay_interface_init_socket(int interface_index) return 0; } -static int re_init_socket(int interface_index){ - if (overlay_interface_init_socket(interface_index)) - return -1; - overlay_interface *interface = &overlay_interfaces[interface_index]; - // schedule the first tick asap - interface->alarm.alarm=gettime_ms(); - interface->alarm.deadline=interface->alarm.alarm; - schedule(&interface->alarm); - interface->state=INTERFACE_STATE_UP; - INFOF("Interface %s addr %s:%d, is up",interface->name, - inet_ntoa(interface->address.sin_addr), ntohs(interface->address.sin_port)); - - directory_registration(); - - return 0; -} - /* Returns 0 if interface is successfully added. * Returns 1 if interface is not added (eg, dummy file does not exist). * Returns -1 in case of error (misconfiguration or system error). */ static int -overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr netmask, struct in_addr broadcast, +overlay_interface_init(const char *name, struct socket_address *addr, + struct socket_address *broadcast, const struct config_network_interface *ifconfig) { int cleanup_ret = -1; @@ -488,20 +462,14 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr limit_init(&interface->destination->transfer_limit, packet_interval); - interface->address.sin_family=AF_INET; - interface->address.sin_port = htons(ifconfig->port); - - interface->destination->address.sin_family=AF_INET; - interface->destination->address.sin_port = htons(ifconfig->port); + interface->address = *addr; + interface->destination->address = *broadcast; interface->alarm.function = overlay_interface_poll; interface_poll_stats.name="overlay_interface_poll"; interface->alarm.stats=&interface_poll_stats; if (ifconfig->socket_type==SOCK_DGRAM){ - interface->address.sin_addr = src_addr; - interface->destination->address.sin_addr = broadcast; - interface->netmask = netmask; interface->local_echo = 1; if (overlay_interface_init_socket(overlay_interface_count)) @@ -509,9 +477,6 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr }else{ char read_file[1024]; - interface->address.sin_addr = ifconfig->dummy_address; - interface->netmask = ifconfig->dummy_netmask; - interface->destination->address.sin_addr.s_addr = interface->address.sin_addr.s_addr | ~interface->netmask.s_addr; interface->local_echo = interface->point_to_point?0:1; strbuf d = strbuf_local(read_file, sizeof read_file); @@ -551,8 +516,7 @@ overlay_interface_init(const char *name, struct in_addr src_addr, struct in_addr interface->alarm.deadline=interface->alarm.alarm; schedule(&interface->alarm); interface->state=INTERFACE_STATE_UP; - INFOF("Interface %s addr %s:%d, is up",interface->name, - inet_ntoa(interface->address.sin_addr), ntohs(interface->address.sin_port)); + INFOF("Interface %s addr %s, is up",interface->name, alloca_socket_address(addr)); directory_registration(); @@ -597,8 +561,8 @@ static void interface_read_dgram(struct overlay_interface *interface) } struct file_packet{ - struct sockaddr_in src_addr; - struct sockaddr_in dst_addr; + struct socket_address src_addr; + struct socket_address dst_addr; int pid; int payload_length; @@ -619,14 +583,14 @@ struct file_packet{ unsigned char payload[1400]; }; -static int should_drop(struct overlay_interface *interface, struct sockaddr_in addr){ +static int should_drop(struct overlay_interface *interface, struct socket_address *addr){ if (interface->drop_packets>=100) return 1; - if (memcmp(&addr, &interface->address, sizeof(addr))==0){ + if (cmp_sockaddr(addr, &interface->address)==0){ if (interface->drop_unicasts) return 1; - }else if (memcmp(&addr, &interface->destination->address, sizeof(addr))==0){ + }else if (cmp_sockaddr(addr, &interface->destination->address)==0){ if (interface->drop_broadcasts) return 1; }else @@ -670,24 +634,21 @@ static void interface_read_file(struct overlay_interface *interface) if (config.debug.overlayinterfaces) DEBUGF("Read from interface %s (filesize=%"PRId64") at offset=%d: src_addr=%s dst_addr=%s pid=%d length=%d", interface->name, (int64_t)length, interface->recv_offset, - alloca_sockaddr(&packet.src_addr, sizeof packet.src_addr), - alloca_sockaddr(&packet.dst_addr, sizeof packet.dst_addr), + alloca_socket_address(&packet.src_addr), + alloca_socket_address(&packet.dst_addr), packet.pid, packet.payload_length ); interface->recv_offset += nread; - if (should_drop(interface, packet.dst_addr) || (packet.pid == getpid() && !interface->local_echo)){ + if (should_drop(interface, &packet.dst_addr) || (packet.pid == getpid() && !interface->local_echo)){ if (config.debug.packetrx) DEBUGF("Ignoring packet from pid=%d src_addr=%s dst_addr=%s", packet.pid, - alloca_sockaddr_in(&packet.src_addr), - alloca_sockaddr_in(&packet.dst_addr) + alloca_socket_address(&packet.src_addr), + alloca_socket_address(&packet.dst_addr) ); }else{ - struct socket_address srcaddr; - srcaddr.addrlen = sizeof packet.src_addr; - srcaddr.inet = packet.src_addr; - packetOkOverlay(interface, packet.payload, packet.payload_length, &srcaddr); + packetOkOverlay(interface, packet.payload, packet.payload_length, &packet.src_addr); } } } @@ -886,7 +847,8 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o case SOCK_DGRAM: { if (config.debug.overlayinterfaces) - DEBUGF("Sending %zu byte overlay frame on %s to %s", len, interface->name, inet_ntoa(destination->address.sin_addr)); + DEBUGF("Sending %zu byte overlay frame on %s to %s", + (size_t)len, interface->name, alloca_socket_address(&destination->address)); ssize_t sent = sendto(interface->alarm.poll.fd, bytes, (size_t)len, 0, (struct sockaddr *)&destination->address, sizeof(destination->address)); @@ -921,15 +883,13 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o /* Register the real interface, or update the existing interface registration. */ int overlay_interface_register(char *name, - struct in_addr addr, - struct in_addr mask) + struct socket_address *addr, + struct socket_address *broadcast) { - struct in_addr broadcast = {.s_addr = addr.s_addr | ~mask.s_addr}; - if (config.debug.overlayinterfaces) { // note, inet_ntop doesn't seem to behave on android - DEBUGF("%s address: %s", name, inet_ntoa(addr)); - DEBUGF("%s broadcast address: %s", name, inet_ntoa(broadcast)); + DEBUGF("%s address: %s", name, alloca_socket_address(addr)); + DEBUGF("%s broadcast address: %s", name, alloca_socket_address(broadcast)); } // Find the matching non-dummy interface rule. @@ -958,49 +918,32 @@ overlay_interface_register(char *name, DEBUGF("Interface %s is explicitly excluded", name); return 0; } + + if (addr->addr.sa_family==AF_INET) + addr->inet.sin_port = htons(ifconfig->port); + if (broadcast->addr.sa_family==AF_INET) + broadcast->inet.sin_port = htons(ifconfig->port); /* Search in the exist list of interfaces */ - int found_interface= -1; for(i = 0; i < overlay_interface_count; i++){ - int broadcast_match = 0; - int name_match =0; + if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN){ + continue; + } - if (overlay_interfaces[i].destination->address.sin_addr.s_addr == broadcast.s_addr) - broadcast_match = 1; - - name_match = !strcasecmp(overlay_interfaces[i].name, name); - - // if we find an exact match we can stop searching - if (name_match && broadcast_match){ + if (strcasecmp(overlay_interfaces[i].name, name) + && cmp_sockaddr(addr, &overlay_interfaces[i].address)==0 + && overlay_interfaces[i].state!=INTERFACE_STATE_DOWN){ + // mark this interface as still alive if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) overlay_interfaces[i].state=INTERFACE_STATE_UP; - - // try to bring the interface back up again even if the address has changed - if (overlay_interfaces[i].state==INTERFACE_STATE_DOWN){ - overlay_interfaces[i].address.sin_addr = addr; - re_init_socket(i); - } - - // we already know about this interface, and it's up so stop looking immediately + return 0; } - - // remember this slot to bring the interface back up again, even if the address has changed - if (name_match && overlay_interfaces[i].state==INTERFACE_STATE_DOWN) - found_interface=i; - } - - if (found_interface>=0){ - // try to reactivate the existing interface - overlay_interfaces[found_interface].address.sin_addr = addr; - overlay_interfaces[found_interface].destination->address.sin_addr = broadcast; - overlay_interfaces[found_interface].netmask = mask; - return re_init_socket(found_interface); } /* New interface, so register it */ - if (overlay_interface_init(name, addr, mask, broadcast, ifconfig)) + if (overlay_interface_init(name, addr, broadcast, ifconfig)) return WHYF("Could not initialise newly seen interface %s", name); else if (config.debug.overlayinterfaces) DEBUGF("Registered interface %s", name); @@ -1039,8 +982,21 @@ void overlay_interface_discover(struct sched_ent *alarm) if (j >= overlay_interface_count) { // New dummy interface, so register it. - struct in_addr dummyaddr = hton_in_addr(INADDR_NONE); - overlay_interface_init(ifconfig->file, dummyaddr, dummyaddr, dummyaddr, ifconfig); + struct socket_address addr, broadcast; + bzero(&addr, sizeof addr); + bzero(&broadcast, sizeof broadcast); + + addr.addrlen=sizeof addr.inet; + addr.inet.sin_family=AF_INET; + addr.inet.sin_port=htons(ifconfig->port); + addr.inet.sin_addr=ifconfig->dummy_address; + + broadcast.addrlen=sizeof addr.inet; + broadcast.inet.sin_family=AF_INET; + broadcast.inet.sin_port=htons(ifconfig->port); + broadcast.inet.sin_addr.s_addr=ifconfig->dummy_address.s_addr | ~ifconfig->dummy_netmask.s_addr; + + overlay_interface_init(ifconfig->file, &addr, &broadcast, ifconfig); } } diff --git a/overlay_interface.h b/overlay_interface.h new file mode 100644 index 00000000..39bb8a51 --- /dev/null +++ b/overlay_interface.h @@ -0,0 +1,145 @@ +#ifndef __SERVAL_DNA__OVERLAY_INTERFACE_H +#define __SERVAL_DNA__OVERLAY_INTERFACE_H + +#include "socket.h" + +#define INTERFACE_STATE_FREE 0 +#define INTERFACE_STATE_UP 1 +#define INTERFACE_STATE_DOWN 2 +#define INTERFACE_STATE_DETECTING 3 + + +struct overlay_interface; + +// where should packets be sent to? +struct network_destination { + int _ref_count; + + // which interface are we actually sending packets out of + struct overlay_interface *interface; + + // The network destination address + // this may be the interface broadcast IP address + // but could be a unicast address + struct socket_address address; + + // should outgoing packets be marked as unicast? + char unicast; + + char packet_version; + + // should we aggregate packets, or send one at a time + char encapsulation; + + // time last packet was sent + time_ms_t last_tx; + + int min_rtt; + int max_rtt; + int resend_delay; + + // sequence number of last packet sent to this destination. + // Used to allow NACKs that can request retransmission of recent packets. + int sequence_number; + + // rate limit for outgoing packets + struct limit_state transfer_limit; + + /* Number of milli-seconds per tick for this interface, which is basically + * related to the the typical TX range divided by the maximum expected + * speed of nodes in the network. This means that short-range communications + * has a higher bandwidth requirement than long-range communications because + * the tick interval has to be shorter to still allow fast-convergence time + * to allow for mobility. + * + * For wifi (nominal range 100m) it is usually 500ms. + * For ~100K ISM915MHz (nominal range 1000m) it will probably be about 5000ms. + * For ~10K ISM915MHz (nominal range ~3000m) it will probably be about 15000ms. + * + * These figures will be refined over time, and we will allow people to set + * them per-interface. + */ + unsigned tick_ms; + + // Number of milliseconds of no packets until we assume the link is dead. + unsigned reachable_timeout_ms; +}; + +typedef struct overlay_interface { + struct sched_ent alarm; + + char name[256]; + + int recv_offset; /* file offset */ + + int recv_count; + int tx_count; + + struct radio_link_state *radio_link_state; + + // copy of ifconfig flags + uint16_t drop_packets; + char drop_broadcasts; + char drop_unicasts; + int port; + int type; + int socket_type; + char send_broadcasts; + char prefer_unicast; + /* Not necessarily the real MTU, but the largest frame size we are willing to TX. + For radio links the actual maximum and the maximum that is likely to be delivered reliably are + potentially two quite different values. */ + int mtu; + // can we use this interface for routes to addresses in other subnets? + int default_route; + // should we log more debug info on this interace? eg hex dumps of packets + char debug; + char local_echo; + + unsigned int uartbps; // set serial port speed (which might be different from link speed) + int ctsrts; // enabled hardware flow control if non-zero + + struct network_destination *destination; + + // can we assume that we will only receive packets from one device? + char point_to_point; + struct subscriber *other_device; + + // the actual address of the interface. + struct socket_address address; + + struct in_addr netmask; + + /* Use one of the INTERFACE_STATE_* constants to indicate the state of this interface. + If the interface stops working or disappears, it will be marked as DOWN and the socket closed. + But if it comes back up again, we should try to reuse this structure, even if the broadcast address has changed. + */ + int state; +} overlay_interface; + +/* Maximum interface count is rather arbitrary. + Memory consumption is O(n) with respect to this parameter, so let's not make it too big for now. + */ +extern overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES]; + +extern unsigned overlay_interface_count; + +struct network_destination * new_destination(struct overlay_interface *interface, char encapsulation); +struct network_destination * create_unicast_destination(struct socket_address *addr, struct overlay_interface *interface); +struct network_destination * add_destination_ref(struct network_destination *ref); +void release_destination_ref(struct network_destination *ref); +int set_destination_ref(struct network_destination **ptr, struct network_destination *ref); + + +void overlay_interface_discover(struct sched_ent *alarm); +int overlay_interface_register(char *name, + struct socket_address *addr, + struct socket_address *broadcast); +overlay_interface * overlay_interface_get_default(); +overlay_interface * overlay_interface_find(struct in_addr addr, int return_default); +overlay_interface * overlay_interface_find_name(const char *name); +int overlay_interface_compare(overlay_interface *one, overlay_interface *two); +int overlay_broadcast_ensemble(struct network_destination *destination, struct overlay_buffer *buffer); +void interface_state_html(struct strbuf *b, struct overlay_interface *interface); + +#endif // __SERVAL_DNA__OVERLAY_INTERFACE_H diff --git a/overlay_link.c b/overlay_link.c index a622a03c..e2f14e55 100644 --- a/overlay_link.c +++ b/overlay_link.c @@ -23,16 +23,13 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "str.h" #include "overlay_address.h" #include "overlay_buffer.h" +#include "overlay_interface.h" #include "overlay_packet.h" #include "keyring.h" +#include "strbuf_helpers.h" #define MIN_BURST_LENGTH 5000 -struct probe_contents{ - struct sockaddr_in addr; - unsigned char interface; -}; - static void update_limit_state(struct limit_state *state, time_ms_t now){ if (state->next_interval > now || state->burst_size==0){ return; @@ -177,14 +174,15 @@ int load_subscriber_address(struct subscriber *subscriber) if (!interface) return WHY("Can't fund configured interface"); } - struct sockaddr_in addr; + struct socket_address addr; bzero(&addr, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr = hostc->address; - addr.sin_port = htons(hostc->port); - if (addr.sin_addr.s_addr==INADDR_NONE){ + addr.addrlen = sizeof(addr.inet); + addr.inet.sin_family = AF_INET; + addr.inet.sin_addr = hostc->address; + addr.inet.sin_port = htons(hostc->port); + if (addr.inet.sin_addr.s_addr==INADDR_NONE){ if (interface || overlay_interface_get_default()){ - if (resolve_name(hostc->host, &addr.sin_addr)) + if (resolve_name(hostc->host, &addr.inet.sin_addr)) return -1; }else{ // interface isnt up yet @@ -192,8 +190,8 @@ int load_subscriber_address(struct subscriber *subscriber) } } if (config.debug.overlayrouting) - DEBUGF("Loaded address %s:%d for %s", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port), alloca_tohex_sid_t(subscriber->sid)); - struct network_destination *destination = create_unicast_destination(addr, interface); + DEBUGF("Loaded address %s for %s", alloca_socket_address(&addr), alloca_tohex_sid_t(subscriber->sid)); + struct network_destination *destination = create_unicast_destination(&addr, interface); if (!destination) return -1; int ret=overlay_send_probe(subscriber, destination, OQ_MESH_MANAGEMENT); @@ -206,7 +204,7 @@ int overlay_mdp_service_probe(struct overlay_frame *frame, overlay_mdp_frame *mdp) { IN(); - if (mdp->out.src.port!=MDP_PORT_ECHO || mdp->out.payload_length != sizeof(struct probe_contents)){ + if (mdp->out.src.port!=MDP_PORT_ECHO){ WARN("Probe packets should be returned from remote echo port"); RETURN(-1); } @@ -214,12 +212,16 @@ overlay_mdp_service_probe(struct overlay_frame *frame, overlay_mdp_frame *mdp) if (frame->source->reachable == REACHABLE_SELF) RETURN(0); - struct probe_contents probe; - bcopy(&mdp->out.payload, &probe, sizeof(struct probe_contents)); - if (probe.addr.sin_family!=AF_INET) - RETURN(WHY("Unsupported address family")); + uint8_t interface = mdp->out.payload[0]; + struct socket_address addr; + addr.addrlen = mdp->out.payload_length - 1; - RETURN(link_unicast_ack(frame->source, &overlay_interfaces[probe.interface], probe.addr)); + if (addr.addrlen > sizeof(addr.store)) + RETURN(-1); + + bcopy(&mdp->out.payload[1], &addr.addr, addr.addrlen); + + RETURN(link_unicast_ack(frame->source, &overlay_interfaces[interface], &addr)); OUT(); } @@ -250,25 +252,18 @@ int overlay_send_probe(struct subscriber *peer, struct network_destination *dest // TODO call mdp payload encryption / signing without calling overlay_mdp_dispatch... overlay_mdp_encode_ports(frame->payload, MDP_PORT_ECHO, MDP_PORT_PROBE); - // not worried about byte order here as we are the only node that should be parsing the contents. - unsigned char *dst=ob_append_space(frame->payload, sizeof(struct probe_contents)); - if (!dst){ - op_free(frame); - return -1; - } - struct probe_contents probe; - probe.addr=destination->address; - // get interface number - probe.interface = destination->interface - overlay_interfaces; - bcopy(&probe, dst, sizeof(struct probe_contents)); + + ob_append_byte(frame->payload, destination->interface - overlay_interfaces); + ob_append_bytes(frame->payload, (uint8_t*)&destination->address.addr, destination->address.addrlen); + if (overlay_payload_enqueue(frame)){ op_free(frame); return -1; } if (config.debug.overlayrouting) - DEBUGF("Queued probe packet on interface %s to %s:%d for %s", + DEBUGF("Queued probe packet on interface %s to %s for %s", destination->interface->name, - inet_ntoa(destination->address.sin_addr), ntohs(destination->address.sin_port), + alloca_socket_address(&destination->address), peer?alloca_tohex_sid_t(peer->sid):"ANY"); return 0; } @@ -278,11 +273,11 @@ static void overlay_append_unicast_address(struct subscriber *subscriber, struct { if ( subscriber->destination && subscriber->destination->unicast - && subscriber->destination->address.sin_family==AF_INET + && subscriber->destination->address.addr.sa_family==AF_INET ) { overlay_address_append(NULL, buff, subscriber); - ob_append_ui32(buff, subscriber->destination->address.sin_addr.s_addr); - ob_append_ui16(buff, subscriber->destination->address.sin_port); + ob_append_ui32(buff, subscriber->destination->address.inet.sin_addr.s_addr); + ob_append_ui16(buff, subscriber->destination->address.inet.sin_port); if (config.debug.overlayrouting) DEBUGF("Added STUN info for %s", alloca_tohex_sid_t(subscriber->sid)); }else{ @@ -349,22 +344,22 @@ int overlay_mdp_service_stun(overlay_mdp_frame *mdp) while(ob_remaining(buff)>0){ struct subscriber *subscriber=NULL; - struct sockaddr_in addr; // TODO explain addresses, link expiry time, resolve differences between addresses... if (overlay_address_parse(NULL, buff, &subscriber)){ break; } - - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = ob_get_ui32(buff); - addr.sin_port = ob_get_ui16(buff); + struct socket_address addr; + addr.addrlen = sizeof(addr.inet); + addr.inet.sin_family = AF_INET; + addr.inet.sin_addr.s_addr = ob_get_ui32(buff); + addr.inet.sin_port = ob_get_ui16(buff); if (!subscriber || (subscriber->reachable!=REACHABLE_NONE)) continue; - struct network_destination *destination = create_unicast_destination(addr, NULL); + struct network_destination *destination = create_unicast_destination(&addr, NULL); if (destination){ overlay_send_probe(subscriber, destination, OQ_MESH_MANAGEMENT); release_destination_ref(destination); diff --git a/overlay_mdp.c b/overlay_mdp.c index 299e976c..755dd417 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -57,6 +57,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "strbuf_helpers.h" #include "overlay_buffer.h" #include "overlay_address.h" +#include "overlay_interface.h" #include "overlay_packet.h" #include "mdp_client.h" #include "crypto.h" @@ -1058,20 +1059,21 @@ struct scan_state scans[OVERLAY_MAX_INTERFACES]; static void overlay_mdp_scan(struct sched_ent *alarm) { - struct sockaddr_in addr={ - .sin_family=AF_INET, - .sin_port=htons(PORT_DNA), - .sin_addr={0}, - }; + struct socket_address addr; + bzero(&addr, sizeof(addr)); + addr.addrlen = sizeof(addr.inet); + addr.inet.sin_family=AF_INET; + addr.inet.sin_port=htons(PORT_DNA); + struct scan_state *state = (struct scan_state *)alarm; uint32_t stop = state->last; if (stop - state->current > 25) stop = state->current+25; while(state->current <= stop){ - addr.sin_addr.s_addr=htonl(state->current); - if (addr.sin_addr.s_addr != state->interface->address.sin_addr.s_addr){ - struct network_destination *destination = create_unicast_destination(addr, state->interface); + addr.inet.sin_addr.s_addr=htonl(state->current); + if (addr.inet.sin_addr.s_addr != state->interface->address.inet.sin_addr.s_addr){ + struct network_destination *destination = create_unicast_destination(&addr, state->interface); if (!destination) break; int ret = overlay_send_probe(NULL, destination, OQ_ORDINARY); @@ -1630,12 +1632,14 @@ static void overlay_mdp_poll(struct sched_ent *alarm) struct overlay_interface *interface = &overlay_interfaces[i]; if (interface->state!=INTERFACE_STATE_UP) continue; - + if (interface->address.addr.sa_family!=AF_INET) + continue; scans[i].interface = interface; - scans[i].current = ntohl(interface->address.sin_addr.s_addr & interface->netmask.s_addr)+1; - scans[i].last = ntohl(interface->destination->address.sin_addr.s_addr)-1; + scans[i].current = ntohl(interface->address.inet.sin_addr.s_addr & ~interface->netmask.s_addr)+1; + scans[i].last = ntohl(interface->destination->address.inet.sin_addr.s_addr)-1; if (scans[i].last - scans[i].current>0x10000){ - INFOF("Skipping scan on interface %s as the address space is too large",interface->name); + INFOF("Skipping scan on interface %s as the address space is too large (%04x %04x)", + interface->name, scans[i].last, scans[i].current); continue; } scans[i].alarm.alarm=start; diff --git a/overlay_olsr.c b/overlay_olsr.c index aa4c4677..fe7bc7a0 100644 --- a/overlay_olsr.c +++ b/overlay_olsr.c @@ -62,6 +62,7 @@ #include "serval.h" #include "conf.h" +#include "overlay_interface.h" #include "overlay_packet.h" #include "overlay_buffer.h" #include "overlay_address.h" diff --git a/overlay_packet.h b/overlay_packet.h index 3c70a724..bc0cdd5c 100644 --- a/overlay_packet.h +++ b/overlay_packet.h @@ -84,7 +84,7 @@ struct overlay_frame { int source_full; // how did we receive this packet? - overlay_interface *interface; + struct overlay_interface *interface; struct sockaddr_in recvaddr; // packet envelope header; // Was it a unicast frame diff --git a/overlay_packetformats.c b/overlay_packetformats.c index 1ff83556..177ffab3 100644 --- a/overlay_packetformats.c +++ b/overlay_packetformats.c @@ -22,9 +22,12 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "socket.h" #include "str.h" #include "strbuf.h" +#include "strbuf_helpers.h" #include "overlay_buffer.h" +#include "overlay_interface.h" #include "overlay_packet.h" + struct sockaddr_in loopback; @@ -259,7 +262,7 @@ int parseMdpPacketHeader(struct decode_context *context, struct overlay_frame *f } int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface *interface, - struct sockaddr_in *addr, struct overlay_buffer *buffer){ + struct socket_address *addr, struct overlay_buffer *buffer){ IN(); context->interface = interface; @@ -387,7 +390,7 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s } if (recvaddr && recvaddr->addr.sa_family != AF_INET) - RETURN(WHYF("Unexpected protocol family %d", recvaddr->addr.sa_family)); + RETURN(WHYF("Unexpected address %s", alloca_socket_address(recvaddr))); struct overlay_frame f; struct decode_context context; @@ -404,7 +407,7 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s else bzero(&f.recvaddr, sizeof f.recvaddr); - int ret=parseEnvelopeHeader(&context, interface, recvaddr ? &recvaddr->inet : NULL, b); + int ret=parseEnvelopeHeader(&context, interface, recvaddr, b); if (ret){ ob_free(b); RETURN(ret); diff --git a/overlay_packetradio.c b/overlay_packetradio.c index c8a967a3..44c6ae36 100644 --- a/overlay_packetradio.c +++ b/overlay_packetradio.c @@ -18,9 +18,10 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include "serval.h" #include "conf.h" -#include +#include "overlay_interface.h" int overlay_packetradio_setup_port(overlay_interface *interface) { diff --git a/overlay_queue.c b/overlay_queue.c index 5c48965b..6b8f737c 100644 --- a/overlay_queue.c +++ b/overlay_queue.c @@ -21,6 +21,7 @@ #include "serval.h" #include "conf.h" #include "overlay_buffer.h" +#include "overlay_interface.h" #include "overlay_packet.h" #include "radio_link.h" #include "str.h" diff --git a/performance_timing.c b/performance_timing.c index 6e1a9522..4695eb4e 100644 --- a/performance_timing.c +++ b/performance_timing.c @@ -178,9 +178,6 @@ int fd_showstats() stats = stats->_next; } - // Show periodic rhizome transfer information - rhizome_fetch_log_short_status(); - // Report any functions that take too much time if (!config.debug.timing) { diff --git a/radio_link.c b/radio_link.c index c3a2e53b..222f21af 100644 --- a/radio_link.c +++ b/radio_link.c @@ -47,6 +47,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "conf.h" #include "overlay_buffer.h" +#include "overlay_interface.h" #include "golay.h" #include "radio_link.h" diff --git a/rhizome.h b/rhizome.h index 91fd46c7..b67ba248 100644 --- a/rhizome.h +++ b/rhizome.h @@ -706,7 +706,7 @@ void rhizome_list_release(struct rhizome_list_cursor *); #define MAX_RHIZOME_MANIFESTS 40 #define MAX_CANDIDATES 32 -int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sockaddr_in *peerip, const sid_t *peersidp); +int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct socket_address *addr, const sid_t *peersidp); rhizome_manifest * rhizome_fetch_search(const unsigned char *id, int prefix_length); /* Rhizome file storage api */ @@ -994,7 +994,10 @@ enum rhizome_start_fetch_result { SLOTBUSY }; -enum rhizome_start_fetch_result rhizome_fetch_request_manifest_by_prefix(const struct sockaddr_in *peerip, const sid_t *sidp, const unsigned char *prefix, size_t prefix_length); +enum rhizome_start_fetch_result +rhizome_fetch_request_manifest_by_prefix(const struct socket_address *addr, + const sid_t *peersidp, + const unsigned char *prefix, size_t prefix_length); int rhizome_any_fetch_active(); int rhizome_any_fetch_queued(); int rhizome_fetch_status_html(struct strbuf *b); diff --git a/rhizome_direct_http.c b/rhizome_direct_http.c index a5a7b60f..5ec1759b 100644 --- a/rhizome_direct_http.c +++ b/rhizome_direct_http.c @@ -17,16 +17,19 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include +#include +#include +#include + #include "serval.h" #include "rhizome.h" #include "conf.h" #include "str.h" #include "strbuf.h" #include "strbuf_helpers.h" -#include -#include -#include -#include +#include "socket.h" + static int _form_temporary_file_path(struct __sourceloc __whence, rhizome_http_request *r, char *pathbuf, size_t bufsiz, const char *field) { @@ -488,14 +491,15 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r) goto end; } - struct sockaddr_in addr; - addr.sin_family = AF_INET; - addr.sin_port = htons(state->port); - addr.sin_addr = *((struct in_addr *)hostent->h_addr); - bzero(&(addr.sin_zero),8); + struct socket_address addr; + bzero(&addr,sizeof(addr)); + addr.addrlen = sizeof(addr.inet); + addr.inet.sin_family = AF_INET; + addr.inet.sin_port = htons(state->port); + addr.inet.sin_addr = *((struct in_addr *)hostent->h_addr); - if (connect(sock, (struct sockaddr *)&addr, sizeof addr) == -1) { - WHYF_perror("connect(%s)", alloca_sockaddr(&addr, sizeof addr)); + if (connect(sock, &addr.addr, addr.addrlen) == -1) { + WHYF_perror("connect(%s)", alloca_socket_address(&addr)); close(sock); goto end; } @@ -693,18 +697,13 @@ void rhizome_direct_http_dispatch(rhizome_direct_sync_request *r) len+=m->manifest_all_bytes; len+=snprintf(&buffer[len],8192-len,template3,boundary); - addr.sin_family = AF_INET; - addr.sin_port = htons(state->port); - addr.sin_addr = *((struct in_addr *)hostent->h_addr); - bzero(&(addr.sin_zero),8); - sock=socket(AF_INET, SOCK_STREAM, 0); if (sock==-1) { if (config.debug.rhizome_tx) DEBUGF("could not open socket"); goto closeit; } - if (connect(sock,(struct sockaddr *)&addr,sizeof(struct sockaddr)) == -1) { + if (connect(sock,&addr.addr,addr.addrlen) == -1) { if (config.debug.rhizome_tx) DEBUGF("Could not connect to remote"); goto closeit; diff --git a/rhizome_fetch.c b/rhizome_fetch.c index 903fc8a9..62ce96f1 100644 --- a/rhizome_fetch.c +++ b/rhizome_fetch.c @@ -37,7 +37,7 @@ struct rhizome_fetch_candidate { /* Address of node offering manifest. Can be either IP+port for HTTP or it can be a SID for MDP. */ - struct sockaddr_in peer_ipandport; + struct socket_address addr; sid_t peer_sid; int priority; @@ -50,7 +50,7 @@ struct rhizome_fetch_slot { struct sched_ent alarm; // must be first element in struct rhizome_manifest *manifest; - struct sockaddr_in peer_ipandport; + struct socket_address addr; sid_t peer_sid; int state; @@ -593,34 +593,25 @@ schedule_fetch(struct rhizome_fetch_slot *slot) slot->alarm.function = rhizome_fetch_poll; slot->alarm.stats = &fetch_stats; - if (slot->peer_ipandport.sin_family == AF_INET && slot->peer_ipandport.sin_port) { + if (slot->addr.addr.sa_family == AF_INET && slot->addr.inet.sin_port) { /* Transfer via HTTP over IPv4 */ if ((sock = esocket(AF_INET, SOCK_STREAM, 0)) == -1) goto bail_http; if (set_nonblock(sock) == -1) goto bail_http; - char buf[INET_ADDRSTRLEN]; - if (inet_ntop(AF_INET, &slot->peer_ipandport.sin_addr, buf, sizeof buf) == NULL) { - buf[0] = '*'; - buf[1] = '\0'; - } - if (connect(sock, (struct sockaddr*)&slot->peer_ipandport, - sizeof slot->peer_ipandport) == -1) { + if (connect(sock, &slot->addr.addr, slot->addr.addrlen) == -1) { if (errno == EINPROGRESS) { if (config.debug.rhizome_rx) DEBUGF("connect() returned EINPROGRESS"); } else { - WHYF_perror("connect(%d, %s:%u)", sock, buf, - ntohs(slot->peer_ipandport.sin_port)); + WHYF_perror("connect(%d, %s)", sock, alloca_socket_address(&slot->addr)); goto bail_http; } } if (config.debug.rhizome_rx) - DEBUGF("RHIZOME HTTP REQUEST family=%u addr=%s sid=%s port=%u %s", - slot->peer_ipandport.sin_family, - buf, + DEBUGF("RHIZOME HTTP REQUEST addr=%s sid=%s %s", + alloca_socket_address(&slot->addr), alloca_tohex_sid_t(slot->peer_sid), - ntohs(slot->peer_ipandport.sin_port), alloca_str_toprint(slot->request) ); slot->alarm.poll.fd = sock; @@ -684,7 +675,8 @@ schedule_fetch(struct rhizome_fetch_slot *slot) * @author Andrew Bettison */ static enum rhizome_start_fetch_result -rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct sockaddr_in *peerip, const sid_t *peersidp) +rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, + const struct socket_address *addr, const sid_t *peersidp) { IN(); if (slot->state != RHIZOME_FETCH_FREE) @@ -705,12 +697,12 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct */ if (config.debug.rhizome_rx) - DEBUGF("Fetching bundle slot=%d bid=%s version=%"PRIu64" size=%"PRIu64" peerip=%s", + DEBUGF("Fetching bundle slot=%d bid=%s version=%"PRIu64" size=%"PRIu64" addr=%s", slotno(slot), alloca_tohex_rhizome_bid_t(m->cryptoSignPublic), m->version, m->filesize, - alloca_sockaddr(peerip, sizeof(struct sockaddr_in)) + alloca_socket_address(addr) ); // If the payload is empty, no need to fetch, so import now. @@ -767,7 +759,7 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct DEBUGF(" is new"); /* Prepare for fetching */ - slot->peer_ipandport = *peerip; + slot->addr = *addr; slot->peer_sid = *peersidp; slot->manifest = m; @@ -787,17 +779,17 @@ rhizome_fetch(struct rhizome_fetch_slot *slot, rhizome_manifest *m, const struct * Returns -1 on error. */ enum rhizome_start_fetch_result -rhizome_fetch_request_manifest_by_prefix(const struct sockaddr_in *peerip, +rhizome_fetch_request_manifest_by_prefix(const struct socket_address *addr, const sid_t *peersidp, const unsigned char *prefix, size_t prefix_length) { - assert(peerip); + assert(addr); struct rhizome_fetch_slot *slot = rhizome_find_fetch_slot(MAX_MANIFEST_BYTES); if (slot == NULL) return SLOTBUSY; /* Prepare for fetching via HTTP */ - slot->peer_ipandport = *peerip; + slot->addr = *addr; slot->manifest = NULL; slot->peer_sid = *peersidp; bcopy(prefix, slot->bid.binary, prefix_length); @@ -824,7 +816,7 @@ static void rhizome_start_next_queued_fetch(struct rhizome_fetch_slot *slot) unsigned i = 0; struct rhizome_fetch_candidate *c; while (i < q->candidate_queue_size && (c = &q->candidate_queue[i])->manifest) { - int result = rhizome_fetch(slot, c->manifest, &c->peer_ipandport, &c->peer_sid); + int result = rhizome_fetch(slot, c->manifest, &c->addr, &c->peer_sid); switch (result) { case SLOTBUSY: OUT(); return; @@ -880,7 +872,7 @@ int rhizome_fetch_has_queue_space(unsigned char log2_size){ return 0; } -/* Queue a fetch for the payload of the given manifest. If 'peerip' is not NULL, then it is used as +/* Queue a fetch for the payload of the given manifest. If 'addr' is not NULL, then it is used as * the port and IP address of an HTTP server from which the fetch is performed. Otherwise the fetch * is performed over MDP. * @@ -897,7 +889,7 @@ int rhizome_fetch_has_queue_space(unsigned char log2_size){ * * @author Andrew Bettison */ -int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sockaddr_in *peerip, const sid_t *peersidp) +int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct socket_address *addr, const sid_t *peersidp) { IN(); @@ -1000,7 +992,7 @@ int rhizome_suggest_queue_manifest_import(rhizome_manifest *m, const struct sock struct rhizome_fetch_candidate *c = rhizome_fetch_insert(qi, ci); c->manifest = m; c->priority = priority; - c->peer_ipandport = *peerip; + c->addr = *addr; c->peer_sid = *peersidp; if (config.debug.rhizome_rx) { @@ -1332,13 +1324,8 @@ static int rhizome_write_complete(struct rhizome_fetch_slot *slot) } if (slot->state==RHIZOME_FETCH_RXFILE) { - char buf[INET_ADDRSTRLEN]; - if (inet_ntop(AF_INET, &slot->peer_ipandport.sin_addr, buf, sizeof buf) == NULL) { - buf[0] = '*'; - buf[1] = '\0'; - } - INFOF("Completed http request from %s:%u for file %s", - buf, ntohs(slot->peer_ipandport.sin_port), + INFOF("Completed http request from %s for file %s", + alloca_socket_address(&slot->addr), alloca_tohex_rhizome_filehash_t(slot->manifest->filehash)); } else { INFOF("Completed MDP request from %s for file %s", @@ -1362,11 +1349,12 @@ static int rhizome_write_complete(struct rhizome_fetch_slot *slot) rhizome_manifest_free(m); } else { if (config.debug.rhizome_rx){ - DEBUGF("All looks good for importing manifest id=%s", alloca_tohex_rhizome_bid_t(m->cryptoSignPublic)); - dump("slot->peerip",&slot->peer_ipandport,sizeof(slot->peer_ipandport)); - dump("slot->peersid",&slot->peer_sid,sizeof(slot->peer_sid)); + DEBUGF("All looks good for importing manifest id=%s, addr=%s, sid=%s", + alloca_tohex_rhizome_bid_t(m->cryptoSignPublic), + alloca_socket_address(&slot->addr), + alloca_tohex_sid_t(slot->peer_sid)); } - rhizome_suggest_queue_manifest_import(m, &slot->peer_ipandport, &slot->peer_sid); + rhizome_suggest_queue_manifest_import(m, &slot->addr, &slot->peer_sid); } } } diff --git a/rhizome_http.c b/rhizome_http.c index 68e31a27..d2480ae4 100644 --- a/rhizome_http.c +++ b/rhizome_http.c @@ -35,6 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "rhizome.h" #include "dataformats.h" #include "http_server.h" +#include "overlay_interface.h" #define RHIZOME_SERVER_MAX_LIVE_REQUESTS 32 diff --git a/rhizome_packetformats.c b/rhizome_packetformats.c index c7c9e716..130e562c 100644 --- a/rhizome_packetformats.c +++ b/rhizome_packetformats.c @@ -290,14 +290,17 @@ int overlay_rhizome_saw_advertisements(struct decode_context *context, struct ov RETURN(0); int ad_frame_type=ob_get(f->payload); - struct sockaddr_in httpaddr = context->addr; - httpaddr.sin_port = htons(RHIZOME_HTTP_PORT); + struct socket_address httpaddr = context->addr; + if (httpaddr.addr.sa_family == AF_INET) + httpaddr.inet.sin_port = htons(RHIZOME_HTTP_PORT); rhizome_manifest *m=NULL; int (*oldfunc)() = sqlite_set_tracefunc(is_debug_rhizome_ads); if (ad_frame_type & HAS_PORT){ - httpaddr.sin_port = htons(ob_get_ui16(f->payload)); + uint16_t port = ob_get_ui16(f->payload); + if (httpaddr.addr.sa_family == AF_INET) + httpaddr.inet.sin_port = htons(port); } if (ad_frame_type & HAS_MANIFESTS){ diff --git a/route_link.c b/route_link.c index 8761209b..0da0734c 100644 --- a/route_link.c +++ b/route_link.c @@ -20,6 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "serval.h" #include "overlay_address.h" #include "overlay_buffer.h" +#include "overlay_interface.h" #include "overlay_packet.h" #include "str.h" #include "conf.h" @@ -189,9 +190,9 @@ struct network_destination * new_destination(struct overlay_interface *interface return ret; } -struct network_destination * create_unicast_destination(struct sockaddr_in addr, struct overlay_interface *interface){ - if (!interface) - interface = overlay_interface_find(addr.sin_addr, 1); +struct network_destination * create_unicast_destination(struct socket_address *addr, struct overlay_interface *interface){ + if (!interface && addr->addr.sa_family == AF_INET) + interface = overlay_interface_find(addr->inet.sin_addr, 1); if (!interface){ WHY("I don't know which interface to use"); return NULL; @@ -200,14 +201,12 @@ struct network_destination * create_unicast_destination(struct sockaddr_in addr, WHY("The interface is down."); return NULL; } - if (addr.sin_addr.s_addr==0 || addr.sin_port==0){ -// WHY("Invalid unicast address"); + if (addr->addr.sa_family == AF_INET && (addr->inet.sin_addr.s_addr==0 || addr->inet.sin_port==0)) return NULL; - } struct network_destination *ret = new_destination(interface, ENCAP_OVERLAY); if (ret){ - ret->address = addr; + ret->address = *addr; ret->unicast = 1; ret->tick_ms = interface->destination->tick_ms; ret->sequence_number = -1; @@ -1107,20 +1106,20 @@ int link_received_duplicate(struct subscriber *subscriber, int payload_seq) } // remote peer has confirmed hearing a recent unicast packet -int link_unicast_ack(struct subscriber *UNUSED(subscriber), struct overlay_interface *UNUSED(interface), struct sockaddr_in UNUSED(addr)) +int link_unicast_ack(struct subscriber *UNUSED(subscriber), struct overlay_interface *UNUSED(interface), struct socket_address *UNUSED(addr)) { // TODO find / create network destination, keep it alive return 0; } -static struct link_out *create_out_link(struct neighbour *neighbour, overlay_interface *interface, struct sockaddr_in *addr, char unicast) +static struct link_out *create_out_link(struct neighbour *neighbour, overlay_interface *interface, struct socket_address *addr, char unicast) { struct link_out *ret=emalloc_zero(sizeof(struct link_out)); if (ret){ ret->_next=neighbour->out_links; neighbour->out_links=ret; if (unicast) - ret->destination = create_unicast_destination(*addr, interface); + ret->destination = create_unicast_destination(addr, interface); else ret->destination = add_destination_ref(interface->destination); if (config.debug.linkstate) @@ -1135,7 +1134,7 @@ static struct link_out *create_out_link(struct neighbour *neighbour, overlay_int return ret; } -static void create_out_links(struct neighbour *neighbour, overlay_interface *interface, struct sockaddr_in *addr){ +static void create_out_links(struct neighbour *neighbour, overlay_interface *interface, struct socket_address *addr){ struct link_out *l = neighbour->out_links; while(l){ if (l->destination->interface==interface) @@ -1143,13 +1142,13 @@ static void create_out_links(struct neighbour *neighbour, overlay_interface *int l=l->_next; } // if this packet arrived in an IPv4 packet, assume we need to send them unicast packets - if (addr && addr->sin_family==AF_INET && addr->sin_port!=0 && addr->sin_addr.s_addr!=0) + if (addr && addr->addr.sa_family==AF_INET && addr->inet.sin_port!=0 && addr->inet.sin_addr.s_addr!=0) create_out_link(neighbour, interface, addr, 1); // if this packet arrived from the same IPv4 subnet, or a different type of network, assume they can hear our broadcasts - if (!addr || addr->sin_family!=AF_INET || - (addr->sin_addr.s_addr & interface->netmask.s_addr) - == (interface->address.sin_addr.s_addr & interface->netmask.s_addr)) + if (!addr || addr->addr.sa_family!=AF_INET || + (addr->inet.sin_addr.s_addr & interface->netmask.s_addr) + == (interface->address.inet.sin_addr.s_addr & interface->netmask.s_addr)) create_out_link(neighbour, interface, addr, 0); } diff --git a/serval.h b/serval.h index 2a7794e5..6d6ff7fe 100644 --- a/serval.h +++ b/serval.h @@ -244,12 +244,12 @@ extern char *batman_peerfile; struct subscriber; struct decode_context; struct socket_address; +struct overlay_interface; +struct network_destination; /* Make sure we have space to put bytes of the packet as we go along */ #define CHECK_PACKET_LEN(B) {if (((*packet_len)+(B))>=packet_maxlen) { return WHY("Packet composition ran out of space."); } } -extern int sock; - struct limit_state{ // length of time for a burst time_ms_t burst_length; @@ -270,11 +270,6 @@ struct broadcast; extern int overlayMode; -#define INTERFACE_STATE_FREE 0 -#define INTERFACE_STATE_UP 1 -#define INTERFACE_STATE_DOWN 2 -#define INTERFACE_STATE_DETECTING 3 - // Specify the size of the receive buffer. // This effectively sets the MRU for packet radio interfaces // where we have to buffer packets on the receive side @@ -305,123 +300,6 @@ struct slip_decode_state{ unsigned dst_offset; }; -struct overlay_interface; - -// where should packets be sent to? -struct network_destination { - int _ref_count; - - // which interface are we actually sending packets out of - struct overlay_interface *interface; - - // The IPv4 destination address, this may be the interface broadcast address. - struct sockaddr_in address; - - // should outgoing packets be marked as unicast? - char unicast; - - char packet_version; - - // should we aggregate packets, or send one at a time - char encapsulation; - - // time last packet was sent - time_ms_t last_tx; - - int min_rtt; - int max_rtt; - int resend_delay; - - // sequence number of last packet sent to this destination. - // Used to allow NACKs that can request retransmission of recent packets. - int sequence_number; - - // rate limit for outgoing packets - struct limit_state transfer_limit; - - /* Number of milli-seconds per tick for this interface, which is basically - * related to the the typical TX range divided by the maximum expected - * speed of nodes in the network. This means that short-range communications - * has a higher bandwidth requirement than long-range communications because - * the tick interval has to be shorter to still allow fast-convergence time - * to allow for mobility. - * - * For wifi (nominal range 100m) it is usually 500ms. - * For ~100K ISM915MHz (nominal range 1000m) it will probably be about 5000ms. - * For ~10K ISM915MHz (nominal range ~3000m) it will probably be about 15000ms. - * - * These figures will be refined over time, and we will allow people to set - * them per-interface. - */ - unsigned tick_ms; - - // Number of milliseconds of no packets until we assume the link is dead. - unsigned reachable_timeout_ms; -}; - -struct network_destination * new_destination(struct overlay_interface *interface, char encapsulation); -struct network_destination * create_unicast_destination(struct sockaddr_in addr, struct overlay_interface *interface); -struct network_destination * add_destination_ref(struct network_destination *ref); -void release_destination_ref(struct network_destination *ref); -int set_destination_ref(struct network_destination **ptr, struct network_destination *ref); - -typedef struct overlay_interface { - struct sched_ent alarm; - - char name[256]; - - int recv_offset; /* file offset */ - - int recv_count; - int tx_count; - - struct radio_link_state *radio_link_state; - - // copy of ifconfig flags - uint16_t drop_packets; - char drop_broadcasts; - char drop_unicasts; - int port; - int type; - int socket_type; - char send_broadcasts; - char prefer_unicast; - /* Not necessarily the real MTU, but the largest frame size we are willing to TX. - For radio links the actual maximum and the maximum that is likely to be delivered reliably are - potentially two quite different values. */ - int mtu; - // can we use this interface for routes to addresses in other subnets? - int default_route; - // should we log more debug info on this interace? eg hex dumps of packets - char debug; - char local_echo; - - unsigned int uartbps; // set serial port speed (which might be different from link speed) - int ctsrts; // enabled hardware flow control if non-zero - - struct network_destination *destination; - - // can we assume that we will only receive packets from one device? - char point_to_point; - struct subscriber *other_device; - - // the actual address of the interface. - struct sockaddr_in address; - struct in_addr netmask; - - /* Use one of the INTERFACE_STATE_* constants to indicate the state of this interface. - If the interface stops working or disappears, it will be marked as DOWN and the socket closed. - But if it comes back up again, we should try to reuse this structure, even if the broadcast address has changed. - */ - int state; -} overlay_interface; - -/* Maximum interface count is rather arbitrary. - Memory consumption is O(n) with respect to this parameter, so let's not make it too big for now. - */ -extern overlay_interface overlay_interfaces[OVERLAY_MAX_INTERFACES]; -extern int overlay_last_interface_number; // used to remember where a packet came from -extern unsigned int overlay_sequence_number; int server_pid(); void server_save_argv(int argc, const char *const *argv); @@ -439,14 +317,11 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s int parseMdpPacketHeader(struct decode_context *context, struct overlay_frame *frame, struct overlay_buffer *buffer, struct subscriber **nexthop); int parseEnvelopeHeader(struct decode_context *context, struct overlay_interface *interface, - struct sockaddr_in *addr, struct overlay_buffer *buffer); + struct socket_address *addr, struct overlay_buffer *buffer); int process_incoming_frame(time_ms_t now, struct overlay_interface *interface, struct overlay_frame *f, struct decode_context *context); int overlay_frame_process(struct overlay_interface *interface, struct overlay_frame *f); -int overlay_frame_resolve_addresses(struct overlay_frame *f); - -time_ms_t overlay_time_until_next_tick(); int overlay_frame_append_payload(struct decode_context *context, int encapsulation, struct overlay_frame *p, struct overlay_buffer *b, @@ -454,20 +329,9 @@ int overlay_frame_append_payload(struct decode_context *context, int encapsulati int overlay_packet_init_header(int packet_version, int encapsulation, struct decode_context *context, struct overlay_buffer *buff, char unicast, char interface, int seq); -int overlay_interface_args(const char *arg); void overlay_rhizome_advertise(struct sched_ent *alarm); void rhizome_sync_status_html(struct strbuf *b, struct subscriber *subscriber); int rhizome_cache_count(); -int overlay_add_local_identity(unsigned char *s); - -extern unsigned overlay_interface_count; - -extern int overlay_local_identity_count; -extern unsigned char *overlay_local_identities[OVERLAY_MAX_LOCAL_IDENTITIES]; - -int rfs_length(int l); -int rfs_encode(int l,unsigned char *b); -int rfs_decode(unsigned char *b,int *offset); int overlayServerMode(const struct cli_parsed *parsed); int overlay_payload_enqueue(struct overlay_frame *p); @@ -477,7 +341,6 @@ int overlay_send_tick_packet(struct network_destination *destination); int overlay_queue_ack(struct subscriber *neighbour, struct network_destination *destination, uint32_t ack_mask, int ack_seq); int overlay_rhizome_saw_advertisements(struct decode_context *context, struct overlay_frame *f); -int rhizome_server_get_fds(struct pollfd *fds,int *fdcount,int fdmax); int rhizome_saw_voice_traffic(); int overlay_saw_mdp_containing_frame(struct overlay_frame *f); @@ -486,13 +349,10 @@ int serval_packetvisualise_xpf(XPRINTF xpf, const char *message, const unsigned void logServalPacket(int level, struct __sourceloc __whence, const char *message, const unsigned char *packet, size_t len); #define DEBUG_packet_visualise(M,P,N) logServalPacket(LOG_LEVEL_DEBUG, __WHENCE__, (M), (P), (N)) -int rhizome_fetching_get_fds(struct pollfd *fds,int *fdcount,int fdmax); int rhizome_opendb(); int parseCommandLine(struct cli_context *context, const char *argv0, int argc, const char *const *argv); -int overlay_mdp_get_fds(struct pollfd *fds,int *fdcount,int fdmax); - typedef uint32_t mdp_port_t; #define PRImdp_port_t "#08" PRIx32 @@ -567,7 +427,6 @@ int mdp_unbind_internal(struct subscriber *subscriber, mdp_port_t port, struct vomp_call_state; void set_codec_flag(int codec, unsigned char *flags); -int is_codec_set(int codec, unsigned char *flags); struct vomp_call_state *vomp_find_call_by_session(unsigned int session_token); int vomp_mdp_received(overlay_mdp_frame *mdp); @@ -580,17 +439,6 @@ int vomp_received_audio(struct vomp_call_state *call, int audio_codec, int time, const unsigned char *audio, int audio_length); void monitor_get_all_supported_codecs(unsigned char *codecs); -int overlay_route_node_info(overlay_mdp_nodeinfo *node_info); -int overlay_interface_register(char *name, - struct in_addr addr, - struct in_addr mask); -overlay_interface * overlay_interface_get_default(); -overlay_interface * overlay_interface_find(struct in_addr addr, int return_default); -overlay_interface * overlay_interface_find_name(const char *name); -int overlay_interface_compare(overlay_interface *one, overlay_interface *two); -int overlay_broadcast_ensemble(struct network_destination *destination, struct overlay_buffer *buffer); -void interface_state_html(struct strbuf *b, struct overlay_interface *interface); - int directory_registration(); int directory_service_init(); @@ -616,37 +464,9 @@ int monitor_tell_formatted(int mask, char *fmt, ...); int monitor_client_interested(int mask); extern int monitor_socket_count; - -typedef struct monitor_audio { - char name[128]; - int (*start)(); - int (*stop)(); - int (*poll_fds)(struct pollfd *,int); - int (*read)(unsigned char *,int); - int (*write)(unsigned char *,int); -} monitor_audio; -extern monitor_audio *audev; - -monitor_audio *audio_msm_g1_detect(); -monitor_audio *audio_alsa_detect(); -monitor_audio *audio_reflector_detect(); -int detectAudioDevice(); -int getAudioPlayFd(); -int getAudioRecordFd(); -int getAudioBytes(unsigned char *buffer, - int offset, - int bufferSize); -int encodeAndDispatchRecordedAudio(int fd,int callSessionToken, - int recordCodec, - unsigned char *sampleData, - int sampleBytes); int scrapeProcNetRoute(); int lsif(); int doifaddrs(); -int bufferAudioForPlayback(int codec, time_ms_t start_time, time_ms_t end_time, - unsigned char *data,int dataLen); -int startAudio(); -int stopAudio(); #define SERVER_UNKNOWN 1 #define SERVER_NOTRESPONDING 2 @@ -667,11 +487,7 @@ void sigIoHandler(int signal); int overlay_mdp_setup_sockets(); -void overlay_interface_discover(struct sched_ent *alarm); -void overlay_packetradio_poll(struct sched_ent *alarm); -int overlay_packetradio_setup_port(overlay_interface *interface); -int overlay_packetradio_tx_packet(struct overlay_frame *frame); -void overlay_dummy_poll(struct sched_ent *alarm); +int overlay_packetradio_setup_port(struct overlay_interface *interface); void server_config_reload(struct sched_ent *alarm); void server_shutdown_check(struct sched_ent *alarm); int overlay_mdp_try_internal_services(struct overlay_frame *frame, overlay_mdp_frame *mdp); @@ -680,7 +496,6 @@ int overlay_send_stun_request(struct subscriber *server, struct subscriber *requ void fd_periodicstats(struct sched_ent *alarm); void rhizome_check_connections(struct sched_ent *alarm); -int overlay_tick_interface(int i, time_ms_t now); int overlay_queue_init(); void monitor_client_poll(struct sched_ent *alarm); @@ -722,7 +537,7 @@ int link_state_announce_links(); int link_state_legacy_ack(struct overlay_frame *frame, time_ms_t now); int link_state_ack_soon(struct subscriber *sender); int link_state_should_forward_broadcast(struct subscriber *transmitter); -int link_unicast_ack(struct subscriber *subscriber, struct overlay_interface *interface, struct sockaddr_in addr); +int link_unicast_ack(struct subscriber *subscriber, struct overlay_interface *interface, struct socket_address *addr); int link_add_destinations(struct overlay_frame *frame); void link_neighbour_short_status_html(struct strbuf *b, const char *link_prefix); void link_neighbour_status_html(struct strbuf *b, struct subscriber *neighbour); diff --git a/server.c b/server.c index 317522e6..3882f127 100644 --- a/server.c +++ b/server.c @@ -27,6 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "conf.h" #include "strbuf.h" #include "strbuf_helpers.h" +#include "overlay_interface.h" #define PIDFILE_NAME "servald.pid" #define STOPFILE_NAME "servald.stop" diff --git a/socket.c b/socket.c index 195ecf03..7c0df893 100644 --- a/socket.c +++ b/socket.c @@ -164,6 +164,7 @@ int cmp_sockaddr(const struct socket_address *addrA, const struct socket_address (addrA->addrlen < addrB->addrlen ? addrA->addrlen : addrB->addrlen) - sizeof addrA->addr.sa_family); if (c == 0) c = addrA->addrlen < addrB->addrlen ? -1 : addrA->addrlen > addrB->addrlen ? 1 : 0; + return c; } @@ -234,6 +235,24 @@ int _socket_set_rcvbufsize(struct __sourceloc __whence, int sock, unsigned buffe return 0; } +int socket_unlink_close(int sock) +{ + // get the socket name and unlink it from the filesystem if not abstract + struct socket_address addr; + addr.addrlen = sizeof addr.store; + if (getsockname(sock, &addr.addr, &addr.addrlen)) + WHYF_perror("getsockname(%d)", sock); + else if (addr.addr.sa_family==AF_UNIX + && addr.addrlen > sizeof addr.local.sun_family + && addr.addrlen <= sizeof addr.local + && addr.local.sun_path[0] != '\0') { + if (unlink(addr.local.sun_path) == -1) + WARNF_perror("unlink(%s)", alloca_str_toprint(addr.local.sun_path)); + } + close(sock); + return 0; +} + ssize_t _send_message(struct __sourceloc __whence, int fd, const struct socket_address *address, const struct fragmented_data *data) { struct msghdr hdr={ @@ -260,5 +279,6 @@ ssize_t _recv_message(struct __sourceloc __whence, int fd, struct socket_address ssize_t ret = recvmsg(fd, &hdr, 0); if (ret==-1) WHYF_perror("recvmsg(%d,%s,%lu)", fd, alloca_socket_address(address), (unsigned long)address->addrlen); + address->addrlen = hdr.msg_namelen; return ret; } diff --git a/socket.h b/socket.h index ce8743be..551d02c8 100644 --- a/socket.h +++ b/socket.h @@ -54,6 +54,7 @@ int _socket_connect(struct __sourceloc, int sock, const struct sockaddr *addr, s int _socket_listen(struct __sourceloc, int sock, int backlog); int _socket_set_reuseaddr(struct __sourceloc, int sock, int reuseP); int _socket_set_rcvbufsize(struct __sourceloc, int sock, unsigned buffer_size); +int socket_unlink_close(int sock); #define make_local_sockaddr(sockname, fmt,...) _make_local_sockaddr(__WHENCE__, (sockname), (fmt), ##__VA_ARGS__) #define esocket(domain, type, protocol) _esocket(__WHENCE__, (domain), (type), (protocol)) From 506518ad06f1a6bb16b14c19af4e9fff892efb75 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 11 Dec 2013 16:41:57 +1030 Subject: [PATCH 06/18] Allow interfaces to use local unix addresses - broadcast packets are sent to all sockets in the same folder - switched most tests to use local sockets --- conf_schema.c | 8 -- overlay_interface.c | 168 ++++++++++++++++++++++++++++++---------- overlay_interface.h | 1 + overlay_mdp.c | 2 +- overlay_packet.h | 2 +- overlay_packetformats.c | 7 -- route_link.c | 3 +- serval.h | 1 + server.c | 11 +-- tests/routing | 115 ++++++++++++++------------- 10 files changed, 196 insertions(+), 122 deletions(-) diff --git a/conf_schema.c b/conf_schema.c index 928d3360..0475b237 100644 --- a/conf_schema.c +++ b/conf_schema.c @@ -985,14 +985,6 @@ int vld_network_interface(const struct cf_om_node *parent, struct config_network return result | CFINCOMPLETE; } } else { - if (nifp->socket_type == SOCK_DGRAM && nifp->file[0]){ - int nodei_socket_type = cf_om_get_child(parent, "socket_type", NULL); - int nodei_file = cf_om_get_child(parent, "file", NULL); - assert(nodei_socket_type != -1); - assert(nodei_file != -1); - cf_warn_incompatible(parent->nodv[nodei_socket_type], parent->nodv[nodei_file]); - return result | CFSUB(CFINCOMPATIBLE); - } if (nifp->socket_type != SOCK_DGRAM && !nifp->file[0]){ cf_warn_missing_node(parent, "file"); return result | CFSUB(CFINCOMPATIBLE); diff --git a/overlay_interface.c b/overlay_interface.c index c7e53bda..4ce5eed6 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -17,7 +17,9 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include #include +#include #include #include #include @@ -54,6 +56,8 @@ static void overlay_interface_poll(struct sched_ent *alarm); static void overlay_interface_close(overlay_interface *interface){ + if (interface->address.addr.sa_family == AF_UNIX) + unlink(interface->address.local.sun_path); link_interface_down(interface); INFOF("Interface %s addr %s is down", interface->name, alloca_socket_address(&interface->address)); @@ -66,6 +70,15 @@ overlay_interface_close(overlay_interface *interface){ interface->state=INTERFACE_STATE_DOWN; } +void overlay_interface_close_all() +{ + unsigned i; + for (i=0;istate){ @@ -320,10 +333,8 @@ static int overlay_interface_init_any(int port) } static int -overlay_interface_init_socket(int interface_index) +overlay_interface_init_socket(overlay_interface *interface) { - overlay_interface *const interface = &overlay_interfaces[interface_index]; - /* On linux you can bind to the broadcast address to receive broadcast packets per interface [or subnet], but then you can't receive unicast packets on the same socket. @@ -371,7 +382,9 @@ overlay_interface_init(const char *name, struct socket_address *addr, return WHY("Too many interfaces -- Increase OVERLAY_MAX_INTERFACES"); overlay_interface *const interface = &overlay_interfaces[overlay_interface_count]; - + bzero(interface, sizeof(overlay_interface)); + interface->state=INTERFACE_STATE_DOWN; + strncpy(interface->name, name, sizeof interface->name); // copy ifconfig values @@ -394,7 +407,6 @@ overlay_interface_init(const char *name, struct socket_address *addr, interface->mtu = 1200; interface->point_to_point = ifconfig->point_to_point; - interface->state=INTERFACE_STATE_DOWN; interface->alarm.poll.fd=0; interface->debug = ifconfig->debug; interface->tx_count=0; @@ -462,17 +474,19 @@ overlay_interface_init(const char *name, struct socket_address *addr, limit_init(&interface->destination->transfer_limit, packet_interval); - interface->address = *addr; - interface->destination->address = *broadcast; + if (addr) + interface->address = *addr; + if (broadcast) + interface->destination->address = *broadcast; interface->alarm.function = overlay_interface_poll; interface_poll_stats.name="overlay_interface_poll"; interface->alarm.stats=&interface_poll_stats; - if (ifconfig->socket_type==SOCK_DGRAM){ + if (ifconfig->socket_type == SOCK_DGRAM){ interface->local_echo = 1; - if (overlay_interface_init_socket(overlay_interface_count)) + if (overlay_interface_init_socket(interface)) return WHY("overlay_interface_init_socket() failed"); }else{ char read_file[1024]; @@ -767,6 +781,44 @@ static void overlay_interface_poll(struct sched_ent *alarm) } } +static int send_local_broadcast(int fd, const uint8_t *bytes, size_t len, struct socket_address *address) +{ + DIR *dir; + struct dirent *dp; + if ((dir = opendir(address->local.sun_path)) == NULL) { + WARNF_perror("opendir(%s)", alloca_str_toprint(address->local.sun_path)); + return -1; + } + while ((dp = readdir(dir)) != NULL) { + struct socket_address addr; + + strbuf d = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path); + strbuf_path_join(d, address->local.sun_path, dp->d_name, NULL); + if (strbuf_overrun(d)){ + WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d))); + continue; + } + + struct stat st; + if (lstat(addr.local.sun_path, &st)) { + WARNF_perror("stat(%s)", alloca_str_toprint(addr.local.sun_path)); + continue; + } + + if (S_ISSOCK(st.st_mode)){ + addr.local.sun_family = AF_UNIX; + addr.addrlen = sizeof(addr.local.sun_family) + strlen(addr.local.sun_path)+1; + + ssize_t sent = sendto(fd, bytes, len, 0, + &addr.addr, addr.addrlen); + if (sent == -1) + WHYF_perror("sendto(%d, %zu, %s)", fd, len, alloca_socket_address(&addr)); + } + } + closedir(dir); + return 0; +} + int overlay_broadcast_ensemble(struct network_destination *destination, struct overlay_buffer *buffer) { assert(destination && destination->interface); @@ -849,28 +901,33 @@ int overlay_broadcast_ensemble(struct network_destination *destination, struct o if (config.debug.overlayinterfaces) DEBUGF("Sending %zu byte overlay frame on %s to %s", (size_t)len, interface->name, alloca_socket_address(&destination->address)); - ssize_t sent = sendto(interface->alarm.poll.fd, - bytes, (size_t)len, 0, - (struct sockaddr *)&destination->address, sizeof(destination->address)); - ob_free(buffer); - if (sent == -1 || (size_t)sent != len) { - if (sent == -1) + + if (destination->address.addr.sa_family == AF_UNIX + && !destination->unicast){ + // find all sockets in this folder and send to them + send_local_broadcast(interface->alarm.poll.fd, + bytes, (size_t)len, &destination->address); + }else{ + ssize_t sent = sendto(interface->alarm.poll.fd, + bytes, (size_t)len, 0, + &destination->address.addr, destination->address.addrlen); + if (sent == -1){ WHYF_perror("sendto(fd=%d,len=%zu,addr=%s) on interface %s", interface->alarm.poll.fd, - len, - alloca_sockaddr((struct sockaddr *)&destination->address, sizeof destination->address), + (size_t)len, + alloca_socket_address(&destination->address), interface->name ); - else - WHYF("sendto() sent %zu bytes of overlay frame (%zu) to interface %s (socket=%d)", - (size_t)sent, len, interface->name, interface->alarm.poll.fd); - // close the interface if we had any error while sending broadcast packets, - // unicast packets should not bring the interface down - if (destination == interface->destination) - overlay_interface_close(interface); - // TODO mark unicast destination as failed - return -1; + // close the interface if we had any error while sending broadcast packets, + // unicast packets should not bring the interface down + // TODO mark unicast destination as failed? + if (destination == interface->destination) + overlay_interface_close(interface); + ob_free(buffer); + return -1; + } } + ob_free(buffer); return 0; } @@ -966,7 +1023,7 @@ void overlay_interface_discover(struct sched_ent *alarm) ifconfig = &config.interfaces.av[i].value; if (ifconfig->exclude) continue; - if (ifconfig->socket_type==SOCK_DGRAM) { + if (!*ifconfig->file) { detect_real_interfaces = 1; continue; } @@ -981,22 +1038,55 @@ void overlay_interface_discover(struct sched_ent *alarm) } if (j >= overlay_interface_count) { - // New dummy interface, so register it. + // New file interface, so register it. struct socket_address addr, broadcast; bzero(&addr, sizeof addr); bzero(&broadcast, sizeof broadcast); - addr.addrlen=sizeof addr.inet; - addr.inet.sin_family=AF_INET; - addr.inet.sin_port=htons(ifconfig->port); - addr.inet.sin_addr=ifconfig->dummy_address; - - broadcast.addrlen=sizeof addr.inet; - broadcast.inet.sin_family=AF_INET; - broadcast.inet.sin_port=htons(ifconfig->port); - broadcast.inet.sin_addr.s_addr=ifconfig->dummy_address.s_addr | ~ifconfig->dummy_netmask.s_addr; - - overlay_interface_init(ifconfig->file, &addr, &broadcast, ifconfig); + switch(ifconfig->socket_type){ + case SOCK_FILE: + // use a fake inet address + addr.addrlen=sizeof addr.inet; + addr.inet.sin_family=AF_INET; + addr.inet.sin_port=htons(ifconfig->port); + addr.inet.sin_addr=ifconfig->dummy_address; + + broadcast.addrlen=sizeof addr.inet; + broadcast.inet.sin_family=AF_INET; + broadcast.inet.sin_port=htons(ifconfig->port); + broadcast.inet.sin_addr.s_addr=ifconfig->dummy_address.s_addr | ~ifconfig->dummy_netmask.s_addr; + // Fallthrough + case SOCK_STREAM: + overlay_interface_init(ifconfig->file, &addr, &broadcast, ifconfig); + break; + case SOCK_DGRAM: + { + // use a local dgram socket + // no abstract sockets for now + strbuf d = strbuf_local(addr.local.sun_path, sizeof addr.local.sun_path); + strbuf_path_join(d, serval_instancepath(), config.server.interface_path, ifconfig->file, NULL); + if (strbuf_overrun(d)){ + WHYF("interface file name overrun: %s", alloca_str_toprint(strbuf_str(d))); + // TODO set ifconfig->exclude to prevent spam?? + break; + } + unlink(addr.local.sun_path); + addr.local.sun_family=AF_UNIX; + size_t len = strlen(addr.local.sun_path); + + addr.addrlen=sizeof addr.local.sun_family + len + 1; + + broadcast = addr; + while(len && broadcast.local.sun_path[len]!='/') + broadcast.local.sun_path[len--]='\0'; + broadcast.addrlen = sizeof addr.local.sun_family + len + 2; + + DEBUGF("Attempting to bind local socket w. addr %s, broadcast %s", + alloca_socket_address(&addr), alloca_socket_address(&broadcast)); + overlay_interface_init(ifconfig->file, &addr, &broadcast, ifconfig); + break; + } + } } } diff --git a/overlay_interface.h b/overlay_interface.h index 39bb8a51..736144bf 100644 --- a/overlay_interface.h +++ b/overlay_interface.h @@ -135,6 +135,7 @@ void overlay_interface_discover(struct sched_ent *alarm); int overlay_interface_register(char *name, struct socket_address *addr, struct socket_address *broadcast); +void overlay_interface_close_all(); overlay_interface * overlay_interface_get_default(); overlay_interface * overlay_interface_find(struct in_addr addr, int return_default); overlay_interface * overlay_interface_find_name(const char *name); diff --git a/overlay_mdp.c b/overlay_mdp.c index 755dd417..50354660 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -87,7 +87,7 @@ static int mdp_send2(struct socket_address *client, struct mdp_header *header, const uint8_t *payload, size_t payload_len); /* Delete all UNIX socket files in instance directory. */ -static void overlay_mdp_clean_socket_files() +void overlay_mdp_clean_socket_files() { const char *instance_path = serval_instancepath(); DIR *dir; diff --git a/overlay_packet.h b/overlay_packet.h index bc0cdd5c..3c734829 100644 --- a/overlay_packet.h +++ b/overlay_packet.h @@ -85,7 +85,7 @@ struct overlay_frame { // how did we receive this packet? struct overlay_interface *interface; - struct sockaddr_in recvaddr; + // packet envelope header; // Was it a unicast frame char unicast; diff --git a/overlay_packetformats.c b/overlay_packetformats.c index 177ffab3..e51754d3 100644 --- a/overlay_packetformats.c +++ b/overlay_packetformats.c @@ -389,9 +389,6 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s } } - if (recvaddr && recvaddr->addr.sa_family != AF_INET) - RETURN(WHYF("Unexpected address %s", alloca_socket_address(recvaddr))); - struct overlay_frame f; struct decode_context context; bzero(&context, sizeof context); @@ -402,10 +399,6 @@ int packetOkOverlay(struct overlay_interface *interface,unsigned char *packet, s ob_limitsize(b, len); f.interface = interface; - if (recvaddr) - f.recvaddr = recvaddr->inet; - else - bzero(&f.recvaddr, sizeof f.recvaddr); int ret=parseEnvelopeHeader(&context, interface, recvaddr, b); if (ret){ diff --git a/route_link.c b/route_link.c index 0da0734c..20f3e432 100644 --- a/route_link.c +++ b/route_link.c @@ -1142,8 +1142,7 @@ static void create_out_links(struct neighbour *neighbour, overlay_interface *int l=l->_next; } // if this packet arrived in an IPv4 packet, assume we need to send them unicast packets - if (addr && addr->addr.sa_family==AF_INET && addr->inet.sin_port!=0 && addr->inet.sin_addr.s_addr!=0) - create_out_link(neighbour, interface, addr, 1); + create_out_link(neighbour, interface, addr, 1); // if this packet arrived from the same IPv4 subnet, or a different type of network, assume they can hear our broadcasts if (!addr || addr->addr.sa_family!=AF_INET || diff --git a/serval.h b/serval.h index 6d6ff7fe..204c76a9 100644 --- a/serval.h +++ b/serval.h @@ -307,6 +307,7 @@ int server(const struct cli_parsed *parsed); int server_create_stopfile(); int server_remove_stopfile(); int server_check_stopfile(); +void overlay_mdp_clean_socket_files(); void serverCleanUp(); int isTransactionInCache(unsigned char *transaction_id); void insertTransactionInCache(unsigned char *transaction_id); diff --git a/server.c b/server.c index 3882f127..1c9f8bb0 100644 --- a/server.c +++ b/server.c @@ -234,17 +234,10 @@ void serverCleanUp() if (serverMode){ rhizome_close_db(); dna_helper_shutdown(); + overlay_interface_close_all(); } - char filename[1024]; - if (FORM_SERVAL_INSTANCE_PATH(filename, "mdp.socket")) - unlink(filename); - - if (FORM_SERVAL_INSTANCE_PATH(filename, "mdp.2.socket")) - unlink(filename); - - if (FORM_SERVAL_INSTANCE_PATH(filename, "monitor.socket")) - unlink(filename); + overlay_mdp_clean_socket_files(); /* Try to remove shutdown and PID files and exit */ server_remove_stopfile(); diff --git a/tests/routing b/tests/routing index 2d2381e6..41691acc 100755 --- a/tests/routing +++ b/tests/routing @@ -22,7 +22,14 @@ source "${0%/*}/../testframework.sh" source "${0%/*}/../testdefs.sh" -add_interface() { +add_local_interface() { + mkdir $SERVALD_VAR/dummy$1 + executeOk_servald config \ + set interfaces.$1.file dummy$1/$instance_number \ + set interfaces.$1.socket_type dgram +} + +add_dummy_interface() { >$SERVALD_VAR/dummy$1 executeOk_servald config \ set interfaces.$1.file dummy$1 \ @@ -81,7 +88,6 @@ start_routing_instance() { set debug.mdprequests yes \ set debug.linkstate yes \ set debug.verbose yes \ - set debug.subscriber yes \ set debug.overlayrouting yes \ set log.console.level debug \ set log.console.show_pid on \ @@ -109,7 +115,7 @@ setup_single_link() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_local_interface 1 foreach_instance +A +B start_routing_instance } test_single_link() { @@ -125,7 +131,7 @@ setup_multiple_ids() { setup_servald assert_no_servald_processes foreach_instance +A +B create_identities 2 - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_local_interface 1 foreach_instance +A +B start_routing_instance } test_multiple_ids() { @@ -152,7 +158,7 @@ setup_unlock_ids() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_local_interface 1 set_instance +A executeOk_servald keyring add 'entry-pin' extract_stdout_keyvalue SIDX sid "$rexp_sid" @@ -182,7 +188,7 @@ setup_migrate_id() { set_instance +B executeOk_servald keyring load sidx '' 'entry-pin' foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_local_interface 1 foreach_instance +A +B start_routing_instance } test_migrate_id() { @@ -201,7 +207,7 @@ setup_single_mdp() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_local_interface 1 foreach_instance +A +B executeOk_servald config set interfaces.1.encapsulation single foreach_instance +A +B start_routing_instance } @@ -218,7 +224,7 @@ setup_mismatched_encap() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_local_interface 1 foreach_instance +A executeOk_servald config set interfaces.1.encapsulation single foreach_instance +A +B start_routing_instance } @@ -235,10 +241,9 @@ setup_single_p2p() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_local_interface 1 foreach_instance +A +B \ executeOk_servald config \ - set interfaces.1.debug 1 \ set interfaces.1.encapsulation single \ set interfaces.1.point_to_point on foreach_instance +A +B start_routing_instance @@ -314,7 +319,7 @@ setup_multiple_nodes() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B +C +D add_interface 1 + foreach_instance +A +B +C +D add_local_interface 1 foreach_instance +A +B +C +D start_routing_instance } test_multiple_nodes() { @@ -338,7 +343,7 @@ setup_scan() { setup_servald assert_no_servald_processes foreach_instance +A +B +C create_single_identity - foreach_instance +A +B +C add_interface 1 + foreach_instance +A +B +C add_dummy_interface 1 foreach_instance +A +B +C \ executeOk_servald config \ set interfaces.1.drop_broadcasts on @@ -388,7 +393,7 @@ setup_single_filter() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_dummy_interface 1 set_instance +B executeOk_servald config \ set interfaces.1.drop_broadcasts on @@ -412,7 +417,7 @@ setup_broadcast_only() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_dummy_interface 1 foreach_instance +A +B \ executeOk_servald config set interfaces.1.drop_unicasts 1 foreach_instance +A +B start_routing_instance @@ -432,7 +437,7 @@ setup_prefer_unicast() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_local_interface 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.prefer_unicast 1 \ @@ -454,9 +459,9 @@ setup_multihop_linear() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B add_interface 1 - foreach_instance +B +C add_interface 2 - foreach_instance +C +D add_interface 3 + foreach_instance +A +B add_local_interface 1 + foreach_instance +B +C add_local_interface 2 + foreach_instance +C +D add_local_interface 3 foreach_instance +A +B +C +D start_routing_instance } test_multihop_linear() { @@ -480,9 +485,9 @@ setup_unicast_route() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B add_interface 1 - foreach_instance +B +C add_interface 2 - foreach_instance +C +D add_interface 3 + foreach_instance +A +B add_dummy_interface 1 + foreach_instance +B +C add_dummy_interface 2 + foreach_instance +C +D add_dummy_interface 3 set_instance +A executeOk_servald config \ set interfaces.1.drop_broadcasts on @@ -504,8 +509,8 @@ setup_offline() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B +C add_interface 1 - foreach_instance +A +B +D add_interface 2 + foreach_instance +A +B +C add_local_interface 1 + foreach_instance +A +B +D add_local_interface 2 foreach_instance +A +B +C +D start_routing_instance } @@ -543,8 +548,8 @@ setup_lose_neighbours() { setup_servald assert_no_servald_processes foreach_instance +A +B +C create_single_identity - foreach_instance +A +B add_interface 1 - foreach_instance +B +C add_interface 2 + foreach_instance +A +B add_local_interface 1 + foreach_instance +B +C add_local_interface 2 foreach_instance +A +B +C start_routing_instance } test_lose_neighbours() { @@ -556,8 +561,8 @@ test_lose_neighbours() { set_instance +A wait_until --timeout=30 instance_offline +C start_servald_server +B - wait_until path_exists +A +B +C - wait_until path_exists +C +B +A + wait_until --timeout=20 path_exists +A +B +C + wait_until --timeout=20 path_exists +C +B +A } setup_multi_interface() { @@ -603,7 +608,7 @@ setup_ping_unreliable() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_dummy_interface 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.drop_packets 40 @@ -622,11 +627,11 @@ setup_ping_unreliable2() { setup_servald assert_no_servald_processes foreach_instance +A +B +C create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_dummy_interface 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.drop_packets 40 - foreach_instance +B +C add_interface 2 + foreach_instance +B +C add_dummy_interface 2 foreach_instance +B +C \ executeOk_servald config \ set interfaces.2.drop_packets 40 @@ -645,7 +650,7 @@ setup_brping_unreliable() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_interface 1 + foreach_instance +A +B add_dummy_interface 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.drop_packets 20 @@ -664,9 +669,9 @@ setup_unreliable_links() { setup_servald assert_no_servald_processes foreach_instance +A +B +C create_single_identity - foreach_instance +A +B add_interface 1 - foreach_instance +B +C add_interface 2 - foreach_instance +A +C add_interface 3 + foreach_instance +A +B add_dummy_interface 1 + foreach_instance +B +C add_dummy_interface 2 + foreach_instance +A +C add_dummy_interface 3 set_instance +A executeOk_servald config \ set interfaces.1.drop_packets 5 \ @@ -696,12 +701,12 @@ setup_unreliable_links2() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B add_interface 1 - foreach_instance +A +C add_interface 2 - foreach_instance +A +D add_interface 3 - foreach_instance +B +C add_interface 4 - foreach_instance +B +D add_interface 5 - foreach_instance +C +D add_interface 6 + foreach_instance +A +B add_dummy_interface 1 + foreach_instance +A +C add_dummy_interface 2 + foreach_instance +A +D add_dummy_interface 3 + foreach_instance +B +C add_dummy_interface 4 + foreach_instance +B +D add_dummy_interface 5 + foreach_instance +C +D add_dummy_interface 6 set_instance +A executeOk_servald config \ set interfaces.1.drop_packets 5 \ @@ -736,14 +741,14 @@ setup_circle() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D +E +F +G +H create_single_identity - foreach_instance +A +B add_interface 1 - foreach_instance +B +C add_interface 2 - foreach_instance +C +D add_interface 3 - foreach_instance +D +E add_interface 4 - foreach_instance +E +F add_interface 5 - foreach_instance +F +G add_interface 6 - foreach_instance +G +H add_interface 7 - foreach_instance +H +A add_interface 8 + foreach_instance +A +B add_local_interface 1 + foreach_instance +B +C add_local_interface 2 + foreach_instance +C +D add_local_interface 3 + foreach_instance +D +E add_local_interface 4 + foreach_instance +E +F add_local_interface 5 + foreach_instance +F +G add_local_interface 6 + foreach_instance +G +H add_local_interface 7 + foreach_instance +H +A add_local_interface 8 foreach_instance +A +B +C +D +E +F +G +H start_routing_instance } @@ -775,13 +780,13 @@ setup_crowded_mess() { assert_no_servald_processes # BCDE & DEFG form squares, ABC & FGH form triangles foreach_instance +A +B +C +D +E +F +G +H create_single_identity - foreach_instance +A +B +C add_interface 1 - foreach_instance +B +D add_interface 2 - foreach_instance +C +E add_interface 3 - foreach_instance +D +E add_interface 4 - foreach_instance +D +F add_interface 5 - foreach_instance +E +G add_interface 6 - foreach_instance +F +G +H add_interface 7 + foreach_instance +A +B +C add_local_interface 1 + foreach_instance +B +D add_local_interface 2 + foreach_instance +C +E add_local_interface 3 + foreach_instance +D +E add_local_interface 4 + foreach_instance +D +F add_local_interface 5 + foreach_instance +E +G add_local_interface 6 + foreach_instance +F +G +H add_local_interface 7 foreach_instance +A +B +C +D +E +F +G +H \ executeOk_servald config \ set mdp.iftype.wifi.reachable_timeout_ms 60000 From 60a2aaa5478090377684d73474ab1eb886da87f5 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Fri, 13 Dec 2013 11:42:01 +1030 Subject: [PATCH 07/18] Ensure only interfaces that are UP are closed --- overlay_interface.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/overlay_interface.c b/overlay_interface.c index 4ce5eed6..a97c1164 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -56,13 +56,14 @@ static void overlay_interface_poll(struct sched_ent *alarm); static void overlay_interface_close(overlay_interface *interface){ + INFOF("Interface %s addr %s is down", + interface->name, alloca_socket_address(&interface->address)); if (interface->address.addr.sa_family == AF_UNIX) unlink(interface->address.local.sun_path); link_interface_down(interface); - INFOF("Interface %s addr %s is down", - interface->name, alloca_socket_address(&interface->address)); unschedule(&interface->alarm); - unwatch(&interface->alarm); + if (is_watching(&interface->alarm)) + unwatch(&interface->alarm); close(interface->alarm.poll.fd); if (interface->radio_link_state) radio_link_free(interface); @@ -74,7 +75,7 @@ void overlay_interface_close_all() { unsigned i; for (i=0;i Date: Fri, 13 Dec 2013 17:48:58 +1030 Subject: [PATCH 08/18] Generalise method for defining multiple interfaces --- overlay_interface.c | 11 ++-- overlay_interface.h | 2 +- testdefs.sh | 45 +++++++++---- tests/directory_service | 1 + tests/dnahelper | 1 + tests/dnaprotocol | 3 +- tests/rhizomechannels | 1 + tests/rhizomeprotocol | 3 +- tests/rhizomestress | 1 + tests/routing | 142 ++++++++++++++++------------------------ 10 files changed, 106 insertions(+), 104 deletions(-) diff --git a/overlay_interface.c b/overlay_interface.c index a97c1164..73e69430 100644 --- a/overlay_interface.c +++ b/overlay_interface.c @@ -626,10 +626,12 @@ static void interface_read_file(struct overlay_interface *interface) /* Read from interface file */ off_t length = lseek(interface->alarm.poll.fd, (off_t)0, SEEK_END); - + if (interface->recv_offset > length) + FATALF("File shrunk? It shouldn't shrink! Ever"); int new_packets = (length - interface->recv_offset) / sizeof packet; if (new_packets > 20) - WARNF("Getting behind, there are %d unread packets", new_packets); + WARNF("Getting behind, there are %d unread packets (%"PRId64" vs %"PRId64")", + new_packets, (int64_t)interface->recv_offset, (int64_t)length); if (interface->recv_offsetalarm.poll.fd,interface->recv_offset,SEEK_SET) == -1){ @@ -647,8 +649,8 @@ static void interface_read_file(struct overlay_interface *interface) if (nread == sizeof packet) { if (config.debug.overlayinterfaces) - DEBUGF("Read from interface %s (filesize=%"PRId64") at offset=%d: src_addr=%s dst_addr=%s pid=%d length=%d", - interface->name, (int64_t)length, interface->recv_offset, + DEBUGF("Read from interface %s (filesize=%"PRId64") at offset=%"PRId64": src_addr=%s dst_addr=%s pid=%d length=%d", + interface->name, (int64_t)length, (int64_t)interface->recv_offset, alloca_socket_address(&packet.src_addr), alloca_socket_address(&packet.dst_addr), packet.pid, @@ -1114,7 +1116,6 @@ void overlay_interface_discover(struct sched_ent *alarm) // Close any interfaces that have gone away. for(i = 0; i < overlay_interface_count; i++) if (overlay_interfaces[i].state==INTERFACE_STATE_DETECTING) { - DEBUGF("Closing interface stuck in DETECTING state."); overlay_interface_close(&overlay_interfaces[i]); } diff --git a/overlay_interface.h b/overlay_interface.h index 736144bf..55d02e53 100644 --- a/overlay_interface.h +++ b/overlay_interface.h @@ -70,7 +70,7 @@ typedef struct overlay_interface { char name[256]; - int recv_offset; /* file offset */ + off_t recv_offset; /* file offset */ int recv_count; int tx_count; diff --git a/testdefs.sh b/testdefs.sh index def06464..077e6992 100644 --- a/testdefs.sh +++ b/testdefs.sh @@ -654,7 +654,38 @@ create_identities() { # - set up the configuration immediately prior to starting a servald server process # - called by start_servald_instances configure_servald_server() { - : + add_servald_interface +} + +add_servald_interface() { + local SOCKET_TYPE="dgram" + local INTERFACE="1" + local TYPE="wifi" + while [ $# -ne 0 ]; do + case "$1" in + --wifi) TYPE="wifi"; shift;; + --ethernet) TYPE="ethernet"; shift;; + --file) SOCKET_TYPE="file"; shift;; + *) INTERFACE="$1"; shift;; + esac + done + if [ "${SOCKET_TYPE}" == "file" ]; then + >>$SERVALD_VAR/dummy$INTERFACE + executeOk_servald config \ + set server.interface_path $SERVALD_VAR \ + set interfaces.$INTERFACE.socket_type $SOCKET_TYPE \ + set interfaces.$INTERFACE.file dummy$INTERFACE \ + set interfaces.$INTERFACE.type $TYPE \ + set interfaces.$INTERFACE.dummy_address 127.0.$INTERFACE.$instance_number \ + set interfaces.$INTERFACE.dummy_netmask 255.255.255.224 + else + mkdir "$SERVALD_VAR/dummy$INTERFACE/" + executeOk_servald config \ + set server.interface_path $SERVALD_VAR \ + set interfaces.$INTERFACE.socket_type $SOCKET_TYPE \ + set interfaces.$INTERFACE.file dummy$INTERFACE/$instance_name \ + set interfaces.$INTERFACE.type $TYPE + fi } # Utility function: @@ -666,29 +697,19 @@ configure_servald_server() { # - wait for all instances to detect each other # - assert that all instances are in each others' peer lists start_servald_instances() { - local DUMMY=dummy - case "$1" in - dummy*) DUMMY="$1"; shift;; - esac push_instance - tfw_log "# start servald instances DUMMY=$DUMMY $*" - local DUMMYNET="$SERVALD_VAR/$DUMMY" - >$DUMMYNET + tfw_log "# start servald instances $*" local I for I; do set_instance $I # These config settings can be overridden in a caller-supplied configure_servald_server(). # They are extremely useful for the majority of fixtures. - executeOk_servald config \ - set interfaces.1.file "$DUMMYNET" configure_servald_server start_servald_server - eval DUMMY$instance_name="\$DUMMYNET" done # Now wait until they see each other. foreach_instance "$@" \ wait_until --sleep=0.25 has_seen_instances "$@" - tfw_log "# dummynet file:" $(ls -l $DUMMYNET) pop_instance } diff --git a/tests/directory_service b/tests/directory_service index 16e01cbc..f2202b2e 100755 --- a/tests/directory_service +++ b/tests/directory_service @@ -22,6 +22,7 @@ source "${0%/*}/../testframework.sh" source "${0%/*}/../testdefs.sh" configure_servald_server() { + add_servald_interface executeOk_servald config \ set log.console.show_pid on \ set log.console.show_time on \ diff --git a/tests/dnahelper b/tests/dnahelper index b885630a..995ffdaa 100755 --- a/tests/dnahelper +++ b/tests/dnahelper @@ -41,6 +41,7 @@ teardown() { # Called by start_servald_instances immediately before starting the server # process in each instance. configure_servald_server() { + add_servald_interface executeOk_servald config \ set log.console.level debug \ set log.console.show_pid on \ diff --git a/tests/dnaprotocol b/tests/dnaprotocol index d53ccce6..9b64e0be 100755 --- a/tests/dnaprotocol +++ b/tests/dnaprotocol @@ -25,7 +25,7 @@ setup() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - configure_servald_server() { set_server_vars; } + configure_servald_server() { add_servald_interface; set_server_vars; } start_servald_instances +A +B set_instance +A } @@ -125,6 +125,7 @@ EOF chmod 0755 "$dnahelper" foreach_instance +A +B +C +D create_single_identity configure_servald_server() { + add_servald_interface set_server_vars executeOk_servald config \ set debug.dnahelper on \ diff --git a/tests/rhizomechannels b/tests/rhizomechannels index ee67bd7d..2024e1e3 100755 --- a/tests/rhizomechannels +++ b/tests/rhizomechannels @@ -36,6 +36,7 @@ teardown() { # Called by start_servald_instances for each instance. configure_servald_server() { + add_servald_interface executeOk_servald config \ set log.show_pid on \ set log.show_time on \ diff --git a/tests/rhizomeprotocol b/tests/rhizomeprotocol index 7c55c388..df0692ab 100755 --- a/tests/rhizomeprotocol +++ b/tests/rhizomeprotocol @@ -36,6 +36,7 @@ teardown() { # Called by start_servald_instances for each instance. configure_servald_server() { + add_servald_interface executeOk_servald config \ set log.console.level debug \ set log.console.show_pid on \ @@ -574,7 +575,7 @@ setup_direct() { rhizome_add_file fileA3 100000 BID_A3=$BID VERSION_A3=$VERSION - start_servald_instances dummy1 +A + start_servald_instances +A wait_until rhizome_http_server_started +A get_rhizome_server_port PORTA +A set_instance +B diff --git a/tests/rhizomestress b/tests/rhizomestress index 13170677..6fb5d53f 100755 --- a/tests/rhizomestress +++ b/tests/rhizomestress @@ -36,6 +36,7 @@ teardown() { # Called by start_servald_instances for each instance. configure_servald_server() { + add_servald_interface executeOk_servald config \ set log.file.show_pid on \ set log.file.show_time on \ diff --git a/tests/routing b/tests/routing index 41691acc..5650ec2b 100755 --- a/tests/routing +++ b/tests/routing @@ -22,21 +22,6 @@ source "${0%/*}/../testframework.sh" source "${0%/*}/../testdefs.sh" -add_local_interface() { - mkdir $SERVALD_VAR/dummy$1 - executeOk_servald config \ - set interfaces.$1.file dummy$1/$instance_number \ - set interfaces.$1.socket_type dgram -} - -add_dummy_interface() { - >$SERVALD_VAR/dummy$1 - executeOk_servald config \ - set interfaces.$1.file dummy$1 \ - set interfaces.$1.dummy_address 127.0.$1.$instance_number \ - set interfaces.$1.dummy_netmask 255.255.255.224 -} - interface_up() { $GREP "Interface .* is up" $instance_servald_log || return 1 return 0 @@ -84,7 +69,6 @@ path_exists() { start_routing_instance() { executeOk_servald config \ - set server.interface_path "$SERVALD_VAR" \ set debug.mdprequests yes \ set debug.linkstate yes \ set debug.verbose yes \ @@ -115,7 +99,7 @@ setup_single_link() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_local_interface 1 + foreach_instance +A +B add_servald_interface 1 foreach_instance +A +B start_routing_instance } test_single_link() { @@ -131,7 +115,7 @@ setup_multiple_ids() { setup_servald assert_no_servald_processes foreach_instance +A +B create_identities 2 - foreach_instance +A +B add_local_interface 1 + foreach_instance +A +B add_servald_interface 1 foreach_instance +A +B start_routing_instance } test_multiple_ids() { @@ -158,7 +142,7 @@ setup_unlock_ids() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_local_interface 1 + foreach_instance +A +B add_servald_interface 1 set_instance +A executeOk_servald keyring add 'entry-pin' extract_stdout_keyvalue SIDX sid "$rexp_sid" @@ -188,7 +172,7 @@ setup_migrate_id() { set_instance +B executeOk_servald keyring load sidx '' 'entry-pin' foreach_instance +A +B create_single_identity - foreach_instance +A +B add_local_interface 1 + foreach_instance +A +B add_servald_interface 1 foreach_instance +A +B start_routing_instance } test_migrate_id() { @@ -207,7 +191,7 @@ setup_single_mdp() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_local_interface 1 + foreach_instance +A +B add_servald_interface 1 foreach_instance +A +B executeOk_servald config set interfaces.1.encapsulation single foreach_instance +A +B start_routing_instance } @@ -224,7 +208,7 @@ setup_mismatched_encap() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_local_interface 1 + foreach_instance +A +B add_servald_interface 1 foreach_instance +A executeOk_servald config set interfaces.1.encapsulation single foreach_instance +A +B start_routing_instance } @@ -241,7 +225,7 @@ setup_single_p2p() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_local_interface 1 + foreach_instance +A +B add_servald_interface 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.encapsulation single \ @@ -319,7 +303,7 @@ setup_multiple_nodes() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B +C +D add_local_interface 1 + foreach_instance +A +B +C +D add_servald_interface 1 foreach_instance +A +B +C +D start_routing_instance } test_multiple_nodes() { @@ -343,7 +327,7 @@ setup_scan() { setup_servald assert_no_servald_processes foreach_instance +A +B +C create_single_identity - foreach_instance +A +B +C add_dummy_interface 1 + foreach_instance +A +B +C add_servald_interface --file 1 foreach_instance +A +B +C \ executeOk_servald config \ set interfaces.1.drop_broadcasts on @@ -393,7 +377,7 @@ setup_single_filter() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_dummy_interface 1 + foreach_instance +A +B add_servald_interface --file 1 set_instance +B executeOk_servald config \ set interfaces.1.drop_broadcasts on @@ -417,7 +401,7 @@ setup_broadcast_only() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_dummy_interface 1 + foreach_instance +A +B add_servald_interface --file 1 foreach_instance +A +B \ executeOk_servald config set interfaces.1.drop_unicasts 1 foreach_instance +A +B start_routing_instance @@ -437,7 +421,7 @@ setup_prefer_unicast() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_local_interface 1 + foreach_instance +A +B add_servald_interface 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.prefer_unicast 1 \ @@ -459,9 +443,9 @@ setup_multihop_linear() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B add_local_interface 1 - foreach_instance +B +C add_local_interface 2 - foreach_instance +C +D add_local_interface 3 + foreach_instance +A +B add_servald_interface 1 + foreach_instance +B +C add_servald_interface 2 + foreach_instance +C +D add_servald_interface 3 foreach_instance +A +B +C +D start_routing_instance } test_multihop_linear() { @@ -485,9 +469,9 @@ setup_unicast_route() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B add_dummy_interface 1 - foreach_instance +B +C add_dummy_interface 2 - foreach_instance +C +D add_dummy_interface 3 + foreach_instance +A +B add_servald_interface --file 1 + foreach_instance +B +C add_servald_interface --file 2 + foreach_instance +C +D add_servald_interface --file 3 set_instance +A executeOk_servald config \ set interfaces.1.drop_broadcasts on @@ -509,8 +493,8 @@ setup_offline() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B +C add_local_interface 1 - foreach_instance +A +B +D add_local_interface 2 + foreach_instance +A +B +C add_servald_interface 1 + foreach_instance +A +B +D add_servald_interface 2 foreach_instance +A +B +C +D start_routing_instance } @@ -548,8 +532,8 @@ setup_lose_neighbours() { setup_servald assert_no_servald_processes foreach_instance +A +B +C create_single_identity - foreach_instance +A +B add_local_interface 1 - foreach_instance +B +C add_local_interface 2 + foreach_instance +A +B add_servald_interface 1 + foreach_instance +B +C add_servald_interface 2 foreach_instance +A +B +C start_routing_instance } test_lose_neighbours() { @@ -569,37 +553,27 @@ setup_multi_interface() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - >$SERVALD_VAR/dummywifi - >$SERVALD_VAR/dummyeth - foreach_instance +A +B \ - executeOk_servald config \ - set interfaces.1.file dummywifi \ - set interfaces.1.dummy_address 127.0.1.$instance_number \ - set interfaces.1.dummy_netmask 255.255.255.224 \ - set interfaces.1.type wifi \ - set interfaces.2.file dummyeth \ - set interfaces.2.dummy_address 127.0.2.$instance_number \ - set interfaces.2.dummy_netmask 255.255.255.224 \ - set interfaces.2.type ethernet + foreach_instance +A +B add_servald_interface --wifi 1 + foreach_instance +A +B add_servald_interface --ethernet 2 foreach_instance +A +B start_routing_instance } doc_multi_interface="Multiple links of different types to the same neighbour" test_multi_interface() { set_instance +A - wait_until has_link dummyeth +A +B +B $SIDB $SIDB + wait_until has_link "dummy2.*" +A +B +B $SIDB $SIDB set_instance +B - wait_until has_link dummyeth +B +A +A $SIDA $SIDA + wait_until has_link "dummy2.*" +B +A +A $SIDA $SIDA set_instance +A executeOk_servald config set interfaces.2.exclude 1 - wait_until has_link dummywifi +A +B +B $SIDB $SIDB + wait_until has_link "dummy1.*" +A +B +B $SIDB $SIDB set_instance +B - wait_until has_link dummywifi +B +A +A $SIDA $SIDA + wait_until has_link "dummy1.*" +B +A +A $SIDA $SIDA set_instance +A executeOk_servald config del interfaces.2.exclude - wait_until has_link dummyeth +A +B +B $SIDB $SIDB + wait_until has_link "dummy2.*" +A +B +B $SIDB $SIDB set_instance +B - wait_until has_link dummyeth +B +A +A $SIDA $SIDA + wait_until has_link "dummy2.*" +B +A +A $SIDA $SIDA } # TODO assert that all packets arrive? assert that no duplicates arrive? @@ -608,7 +582,7 @@ setup_ping_unreliable() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_dummy_interface 1 + foreach_instance +A +B add_servald_interface --file 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.drop_packets 40 @@ -627,11 +601,11 @@ setup_ping_unreliable2() { setup_servald assert_no_servald_processes foreach_instance +A +B +C create_single_identity - foreach_instance +A +B add_dummy_interface 1 + foreach_instance +A +B add_servald_interface --file 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.drop_packets 40 - foreach_instance +B +C add_dummy_interface 2 + foreach_instance +B +C add_servald_interface --file 2 foreach_instance +B +C \ executeOk_servald config \ set interfaces.2.drop_packets 40 @@ -650,7 +624,7 @@ setup_brping_unreliable() { setup_servald assert_no_servald_processes foreach_instance +A +B create_single_identity - foreach_instance +A +B add_dummy_interface 1 + foreach_instance +A +B add_servald_interface --file 1 foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.drop_packets 20 @@ -669,9 +643,9 @@ setup_unreliable_links() { setup_servald assert_no_servald_processes foreach_instance +A +B +C create_single_identity - foreach_instance +A +B add_dummy_interface 1 - foreach_instance +B +C add_dummy_interface 2 - foreach_instance +A +C add_dummy_interface 3 + foreach_instance +A +B add_servald_interface --file 1 + foreach_instance +B +C add_servald_interface --file 2 + foreach_instance +A +C add_servald_interface --file 3 set_instance +A executeOk_servald config \ set interfaces.1.drop_packets 5 \ @@ -701,12 +675,12 @@ setup_unreliable_links2() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity - foreach_instance +A +B add_dummy_interface 1 - foreach_instance +A +C add_dummy_interface 2 - foreach_instance +A +D add_dummy_interface 3 - foreach_instance +B +C add_dummy_interface 4 - foreach_instance +B +D add_dummy_interface 5 - foreach_instance +C +D add_dummy_interface 6 + foreach_instance +A +B add_servald_interface --file 1 + foreach_instance +A +C add_servald_interface --file 2 + foreach_instance +A +D add_servald_interface --file 3 + foreach_instance +B +C add_servald_interface --file 4 + foreach_instance +B +D add_servald_interface --file 5 + foreach_instance +C +D add_servald_interface --file 6 set_instance +A executeOk_servald config \ set interfaces.1.drop_packets 5 \ @@ -741,14 +715,14 @@ setup_circle() { setup_servald assert_no_servald_processes foreach_instance +A +B +C +D +E +F +G +H create_single_identity - foreach_instance +A +B add_local_interface 1 - foreach_instance +B +C add_local_interface 2 - foreach_instance +C +D add_local_interface 3 - foreach_instance +D +E add_local_interface 4 - foreach_instance +E +F add_local_interface 5 - foreach_instance +F +G add_local_interface 6 - foreach_instance +G +H add_local_interface 7 - foreach_instance +H +A add_local_interface 8 + foreach_instance +A +B add_servald_interface 1 + foreach_instance +B +C add_servald_interface 2 + foreach_instance +C +D add_servald_interface 3 + foreach_instance +D +E add_servald_interface 4 + foreach_instance +E +F add_servald_interface 5 + foreach_instance +F +G add_servald_interface 6 + foreach_instance +G +H add_servald_interface 7 + foreach_instance +H +A add_servald_interface 8 foreach_instance +A +B +C +D +E +F +G +H start_routing_instance } @@ -780,13 +754,13 @@ setup_crowded_mess() { assert_no_servald_processes # BCDE & DEFG form squares, ABC & FGH form triangles foreach_instance +A +B +C +D +E +F +G +H create_single_identity - foreach_instance +A +B +C add_local_interface 1 - foreach_instance +B +D add_local_interface 2 - foreach_instance +C +E add_local_interface 3 - foreach_instance +D +E add_local_interface 4 - foreach_instance +D +F add_local_interface 5 - foreach_instance +E +G add_local_interface 6 - foreach_instance +F +G +H add_local_interface 7 + foreach_instance +A +B +C add_servald_interface 1 + foreach_instance +B +D add_servald_interface 2 + foreach_instance +C +E add_servald_interface 3 + foreach_instance +D +E add_servald_interface 4 + foreach_instance +D +F add_servald_interface 5 + foreach_instance +E +G add_servald_interface 6 + foreach_instance +F +G +H add_servald_interface 7 foreach_instance +A +B +C +D +E +F +G +H \ executeOk_servald config \ set mdp.iftype.wifi.reachable_timeout_ms 60000 From 6d942f8d4f65d45d1ba3705594fef2cb7ae7a771 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Mon, 16 Dec 2013 14:54:16 +1030 Subject: [PATCH 09/18] Improve tests --- testdefs.sh | 9 +-- tests/dnaprotocol | 11 +-- tests/rhizomeprotocol | 2 +- tests/routing | 183 ++++++++++++++++++++++-------------------- tests/server | 37 +++++---- 5 files changed, 121 insertions(+), 121 deletions(-) diff --git a/testdefs.sh b/testdefs.sh index 077e6992..5620d278 100644 --- a/testdefs.sh +++ b/testdefs.sh @@ -259,6 +259,7 @@ setup_servald_so() { start_servald_server() { push_instance set_instance_fromarg "$1" && shift + configure_servald_server # Start servald server local -a before_pids local -a after_pids @@ -699,14 +700,8 @@ add_servald_interface() { start_servald_instances() { push_instance tfw_log "# start servald instances $*" - local I - for I; do - set_instance $I - # These config settings can be overridden in a caller-supplied configure_servald_server(). - # They are extremely useful for the majority of fixtures. - configure_servald_server + foreach_instance "$@" \ start_servald_server - done # Now wait until they see each other. foreach_instance "$@" \ wait_until --sleep=0.25 has_seen_instances "$@" diff --git a/tests/dnaprotocol b/tests/dnaprotocol index 9b64e0be..688dc4dd 100755 --- a/tests/dnaprotocol +++ b/tests/dnaprotocol @@ -45,17 +45,10 @@ set_server_vars() { set log.console.level debug \ set log.console.show_pid on \ set log.console.show_time on \ - set mdp.iftype.wifi.tick_ms 100 \ set rhizome.enable No \ - set debug.overlayinterfaces No \ - set debug.overlaybuffer No \ - set debug.packetformats No \ - set debug.overlayframes No \ - set debug.overlayrouting No \ - set debug.packettx No \ - set debug.packetrx No \ set debug.mdprequests Yes \ - set debug.keyring Yes + set debug.keyring Yes \ + set debug.linkstate Yes } doc_LookupWildcard="Lookup by wildcard" diff --git a/tests/rhizomeprotocol b/tests/rhizomeprotocol index df0692ab..f88a9f0e 100755 --- a/tests/rhizomeprotocol +++ b/tests/rhizomeprotocol @@ -36,7 +36,7 @@ teardown() { # Called by start_servald_instances for each instance. configure_servald_server() { - add_servald_interface + add_servald_interface --file executeOk_servald config \ set log.console.level debug \ set log.console.show_pid on \ diff --git a/tests/routing b/tests/routing index 5650ec2b..7cdb3cb5 100755 --- a/tests/routing +++ b/tests/routing @@ -27,30 +27,33 @@ interface_up() { return 0 } -has_link() { - interface_ex=".*" - case "$1" in - dummy*) interface_ex="$1"; shift;; - esac - set_instance $1 - executeOk_servald route print - tfw_log "Looking for link from $1 to $2 ($4)" - if ! grep "^${4}:\(BROADCAST\|UNICAST\):${interface_ex}:0*\$" $_tfw_tmp/stdout; then +link_matches() { + local interface_ex=".*" + local link_type="\(BROADCAST\|\UNICAST\)" + local via="0*" + local sid="" + while [ $# -ne 0 ]; do + case "$1" in + --interface) interface_ex="$2"; shift 2;; + --broadcast) link_type="BROADCAST"; shift;; + --unicast) link_type="UNICAST"; shift;; + --via) link_type="INDIRECT"; via="$2"; interface_ex=""; shift 2;; + *) break;; + esac + done + sid="$1" + tfw_log "Looking for link ${sid}, ${link_type}, ${interface_ex}, ${via}" + if ! grep "^${sid}:${link_type}:${interface_ex}:${via}\$" $_tfw_tmp/stdout; then tfw_log "Link not found" -# tfw_log "^${4}:\(BROADCAST\|UNICAST\):${interface_ex}:0*\$" -# tfw_cat --stdout --stderr - return 1 - fi - [ $4 = $5 ] && return 0; - tfw_log "Path from $1 to $3 should be via $2 ($5, $4)" - if ! grep "^${5}:INDIRECT::${4}\$" $_tfw_tmp/stdout; then - tfw_log "No path found" -# tfw_log "^${5}:INDIRECT::${4}\$" -# tfw_cat --stdout --stderr return 1 fi } +has_link() { + executeOk_servald route print + link_matches $@ +} + path_exists() { local dest eval dest=\$$# @@ -61,13 +64,17 @@ path_exists() { for I; do local sidvar=SID${I#+} [ -n "${!sidvar}" ] || break - has_link $next_inst $I $dest ${!sidvar} ${!dest_sidvar} || return 1 + set_instance $next_inst + executeOk_servald route print + link_matches ${!sidvar} || return 1 + [ $I = $dest ] && return 0 + link_matches --via ${!sidvar} ${!dest_sidvar} || return 1 next_inst=$I done return 0 } -start_routing_instance() { +configure_servald_server() { executeOk_servald config \ set debug.mdprequests yes \ set debug.linkstate yes \ @@ -77,8 +84,6 @@ start_routing_instance() { set log.console.show_pid on \ set log.console.show_time on \ set rhizome.enable no - start_servald_server - wait_until interface_up } log_routing_table() { @@ -100,7 +105,7 @@ setup_single_link() { assert_no_servald_processes foreach_instance +A +B create_single_identity foreach_instance +A +B add_servald_interface 1 - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_single_link() { wait_until --timeout=10 path_exists +A +B @@ -116,25 +121,27 @@ setup_multiple_ids() { assert_no_servald_processes foreach_instance +A +B create_identities 2 foreach_instance +A +B add_servald_interface 1 - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_multiple_ids() { wait_until path_exists +A +B - wait_until has_link +A +B +B $SIDB1 $SIDB2 + set_instance +A + wait_until has_link --via $SIDB1 $SIDB2 wait_until path_exists +B +A - wait_until has_link +B +A +A $SIDA1 $SIDA2 + set_instance +B + wait_until has_link --via $SIDA1 $SIDA2 set_instance +A executeOk_servald mdp ping --timeout=3 $SIDB2 1 tfw_cat --stdout --stderr executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDB1:BROADCAST:dummy.*:0*" - assertStdoutGrep --matches=1 "^$SIDB2:INDIRECT::$SIDB1" + link_matches --broadcast $SIDB1 + link_matches --via $SIDB1 $SIDB2 set_instance +B executeOk_servald mdp ping --timeout=3 $SIDA2 1 tfw_cat --stdout --stderr executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDA1:BROADCAST:dummy.*:0*" - assertStdoutGrep --matches=1 "^$SIDA2:INDIRECT::$SIDA1" + link_matches --broadcast $SIDA1 + link_matches --via $SIDA1 $SIDA2 } doc_unlock_ids="Routes appear and disappear as identities are [un]locked" @@ -146,14 +153,15 @@ setup_unlock_ids() { set_instance +A executeOk_servald keyring add 'entry-pin' extract_stdout_keyvalue SIDX sid "$rexp_sid" - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_unlock_ids() { wait_until path_exists +A +B wait_until path_exists +B +A set_instance +A executeOk_servald id enter pin 'entry-pin' - wait_until has_link +B +A +A $SIDA $SIDX + set_instance +B + wait_until has_link --via $SIDA $SIDX set_instance +A executeOk_servald id relinquish pin 'entry-pin' set_instance +B @@ -173,17 +181,19 @@ setup_migrate_id() { executeOk_servald keyring load sidx '' 'entry-pin' foreach_instance +A +B create_single_identity foreach_instance +A +B add_servald_interface 1 - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_migrate_id() { wait_until path_exists +A +B wait_until path_exists +B +A set_instance +A executeOk_servald id enter pin 'entry-pin' - wait_until has_link +B +A +A $SIDA $SIDX + set_instance +B + wait_until has_link --via $SIDA $SIDX set_instance +B executeOk_servald id enter pin 'entry-pin' - wait_until --timeout=30 has_link +A +B +B $SIDB $SIDX + set_instance +A + wait_until --timeout=30 has_link --via $SIDB $SIDX } doc_single_mdp="Use single MDP per packet encapsulation" @@ -193,7 +203,7 @@ setup_single_mdp() { foreach_instance +A +B create_single_identity foreach_instance +A +B add_servald_interface 1 foreach_instance +A +B executeOk_servald config set interfaces.1.encapsulation single - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_single_mdp() { wait_until path_exists +A +B @@ -210,7 +220,7 @@ setup_mismatched_encap() { foreach_instance +A +B create_single_identity foreach_instance +A +B add_servald_interface 1 foreach_instance +A executeOk_servald config set interfaces.1.encapsulation single - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_mismatched_encap() { wait_until path_exists +A +B @@ -230,7 +240,7 @@ setup_single_p2p() { executeOk_servald config \ set interfaces.1.encapsulation single \ set interfaces.1.point_to_point on - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_single_p2p() { wait_until path_exists +A +B @@ -282,7 +292,7 @@ setup_simulate_extender() { set interfaces.1.socket_type STREAM \ set interfaces.1.encapsulation SINGLE \ set interfaces.1.point_to_point on - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_simulate_extender() { wait_until path_exists +A +B @@ -304,7 +314,7 @@ setup_multiple_nodes() { assert_no_servald_processes foreach_instance +A +B +C +D create_single_identity foreach_instance +A +B +C +D add_servald_interface 1 - foreach_instance +A +B +C +D start_routing_instance + foreach_instance +A +B +C +D start_servald_server } test_multiple_nodes() { wait_until path_exists +A +B @@ -331,7 +341,9 @@ setup_scan() { foreach_instance +A +B +C \ executeOk_servald config \ set interfaces.1.drop_broadcasts on - foreach_instance +A +B +C start_routing_instance + foreach_instance +A +B +C start_servald_server + foreach_instance +A +B +C \ + wait_until interface_up } test_scan() { set_instance +A @@ -339,14 +351,14 @@ test_scan() { wait_until scan_completed wait_until --timeout=10 has_seen_instances +B +C executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDB:UNICAST:" - assertStdoutGrep --matches=1 "^$SIDC:UNICAST:" + link_matches --unicast $SIDB + link_matches --unicast $SIDC executeOk_servald mdp ping --timeout=3 $SIDB 1 tfw_cat --stdout --stderr set_instance +B executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDA:UNICAST:" - assertStdoutGrep --matches=1 "^$SIDC:INDIRECT:" + link_matches --unicast $SIDA + link_matches --via $SIDA $SIDC executeOk_servald mdp ping --timeout=3 $SIDC 1 tfw_cat --stdout --stderr } @@ -361,7 +373,7 @@ test_scan_one() { wait_until scan_completed wait_until --timeout=10 has_seen_instances +B executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDB:UNICAST:" + link_matches --unicast $SIDB assertStdoutGrep --matches=0 "^$SIDC:" executeOk_servald mdp ping --timeout=3 $SIDB 1 tfw_cat --stdout --stderr @@ -381,19 +393,15 @@ setup_single_filter() { set_instance +B executeOk_servald config \ set interfaces.1.drop_broadcasts on - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_single_filter() { - wait_until --timeout=10 path_exists +A +B - wait_until --timeout=5 path_exists +B +A set_instance +A + wait_until --timeout=10 has_link --unicast $SIDB + set_instance +B + wait_until --timeout=5 has_link --broadcast $SIDA executeOk_servald mdp ping --timeout=3 $SIDB 1 tfw_cat --stdout --stderr - executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDB:UNICAST:" - set_instance +B - executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDA:BROADCAST:" } doc_broadcast_only="Broadcast packets only" @@ -404,16 +412,16 @@ setup_broadcast_only() { foreach_instance +A +B add_servald_interface --file 1 foreach_instance +A +B \ executeOk_servald config set interfaces.1.drop_unicasts 1 - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_broadcast_only() { - wait_until path_exists +A +B - wait_until path_exists +B +A + set_instance +A + wait_until has_link --broadcast $SIDB + set_instance +B + wait_until has_link --broadcast $SIDA set_instance +A executeOk_servald mdp ping --timeout=3 $SIDB 1 tfw_cat --stdout --stderr - executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDB:BROADCAST:" } doc_prefer_unicast="Prefer unicast packets" @@ -426,16 +434,18 @@ setup_prefer_unicast() { executeOk_servald config \ set interfaces.1.prefer_unicast 1 \ set debug.overlayframes 1 - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_prefer_unicast() { + set_instance +A + wait_until has_link --unicast $SIDB + set_instance +B + wait_until has_link --unicast $SIDA wait_until path_exists +A +B wait_until path_exists +B +A set_instance +A executeOk_servald mdp ping --timeout=3 $SIDB 1 tfw_cat --stdout --stderr - executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDB:UNICAST:" } doc_multihop_linear="Start 4 instances in a linear arrangement" @@ -446,7 +456,7 @@ setup_multihop_linear() { foreach_instance +A +B add_servald_interface 1 foreach_instance +B +C add_servald_interface 2 foreach_instance +C +D add_servald_interface 3 - foreach_instance +A +B +C +D start_routing_instance + foreach_instance +A +B +C +D start_servald_server } test_multihop_linear() { wait_until path_exists +A +B +C +D @@ -479,7 +489,7 @@ setup_unicast_route() { executeOk_servald config \ set interfaces.2.drop_broadcasts on \ set interfaces.3.drop_broadcasts on - foreach_instance +A +B +C +D start_routing_instance + foreach_instance +A +B +C +D start_servald_server } test_unicast_route() { wait_until --timeout=20 path_exists +A +B +C +D @@ -495,7 +505,7 @@ setup_offline() { foreach_instance +A +B +C +D create_single_identity foreach_instance +A +B +C add_servald_interface 1 foreach_instance +A +B +D add_servald_interface 2 - foreach_instance +A +B +C +D start_routing_instance + foreach_instance +A +B +C +D start_servald_server } sid_offline() { @@ -534,7 +544,7 @@ setup_lose_neighbours() { foreach_instance +A +B +C create_single_identity foreach_instance +A +B add_servald_interface 1 foreach_instance +B +C add_servald_interface 2 - foreach_instance +A +B +C start_routing_instance + foreach_instance +A +B +C start_servald_server } test_lose_neighbours() { wait_until path_exists +A +B +C @@ -555,25 +565,25 @@ setup_multi_interface() { foreach_instance +A +B create_single_identity foreach_instance +A +B add_servald_interface --wifi 1 foreach_instance +A +B add_servald_interface --ethernet 2 - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } doc_multi_interface="Multiple links of different types to the same neighbour" test_multi_interface() { set_instance +A - wait_until has_link "dummy2.*" +A +B +B $SIDB $SIDB + wait_until has_link --interface "dummy2.*" $SIDB set_instance +B - wait_until has_link "dummy2.*" +B +A +A $SIDA $SIDA + wait_until has_link --interface "dummy2.*" $SIDA set_instance +A executeOk_servald config set interfaces.2.exclude 1 - wait_until has_link "dummy1.*" +A +B +B $SIDB $SIDB + wait_until has_link --interface "dummy1.*" $SIDB set_instance +B - wait_until has_link "dummy1.*" +B +A +A $SIDA $SIDA + wait_until has_link --interface "dummy1.*" $SIDA set_instance +A executeOk_servald config del interfaces.2.exclude - wait_until has_link "dummy2.*" +A +B +B $SIDB $SIDB + wait_until has_link --interface "dummy2.*" $SIDB set_instance +B - wait_until has_link "dummy2.*" +B +A +A $SIDA $SIDA + wait_until has_link --interface "dummy2.*" $SIDA } # TODO assert that all packets arrive? assert that no duplicates arrive? @@ -586,7 +596,7 @@ setup_ping_unreliable() { foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.drop_packets 40 - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_ping_unreliable() { wait_until path_exists +A +B @@ -609,7 +619,7 @@ setup_ping_unreliable2() { foreach_instance +B +C \ executeOk_servald config \ set interfaces.2.drop_packets 40 - foreach_instance +A +B +C start_routing_instance + foreach_instance +A +B +C start_servald_server } test_ping_unreliable2() { wait_until path_exists +A +B +C @@ -628,7 +638,7 @@ setup_brping_unreliable() { foreach_instance +A +B \ executeOk_servald config \ set interfaces.1.drop_packets 20 - foreach_instance +A +B start_routing_instance + foreach_instance +A +B start_servald_server } test_brping_unreliable() { wait_until path_exists +A +B @@ -658,7 +668,7 @@ setup_unreliable_links() { executeOk_servald config \ set interfaces.2.drop_packets 5 \ set interfaces.3.drop_packets 70 - foreach_instance +A +B +C start_routing_instance + foreach_instance +A +B +C start_servald_server } test_unreliable_links() { wait_until path_exists +A +B +C @@ -701,7 +711,7 @@ setup_unreliable_links2() { set interfaces.3.drop_packets 90 \ set interfaces.5.drop_packets 40 \ set interfaces.6.drop_packets 5 - foreach_instance +A +B +C +D start_routing_instance + foreach_instance +A +B +C +D start_servald_server } test_unreliable_links2() { wait_until path_exists +A +B +C +D @@ -723,7 +733,7 @@ setup_circle() { foreach_instance +F +G add_servald_interface 6 foreach_instance +G +H add_servald_interface 7 foreach_instance +H +A add_servald_interface 8 - foreach_instance +A +B +C +D +E +F +G +H start_routing_instance + foreach_instance +A +B +C +D +E +F +G +H start_servald_server } doc_circle="Circle of nodes with one going offline" @@ -735,8 +745,6 @@ test_circle() { set_instance +A executeOk_servald mdp ping --timeout=3 $SIDC 1 tfw_cat --stdout --stderr - executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDC:INDIRECT:" stop_servald_server +B foreach_instance +A +C \ wait_until --timeout=10 instance_offline +B @@ -745,8 +753,6 @@ test_circle() { set_instance +A executeOk_servald mdp ping --timeout=3 $SIDC 1 tfw_cat --stdout --stderr - executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDC:INDIRECT:" } setup_crowded_mess() { @@ -764,16 +770,15 @@ setup_crowded_mess() { foreach_instance +A +B +C +D +E +F +G +H \ executeOk_servald config \ set mdp.iftype.wifi.reachable_timeout_ms 60000 - foreach_instance +A +B +C +D +E +F +G +H start_routing_instance + foreach_instance +A +B +C +D +E +F +G +H start_servald_server } doc_crowded_mess="Multiple possible paths" test_crowded_mess() { - foreach_instance +A +H \ - wait_until has_seen_instances +A +H + set_instance +H + wait_until has_link --via "[0-9A-F]*" $SIDA set_instance +A - executeOk_servald route print - assertStdoutGrep --matches=1 "^$SIDH:INDIRECT:" + wait_until has_link --via "[0-9A-F]*" $SIDH executeOk_servald mdp ping --timeout=3 $SIDH 1 tfw_cat --stdout --stderr } diff --git a/tests/server b/tests/server index 754bcb51..0c8695ca 100755 --- a/tests/server +++ b/tests/server @@ -26,17 +26,17 @@ setup() { assert_no_servald_processes } -setup_interfaces() { - >$TFWTMP/dummy - executeOk_servald config set interfaces "+>$TFWTMP/dummy" -} - teardown() { get_servald_server_pidfile && stop_servald_server kill_all_servald_processes assert_no_servald_processes } +# make sure servald config is blank +configure_servald_server() { + : +} + doc_StartCreateInstanceDir="Starting server creates instance directory" setup_StartCreateInstanceDir() { setup @@ -53,10 +53,8 @@ setup_StartLogfile() { executeOk_servald config set log.file.directory_path "$PWD/log" } test_StartLogfile() { - executeOk_servald start - sleep 0.1 - assert [ -s log/*.log ] - tfw_cat log/*.log + start_servald_server + assert_servald_server_no_errors } doc_StartNoInterfaces="Starting server with no configured interfaces gives warning" @@ -70,14 +68,26 @@ test_StartNoInterfaces() { tfw_cat "$instance_servald_log" } -doc_StartNoErrors="Starting server on dummy interface gives no errors" +doc_StartNoErrors="Starting server on dummy file interface gives no errors" setup_StartNoErrors() { setup - setup_interfaces + add_servald_interface --file } test_StartNoErrors() { start_servald_server - sleep 0.1 + wait_until grep "Interface .* is up" $instance_servald_log + assert_servald_server_no_errors + tfw_cat "$instance_servald_log" +} + +doc_StartLocalNoErrors="Starting server on local interface gives no errors" +setup_StartLocalNoErrors() { + setup + add_servald_interface +} +test_StartLocalNoErrors() { + start_servald_server + wait_until grep "Interface .* is up" $instance_servald_log assert_servald_server_no_errors tfw_cat "$instance_servald_log" } @@ -85,7 +95,6 @@ test_StartNoErrors() { doc_StartStart="Start server while already running" setup_StartStart() { setup - setup_interfaces start_servald_server } test_StartStart() { @@ -99,7 +108,6 @@ test_StartStart() { doc_StartStopFast="Stop server before it finishes starting" setup_StartStopFast() { setup - setup_interfaces export SERVALD_SERVER_START_DELAY=250 } test_StartStopFast() { @@ -110,7 +118,6 @@ test_StartStopFast() { doc_NoZombie="Server process does not become a zombie" setup_NoZombie() { setup - setup_interfaces export SERVALD_START_POST_SLEEP=1000 servald_start & start_pid=$! From 6045eb10e818e69d744bf062627661bc31e73c84 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Mon, 16 Dec 2013 14:54:30 +1030 Subject: [PATCH 10/18] Reduce spam of link state packets --- overlay_queue.c | 3 +++ route_link.c | 31 ++++++++++++++----------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/overlay_queue.c b/overlay_queue.c index 6b8f737c..b62d3a19 100644 --- a/overlay_queue.c +++ b/overlay_queue.c @@ -569,6 +569,9 @@ int overlay_queue_ack(struct subscriber *neighbour, struct network_destination * if (acked){ int rtt = now - frame->destinations[j].transmit_time; + // if we're on a fake network, the actual rtt can be unrealistic + if (rtt <5) + rtt=5; if (!destination->min_rtt || rtt < destination->min_rtt){ destination->min_rtt = rtt; int delay = rtt * 2 + 40; diff --git a/route_link.c b/route_link.c index 20f3e432..39fa8bef 100644 --- a/route_link.c +++ b/route_link.c @@ -39,7 +39,6 @@ Link state routing; */ -#define INCLUDE_ANYWAY (200) #define MAX_LINK_STATES 512 #define FLAG_HAS_INTERFACE (1<<0) @@ -172,6 +171,7 @@ static struct profile_total link_send_stats={ static struct sched_ent link_send_alarm={ .function = link_send, .stats = &link_send_stats, + .alarm = TIME_NEVER_WILL, }; struct neighbour *neighbours=NULL; @@ -185,6 +185,7 @@ struct network_destination * new_destination(struct overlay_interface *interface ret->encapsulation = encapsulation; ret->interface = interface; ret->resend_delay = 1000; + ret->last_tx = TIME_NEVER_HAS; // DEBUGF("Create ref %p, %d - %s", ret, ret->_ref_count, ret->interface->name); } return ret; @@ -525,7 +526,7 @@ static int append_link(struct subscriber *subscriber, void *context) struct link *best_link = find_best_link(subscriber); if (subscriber->reachable==REACHABLE_SELF){ - if (state->next_update - INCLUDE_ANYWAY <= now){ + if (state->next_update - 20 <= now){ // Other entries in our keyring are always one hop away from us. if (append_link_state(payload, 0, my_subscriber, subscriber, -1, 1, -1, 0, 0)){ link_send_alarm.alarm = now+5; @@ -539,7 +540,7 @@ static int append_link(struct subscriber *subscriber, void *context) if (subscriber->identity) keyring_send_unlock(subscriber); - if (state->next_update - INCLUDE_ANYWAY <= now){ + if (state->next_update - 20 <= now){ if (append_link_state(payload, 0, state->transmitter, subscriber, -1, best_link?best_link->link_version:-1, -1, 0, best_link?best_link->drop_rate:32)){ link_send_alarm.alarm = now+5; @@ -853,7 +854,7 @@ static int link_send_neighbours() while (n){ neighbour_find_best_link(n); - if (n->next_neighbour_update - INCLUDE_ANYWAY <= now){ + if (n->next_neighbour_update <= now){ send_neighbour_link(n); } @@ -879,9 +880,7 @@ static int link_send_neighbours() // send link details static void link_send(struct sched_ent *alarm) { - time_ms_t now = gettime_ms(); - - alarm->alarm=now + 60000; + alarm->alarm=TIME_NEVER_WILL; // TODO use a separate alarm link_send_neighbours(); @@ -904,11 +903,9 @@ static void link_send(struct sched_ent *alarm) op_free(frame); else if (overlay_payload_enqueue(frame)) op_free(frame); - if (neighbours){ - alarm->deadline = alarm->alarm; - schedule(alarm); - }else - alarm->alarm=0; + + alarm->deadline = alarm->alarm; + schedule(alarm); } } @@ -916,7 +913,7 @@ static void update_alarm(struct __sourceloc __whence, time_ms_t limit) { if (limit == 0) FATALF("limit == 0"); - if (link_send_alarm.alarm>limit || link_send_alarm.alarm==0){ + if (link_send_alarm.alarm>limit){ unschedule(&link_send_alarm); link_send_alarm.alarm = limit; link_send_alarm.deadline = limit+10; @@ -1065,8 +1062,8 @@ int link_state_ack_soon(struct subscriber *subscriber) if (neighbour->using_us && subscriber->reachable & REACHABLE_DIRECT && subscriber->destination){ - if (neighbour->next_neighbour_update > now + subscriber->destination->min_rtt){ - neighbour->next_neighbour_update = now + subscriber->destination->min_rtt; + if (neighbour->next_neighbour_update > now + 40 + subscriber->destination->min_rtt){ + neighbour->next_neighbour_update = now + 40 + subscriber->destination->min_rtt; if (config.debug.ack) DEBUGF("Asking for next ACK Real Soon Now"); } @@ -1419,7 +1416,7 @@ int link_receive(struct overlay_frame *frame, overlay_mdp_frame *mdp) if (changed){ route_version++; neighbour->path_version ++; - if (link_send_alarm.alarm>now+5 || link_send_alarm.alarm==0){ + if (link_send_alarm.alarm>now+5){ unschedule(&link_send_alarm); link_send_alarm.alarm=now+5; // read all incoming packets first @@ -1492,7 +1489,7 @@ int link_state_legacy_ack(struct overlay_frame *frame, time_ms_t now) if (changed){ route_version++; neighbour->path_version ++; - if (link_send_alarm.alarm>now+5 || link_send_alarm.alarm==0){ + if (link_send_alarm.alarm>now+5){ unschedule(&link_send_alarm); link_send_alarm.alarm=now+5; // read all incoming packets first From e09387b27d96f21f6d863ace87ad2833e8aa4360 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Wed, 18 Dec 2013 14:37:46 +1030 Subject: [PATCH 11/18] Refactor stdio handling --- msp_client.c | 22 ++++- msp_client.h | 1 + msp_proxy.c | 255 ++++++++++++++++++++++++++------------------------- tests/all | 1 + 4 files changed, 150 insertions(+), 129 deletions(-) diff --git a/msp_client.c b/msp_client.c index bb95f091..88e94956 100644 --- a/msp_client.c +++ b/msp_client.c @@ -68,6 +68,17 @@ struct msp_sock * msp_socket(int mdp_sock) return ret; } +unsigned msp_socket_count() +{ + unsigned i=0; + struct msp_sock *p=root; + while(p){ + i++; + p=p->_next; + } + return i; +} + static void free_all_packets(struct msp_window *window) { struct msp_packet *p = window->_head; @@ -114,11 +125,7 @@ static void free_acked_packets(struct msp_window *window, uint16_t seq) static void msp_free(struct msp_sock *sock) { sock->state |= MSP_STATE_CLOSED; - - // last chance to free other resources - if (sock->handler) - sock->handler(sock, sock->state, NULL, 0, sock->context); - + // remove from the list first if (sock->_prev) sock->_prev->_next = sock->_next; else @@ -126,6 +133,10 @@ static void msp_free(struct msp_sock *sock) if (sock->_next) sock->_next->_prev = sock->_prev; + // last chance to free other resources + if (sock->handler) + sock->handler(sock, sock->state, NULL, 0, sock->context); + free_all_packets(&sock->tx); free_all_packets(&sock->rx); @@ -134,6 +145,7 @@ static void msp_free(struct msp_sock *sock) void msp_close(struct msp_sock *sock) { + // TODO if never sent / received, just free it sock->state |= MSP_STATE_CLOSED; } diff --git a/msp_client.h b/msp_client.h index bf68d284..e2d2717a 100644 --- a/msp_client.h +++ b/msp_client.h @@ -27,6 +27,7 @@ typedef uint16_t msp_state_t; struct msp_sock * msp_socket(int mdp_sock); void msp_close(struct msp_sock *sock); void msp_close_all(int mdp_sock); +unsigned msp_socket_count(); int msp_set_handler(struct msp_sock *sock, int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context), diff --git a/msp_proxy.c b/msp_proxy.c index 595cf59c..47fcc3e6 100644 --- a/msp_proxy.c +++ b/msp_proxy.c @@ -4,6 +4,7 @@ #include "dataformats.h" #include "mdp_client.h" #include "msp_client.h" +#include "socket.h" struct buffer{ size_t position; @@ -13,49 +14,62 @@ struct buffer{ }; struct connection{ + struct sched_ent alarm_in; + struct sched_ent alarm_out; struct msp_sock *sock; struct buffer *in; struct buffer *out; int last_state; }; -struct connection *stdio_connection=NULL; +int saw_error=0; struct msp_sock *listener=NULL; +struct mdp_sockaddr remote_addr; -static int try_send(); +static int try_send(struct connection *conn); static void msp_poll(struct sched_ent *alarm); -static void stdin_poll(struct sched_ent *alarm); -static void stdout_poll(struct sched_ent *alarm); +static void io_poll(struct sched_ent *alarm); struct profile_total mdp_sock_stats={ .name="msp_poll" }; + struct sched_ent mdp_sock={ + .poll.revents = 0, + .poll.events = POLLIN, + .poll.fd = -1, .function = msp_poll, .stats = &mdp_sock_stats, }; -struct profile_total stdin_stats={ - .name="stdin_poll" -}; -struct sched_ent stdin_alarm={ - .function = stdin_poll, - .stats = &stdin_stats, +struct profile_total io_stats={ + .name="io_stats" }; -struct profile_total stdout_stats={ - .name="stdout_poll" -}; -struct sched_ent stdout_alarm={ - .function = stdout_poll, - .stats = &stdout_stats, -}; -static struct connection *alloc_connection() +static struct connection *alloc_connection( + struct msp_sock *sock, + int fd_in, + void (*func_in)(struct sched_ent *alarm), + int fd_out, + void (*func_out)(struct sched_ent *alarm)) { struct connection *conn = emalloc_zero(sizeof(struct connection)); if (!conn) return NULL; + + conn->sock = sock; + conn->alarm_in.poll.fd = fd_in; + conn->alarm_in.poll.events = POLLIN; + conn->alarm_in.function = func_in; + conn->alarm_in.stats = &io_stats; + conn->alarm_in.context = conn; + conn->alarm_out.poll.fd = fd_out; + conn->alarm_out.poll.events = POLLOUT; + conn->alarm_out.function = func_out; + conn->alarm_out.stats = &io_stats; + conn->alarm_out.context = conn; + watch(&conn->alarm_in); conn->in = emalloc(1024 + sizeof(struct buffer)); if (!conn->in){ free(conn); @@ -77,11 +91,28 @@ static void free_connection(struct connection *conn) { if (!conn) return; + if (is_watching(&conn->alarm_in)) + unwatch(&conn->alarm_in); + if (is_watching(&conn->alarm_out)) + unwatch(&conn->alarm_out); if (conn->in) free(conn->in); if (conn->out) free(conn->out); + if (conn->alarm_in.poll.fd!=-1) + close(conn->alarm_in.poll.fd); + if (conn->alarm_out.poll.fd!=-1 && conn->alarm_out.poll.fd != conn->alarm_in.poll.fd) + close(conn->alarm_out.poll.fd); + DEBUGF("Freeing connection %p", conn); free(conn); + + if (msp_socket_count()==0){ + DEBUGF("All sockets closed"); + unschedule(&mdp_sock); + + if (is_watching(&mdp_sock)) + unwatch(&mdp_sock); + } } static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context) @@ -89,23 +120,26 @@ static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t * struct connection *conn = context; conn->last_state=state; + if (state & MSP_STATE_ERROR) + saw_error=1; + if (payload && len){ if (conn->out->limit){ // attempt to write immediately - stdout_alarm.poll.revents=POLLOUT; - stdout_poll(&stdout_alarm); + conn->alarm_out.poll.revents=POLLOUT; + conn->alarm_out.function(&conn->alarm_out); } if (conn->out->capacity < len + conn->out->limit) return 1; bcopy(payload, &conn->out->bytes[conn->out->limit], len); conn->out->limit+=len; + if (!is_watching(&conn->alarm_out)) + watch(&conn->alarm_out); + // attempt to write immediately - if (!is_watching(&stdout_alarm)) - watch(&stdout_alarm); - - stdout_alarm.poll.revents=POLLOUT; - stdout_poll(&stdout_alarm); + conn->alarm_out.poll.revents=POLLOUT; + conn->alarm_out.function(&conn->alarm_out); } if (state & MSP_STATE_CLOSED){ @@ -115,20 +149,17 @@ static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t * conn->sock = NULL; - if (conn != stdio_connection) + if (!conn->out->limit){ free_connection(conn); + } - unschedule(&mdp_sock); - - if (is_watching(&mdp_sock)) - unwatch(&mdp_sock); return 0; } if (state&MSP_STATE_DATAOUT){ - try_send(); - if (stdio_connection->in->limitin->capacity && !is_watching(&stdin_alarm)) - watch(&stdin_alarm); + try_send(conn); + if (conn->in->limitin->capacity && !is_watching(&conn->alarm_in)) + watch(&conn->alarm_in); } return 0; } @@ -142,14 +173,12 @@ static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t msp_get_remote_adr(sock, &remote); INFOF(" - New connection from %s:%d", alloca_tohex_sid_t(remote.sid), remote.port); - struct connection *conn = alloc_connection(); + struct connection *conn = alloc_connection(sock, STDIN_FILENO, io_poll, STDOUT_FILENO, io_poll); if (!conn) return -1; + conn->sock = sock; - if (!stdio_connection){ - stdio_connection=conn; - watch(&stdin_alarm); - } + watch(&conn->alarm_in); msp_set_handler(sock, msp_handler, conn); if (payload) return msp_handler(sock, state, payload, len, conn); @@ -178,35 +207,32 @@ static void msp_poll(struct sched_ent *alarm) } } -static int try_send() +static int try_send(struct connection *conn) { - if (!stdio_connection->in->limit) + if (!conn->in->limit) return 0; - if (msp_send(stdio_connection->sock, stdio_connection->in->bytes, stdio_connection->in->limit)==-1) + if (msp_send(conn->sock, conn->in->bytes, conn->in->limit)==-1) return 0; // if this packet was acceptted, clear the read buffer - stdio_connection->in->limit = stdio_connection->in->position = 0; + conn->in->limit = conn->in->position = 0; return 1; } -static void stdin_poll(struct sched_ent *alarm) +static void io_poll(struct sched_ent *alarm) { + struct connection *conn = alarm->context; + if (alarm->poll.revents & POLLIN) { - if (!stdio_connection){ - unwatch(alarm); - return; - } - - size_t remaining = stdio_connection->in->capacity - stdio_connection->in->limit; + size_t remaining = conn->in->capacity - conn->in->limit; if (remaining>0){ ssize_t r = read(alarm->poll.fd, - stdio_connection->in->bytes + stdio_connection->in->limit, + conn->in->bytes + conn->in->limit, remaining); if (r>0){ - stdio_connection->in->limit+=r; - if (try_send()){ + conn->in->limit+=r; + if (try_send(conn)){ // attempt to process this socket asap mdp_sock.alarm = gettime_ms(); mdp_sock.deadline = mdp_sock.alarm+10; @@ -214,11 +240,11 @@ static void stdin_poll(struct sched_ent *alarm) schedule(&mdp_sock); } // stop reading input when the buffer is full - if (stdio_connection->in->limit==stdio_connection->in->capacity){ + if (conn->in->limit==conn->in->capacity){ unwatch(alarm); } }else{ - if (stdio_connection->in->limit) + if (conn->in->limit) unwatch(alarm); else // EOF and no data in the buffer, just trigger our error handler @@ -227,15 +253,53 @@ static void stdin_poll(struct sched_ent *alarm) } } + if (alarm->poll.revents & POLLOUT) { + // try to write some data + size_t data = conn->out->limit-conn->out->position; + if (data>0){ + ssize_t r = write(alarm->poll.fd, + conn->out->bytes+conn->out->position, + data); + if (r > 0) + conn->out->position+=r; + } + + // if the buffer is empty now, reset it and unwatch the handle + if (conn->out->position==conn->out->limit){ + conn->out->limit=0; + conn->out->position=0; + if (is_watching(alarm)) + unwatch(alarm); + } + + if (conn->out->limit < conn->out->capacity){ + if (conn->sock){ + // make sure we try to process this socket soon for more data + mdp_sock.alarm = gettime_ms(); + mdp_sock.deadline = mdp_sock.alarm+10; + unschedule(&mdp_sock); + schedule(&mdp_sock); + }else{ + free_connection(conn); + } + } + } + if (alarm->poll.revents & (POLLHUP | POLLERR)) { // input has closed? - struct mdp_sockaddr remote; - msp_get_remote_adr(stdio_connection->sock, &remote); - msp_shutdown(stdio_connection->sock); + if (conn->sock){ + struct mdp_sockaddr remote; + msp_get_remote_adr(conn->sock, &remote); + msp_shutdown(conn->sock); + INFOF(" - Connection with %s:%d local shutdown", alloca_tohex_sid_t(remote.sid), remote.port); + } + if (is_watching(alarm)) unwatch(alarm); - INFOF(" - Connection with %s:%d local shutdown", alloca_tohex_sid_t(remote.sid), remote.port); - // attempt to process this socket asap + close(alarm->poll.fd); + alarm->poll.fd=-1; + + // attempt to process this msp socket asap mdp_sock.alarm = gettime_ms(); mdp_sock.deadline = mdp_sock.alarm+10; unschedule(&mdp_sock); @@ -243,60 +307,19 @@ static void stdin_poll(struct sched_ent *alarm) } } -static void stdout_poll(struct sched_ent *alarm) -{ - if (alarm->poll.revents & POLLOUT) { - if (!stdio_connection){ - if (is_watching(alarm)) - unwatch(alarm); - return; - } - // try to write some data - size_t data = stdio_connection->out->limit-stdio_connection->out->position; - if (data>0){ - ssize_t r = write(alarm->poll.fd, - stdio_connection->out->bytes+stdio_connection->out->position, - data); - if (r > 0) - stdio_connection->out->position+=r; - } - - // if the buffer is empty now, reset it and unwatch the handle - if (stdio_connection->out->position==stdio_connection->out->limit){ - stdio_connection->out->limit=0; - stdio_connection->out->position=0; - if (is_watching(alarm)) - unwatch(alarm); - } - - if (stdio_connection->out->limit < stdio_connection->out->capacity){ - // make sure we try to process this socket soon for more data - mdp_sock.alarm = gettime_ms(); - mdp_sock.deadline = mdp_sock.alarm+10; - unschedule(&mdp_sock); - schedule(&mdp_sock); - } - } - - if (alarm->poll.revents & (POLLHUP | POLLERR)) { - if (is_watching(alarm)) - unwatch(alarm); - } -} - int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) { const char *sidhex, *port_string; - if (cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, NULL) == -1) - return -1; - if (cli_arg(parsed, "port", &port_string, cli_uint, NULL) == -1) + if ( cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, NULL) == -1 + || cli_arg(parsed, "port", &port_string, cli_uint, NULL) == -1) return -1; struct mdp_sockaddr addr; bzero(&addr, sizeof addr); addr.port = atoi(port_string); + saw_error=0; if (sidhex && *sidhex){ if (str_to_sid_t(&addr.sid, sidhex) == -1) @@ -309,30 +332,19 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS mdp_sock.poll.fd = mdp_socket(); if (mdp_sock.poll.fd==-1) goto end; - mdp_sock.poll.events = POLLIN; watch(&mdp_sock); set_nonblock(STDIN_FILENO); set_nonblock(STDOUT_FILENO); - stdin_alarm.poll.fd=STDIN_FILENO; - stdin_alarm.poll.events=POLLIN; - - stdout_alarm.poll.fd=STDOUT_FILENO; - stdout_alarm.poll.events=POLLOUT; - sock = msp_socket(mdp_sock.poll.fd); if (sidhex && *sidhex){ - stdio_connection = alloc_connection(); - if (!stdio_connection) + struct connection *conn=alloc_connection(sock, STDIN_FILENO, io_poll, STDOUT_FILENO, io_poll); + if (!conn) goto end; - stdio_connection->sock = sock; - msp_set_handler(sock, msp_handler, stdio_connection); + msp_set_handler(sock, msp_handler, conn); msp_set_remote(sock, addr); INFOF("- Connecting to %s:%d", alloca_tohex_sid_t(addr.sid), addr.port); - - // note we only watch these stdio handles when we have space / bytes in our buffers - watch(&stdin_alarm); }else{ msp_set_handler(sock, msp_listener, NULL); msp_set_local(sock, addr); @@ -353,22 +365,17 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS ; } - if (stdio_connection && stdio_connection->last_state & MSP_STATE_ERROR) - ret = 1; - else - ret = 0; + ret = saw_error; end: listener=NULL; if (is_watching(&mdp_sock)) unwatch(&mdp_sock); - if (mdp_sock.poll.fd>=0){ + if (mdp_sock.poll.fd!=-1){ msp_close_all(mdp_sock.poll.fd); mdp_close(mdp_sock.poll.fd); } unschedule(&mdp_sock); - free_connection(stdio_connection); - stdio_connection=NULL; return ret; } diff --git a/tests/all b/tests/all index 422db671..190e3d73 100755 --- a/tests/all +++ b/tests/all @@ -25,6 +25,7 @@ includeTests config includeTests keyring includeTests server includeTests routing +includeTests msp includeTests dnahelper includeTests dnaprotocol includeTests rhizomeops From 99e08d151636227512573efb928f26932d515bcb Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Thu, 19 Dec 2013 14:45:58 +1030 Subject: [PATCH 12/18] Add command to support forwarding TCP connections to an MSP service --- commandline.c | 2 +- msp_client.c | 14 ++++ msp_client.h | 2 + msp_proxy.c | 196 ++++++++++++++++++++++++++++++++++---------------- tests/msp | 64 +++++++++-------- 5 files changed, 187 insertions(+), 91 deletions(-) diff --git a/commandline.c b/commandline.c index 820ab451..2c786051 100644 --- a/commandline.c +++ b/commandline.c @@ -3058,7 +3058,7 @@ struct cli_schema command_line_options[]={ "Run serial encapsulation test"}, {app_msp_connection,{"msp", "listen", "", NULL}, 0, "Listen for incoming connections"}, - {app_msp_connection,{"msp", "connect", "", "", NULL}, 0, + {app_msp_connection,{"msp", "connect", "[--once]", "[--forward=]", "", "", NULL}, 0, "Connect to a remote party"}, #ifdef HAVE_VOIPTEST {app_pa_phone,{"phone",NULL}, 0, diff --git a/msp_client.c b/msp_client.c index 88e94956..a75e7984 100644 --- a/msp_client.c +++ b/msp_client.c @@ -79,6 +79,18 @@ unsigned msp_socket_count() return i; } +void msp_debug() +{ + struct msp_sock *p=root; + DEBUGF("Msp sockets;"); + while(p){ + DEBUGF("State %d, from %s:%d to %s:%d", p->state, + alloca_tohex_sid_t(p->header.local.sid), p->header.local.port, + alloca_tohex_sid_t(p->header.remote.sid), p->header.remote.port); + p=p->_next; + } +} + static void free_all_packets(struct msp_window *window) { struct msp_packet *p = window->_head; @@ -113,6 +125,8 @@ static void free_acked_packets(struct msp_window *window, uint16_t seq) } window->_head = p; if (rtt){ + if (rtt < 10) + rtt=10; window->rtt = rtt; if (window->base_rtt > rtt) window->base_rtt = rtt; diff --git a/msp_client.h b/msp_client.h index e2d2717a..6a6e1dcc 100644 --- a/msp_client.h +++ b/msp_client.h @@ -29,6 +29,8 @@ void msp_close(struct msp_sock *sock); void msp_close_all(int mdp_sock); unsigned msp_socket_count(); +void msp_debug(); + int msp_set_handler(struct msp_sock *sock, int (*handler)(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context), void *context); diff --git a/msp_proxy.c b/msp_proxy.c index 47fcc3e6..a12528eb 100644 --- a/msp_proxy.c +++ b/msp_proxy.c @@ -1,6 +1,8 @@ #include "serval.h" #include "str.h" +#include "strbuf.h" +#include "strbuf_helpers.h" #include "dataformats.h" #include "mdp_client.h" #include "msp_client.h" @@ -23,11 +25,13 @@ struct connection{ }; int saw_error=0; +int once =0; struct msp_sock *listener=NULL; struct mdp_sockaddr remote_addr; static int try_send(struct connection *conn); static void msp_poll(struct sched_ent *alarm); +static void listen_poll(struct sched_ent *alarm); static void io_poll(struct sched_ent *alarm); struct profile_total mdp_sock_stats={ @@ -46,6 +50,17 @@ struct profile_total io_stats={ .name="io_stats" }; +struct profile_total listen_stats={ + .name="listen_poll" +}; + +struct sched_ent listen_alarm={ + .poll.revents = 0, + .poll.events = POLLIN, + .poll.fd = -1, + .function = listen_poll, + .stats = &listen_stats, +}; static struct connection *alloc_connection( struct msp_sock *sock, @@ -103,6 +118,10 @@ static void free_connection(struct connection *conn) close(conn->alarm_in.poll.fd); if (conn->alarm_out.poll.fd!=-1 && conn->alarm_out.poll.fd != conn->alarm_in.poll.fd) close(conn->alarm_out.poll.fd); + conn->in=NULL; + conn->out=NULL; + conn->alarm_in.poll.fd=-1; + conn->alarm_out.poll.fd=-1; DEBUGF("Freeing connection %p", conn); free(conn); @@ -115,6 +134,14 @@ static void free_connection(struct connection *conn) } } +static void process_msp_asap() +{ + mdp_sock.alarm = gettime_ms(); + mdp_sock.deadline = mdp_sock.alarm+10; + unschedule(&mdp_sock); + schedule(&mdp_sock); +} + static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *context) { struct connection *conn = context; @@ -148,19 +175,16 @@ static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t * INFOF(" - Connection with %s:%d closed", alloca_tohex_sid_t(remote.sid), remote.port); conn->sock = NULL; - - if (!conn->out->limit){ + if (is_watching(&conn->alarm_in)) + unwatch(&conn->alarm_in); + if (!is_watching(&conn->alarm_out)) free_connection(conn); - } return 0; } - if (state&MSP_STATE_DATAOUT){ + if (state&MSP_STATE_DATAOUT) try_send(conn); - if (conn->in->limitin->capacity && !is_watching(&conn->alarm_in)) - watch(&conn->alarm_in); - } return 0; } @@ -183,9 +207,10 @@ static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t if (payload) return msp_handler(sock, state, payload, len, conn); - // stop listening after the first incoming connection - msp_close(listener); - + if (once){ + // stop listening after the first incoming connection + msp_close(listener); + } return 0; } @@ -207,6 +232,14 @@ static void msp_poll(struct sched_ent *alarm) } } +static void local_shutdown(struct connection *conn) +{ + struct mdp_sockaddr remote; + msp_get_remote_adr(conn->sock, &remote); + msp_shutdown(conn->sock); + INFOF(" - Connection with %s:%d local shutdown", alloca_tohex_sid_t(remote.sid), remote.port); +} + static int try_send(struct connection *conn) { if (!conn->in->limit) @@ -216,7 +249,13 @@ static int try_send(struct connection *conn) // if this packet was acceptted, clear the read buffer conn->in->limit = conn->in->position = 0; - + // hit end of data? + if (conn->alarm_in.poll.events==0){ + local_shutdown(conn); + }else{ + if (!is_watching(&conn->alarm_in)) + watch(&conn->alarm_in); + } return 1; } @@ -232,23 +271,15 @@ static void io_poll(struct sched_ent *alarm) remaining); if (r>0){ conn->in->limit+=r; - if (try_send(conn)){ - // attempt to process this socket asap - mdp_sock.alarm = gettime_ms(); - mdp_sock.deadline = mdp_sock.alarm+10; - unschedule(&mdp_sock); - schedule(&mdp_sock); - } + if (try_send(conn)) + process_msp_asap(); // stop reading input when the buffer is full if (conn->in->limit==conn->in->capacity){ unwatch(alarm); } }else{ - if (conn->in->limit) - unwatch(alarm); - else - // EOF and no data in the buffer, just trigger our error handler - alarm->poll.revents|=POLLERR; + // EOF? trigger a graceful shutdown + alarm->poll.revents = POLLHUP; } } } @@ -266,52 +297,75 @@ static void io_poll(struct sched_ent *alarm) // if the buffer is empty now, reset it and unwatch the handle if (conn->out->position==conn->out->limit){ - conn->out->limit=0; - conn->out->position=0; + conn->out->limit = conn->out->position = 0; if (is_watching(alarm)) unwatch(alarm); } if (conn->out->limit < conn->out->capacity){ if (conn->sock){ - // make sure we try to process this socket soon for more data - mdp_sock.alarm = gettime_ms(); - mdp_sock.deadline = mdp_sock.alarm+10; - unschedule(&mdp_sock); - schedule(&mdp_sock); + process_msp_asap(); }else{ free_connection(conn); } } } - if (alarm->poll.revents & (POLLHUP | POLLERR)) { - // input has closed? - if (conn->sock){ - struct mdp_sockaddr remote; - msp_get_remote_adr(conn->sock, &remote); - msp_shutdown(conn->sock); - INFOF(" - Connection with %s:%d local shutdown", alloca_tohex_sid_t(remote.sid), remote.port); + if (alarm->poll.revents & POLLHUP) { + // EOF? trigger a graceful shutdown + unwatch(alarm); + alarm->poll.events = 0; + if (!conn->in->limit){ + local_shutdown(conn); + process_msp_asap(); } + } + + if (alarm->poll.revents & POLLERR) { + free_connection(conn); + process_msp_asap(); + } +} + +static void listen_poll(struct sched_ent *alarm) +{ + if (alarm->poll.revents & POLLIN) { + struct socket_address addr; + addr.addrlen = sizeof addr.store; + int fd = accept(alarm->poll.fd, &addr.addr, &addr.addrlen); + if (fd==-1){ + WHYF_perror("accept(%d)", alarm->poll.fd); + return; + } + INFOF("- Incoming TCP connection from %s", alloca_socket_address(&addr)); + struct msp_sock *sock = msp_socket(mdp_sock.poll.fd); + if (!sock) + return; - if (is_watching(alarm)) + struct connection *connection = alloc_connection(sock, fd, io_poll, fd, io_poll); + if (!connection){ + msp_close(sock); + return; + } + + msp_set_handler(sock, msp_handler, connection); + msp_set_remote(sock, remote_addr); + + if (once){ unwatch(alarm); - close(alarm->poll.fd); - alarm->poll.fd=-1; - - // attempt to process this msp socket asap - mdp_sock.alarm = gettime_ms(); - mdp_sock.deadline = mdp_sock.alarm+10; - unschedule(&mdp_sock); - schedule(&mdp_sock); + close(alarm->poll.fd); + alarm->poll.fd=-1; + } } } int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUSED(context)) { - const char *sidhex, *port_string; - - if ( cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, NULL) == -1 + const char *sidhex, *port_string, *local_port_string; + once = cli_arg(parsed, "--once", NULL, NULL, NULL) == 0; + + if ( cli_arg(parsed, "--forward", &local_port_string, cli_uint, NULL) == -1 + || cli_arg(parsed, "sid", &sidhex, str_is_subscriber_id, NULL) == -1 || cli_arg(parsed, "port", &port_string, cli_uint, NULL) == -1) return -1; @@ -337,15 +391,36 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS set_nonblock(STDIN_FILENO); set_nonblock(STDOUT_FILENO); - sock = msp_socket(mdp_sock.poll.fd); if (sidhex && *sidhex){ - struct connection *conn=alloc_connection(sock, STDIN_FILENO, io_poll, STDOUT_FILENO, io_poll); - if (!conn) - goto end; - msp_set_handler(sock, msp_handler, conn); - msp_set_remote(sock, addr); - INFOF("- Connecting to %s:%d", alloca_tohex_sid_t(addr.sid), addr.port); + if (local_port_string){ + remote_addr = addr; + listen_alarm.poll.fd = esocket(PF_INET, SOCK_STREAM, 0); + if (listen_alarm.poll.fd==-1) + goto end; + struct socket_address ip_addr; + ip_addr.addrlen = sizeof(ip_addr.inet); + ip_addr.inet.sin_family = AF_INET; + ip_addr.inet.sin_port = htons(atoi(local_port_string)); + ip_addr.inet.sin_addr.s_addr = INADDR_ANY; + if (socket_bind(listen_alarm.poll.fd, &ip_addr.addr, ip_addr.addrlen)==-1) + goto end; + if (socket_listen(listen_alarm.poll.fd, 0)==-1) + goto end; + watch(&listen_alarm); + INFOF("- Forwarding from port %d to %s:%d", ntohs(ip_addr.inet.sin_port), alloca_tohex_sid_t(addr.sid), addr.port); + }else{ + sock = msp_socket(mdp_sock.poll.fd); + once = 1; + struct connection *conn=alloc_connection(sock, STDIN_FILENO, io_poll, STDOUT_FILENO, io_poll); + if (!conn) + goto end; + msp_set_handler(sock, msp_handler, conn); + msp_set_remote(sock, addr); + INFOF("- Connecting to %s:%d", alloca_tohex_sid_t(addr.sid), addr.port); + } }else{ + sock = msp_socket(mdp_sock.poll.fd); + once = 1; msp_set_handler(sock, msp_listener, NULL); msp_set_local(sock, addr); @@ -357,14 +432,11 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS INFOF(" - Listening on port %d", addr.port); } - // run msp_processing once to init alarm timer - mdp_sock.poll.revents=0; - msp_poll(&mdp_sock); + process_msp_asap(); while(fd_poll()){ ; } - ret = saw_error; end: @@ -375,6 +447,10 @@ end: msp_close_all(mdp_sock.poll.fd); mdp_close(mdp_sock.poll.fd); } + if (listen_alarm.poll.fd !=-1 && is_watching(&listen_alarm)) + unwatch(&listen_alarm); + if (listen_alarm.poll.fd!=-1) + close(listen_alarm.poll.fd); unschedule(&mdp_sock); return ret; } diff --git a/tests/msp b/tests/msp index efecd154..50c2ec24 100755 --- a/tests/msp +++ b/tests/msp @@ -29,16 +29,21 @@ teardown() { report_all_servald_servers } +configure_servald_server() { + create_single_identity + add_servald_interface + executeOk_servald config \ + set debug.mdprequests on \ + set log.console.level DEBUG \ + set log.console.show_time on +} + doc_connect_fail="Timeout when the connection isn't reachable" setup_connect_fail() { setup_servald assert_no_servald_processes - foreach_instance +A +B create_single_identity - foreach_instance +A +B \ - executeOk_servald config \ - set debug.mdprequests on \ - set log.console.level DEBUG \ - set log.console.show_time on + set_instance +B + create_single_identity start_servald_instances +A } test_connect_fail() { @@ -53,12 +58,6 @@ doc_hello="Simple Hello World" setup_hello() { setup_servald assert_no_servald_processes - foreach_instance +A +B create_single_identity - foreach_instance +A +B \ - executeOk_servald config \ - set debug.mdprequests on \ - set log.console.level DEBUG \ - set log.console.show_time on start_servald_instances +A +B } server_hello() { @@ -66,6 +65,7 @@ server_hello() { Hello from the server EOF assertStdoutGrep --matches=1 "^Hello from the client$" + tfw_cat --stderr } test_hello() { set_instance +A @@ -84,12 +84,6 @@ setup_client_no_data() { setup_servald assert_no_servald_processes create_file file1 64000 - foreach_instance +A +B create_single_identity - foreach_instance +A +B \ - executeOk_servald config \ - set debug.mdprequests on \ - set log.console.level DEBUG \ - set log.console.show_time on start_servald_instances +A +B } server_client_no_data() { @@ -113,12 +107,6 @@ setup_server_no_data() { setup_servald assert_no_servald_processes create_file file1 64000 - foreach_instance +A +B create_single_identity - foreach_instance +A +B \ - executeOk_servald config \ - set debug.mdprequests on \ - set log.console.level DEBUG \ - set log.console.show_time on start_servald_instances +A +B } server_server_no_data() { @@ -141,12 +129,6 @@ doc_keep_alive="Keep the connection alive with no data" setup_keep_alive() { setup_servald assert_no_servald_processes - foreach_instance +A +B create_single_identity - foreach_instance +A +B \ - executeOk_servald config \ - set debug.mdprequests on \ - set log.console.level DEBUG \ - set log.console.show_time on start_servald_instances +A +B } listen_pipe() { @@ -166,4 +148,26 @@ test_keep_alive() { fork_wait_all } +doc_forward="Forward TCP connections to a remote server" +setup_forward() { + setup_servald + assert_no_servald_processes + start_servald_instances +A +B +} +client_forward() { + executeOk --timeout=20 $servald msp connect --once --forward=2048 $1 512 + tfw_cat --stdout --stderr +} +test_forward() { + set_instance +A + fork server_hello + wait_until --timeout=10 grep "Bind MDP $SIDA:512" "$instance_servald_log" + set_instance +B + fork client_forward $SIDA + sleep 1 + executeOk nc -v 127.0.0.1 2048 < <(echo "Hello from the client") + assertStdoutGrep --matches=1 "^Hello from the server$" + fork_wait_all +} + runTests "$@" From 48dce9a5751cbcf022da23fe19ce815e7b0a8860 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Thu, 19 Dec 2013 16:17:09 +1030 Subject: [PATCH 13/18] Add tcp forwarding on the listen end of an MSP connection --- commandline.c | 2 +- msp_proxy.c | 43 ++++++++++++++++++++++++++++++++----------- tests/msp | 31 +++++++++++++++++++++++++++++-- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/commandline.c b/commandline.c index 2c786051..053e810d 100644 --- a/commandline.c +++ b/commandline.c @@ -3056,7 +3056,7 @@ struct cli_schema command_line_options[]={ "Run byte order handling test"}, {app_slip_test,{"test","slip","[--seed=]","[--duration=|--iterations=]",NULL}, 0, "Run serial encapsulation test"}, - {app_msp_connection,{"msp", "listen", "", NULL}, 0, + {app_msp_connection,{"msp", "listen", "[--once]", "[--forward=]", "", NULL}, 0, "Listen for incoming connections"}, {app_msp_connection,{"msp", "connect", "[--once]", "[--forward=]", "", "", NULL}, 0, "Connect to a remote party"}, diff --git a/msp_proxy.c b/msp_proxy.c index a12528eb..df7179a8 100644 --- a/msp_proxy.c +++ b/msp_proxy.c @@ -28,6 +28,7 @@ int saw_error=0; int once =0; struct msp_sock *listener=NULL; struct mdp_sockaddr remote_addr; +struct socket_address ip_addr; static int try_send(struct connection *conn); static void msp_poll(struct sched_ent *alarm); @@ -122,11 +123,9 @@ static void free_connection(struct connection *conn) conn->out=NULL; conn->alarm_in.poll.fd=-1; conn->alarm_out.poll.fd=-1; - DEBUGF("Freeing connection %p", conn); free(conn); if (msp_socket_count()==0){ - DEBUGF("All sockets closed"); unschedule(&mdp_sock); if (is_watching(&mdp_sock)) @@ -196,8 +195,23 @@ static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t struct mdp_sockaddr remote; msp_get_remote_adr(sock, &remote); INFOF(" - New connection from %s:%d", alloca_tohex_sid_t(remote.sid), remote.port); + int fd_in = STDIN_FILENO; + int fd_out = STDOUT_FILENO; - struct connection *conn = alloc_connection(sock, STDIN_FILENO, io_poll, STDOUT_FILENO, io_poll); + if (ip_addr.addrlen){ + int fd = esocket(PF_INET, SOCK_STREAM, 0); + if (fd==-1){ + msp_close(sock); + return -1; + } + if (socket_connect(fd, &ip_addr.addr, ip_addr.addrlen)==-1){ + msp_close(sock); + close(fd); + return -1; + } + fd_in = fd_out = fd; + } + struct connection *conn = alloc_connection(sock, fd_in, io_poll, fd_out, io_poll); if (!conn) return -1; @@ -390,6 +404,14 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS set_nonblock(STDIN_FILENO); set_nonblock(STDOUT_FILENO); + bzero(&ip_addr, sizeof ip_addr); + + if (local_port_string){ + ip_addr.addrlen = sizeof(ip_addr.inet); + ip_addr.inet.sin_family = AF_INET; + ip_addr.inet.sin_port = htons(atoi(local_port_string)); + ip_addr.inet.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + } if (sidhex && *sidhex){ if (local_port_string){ @@ -397,17 +419,12 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS listen_alarm.poll.fd = esocket(PF_INET, SOCK_STREAM, 0); if (listen_alarm.poll.fd==-1) goto end; - struct socket_address ip_addr; - ip_addr.addrlen = sizeof(ip_addr.inet); - ip_addr.inet.sin_family = AF_INET; - ip_addr.inet.sin_port = htons(atoi(local_port_string)); - ip_addr.inet.sin_addr.s_addr = INADDR_ANY; if (socket_bind(listen_alarm.poll.fd, &ip_addr.addr, ip_addr.addrlen)==-1) goto end; if (socket_listen(listen_alarm.poll.fd, 0)==-1) goto end; watch(&listen_alarm); - INFOF("- Forwarding from port %d to %s:%d", ntohs(ip_addr.inet.sin_port), alloca_tohex_sid_t(addr.sid), addr.port); + INFOF("- Forwarding from %s to %s:%d", alloca_socket_address(&ip_addr), alloca_tohex_sid_t(addr.sid), addr.port); }else{ sock = msp_socket(mdp_sock.poll.fd); once = 1; @@ -420,7 +437,6 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS } }else{ sock = msp_socket(mdp_sock.poll.fd); - once = 1; msp_set_handler(sock, msp_listener, NULL); msp_set_local(sock, addr); @@ -429,7 +445,12 @@ int app_msp_connection(const struct cli_parsed *parsed, struct cli_context *UNUS goto end; listener=sock; - INFOF(" - Listening on port %d", addr.port); + if (local_port_string){ + INFOF("- Forwarding from port %d to %s", addr.port, alloca_socket_address(&ip_addr)); + }else{ + once = 1; + INFOF(" - Listening on port %d", addr.port); + } } process_msp_asap(); diff --git a/tests/msp b/tests/msp index 50c2ec24..068f1abe 100755 --- a/tests/msp +++ b/tests/msp @@ -155,7 +155,7 @@ setup_forward() { start_servald_instances +A +B } client_forward() { - executeOk --timeout=20 $servald msp connect --once --forward=2048 $1 512 + executeOk --timeout=20 $servald msp connect --once --forward=$1 $2 512 tfw_cat --stdout --stderr } test_forward() { @@ -163,11 +163,38 @@ test_forward() { fork server_hello wait_until --timeout=10 grep "Bind MDP $SIDA:512" "$instance_servald_log" set_instance +B - fork client_forward $SIDA + fork client_forward 2048 $SIDA sleep 1 executeOk nc -v 127.0.0.1 2048 < <(echo "Hello from the client") assertStdoutGrep --matches=1 "^Hello from the server$" fork_wait_all } +doc_tcp_tunnel="Tunnel a tcp connection" +setup_tcp_tunnel() { + setup_servald + assert_no_servald_processes + start_servald_instances +A +B +} +server_forward() { + executeOk_servald msp listen --once --forward=$1 512 + tfw_cat --stderr +} +nc_listen() { + execute nc -v -l $1 < <(echo "Hello from the server") + tfw_cat --stdout --stderr +} + +test_tcp_tunnel() { + fork nc_listen 6000 + set_instance +A + fork server_forward 6000 + set_instance +B + fork client_forward 6001 $SIDA + sleep 1 + executeOk nc -v 127.0.0.1 6001 < <(echo "Hello from the client") + assertStdoutGrep --matches=1 "^Hello from the server$" + fork_wait_all +} + runTests "$@" From dbb65228e6b764a921a6756a599d7e9a24a4ffbe Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Thu, 19 Dec 2013 17:46:54 +1030 Subject: [PATCH 14/18] Deal with errors when binding sockets --- msp_client.c | 13 ++++++++++--- msp_proxy.c | 12 +++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/msp_client.c b/msp_client.c index a75e7984..838fa811 100644 --- a/msp_client.c +++ b/msp_client.c @@ -1,5 +1,6 @@ #include +#include #include "serval.h" #include "mdp_client.h" #include "msp_client.h" @@ -81,12 +82,15 @@ unsigned msp_socket_count() void msp_debug() { + time_ms_t now = gettime_ms(); struct msp_sock *p=root; DEBUGF("Msp sockets;"); while(p){ - DEBUGF("State %d, from %s:%d to %s:%d", p->state, + DEBUGF("State %d, from %s:%d to %s:%d, timeout in %"PRId64"ms", + p->state, alloca_tohex_sid_t(p->header.local.sid), p->header.local.port, - alloca_tohex_sid_t(p->header.remote.sid), p->header.remote.port); + alloca_tohex_sid_t(p->header.remote.sid), p->header.remote.port, + (p->timeout - now)); p=p->_next; } } @@ -218,7 +222,8 @@ int msp_listen(struct msp_sock *sock) return -1; } - sock->timeout = TIME_NEVER_WILL; + sock->timeout = gettime_ms()+1000; + sock->next_action = sock->timeout; return 0; } @@ -560,6 +565,8 @@ static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t s->header.flags &= ~MDP_FLAG_BIND; DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(header->local.sid), header->local.port); s->next_action = gettime_ms(); + if (s->state & MSP_STATE_LISTENING) + s->timeout = TIME_NEVER_WILL; return 0; } diff --git a/msp_proxy.c b/msp_proxy.c index df7179a8..5c1c294e 100644 --- a/msp_proxy.c +++ b/msp_proxy.c @@ -189,8 +189,18 @@ static int msp_handler(struct msp_sock *sock, msp_state_t state, const uint8_t * static int msp_listener(struct msp_sock *sock, msp_state_t state, const uint8_t *payload, size_t len, void *UNUSED(context)) { - if (state & MSP_STATE_CLOSED) + if (state & MSP_STATE_ERROR){ + WHY("Error listening for incoming connections"); + } + if (state & MSP_STATE_CLOSED){ + if (msp_socket_count()==0){ + unschedule(&mdp_sock); + + if (is_watching(&mdp_sock)) + unwatch(&mdp_sock); + } return 0; + } struct mdp_sockaddr remote; msp_get_remote_adr(sock, &remote); From 8d9447ba6b857de2bf136ee5e843d96341b8a733 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Fri, 20 Dec 2013 11:00:20 +1030 Subject: [PATCH 15/18] Ensure connection is initiated with no input --- msp_client.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/msp_client.c b/msp_client.c index 838fa811..cd1f8e2c 100644 --- a/msp_client.c +++ b/msp_client.c @@ -86,10 +86,12 @@ void msp_debug() struct msp_sock *p=root; DEBUGF("Msp sockets;"); while(p){ - DEBUGF("State %d, from %s:%d to %s:%d, timeout in %"PRId64"ms", + DEBUGF("State %d, from %s:%d to %s:%d, next %"PRId64"ms, ack %"PRId64"ms timeout %"PRId64"ms", p->state, alloca_tohex_sid_t(p->header.local.sid), p->header.local.port, alloca_tohex_sid_t(p->header.remote.sid), p->header.remote.port, + (p->next_action - now), + (p->next_ack - now), (p->timeout - now)); p=p->_next; } @@ -205,7 +207,8 @@ int msp_set_remote(struct msp_sock *sock, struct mdp_sockaddr remote) sock->header.remote = remote; sock->state|=MSP_STATE_DATAOUT; // make sure we send a packet soon - sock->next_action = gettime_ms()+10; + sock->next_ack = gettime_ms()+10; + sock->next_action = sock->next_ack; return 0; } @@ -497,6 +500,12 @@ static int process_sock(struct msp_sock *sock) // should we send an ack now without sending a payload? if (now > sock->next_ack){ + if (!sock->header.local.port){ + if (sock->header.flags & MDP_FLAG_BIND) + // wait until we have heard back from the daemon with our port number before sending another packet. + return 0; + sock->header.flags |= MDP_FLAG_BIND; + } int r = send_ack(sock); if (r==-1) return -1; @@ -531,7 +540,8 @@ int msp_processing(time_ms_t *next_action) if (sock->next_action < *next_action) *next_action=sock->next_action; } - } + }else if (sock->next_action < *next_action) + *next_action=sock->next_action; if (sock->state & MSP_STATE_CLOSED){ struct msp_sock *s = sock->_next; msp_free(sock); @@ -547,6 +557,7 @@ static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t { // any kind of error reported by the daemon, close all related msp connections if (header->flags & MDP_FLAG_ERROR){ + WHY("Error returned from daemon"); msp_close_all(mdp_sock); return -1; } From 57b7d7482293a8060bb18a1c852d4a7207e50773 Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Fri, 20 Dec 2013 11:13:00 +1030 Subject: [PATCH 16/18] Fix comparisons for removing mdp port bindings --- overlay_mdp.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/overlay_mdp.c b/overlay_mdp.c index 50354660..18e8c1dd 100644 --- a/overlay_mdp.c +++ b/overlay_mdp.c @@ -167,14 +167,6 @@ struct mdp_binding mdp_bindings[MDP_MAX_BINDINGS]; int mdp_bindings_initialised=0; mdp_port_t next_port_binding=256; -static int compare_client(struct socket_address *one, struct socket_address *two) -{ - if (one->addrlen==two->addrlen - && memcmp(&one->addr, &two->addr, two->addrlen)==0) - return 1; - return 0; -} - static int overlay_mdp_reply(int sock, struct socket_address *client, overlay_mdp_frame *mdpreply) { @@ -229,7 +221,7 @@ static int overlay_mdp_releasebindings(struct socket_address *client) /* Free up any MDP bindings held by this client. */ int i; for(i=0;isid):"All", @@ -1355,8 +1347,13 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header // double check that this binding belongs to this connection if (!binding || binding->internal - || !compare_client(&binding->client, client)) + || cmp_sockaddr(&binding->client, client)!=0){ mdp_reply_error(client, header); + WHYF("Already bound by someone else? %s vs %s", + alloca_socket_address(&binding->client), + alloca_socket_address(client)); + + } break; case MDP_IDENTITY: if (config.debug.mdprequests) @@ -1381,7 +1378,7 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header || binding->internal || !source || header->local.port == 0 - || !compare_client(&binding->client, client)){ + || cmp_sockaddr(&binding->client, client)!=0){ mdp_reply_error(client, header); WHY("No matching binding found"); return; @@ -1435,7 +1432,7 @@ static void mdp_process_packet(struct socket_address *client, struct mdp_header if (binding && !binding->internal && header->flags & MDP_FLAG_CLOSE - && compare_client(&binding->client, client)){ + && cmp_sockaddr(&binding->client, client)==0){ if (config.debug.mdprequests) DEBUGF("Unbind MDP %s:%d from %s", binding->subscriber?alloca_tohex_sid_t(binding->subscriber->sid):"All", From f085ffec500f479a2b6818211a5ce1a4efdecd4d Mon Sep 17 00:00:00 2001 From: Jeremy Lakeman Date: Fri, 20 Dec 2013 11:53:13 +1030 Subject: [PATCH 17/18] Add SIGINT handler to cleanup mdp sockets --- commandline.c | 9 +++++++-- msp_proxy.c | 6 +++++- serval.h | 2 ++ sighandlers.c | 6 ++++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/commandline.c b/commandline.c index 053e810d..528e623d 100644 --- a/commandline.c +++ b/commandline.c @@ -1080,7 +1080,10 @@ int app_mdp_ping(const struct cli_parsed *parsed, struct cli_context *context) if (broadcast) WARN("broadcast ping packets will not be encrypted"); - for (; icount==0 || tx_count Date: Fri, 20 Dec 2013 12:32:47 +1030 Subject: [PATCH 18/18] Add msp debug flag --- conf_schema.h | 1 + msp_client.c | 13 +++++++++---- tests/msp | 1 + 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/conf_schema.h b/conf_schema.h index 6d598da5..6453c061 100644 --- a/conf_schema.h +++ b/conf_schema.h @@ -242,6 +242,7 @@ ATOM(bool_t, gateway, 0, boolean,, "") ATOM(bool_t, keyring, 0, boolean,, "") ATOM(bool_t, security, 0, boolean,, "") ATOM(bool_t, mdprequests, 0, boolean,, "") +ATOM(bool_t, msp, 0, boolean,, "") ATOM(bool_t, radio_link, 0, boolean,, "") ATOM(bool_t, peers, 0, boolean,, "") ATOM(bool_t, overlaybuffer, 0, boolean,, "") diff --git a/msp_client.c b/msp_client.c index cd1f8e2c..b683b347 100644 --- a/msp_client.c +++ b/msp_client.c @@ -2,6 +2,7 @@ #include #include #include "serval.h" +#include "conf.h" #include "mdp_client.h" #include "msp_client.h" #include "str.h" @@ -136,7 +137,8 @@ static void free_acked_packets(struct msp_window *window, uint16_t seq) window->rtt = rtt; if (window->base_rtt > rtt) window->base_rtt = rtt; - DEBUGF("RTT %u, base %u", rtt, window->base_rtt); + if (config.debug.msp) + DEBUGF("RTT %u, base %u", rtt, window->base_rtt); } if (!p) window->_tail = NULL; @@ -342,7 +344,8 @@ static int msp_send_packet(struct msp_sock *sock, struct msp_packet *packet) msp_close_all(sock->mdp_sock); return -1; } - DEBUGF("Sent packet seq %02x len %zd (acked %02x)", packet->seq, packet->len, sock->rx.next_seq); + if (config.debug.msp) + DEBUGF("Sent packet seq %02x len %zd (acked %02x)", packet->seq, packet->len, sock->rx.next_seq); sock->tx.last_activity = packet->sent = gettime_ms(); sock->next_ack = packet->sent + 1500; return 0; @@ -386,7 +389,8 @@ static int send_ack(struct msp_sock *sock) msp_close_all(sock->mdp_sock); return -1; } - DEBUGF("Sent packet (acked %02x)", sock->rx.next_seq); + if (config.debug.msp) + DEBUGF("Sent packet (acked %02x)", sock->rx.next_seq); sock->previous_ack = sock->rx.next_seq; sock->tx.last_activity = gettime_ms(); sock->next_ack = sock->tx.last_activity + 1500; @@ -574,7 +578,8 @@ static int process_packet(int mdp_sock, struct mdp_header *header, const uint8_t // process bind response from the daemon s->header.local = header->local; s->header.flags &= ~MDP_FLAG_BIND; - DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(header->local.sid), header->local.port); + if (config.debug.msp) + DEBUGF("Bound to %s:%d", alloca_tohex_sid_t(header->local.sid), header->local.port); s->next_action = gettime_ms(); if (s->state & MSP_STATE_LISTENING) s->timeout = TIME_NEVER_WILL; diff --git a/tests/msp b/tests/msp index 068f1abe..482c860a 100755 --- a/tests/msp +++ b/tests/msp @@ -34,6 +34,7 @@ configure_servald_server() { add_servald_interface executeOk_servald config \ set debug.mdprequests on \ + set debug.msp on \ set log.console.level DEBUG \ set log.console.show_time on }