Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 42 additions & 10 deletions src/udp-echo-server.c
Original file line number Diff line number Diff line change
Expand Up @@ -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...");

Expand Down