From 94d722d144b92cf64f7be022f542e0cef3341780 Mon Sep 17 00:00:00 2001 From: Laurent Ghigonis Date: Sat, 1 Dec 2012 04:22:41 +0100 Subject: work in progress on implementing a send buffer --- libglouglou/libglouglou.c | 23 ++++++++- libglouglou/libglouglou.h | 1 + libglouglou/sendbuf.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++ libglouglou/sendbuf.h | 21 +++++++++ 4 files changed, 161 insertions(+), 1 deletion(-) create mode 100644 libglouglou/sendbuf.c create mode 100644 libglouglou/sendbuf.h diff --git a/libglouglou/libglouglou.c b/libglouglou/libglouglou.c index c2c284a..c9c0df8 100644 --- a/libglouglou/libglouglou.c +++ b/libglouglou/libglouglou.c @@ -13,6 +13,7 @@ #include #include "libglouglou.h" +#include "sendbuf.h" #define error(fmt, ...) \ if (_verbosity >= 0) \ @@ -58,6 +59,7 @@ gg_server_start(struct event_base *ev_base, char *ip, int port, struct gg_server *srv; struct sockaddr_in sock_addr; struct event *ev; + struct sendbuf *sbuf; int s; int sock_on = 1; @@ -68,6 +70,13 @@ gg_server_start(struct event_base *ev_base, char *ip, int port, srv->handle_conn = handle_conn; srv->handle_packet = handle_packet; srv->usrdata = usrdata; + + sbuf = sendbuf_init(ev_base, PACKET_SNDBUF_MAX * 2, PACKET_SNDBUF_MAX, 200, + cb_srv_send, srv); + if (!sbuf) + goto err; + srv->sbuf = sbuf; + s = socket(AF_INET, SOCK_DGRAM, 0); if (s < 0) goto err; @@ -98,13 +107,25 @@ err: return NULL; } +int +cb_srv_send(void *data, int size, void *usrdata) +{ + struct gg_server *srv; + + srv = usrdata; +} + int gg_server_send(struct gg_server *srv, struct gg_packet *pkt, struct gg_user *usr) { static struct gg_packet *newpkt; int size; - newpkt = pkt_encode(pkt, &size); + // XXX IN PROGRESS get size before + newpkt = sendbuf_gettoken(srv->sndbuf, size); + + pkt_encode(pkt, &size, newpkt); + if (!newpkt) return -1; return server_send(srv, usr, newpkt, size); diff --git a/libglouglou/libglouglou.h b/libglouglou/libglouglou.h index 8ee890f..63fa93a 100644 --- a/libglouglou/libglouglou.h +++ b/libglouglou/libglouglou.h @@ -12,6 +12,7 @@ #define PACKET_VERSION 1 #define PACKET_BUFFER_SIZE 16384 +#define PACKET_SNDBUF_MAX 500 #define GG_PKTARG_MAX 30 #define PACKET_HEADER_SIZE 2 diff --git a/libglouglou/sendbuf.c b/libglouglou/sendbuf.c new file mode 100644 index 0000000..078d6a6 --- /dev/null +++ b/libglouglou/sendbuf.c @@ -0,0 +1,117 @@ +#include "sendbuf.h" + +/* + * Public + */ + +/* + * Create a sendbuf + * send_func should return the number of successfuly sent bytes + */ +struct sendbuf * +sendbuf_init(struct event_base *ev_base, int size, int sndbuf_max, int msec_max, + int (*send_func)(void *, int, void *), void *usrdata) +{ + struct sendbuf *sbuf = NULL; + struct event ev_timer; + struct timeval *tv; + void *buffer; + void *data; + + sbuf = calloc(1, sizeof(struct sendbuf)); + if (!sbuf) + return NULL; + sbuf->ev_base = ev_base; + sbuf->sndbuf_max = sndbuf_max; + sbuf->msec_max = msec_max; + sbuf->usrdata = usrdata; + sbuf->send_func = send_func; + sbuf->buffer_size = size; + sbuf->buffer = malloc(sbuf->buffer_size); + if (!sbuf->buffer) + goto err; + + ev_timer = evtimer_new(ev_base, cb_timer, sbuf); + sbuf->ev_timer = ev_timer; + sbuf->ev_timer_tv.tv_usec = msec_max * 1000; + evtimer_add(ev, &sbuf->ev_timer_tv); + + return sbuf; + +err: + sendbuf_shutdown(sbuf); + return NULL; +} + +void +sendbuf_shutdown(struct sendbuf *sbuf) +{ + if (sbuf->send_timer) + event_del(sbuf->send_timer); + if (sbuf->buffer && sbuf->send_func) + flushbuf(sbuf); + if (sbuf->buffer) + free(sbuf->buffer); + free(sbuf); +} + +/* + * Returns a buffer to write data to be sent + * might return NULL if the sendbuf is temporary full + */ +void * +sendbuf_getoken(struct sendbuf *sbuf, int size) +{ + if (sbuf->buffer_pos + size >= sbuf->buffer_size) + if (flushbuf(sbuf) == -1) + return NULL; + + return sbuf->buffer_pos; +} + +/* + * Private + */ + +/* + * Note that you can still add data to the buffer even if flushing is in + * progress + */ +int +flushbuf(struct sendbuf *sbuf) +{ + int sent; + int sent_total; + int len; + + sbuf->flushing = 1; + + do { + pos = sbuf->buffer + sbuf->flushed_len; + if (sbuf->buffer_pos > sbuf->sndbuf_max) + tosend = sbuf->sndbuf_max; + else + tosend = sbuf->buffer_pos; + sent = sbuf->send_func(sbuf->buffer + pos, tosend, sbuf->usrdata); + sbuf->flushed_len = sbuf->flushed_len + sent; + if (sent == -1) { + // XXX handle erorr + } else if (sent < tosend) { + return -1; + } + } while (sbuf->flushed_len < sbuf->buffer_pos) + + sbuf->flushing = 0; + sbuf->flushed_len = 0; + return 0; +} + +void +cb_timer(evutil_socket_t fd, short what, void *arg) +{ + struct sendbuf *sbuf; + + sbuf = arg; + flushbuf(sbuf); + evtimer_add(sbuf->ev_timer, &sbuf->ev_timer_tv); +} diff --git a/libglouglou/sendbuf.h b/libglouglou/sendbuf.h new file mode 100644 index 0000000..90dc4bc --- /dev/null +++ b/libglouglou/sendbuf.h @@ -0,0 +1,21 @@ +#include + +struct sendbuf { + struct event_base *ev_base; + struct event *ev_timer; + struct timeval ev_timer_tv; + int sndbuf_max; + int msec_max; + int (*send_func)(void *, int, void *); + void *usrdata; + void *buffer; + int buffer_size; + int buffer_pos; + int flushing; + int flushed_len; +}; + +struct sendbuf *sendbuf_init(struct event_base *, int, int, + int (*send_func)(void *, int, void *), void *); +void sendbuf_shutdown(struct sendbuf *); +void *sendbuf_gettoken(struct sendbuf *, int); -- cgit v1.2.3-59-g8ed1b