aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou
diff options
context:
space:
mode:
authorLaurent Ghigonis <laurent@p1sec.com>2012-11-29 21:50:05 +0100
committerLaurent Ghigonis <laurent@p1sec.com>2012-11-29 21:50:05 +0100
commita381958b0d9477c8cc3412cb7d6eda0fba175b03 (patch)
tree387c2f5949b21f909df8c67abad8da58e2aa9f4a /libglouglou
parentcorrectly gg_server_stop() the 2 servers on exit. (diff)
downloadglouglou-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.c210
-rw-r--r--libglouglou/libglouglou.h14
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 *);