Skip to content

Instantly share code, notes, and snippets.

@roxlu
Created May 28, 2014 19:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save roxlu/5c13f2a9ef905e115219 to your computer and use it in GitHub Desktop.
Save roxlu/5c13f2a9ef905e115219 to your computer and use it in GitHub Desktop.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include <rxs_streamer/rxs_stun_io.h>
/* --------------------------------------------------------------------------- */
static void on_resolved(uv_getaddrinfo_t* resolver, int status, struct addrinfo* addr); /* gets called when the stun server domain has been resolved. */
static void on_read(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags);
static void on_alloc(uv_handle_t* handle, size_t nbytes, uv_buf_t* buf);
static rxs_stun_mem* find_free_mem_block(rxs_stun_io* io);
/* --------------------------------------------------------------------------- */
int rxs_stun_io_init(rxs_stun_io* io, const char* server, const char* port) {
int r;
int i;
struct addrinfo hints;
if (!io) { return -1; }
if (rxs_stun_init(&io->stun) < 0) {
printf("Error: cannot init stun.\n");
return -2;
}
io->loop = uv_default_loop();
if (!io->loop) {
printf("Error: cannot get uv loop.\n");
return -3;
}
/* init the memory blocks */
for(i = 0; i < RXS_STUN_IO_NUM_MEM_BLOCKS; ++i) {
io->mem[i].is_free = 0;
io->mem[i].io = io;
}
/* hints for resolver */
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = 0;
/* set user data */
io->resolver.data = (void*)io;
io->port = atoi(port);
r = uv_getaddrinfo(io->loop, &io->resolver,
on_resolved, server, port, &hints);
if (r != 0){
printf("Error: cannot start resolving stun server. %s\n", uv_strerror(r));
return -4;
}
return 0;
}
void rxs_stun_io_update(rxs_stun_io* io) {
#if !defined(NDEBUG)
if (!io) {
printf("Error: rxs_stun_io, cannot update; invalid io.\n");
exit(1);
}
#endif
uv_run(io->loop, UV_RUN_NOWAIT);
}
int rxs_stun_io_clear(rxs_stun_io* io) {
if (!io) { return -1; }
if (rxs_stun_clear(&io->stun) < 0) {
printf("Error: cannot clear rxs_stun in rxs_stun_io.\n");
return -2;
}
return 0;
}
/* --------------------------------------------------------------------------- */
/*
Finds a free memory block in rxs_stun_io. We're using a very
basic memory system for now. We just have a big array with block
of some kb.
*/
static rxs_stun_mem* find_free_mem_block(rxs_stun_io* io) {
int i;
if (!io) { return NULL; }
for (i = 0; i < RXS_STUN_IO_NUM_MEM_BLOCKS; ++i) {
if (io->mem[i].is_free) {
return &io->mem[i];
}
}
return NULL;
}
/* --------------------------------------------------------------------------- */
static void on_resolved(uv_getaddrinfo_t* resolver, int status, struct addrinfo* addr) {
int r = 0;
rxs_stun_io* io;
if(status < 0) {
printf("Error: Something went wrong when resolving the host in rxs_stun_io.\n");
exit(1);
}
io = (rxs_stun_io*) resolver->data;
/* get IP */
uv_ip4_name((struct sockaddr_in*)addr->ai_addr, io->ip, 16);
io->ip[16] = '\0';
/* create our send sockaddr */
r = uv_ip4_addr(io->ip, io->port, &io->saddr);
if (r != 0) {
printf("Error: cannot create ip4 addr struct. %s\n", uv_strerror(r));
exit(1);
}
printf("Resolved host: %s\n", io->ip);
/* init UDP sock */
r = uv_udp_init(io->loop, &io->sock);
if(r != 0) {
printf("Error: cannot create sock for stun io: %s\n", uv_strerror(r));
exit(1);
}
/* create our receiver sockaddr; this will receive data */
struct sockaddr_in raddr;
r = uv_ip4_addr("0.0.0.0", io->port, &raddr);
if (r != 0) {
printf("Error: cannot init ip4 addr.\n");
exit(1);
}
r = uv_udp_bind(&io->sock, (const struct sockaddr*)&raddr, 0);
if(r < 0) {
printf("Error: cannot bind: %s, in rxs_stun_io\n", uv_strerror(r));
exit(1);
}
/* start receiving data. */
r = uv_udp_recv_start(&io->sock, on_alloc, on_read);
if(r < 0) {
printf("Error: cannot start recieving: %s\n", uv_strerror(r));
}
/* @todo --> ready to kickoff stun */
}
static void on_alloc(uv_handle_t* handle, size_t nbytes, uv_buf_t* buf) {
rxs_stun_io* io = (rxs_stun_io*) handle->data;
if (nbytes > RXS_STUN_IO_MEM_BLOCK_SIZE) {
printf("Error: rxs_stun_io needs a memory block bigger then the anticipated on.\n");
exit(1);
}
rxs_stun_mem* mem = find_free_mem_block(io);
if (!mem) {
printf("Error: cannot find any new memory block for rxs_stun_io. Need to allocate more!\n");
exit(1);
}
buf->base = (char*)mem->data;
buf->len = nbytes;
mem->nbytes = nbytes;
}
static void on_send(uv_udp_send_t* req, int status) {
printf("Send some data: %d\n", status);
if(status < 0) {
printf("Error: while sending some data in rxs_stun_io. %s\n", uv_strerror(status));
exit(1);
}
/* @todo -> set memory block free */
}
static void on_read(uv_udp_t* handle, ssize_t nread, const uv_buf_t* buf, const struct sockaddr* addr, unsigned flags) {
printf("Read some data: %ld\n", nread);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment