aboutsummaryrefslogtreecommitdiffstats
path: root/libglouglou/libglouglou.c
diff options
context:
space:
mode:
Diffstat (limited to 'libglouglou/libglouglou.c')
-rw-r--r--libglouglou/libglouglou.c206
1 files changed, 137 insertions, 69 deletions
diff --git a/libglouglou/libglouglou.c b/libglouglou/libglouglou.c
index 85993ce..01355d8 100644
--- a/libglouglou/libglouglou.c
+++ b/libglouglou/libglouglou.c
@@ -36,8 +36,10 @@ int cb_usr_send(void *, int, void *);
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 *);
+int cb_cli_send(void *, int, void *);
struct gg_packet *pkt_decode(char **, int *);
-struct gg_packet *pkt_encode(struct gg_packet *, int *);
+int pkt_getsize(struct gg_packet *);
+int pkt_encode(struct gg_packet *, struct gg_packet *);
int _verbosity = 0;
@@ -93,12 +95,6 @@ gg_server_start(struct event_base *ev_base, char *ip, int port,
event_add(ev, NULL);
srv->ev = ev;
- sbuf = sendbuf_init(srv->ev_base, PACKET_SNDBUF_MAX * 2, PACKET_SNDBUF_MAX,
- 200);
- if (!sbuf)
- goto err;
- srv->sbuf = sbuf;
-
return srv;
err:
@@ -111,26 +107,40 @@ int
gg_server_send(struct gg_server *srv, struct gg_packet *pkt, struct gg_user *usr)
{
static struct gg_packet *newpkt;
+ static struct gg_packet pktbuf;
+ struct gg_user *u;
int size;
+ int res = 0;
+
+ /* optimisation to use sendbuf_gettoken */
+ if (!usr && srv->user_count == 1)
+ usr = LIST_FIRST(&srv->user_list);
+
+ if (usr) {
+ size = pkt_getsize(pkt);
+ newpkt = sendbuf_gettoken(usr->sbuf, size);
+ if (!newpkt)
+ return -1;
+ return pkt_encode(pkt, newpkt);
+ } else {
+ size = pkt_encode(pkt, &pktbuf);
+ LIST_FOREACH(u, &srv->user_list, entry) {
+ res = res + sendbuf_append(u->sbuf, &pktbuf, size);
+ }
+ }
- // XXX IN PROGRESS get size before
- size = pkt_getsize(pkt);
- newpkt = sendbuf_token_get(srv->sndbuf, size);
- pkt_encode(pkt, newpkt);
- sendbuf_token_ready(srv->sndbuf, newpkt);
-
- if (!newpkt)
- return -1;
- return server_send(srv, usr, newpkt, size);
+ return res;
}
void
gg_server_stop(struct gg_server *srv)
{
- if (srv->sock) {
- server_send(srv, NULL, "", 0);
+ struct gg_user *usr;
+
+ LIST_FOREACH(usr, &srv->user_list, entry)
+ user_del(srv, usr);
+ if (srv->sock)
close(srv->sock);
- }
if (srv->ev)
event_del(srv->ev);
free(srv);
@@ -208,22 +218,34 @@ user_add(struct gg_server *srv, struct sockaddr_in *remote)
usr = xcalloc(1, sizeof(struct gg_user));
usr->id = srv->user_id_count;
srv->user_id_count++;
+ srv->user_count++;
usr->sock = srv->sock;
addrcpy(&usr->addr, remote);
- sendbuf_queue_add(srv->sbuf, cb_usr_send, usr);
+ sbuf = sendbuf_new(srv->ev_base, PACKET_SNDBUF_MAX, 200, cb_usr_send, usr);
+ if (!sbuf)
+ goto err;
+ usr->sbuf = sbuf;
LIST_INSERT_HEAD(&srv->user_list, usr, entry);
verbose("Add user %d !", usr->id);
return usr;
+
+err:
+ user_del(srv, usr);
+ return NULL;
}
void
user_del(struct gg_server *srv, struct gg_user *usr)
{
verbose("Del user %d !", usr->id);
+ if (usr->sbuf)
+ sendbuf_free(usr->sbuf);
+ user_send(usr, "", 0);
LIST_REMOVE(usr, entry);
+ srv->user_count--;
free(usr);
}
@@ -245,12 +267,13 @@ user_find(struct gg_server *srv, struct sockaddr_in *remote)
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) {
+ int sent;
+
+ sent = sendto(usr->sock, data, size, 0, (struct sockaddr *)&usr->addr,
+ sizeof(struct sockaddr_in));
+ if (sent == -1)
error("failed: %s", strerror(errno));
- return -1;
- }
- return 0;
+ return sent;
}
int
@@ -259,10 +282,9 @@ cb_usr_send(void *data, int size, void *usrdata)
struct gg_user *usr;
usr = usrdata;
- user_send(usr, NULL, data, size);
+ return user_send(usr, data, size);
}
-
/*
* Client
*/
@@ -281,6 +303,7 @@ gg_client_connect(struct event_base *ev_base, char *ip, int port,
{
struct gg_client *cli;
struct sockaddr_in sock_addr;
+ struct sendbuf *sbuf;
struct event *ev;
struct timeval tv;
int s;
@@ -318,6 +341,11 @@ gg_client_connect(struct event_base *ev_base, char *ip, int port,
tv.tv_sec = 0;
evtimer_add(ev, &tv);
+ sbuf = sendbuf_new(cli->ev_base, PACKET_SNDBUF_MAX, 200, cb_cli_send, cli);
+ if (!sbuf)
+ goto err;
+ cli->sbuf = sbuf;
+
return cli;
err:
@@ -332,15 +360,18 @@ gg_client_send(struct gg_client *cli, struct gg_packet *pkt)
static struct gg_packet *newpkt;
int size;
- newpkt = pkt_encode(pkt, &size);
+ size = pkt_getsize(pkt);
+ newpkt = sendbuf_gettoken(cli->sbuf, size);
if (!newpkt)
return -1;
- return client_send(cli, newpkt, size);
+ return pkt_encode(pkt, newpkt);
}
void
gg_client_disconnect(struct gg_client *cli)
{
+ if (cli->sbuf)
+ sendbuf_free(cli->sbuf);
if (cli->sock) {
client_send(cli, "", 0);
close(cli->sock);
@@ -359,12 +390,13 @@ gg_client_disconnect(struct gg_client *cli)
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) {
+ int sent;
+
+ sent = sendto(cli->sock, data, size, 0, (struct sockaddr *)&cli->addr,
+ sizeof(struct sockaddr_in));
+ if (sent == -1)
error("failed: %s", strerror(errno));
- return -1;
- }
- return 0;
+ return sent;
}
void cb_cli_receive(evutil_socket_t fd, short what, void *arg)
@@ -440,6 +472,15 @@ void cb_cli_timer(evutil_socket_t fd, short what, void *arg)
event_add(cli->ev_timer, &tv);
}
+int
+cb_cli_send(void *data, int size, void *usrdata)
+{
+ struct gg_client *cli;
+
+ cli = usrdata;
+ return client_send(cli, data, size);
+}
+
/*
* Packets - private
*/
@@ -547,72 +588,99 @@ invalid:
* encodes a packet and returns the size before sending it on the wire.
* it assumes that the packet contains correct content.
*/
-struct gg_packet *
-pkt_encode(struct gg_packet *pkt, int *len)
+int
+pkt_encode(struct gg_packet *pkt, struct gg_packet *newpkt)
{
- static struct gg_packet newpkt;
- int packet_len;
-
if (pkt->type < PACKET_TYPE_MIN || pkt->type > PACKET_TYPE_MAX)
invalid("type");
- packet_len = gg_packet_props[pkt->type].size; // XXX never overflow ?
- newpkt.ver = pkt->ver;
- newpkt.type = pkt->type;
+ newpkt->ver = pkt->ver;
+ newpkt->type = pkt->type;
switch(pkt->type) {
case PACKET_NEWCONN:
- newpkt.newconn_id = htons(pkt->newconn_id);
- newpkt.newconn_src = htonl(pkt->newconn_src);
- newpkt.newconn_dst = htonl(pkt->newconn_dst);
- newpkt.newconn_proto = pkt->newconn_proto;
- newpkt.newconn_size = pkt->newconn_size;
+ newpkt->newconn_id = htons(pkt->newconn_id);
+ newpkt->newconn_src = htonl(pkt->newconn_src);
+ newpkt->newconn_dst = htonl(pkt->newconn_dst);
+ newpkt->newconn_proto = pkt->newconn_proto;
+ newpkt->newconn_size = pkt->newconn_size;
break;
case PACKET_DELCONN:
- newpkt.delconn_id = htons(pkt->delconn_id);
+ newpkt->delconn_id = htons(pkt->delconn_id);
break;
case PACKET_DATA:
- newpkt.data_connid = htons(pkt->data_connid);
- newpkt.data_size = pkt->data_size;
+ newpkt->data_connid = htons(pkt->data_connid);
+ newpkt->data_size = pkt->data_size;
break;
case PACKET_NAME:
if (pkt->name_len > GG_PKTARG_MAX)
goto invalid;
- packet_len = packet_len + pkt->name_len;
- newpkt.name_addr = htonl(pkt->name_addr);
- newpkt.name_len = pkt->name_len;
- strncpy((char *)newpkt.name_fqdn, (char *)pkt->name_fqdn,
+ newpkt->name_addr = htonl(pkt->name_addr);
+ newpkt->name_len = pkt->name_len;
+ strncpy((char *)newpkt->name_fqdn, (char *)pkt->name_fqdn,
pkt->name_len);
break;
case PACKET_FORK:
- newpkt.fork_pid = htonl(pkt->fork_pid);
- newpkt.fork_ppid = htonl(pkt->fork_ppid);
- newpkt.fork_cpid = htonl(pkt->fork_cpid);
- newpkt.fork_tgid = htonl(pkt->fork_tgid);
+ newpkt->fork_pid = htonl(pkt->fork_pid);
+ newpkt->fork_ppid = htonl(pkt->fork_ppid);
+ newpkt->fork_cpid = htonl(pkt->fork_cpid);
+ newpkt->fork_tgid = htonl(pkt->fork_tgid);
break;
case PACKET_EXEC:
if (pkt->exec_cmdlen > GG_PKTARG_MAX)
goto invalid;
- packet_len = packet_len + pkt->exec_cmdlen;
- newpkt.exec_pid = htonl(pkt->exec_pid);
- newpkt.exec_cmdlen = pkt->exec_cmdlen;
- strncpy((char *)newpkt.exec_cmd, (char *)pkt->exec_cmd,
+ newpkt->exec_pid = htonl(pkt->exec_pid);
+ newpkt->exec_cmdlen = pkt->exec_cmdlen;
+ strncpy((char *)newpkt->exec_cmd, (char *)pkt->exec_cmd,
pkt->exec_cmdlen);
break;
case PACKET_EXIT:
- newpkt.exit_pid = htonl(pkt->exit_pid);
- newpkt.exit_tgid = htonl(pkt->exit_tgid);
- newpkt.exit_ecode = pkt->exit_ecode;
+ newpkt->exit_pid = htonl(pkt->exit_pid);
+ newpkt->exit_tgid = htonl(pkt->exit_tgid);
+ newpkt->exit_ecode = pkt->exit_ecode;
break;
default:
error("Unsupported packet type");
- return NULL;
+ return -1;
}
- *len = packet_len;
- return &newpkt;
+ return pkt_getsize(newpkt);
invalid:
error("invalid packet");
- return NULL;
+ return -1;
+}
+
+int
+pkt_getsize(struct gg_packet *pkt)
+{
+ int packet_len;
+
+ packet_len = gg_packet_props[pkt->type].size; // XXX never overflow ?
+ switch(pkt->type) {
+ case PACKET_NEWCONN:
+ case PACKET_DELCONN:
+ case PACKET_DATA:
+ case PACKET_FORK:
+ case PACKET_EXIT:
+ break;
+ case PACKET_NAME:
+ if (pkt->name_len > GG_PKTARG_MAX)
+ goto invalid;
+ packet_len = packet_len + pkt->name_len;
+ break;
+ case PACKET_EXEC:
+ if (pkt->exec_cmdlen > GG_PKTARG_MAX)
+ goto invalid;
+ packet_len = packet_len + pkt->exec_cmdlen;
+ break;
+ default:
+ error("Unsupported packet type");
+ return -1;
+ }
+ return packet_len;
+
+invalid:
+ error("invalid packet");
+ return -1;
}
/*