hop-2012/experiments/cmsg/net.c

117 lines
3.1 KiB
C

/* Copyright 2010, 2011, 2012 Tony Garnock-Jones <tonygarnockjones@gmail.com>.
*
* This file is part of Hop.
*
* Hop is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Hop is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
* License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Hop. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <fcntl.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
#include <stdarg.h>
#include <assert.h>
typedef unsigned char u_char;
#include <event.h>
#include "cmsg_private.h"
#include "relay.h"
static struct event accept_event;
void get_addr_name(char *namebuf, size_t buflen, struct sockaddr_in const *sin) {
unsigned char *addr = (unsigned char *) &sin->sin_addr.s_addr;
struct hostent *h = gethostbyaddr(addr, 4, AF_INET);
if (h == NULL) {
snprintf(namebuf, buflen, "%u.%u.%u.%u", addr[0], addr[1], addr[2], addr[3]);
} else {
snprintf(namebuf, buflen, "%s", h->h_name);
}
}
void endpoint_name(struct sockaddr_in const *peername, cmsg_bytes_t result) {
char name[256];
get_addr_name(name, sizeof(name), peername);
snprintf((char *) result.bytes, result.len, "%s:%d", name, ntohs(peername->sin_port));
}
static void accept_connection(int servfd, short what, void *arg) {
struct sockaddr_in s;
socklen_t addrlen = sizeof(s);
int fd = accept(servfd, (struct sockaddr *) &s, &addrlen);
if (fd == -1) {
if (errno != EAGAIN && errno != EINTR) {
warn("accept: errno %d (%s)\n", errno, strerror(errno));
}
return;
}
{
int i = 1;
ICHECK(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &i, sizeof(i)), "setsockopt TCP_NODELAY");
}
start_relay(&s, fd);
}
void start_net(int listen_port) {
int servfd = socket(AF_INET, SOCK_STREAM, 0);
struct sockaddr_in s;
if (servfd < 0) {
die("Could not open listen socket.\n");
}
s.sin_family = AF_INET;
s.sin_addr.s_addr = htonl(INADDR_ANY);
s.sin_port = htons(listen_port);
{
int i = 1;
setsockopt(servfd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i)); // don't care if this fails
}
if (bind(servfd, (struct sockaddr *) &s, sizeof(s)) < 0) {
die("Could not bind listen socket.\n");
}
if (listen(servfd, 5) < 0) {
int savedErrno = errno;
die("Could not listen on listen socket (errno %d: %s).\n",
savedErrno, strerror(savedErrno));
}
event_set(&accept_event, servfd, EV_READ | EV_PERSIST, accept_connection, NULL);
if (event_add(&accept_event, NULL) == -1) {
die("Could not add accept_event.");
}
info("Accepting connections on port %d.\n", listen_port);
}