enum proto_accept_error
proto_accept_connection(int listener_fd, int *read_fd, int *write_fd,
			const char **name)
{
    int timeout = server_int_option("name_lookup_timeout", 5);
    int fd;
    struct sockaddr_in address;
    size_t addr_length = sizeof(address);
    static Stream *s = 0;

    if (!s)
	s = new_stream(100);

    fd = accept(listener_fd, (struct sockaddr *) &address, &addr_length);
    if (fd < 0) {
	if (errno == EMFILE)
	    return PA_FULL;
	else {
	    log_perror("Accepting new network connection");
	    return PA_OTHER;
	}
    }
    *read_fd = *write_fd = fd;
    stream_printf(s, "%s, port %d",
		  lookup_name_from_addr(&address, timeout),
		  (int) ntohs(address.sin_port));
    *name = reset_stream(s);
    return PA_OKAY;
}
Beispiel #2
0
enum proto_accept_error
proto_accept_connection(int listener_fd, int *read_fd, int *write_fd,
			const char **name)
{
    int timeout = server_int_option("name_lookup_timeout", 5);
    int fd;
    struct sockaddr_in *addr = (struct sockaddr_in *) call->addr.buf;
    static Stream *s = 0;

    if (!s)
	s = new_stream(100);

    fd = t_open((void *) "/dev/tcp", O_RDWR, 0);
    if (fd < 0) {
	if (t_errno == TSYSERR && errno == EMFILE)
	    return PA_FULL;
	else {
	    log_ti_error("Opening endpoint for new connection");
	    return PA_OTHER;
	}
    }
    if (t_bind(fd, 0, 0) < 0) {
	log_ti_error("Binding endpoint for new connection");
	t_close(fd);
	return PA_OTHER;
    }
    if (t_listen(listener_fd, call) < 0) {
	log_ti_error("Accepting new network connection");
	t_close(fd);
	return PA_OTHER;
    }
    if (t_accept(listener_fd, fd, call) < 0) {
	log_ti_error("Accepting new network connection");
	t_close(fd);
	return PA_OTHER;
    }
    if (!set_rw_able(fd)) {
	t_close(fd);
	return PA_OTHER;
    }
    *read_fd = *write_fd = fd;
    stream_printf(s, "%s, port %d",
		  lookup_name_from_addr(addr, timeout),
		  (int) ntohs(addr->sin_port));
    *name = reset_stream(s);
    return PA_OKAY;
}
Beispiel #3
0
enum error
proto_open_connection(Var arglist, int *read_fd, int *write_fd,
		      const char **local_name, const char **remote_name)
{
    /* These are `static' rather than `volatile' because I can't cope with
     * getting all those nasty little parameter-passing rules right.  This
     * function isn't recursive anyway, so it doesn't matter.
     */
    struct sockaddr_in rec_addr;
    struct t_bind received;
    static const char *host_name;
    static int port;
    static Timer_ID id;
    int fd, result;
    int timeout = server_int_option("name_lookup_timeout", 5);
    static struct sockaddr_in addr;
    static Stream *st1 = 0, *st2 = 0;

    if (!st1) {
	st1 = new_stream(20);
	st2 = new_stream(50);
    }
    if (arglist.v.list[0].v.num != 2)
	return E_ARGS;
    else if (arglist.v.list[1].type != TYPE_STR ||
	     arglist.v.list[2].type != TYPE_INT)
	return E_TYPE;

    host_name = arglist.v.list[1].v.str;
    port = arglist.v.list[2].v.num;

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = lookup_addr_from_name(host_name, timeout);
    if (addr.sin_addr.s_addr == 0)
	return E_INVARG;

    /* Cast to (void *) here to workaround const-less decls on some systems. */
    fd = t_open((void *) "/dev/tcp", O_RDWR, 0);
    if (fd < 0) {
	if (t_errno != TSYSERR || errno != EMFILE)
	    log_ti_error("Making endpoint in proto_open_connection");
	return E_QUOTA;
    }
    received.addr.maxlen = sizeof(rec_addr);
    received.addr.len = sizeof(rec_addr);
    received.addr.buf = (void *) &rec_addr;

    if (t_bind(fd, 0, &received) < 0) {
	log_ti_error("Binding outbound endpoint");
	t_close(fd);
	return E_QUOTA;
    }
    call->addr.maxlen = sizeof(addr);
    call->addr.len = sizeof(addr);
    call->addr.buf = (void *) &addr;

    TRY
	id = set_timer(server_int_option("outbound_connect_timeout", 5),
		       timeout_proc, 0);
    result = t_connect(fd, call, 0);
    cancel_timer(id);
    EXCEPT(timeout_exception)
	result = -1;
    errno = ETIMEDOUT;
    t_errno = TSYSERR;
    reenable_timers();
    ENDTRY

	if (result < 0) {
	t_close(fd);
	log_ti_error("Connecting in proto_open_connection");
	return E_QUOTA;
    }
    if (!set_rw_able(fd)) {
	t_close(fd);
	return E_QUOTA;
    }
    *read_fd = *write_fd = fd;

    stream_printf(st1, "port %d", (int) ntohs(rec_addr.sin_port));
    *local_name = reset_stream(st1);

    stream_printf(st2, "%s, port %d", host_name, port);
    *remote_name = reset_stream(st2);

    return E_NONE;
}
enum error
proto_open_connection(Var arglist, int *read_fd, int *write_fd,
		      const char **local_name, const char **remote_name)
{
    /* These are `static' rather than `volatile' because I can't cope with
     * getting all those nasty little parameter-passing rules right.  This
     * function isn't recursive anyway, so it doesn't matter.
     */
    static const char *host_name;
    static int port;
    static Timer_ID id;
    size_t length;
    int s, result;
    int timeout = server_int_option("name_lookup_timeout", 5);
    static struct sockaddr_in addr;
    static Stream *st1 = 0, *st2 = 0;

    if (!outbound_network_enabled)
	return E_PERM;

    if (!st1) {
	st1 = new_stream(20);
	st2 = new_stream(50);
    }
    if (arglist.v.list[0].v.num != 2)
	return E_ARGS;
    else if (arglist.v.list[1].type != TYPE_STR ||
	     arglist.v.list[2].type != TYPE_INT)
	return E_TYPE;

    host_name = arglist.v.list[1].v.str;
    port = arglist.v.list[2].v.num;

    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    addr.sin_addr.s_addr = lookup_addr_from_name(host_name, timeout);
    if (addr.sin_addr.s_addr == 0)
	return E_INVARG;

    s = socket(AF_INET, SOCK_STREAM, 0);
    if (s < 0) {
	if (errno != EMFILE)
	    log_perror("Making socket in proto_open_connection");
	return E_QUOTA;
    }
    
    if (bind_local_ip != INADDR_ANY) {
	static struct sockaddr_in local_addr;

	local_addr.sin_family = AF_INET;
	local_addr.sin_addr.s_addr = bind_local_ip;
	local_addr.sin_port = 0;
	/* In theory, if the original listen() succeeded,
	 * then this should too, but who knows, really? */
	if (bind(s, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0) {
	    enum error e = E_QUOTA;

	    log_perror("Binding local address in proto_open_connection");
	    if (errno == EACCES)
		e = E_PERM;
	    close(s);
	    return e;
	}
    }	 
    TRY {
	id = set_timer(server_int_option("outbound_connect_timeout", 5),
		       timeout_proc, 0);
	result = connect(s, (struct sockaddr *) &addr, sizeof(addr));
	cancel_timer(id);
    }
    EXCEPT(timeout_exception) {
	result = -1;
	errno = ETIMEDOUT;
	reenable_timers();
    }
    ENDTRY;

    if (result < 0) {
	close(s);
	if (errno == EADDRNOTAVAIL ||
	    errno == ECONNREFUSED ||
	    errno == ENETUNREACH ||
	    errno == ETIMEDOUT)
	    return E_INVARG;
	log_perror("Connecting in proto_open_connection");
	return E_QUOTA;
    }
    length = sizeof(addr);
    if (getsockname(s, (struct sockaddr *) &addr, &length) < 0) {
	close(s);
	log_perror("Getting local name in proto_open_connection");
	return E_QUOTA;
    }
    *read_fd = *write_fd = s;

    stream_printf(st1, "port %d", (int) ntohs(addr.sin_port));
    *local_name = reset_stream(st1);

    stream_printf(st2, "%s, port %d", host_name, port);
    *remote_name = reset_stream(st2);

    return E_NONE;
}