diff options
author | Laurent Ghigonis <laurent@p1sec.com> | 2012-11-29 21:50:05 +0100 |
---|---|---|
committer | Laurent Ghigonis <laurent@p1sec.com> | 2012-11-29 21:50:05 +0100 |
commit | a381958b0d9477c8cc3412cb7d6eda0fba175b03 (patch) | |
tree | 387c2f5949b21f909df8c67abad8da58e2aa9f4a /libglouglou | |
parent | correctly gg_server_stop() the 2 servers on exit. (diff) | |
download | glouglou-a381958b0d9477c8cc3412cb7d6eda0fba175b03.tar.xz glouglou-a381958b0d9477c8cc3412cb7d6eda0fba175b03.zip |
many improvements, mainly on gg_client
* when client or server disconnects, correctly inform the other party
* add a reconnect mechanism for gg_client() based on timers
* clean function headers
* improve *_send() code
* client now ignores packets from someone else than it's server
Diffstat (limited to 'libglouglou')
-rw-r--r-- | libglouglou/libglouglou.c | 210 | ||||
-rw-r--r-- | libglouglou/libglouglou.h | 14 |
2 files changed, 162 insertions, 62 deletions
diff --git a/libglouglou/libglouglou.c b/libglouglou/libglouglou.c index 8d4a300..999c1b6 100644 --- a/libglouglou/libglouglou.c +++ b/libglouglou/libglouglou.c @@ -10,14 +10,21 @@ #include <errno.h> #include <netinet/in.h> #include <event.h> +#include <signal.h> #include "libglouglou.h" +int server_send(struct gg_server *, struct gg_user *, + void *, int); +void cb_srv_receive(evutil_socket_t, short, void *); +int user_send(struct gg_user *, void *, int); struct gg_user *user_add(struct gg_server *, struct sockaddr_in *); -struct gg_user *user_find(struct gg_server *, struct sockaddr_in *); -void cb_srv_receive(evutil_socket_t, short, void *); -void cb_cli_receive(evutil_socket_t, short, void *); -struct gg_packet *pkt_decode(char **buf, int *buf_len); +void user_del(struct gg_server *, struct gg_user *); +struct gg_user * user_find(struct gg_server *, struct sockaddr_in *); +int client_send(struct gg_client *, void *, int); +void cb_cli_receive(evutil_socket_t, short, void *); +void cb_cli_timer(evutil_socket_t, short, void *); +struct gg_packet *pkt_decode(char **, int *); int pkt_getsize(struct gg_packet *); /* @@ -40,6 +47,7 @@ gg_server_start(struct event_base *ev_base, char *ip, int port, int sock_on = 1; srv = xcalloc(1, sizeof(struct gg_server)); + srv->ev_base = ev_base; srv->ip = ip; srv->port = port; srv->handle_conn = handle_conn; @@ -79,33 +87,21 @@ err: int gg_server_send(struct gg_server *srv, struct gg_packet *pkt, struct gg_user *usr) { - struct gg_user *u; int size; size = pkt_getsize(pkt); - if (usr) { - if (sendto(srv->sock, pkt, size, 0, - (struct sockaddr *)&usr->addr, sizeof(struct sockaddr_in)) == -1) { - printf("gg_server_send failed: %s", strerror(errno)); - return -1; - } - } else { - LIST_FOREACH(u, &srv->user_list, entry) { - if (sendto(srv->sock, pkt, size, 0, - (struct sockaddr *)&u->addr, sizeof(struct sockaddr_in)) == -1) - printf("gg_server_send failed: %s", strerror(errno)); - } - } - return 0; + return server_send(srv, usr, pkt, size); } void gg_server_stop(struct gg_server *srv) { + if (srv->sock) { + server_send(srv, NULL, "", 0); + close(srv->sock); + } if (srv->ev) event_del(srv->ev); - if (srv->sock) - close(srv->sock); free(srv); } @@ -113,33 +109,17 @@ gg_server_stop(struct gg_server *srv) * Server - private */ -struct gg_user * -user_find(struct gg_server *srv, struct sockaddr_in *remote) -{ - struct gg_user *usr; - struct sockaddr_in *u; - - LIST_FOREACH(usr, &srv->user_list, entry) { - u = &usr->addr; - if (u->sin_addr.s_addr == remote->sin_addr.s_addr && - u->sin_port == remote->sin_port) - return usr; - } - return NULL; -} - -struct gg_user * -user_add(struct gg_server *srv, struct sockaddr_in *remote) +int +server_send(struct gg_server *srv, struct gg_user *usr, void *data, int size) { - struct gg_user *usr; - - usr = xcalloc(1, sizeof(struct gg_user)); - usr->id = srv->user_id_count; - srv->user_id_count++; - addrcpy(&usr->addr, remote); - LIST_INSERT_HEAD(&srv->user_list, usr, entry); + struct gg_user *u; - return usr; + if (usr) + return user_send(usr, data, size); + else + LIST_FOREACH(u, &srv->user_list, entry) + user_send(u, data, size); /* XXX return error if at least one error ? */ + return 0; } void cb_srv_receive(evutil_socket_t fd, short what, void *arg) @@ -162,17 +142,22 @@ void cb_srv_receive(evutil_socket_t fd, short what, void *arg) printf("libglouglou: cb_srv_receive: recvfrom failed\n"); return; } + usr = user_find(srv, &remote); if (!usr) { usr = user_add(srv, &remote); if (srv->handle_conn) srv->handle_conn(srv, usr); - printf("srv: New user %d !\n", usr->id); if (sendto(srv->sock, "", strlen(""), 0, (struct sockaddr *)&remote, remote_len) == -1) printf("srv: send failed: %s\n", strerror(errno)); } else { printf("srv: Incoming data from existing user !\n"); + if (len == 0) { + printf("libglouglou: cb_srv_receive: recvfrom = 0\n"); + user_del(srv, usr); + return; + } buf_p = buf; buf_len = len; while (buf_len > 0 && (pkt = pkt_decode(&buf_p, &buf_len))) @@ -185,6 +170,56 @@ void cb_srv_receive(evutil_socket_t fd, short what, void *arg) } } +struct gg_user * +user_add(struct gg_server *srv, struct sockaddr_in *remote) +{ + struct gg_user *usr; + + usr = xcalloc(1, sizeof(struct gg_user)); + usr->id = srv->user_id_count; + srv->user_id_count++; + usr->sock = srv->sock; + addrcpy(&usr->addr, remote); + LIST_INSERT_HEAD(&srv->user_list, usr, entry); + printf("srv: Add user %d !\n", usr->id); + + return usr; +} + +void +user_del(struct gg_server *srv, struct gg_user *usr) +{ + printf("srv: Del user %d !\n", usr->id); + LIST_REMOVE(usr, entry); + free(usr); +} + +struct gg_user * +user_find(struct gg_server *srv, struct sockaddr_in *remote) +{ + struct gg_user *usr; + struct sockaddr_in *u; + + LIST_FOREACH(usr, &srv->user_list, entry) { + u = &usr->addr; + if (u->sin_addr.s_addr == remote->sin_addr.s_addr && + u->sin_port == remote->sin_port) + return usr; + } + return NULL; +} + +int +user_send(struct gg_user *usr, void *data, int size) +{ + if (sendto(usr->sock, data, size, 0, + (struct sockaddr *)&usr->addr, sizeof(struct sockaddr_in)) == -1) { + printf("user_send failed: %s", strerror(errno)); + return -1; + } + return 0; +} + /* * Client */ @@ -201,15 +236,18 @@ gg_client_connect(struct event_base *ev_base, char *ip, int port, struct gg_client *cli; struct sockaddr_in sock_addr; struct event *ev; + struct timeval tv; int s; int sock_on = 1; cli = xcalloc(1, sizeof(struct gg_client)); + cli->ev_base = ev_base; cli->ip = ip; cli->port = port; cli->handle_conn = handle_conn; cli->handle_packet = handle_packet; cli->usrdata = usrdata; + cli->status = GG_CLIENT_STATUS_CONNECTING; s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) goto err; @@ -228,9 +266,11 @@ gg_client_connect(struct event_base *ev_base, char *ip, int port, event_add(ev, NULL); cli->ev = ev; - if (sendto(s, "", strlen(""), 0, - (struct sockaddr *)&sock_addr, sizeof(struct sockaddr_in)) == -1) - printf("cli: send failed: %s\n", strerror(errno)); + ev = evtimer_new(ev_base, cb_cli_timer, cli); + cli->ev_timer = ev; + bzero(&tv, sizeof(struct timeval)); + tv.tv_sec = 0; + evtimer_add(ev, &tv); return cli; @@ -247,21 +287,20 @@ gg_client_send(struct gg_client *cli, struct gg_packet *pkt) int size; size = pkt_getsize(pkt); - if (sendto(cli->sock, pkt, size, 0, - (struct sockaddr *)&cli->addr, sizeof(struct sockaddr_in)) == -1) { - printf("gg_client_send failed: %s", strerror(errno)); - return -1; - } - return 0; + return client_send(cli, pkt, size); } void gg_client_disconnect(struct gg_client *cli) { + if (cli->sock) { + client_send(cli, "", 0); + close(cli->sock); + } if (cli->ev) event_del(cli->ev); - if (cli->sock) - close(cli->sock); + if (cli->ev_timer) + event_del(cli->ev_timer); free(cli); } @@ -269,6 +308,17 @@ gg_client_disconnect(struct gg_client *cli) * Client - private */ +int +client_send(struct gg_client *cli, void *data, int size) +{ + if (sendto(cli->sock, data, size, 0, + (struct sockaddr *)&cli->addr, sizeof(struct sockaddr_in)) == -1) { + printf("gg_client_send failed: %s", strerror(errno)); + return -1; + } + return 0; +} + void cb_cli_receive(evutil_socket_t fd, short what, void *arg) { struct gg_client *cli; @@ -284,19 +334,28 @@ void cb_cli_receive(evutil_socket_t fd, short what, void *arg) remote_len = sizeof(struct sockaddr_in); len = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&remote, &remote_len); + if (addrcmp(&cli->addr, &remote)) { + printf("libglouglou; cb_cli_receive: receiving from stranger !\n"); + return; + } if (len < 0) { printf("libglouglou: cb_cli_receive: recvfrom failed\n"); return; } switch (cli->status) { - case GG_CLIENT_STATUS_DISCONNECTED: + case GG_CLIENT_STATUS_CONNECTING: printf("cli: Connected !\n"); cli->status = GG_CLIENT_STATUS_CONNECTED; if (cli->handle_conn) cli->handle_conn(cli); break; case GG_CLIENT_STATUS_CONNECTED: + if (len == 0) { + printf("libglouglou: cb_cli_receive: recvfrom = 0\n"); + cli->status = GG_CLIENT_STATUS_CONNECTING; + return; + } printf("cli: Incoming data !\n"); buf_p = buf; buf_len = len; @@ -311,6 +370,27 @@ void cb_cli_receive(evutil_socket_t fd, short what, void *arg) } } +void cb_cli_timer(evutil_socket_t fd, short what, void *arg) +{ + struct timeval tv; + struct gg_client *cli; + + cli = arg; + + switch (cli->status) { + case GG_CLIENT_STATUS_CONNECTING: + client_send(cli, "", 0); + break; + case GG_CLIENT_STATUS_CONNECTED: + // XXX send keepalive + break; + } + + bzero(&tv, sizeof(struct timeval)); + tv.tv_sec = 2; + event_add(cli->ev_timer, &tv); +} + /* * Packets - private */ @@ -497,3 +577,15 @@ addrcpy(struct sockaddr_in *dst, struct sockaddr_in *src) dst->sin_port = src->sin_port; dst->sin_family = src->sin_family; } + +int +addrcmp(struct sockaddr_in *a, struct sockaddr_in *b) +{ + if (a->sin_addr.s_addr != b->sin_addr.s_addr) + return -1; + if (a->sin_port != b->sin_port) + return -2; + if (a->sin_family != b->sin_family) + return -3; + return 0; +} diff --git a/libglouglou/libglouglou.h b/libglouglou/libglouglou.h index 04ee779..17be3f7 100644 --- a/libglouglou/libglouglou.h +++ b/libglouglou/libglouglou.h @@ -91,11 +91,13 @@ struct gg_packet { struct gg_user { LIST_ENTRY(gg_user) entry; int id; + int sock; struct sockaddr_in addr; char *buf[16384]; }; struct gg_server { + struct event_base *ev_base; const char *ip; int port; struct sockaddr_in addr; @@ -108,15 +110,20 @@ struct gg_server { int user_id_count; }; +enum client_status { + GG_CLIENT_STATUS_CONNECTING = 0, + GG_CLIENT_STATUS_CONNECTED = 1 +}; + struct gg_client { + struct event_base *ev_base; const char *ip; int port; struct sockaddr_in addr; struct event *ev; + struct event *ev_timer; int sock; - int status; -#define GG_CLIENT_STATUS_DISCONNECTED 0 -#define GG_CLIENT_STATUS_CONNECTED 1 + enum client_status status; int (*handle_conn)(struct gg_client *); int (*handle_packet)(struct gg_client *, struct gg_packet *); void *usrdata; @@ -141,3 +148,4 @@ void *xmalloc(size_t); void *xcalloc(size_t, size_t); void fd_nonblock(int); void addrcpy(struct sockaddr_in *, struct sockaddr_in *); +int addrcmp(struct sockaddr_in *, struct sockaddr_in *); |