diff --git a/src/udp-echo-server.c b/src/udp-echo-server.c index 02f1e13..0f69a63 100644 --- a/src/udp-echo-server.c +++ b/src/udp-echo-server.c @@ -13,29 +13,61 @@ #define DEFAULT_PORT 3333 #define BUF_SIZE 4096 -// Lots of globals, what's the best way to get rid of these? -int sd; // socket descriptor -struct sockaddr_in addr; -int addr_len = sizeof(addr); -char buffer[BUF_SIZE]; +typedef struct { + ev_io watcher; + struct sockaddr addr; + socklen_t addr_len; + char* buffer; + size_t buffer_len; +} response_details; + +// This callback is called when data is writable on the UDP socket, with +// w->data pointing to a response_details instance. +static void udp_response_cb(EV_P_ ev_io *w, int revents) { + response_details *r = w->data; + + // Echo the buffer back + sendto(w->fd, r->buffer, r->buffer_len, 0, &r->addr, r->addr_len); + + // Tell libev not to call this watcher again, because we're freeing it from memory + ev_io_stop(EV_A_ w); + + free(r->buffer); + free(r); +} // This callback is called when data is readable on the UDP socket. static void udp_cb(EV_P_ ev_io *w, int revents) { + struct sockaddr_in addr; + int addr_len = sizeof(addr); + char buffer[BUF_SIZE]; + response_details *r; + puts("udp socket has become readable"); - socklen_t bytes = recvfrom(sd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*) &addr, (socklen_t *) &addr_len); + socklen_t bytes = recvfrom(w->fd, buffer, sizeof(buffer) - 1, 0, (struct sockaddr*) &addr, (socklen_t *) &addr_len); // add a null to terminate the input, as we're going to use it as a string buffer[bytes] = '\0'; printf("udp client said: %s", buffer); - // Echo it back. - // WARNING: this is probably not the right way to do it with libev. - // Question: should we be setting a callback on sd becomming writable here instead? - sendto(sd, buffer, bytes, 0, (struct sockaddr*) &addr, sizeof(addr)); + // Prepare a response_details struct to be passed as w->data to the + // udp_response_cb callback (that will be called when the socket is writable). + r = calloc(1, sizeof(response_details)); + memcpy(&r->addr, &addr, sizeof(addr)); + r->addr_len = addr_len; + r->buffer = calloc(bytes, sizeof(char)); + memcpy(r->buffer, buffer, bytes); + r->buffer_len = bytes; + + ev_io_init(&r->watcher, udp_response_cb, w->fd, EV_WRITE); + r->watcher.data = r; + ev_io_start(EV_A_ &r->watcher); } int main(void) { + struct sockaddr_in addr; + int sd; // socket descriptor int port = DEFAULT_PORT; puts("udp_echo server started...");