hop-2012/relay.c

120 lines
2.9 KiB
C

/* Copyright (C) 2010 Tony Garnock-Jones. All rights reserved. */
#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 <fcntl.h>
#include <sys/wait.h>
#include <time.h>
#include <sys/time.h>
typedef unsigned char u_char;
#include <event.h>
#include "cmsg_private.h"
#include "harness.h"
#include "relay.h"
#include "net.h"
#include "ref.h"
#include "sexp.h"
#include "sexpio.h"
struct boot_args {
struct sockaddr_in peername;
int fd;
};
static void send_sexp_syntax_error(IOHandle *h, char const *message) {
sexp_t *m = NULL;
m = sexp_cons(sexp_bytes(cmsg_cstring_bytes("http://people.csail.mit.edu/rivest/Sexp.txt")), m);
m = sexp_cons(sexp_bytes(cmsg_cstring_bytes(message)), m);
m = sexp_cons(sexp_bytes(cmsg_cstring_bytes("error")), m);
INCREF(m);
iohandle_clear_error(h);
BCHECK(!sexp_write(h, m), "send_sexp_syntax_error sexp_write");
DECREF(m, sexp_destructor);
iohandle_flush(h); /* ignore result here, there's not much we can do with it */
}
static void relay_main(struct boot_args *args) {
IOHandle *h = new_iohandle(args->fd);
IOHandle *out_handle = new_iohandle(1);
sexp_t *message = NULL; /* held */
{
char name[256];
endpoint_name(&args->peername, CMSG_BYTES(sizeof(name), name));
info("Accepted connection from %s on fd %d\n", name, args->fd);
}
free(args);
iohandle_write(h, cmsg_cstring_bytes("(3:hop1:0)"));
ICHECK(iohandle_flush(h), "iohandle_flush 1");
//iohandle_settimeout(h, 3, 0);
while (1) {
DECREF(message, sexp_destructor);
message = NULL;
message = INCREF(sexp_read(h));
if (h->error_kind != 0) goto handle_error;
fflush(NULL);
sexp_write(out_handle, message);
iohandle_write(out_handle, cmsg_cstring_bytes("\n"));
ICHECK(iohandle_flush(out_handle), "iohandle_flush out_handle");
iohandle_write(h, cmsg_cstring_bytes("OK, proceed\n"));
}
handle_error:
switch (h->error_kind) {
case EVBUFFER_EOF:
info("Disconnecting fd %d normally.\n", h->fd);
break;
case SEXP_ERROR_OVERFLOW:
send_sexp_syntax_error(h, "sexp too big");
break;
case SEXP_ERROR_SYNTAX:
send_sexp_syntax_error(h, "sexp syntax error");
break;
default:
warn("Relay handle error on fd %d: 0x%04X\n", h->fd, h->error_kind);
break;
}
goto cleanup;
cleanup:
goto closedown;
closedown:
if (close(h->fd) == -1) {
/* log errors as warnings here and keep on trucking */
warn("Closing file descriptor %d produced errno %d: %s\n",
h->fd, errno, strerror(errno));
}
delete_iohandle(h);
delete_iohandle(out_handle);
}
void start_relay(struct sockaddr_in const *peername, int fd) {
struct boot_args *args = malloc(sizeof(*args));
args->peername = *peername;
args->fd = fd;
spawn((process_main_t) relay_main, args);
}