Ejemplo n.º 1
0
static int
echo_start(struct uinet_demo_config *cfg, uinet_instance_t uinst, struct ev_loop *loop)
{
	struct uinet_demo_echo *echo = (struct uinet_demo_echo *)cfg;
	struct uinet_socket *listen_socket = NULL;
	struct ev_uinet_ctx *soctx = NULL;
	struct uinet_in_addr addr;
	int optlen, optval;
	int error;
	struct uinet_sockaddr_in sin;

	if (uinet_inet_pton(UINET_AF_INET, echo->listen_addr, &addr) <= 0) {
		printf("%s: Malformed address %s\n", echo->cfg.name, echo->listen_addr);
		error = UINET_EINVAL;
		goto fail;
	}

	error = uinet_socreate(echo->cfg.uinst, UINET_PF_INET, &listen_socket, UINET_SOCK_STREAM, 0);
	if (0 != error) {
		printf("%s: Listen socket creation failed (%d)\n", echo->cfg.name, error);
		goto fail;
	}

	soctx = ev_uinet_attach(listen_socket);
	if (NULL == soctx) {
		printf("%s: Failed to alloc libev socket context\n", echo->cfg.name);
		error = UINET_ENOMEM;
		goto fail;
	}

	if (echo->promisc) {
		if ((error = uinet_make_socket_promiscuous(listen_socket, NULL))) {
			printf("%s: Failed to make listen socket promiscuous (%d)\n",
			       echo->cfg.name, error);
			goto fail;
		}
	}

	if (cfg->copy_mode) {
		if ((error = uinet_sosetcopymode(listen_socket, cfg->copy_mode,
						 cfg->copy_limit, cfg->copy_uif))) {
			printf("%s: Failed to set copy mode (%d)\n",
			       echo->cfg.name, error);
			goto fail;
		}
	}
	
	/*
	 * Socket needs to be non-blocking to work with the event system
	 */
	uinet_sosetnonblocking(listen_socket, 1);

	/* Set NODELAY on the listen socket so it will be set on all
	 * accepted sockets via inheritance.
	 */
	optlen = sizeof(optval);
	optval = 1;
	if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_NODELAY,
					&optval, optlen))) {
		printf("%s: Failed to set TCP_NODELAY (%d)\n", echo->cfg.name, error);
		goto fail;
	}

	/* Listen on all VLANs */
	if ((error = uinet_setl2info2(listen_socket, NULL, NULL,
				      UINET_INL2I_TAG_ANY, NULL))) {
		printf("%s: Listen socket L2 info set failed (%d)\n",
		       echo->cfg.name, error);
		goto fail;
	}

	echo->listen_socket = listen_socket;

	memset(&sin, 0, sizeof(struct uinet_sockaddr_in));
	sin.sin_len = sizeof(struct uinet_sockaddr_in);
	sin.sin_family = UINET_AF_INET;
	sin.sin_addr = addr;
	sin.sin_port = htons(echo->listen_port);
	error = uinet_sobind(listen_socket, (struct uinet_sockaddr *)&sin);
	if (0 != error) {
		printf("%s: Bind to %s:%u failed\n", echo->cfg.name,
		       echo->listen_addr, echo->listen_port);
		goto fail;
	}
	
	error = uinet_solisten(echo->listen_socket, -1);
	if (0 != error) {
		printf("%s: Listen on %s:%u failed\n", echo->cfg.name,
		       echo->listen_addr, echo->listen_port);
		goto fail;
	}

	if (echo->cfg.verbose)
		printf("%s: Listening on %s:%u\n", echo->cfg.name,
		       echo->listen_addr, echo->listen_port);

	/*
	 * Set up a read watcher to accept new connections
	 */
	ev_init(&echo->listen_watcher, echo_accept_cb);
	ev_uinet_set(&echo->listen_watcher, soctx, EV_READ);
	echo->listen_watcher.data = echo;
	ev_uinet_start(echo->cfg.loop, &echo->listen_watcher);

	return (0);

fail:
	if (soctx) ev_uinet_detach(soctx);
	if (listen_socket) uinet_soclose(listen_socket);

	return (error);
}
Ejemplo n.º 2
0
static struct passive_context *
create_passive(struct ev_loop *loop, struct server_config *cfg)
{
	struct passive_context *passive = NULL;
	struct uinet_socket *listener = NULL;
	struct ev_uinet_ctx *soctx = NULL;
	struct uinet_in_addr addr;
	int optlen, optval;
	int error;
	struct uinet_sockaddr_in sin;

	if (uinet_inet_pton(UINET_AF_INET, cfg->listen_addr, &addr) <= 0) {
		printf("Malformed address %s\n", cfg->listen_addr);
		goto fail;
	}

	error = uinet_socreate(UINET_PF_INET, &listener, UINET_SOCK_STREAM, 0);
	if (0 != error) {
		printf("Listen socket creation failed (%d)\n", error);
		goto fail;
	}

	soctx = ev_uinet_attach(listener);
	if (NULL == soctx) {
		printf("Failed to alloc libev socket context\n");
		goto fail;
	}
	
	if ((error = uinet_make_socket_passive(listener))) {
		printf("Failed to make listen socket passive (%d)\n", error);
		goto fail;
	}

	if (cfg->interface->promisc) {
		if ((error = uinet_make_socket_promiscuous(listener, cfg->interface->cdom))) {
			printf("Failed to make listen socket promiscuous (%d)\n", error);
			goto fail;
		}
	}

	/* 
	 * The following settings will be inherited by all sockets created
	 * by this listen socket.
	 */

	/*
	 * Need to be non-blocking to work with the event system.
	 */
	uinet_sosetnonblocking(listener, 1);

	/* Wait 5 seconds for connections to complete */
	optlen = sizeof(optval);
	optval = 5;
	if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_KEEPINIT, &optval, optlen)))
		goto fail;

	/* Begin counting down to close after 10 seconds of idle */
	optlen = sizeof(optval);
	optval = 10;
	if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_KEEPIDLE, &optval, optlen)))
		goto fail;

	/* Count down to close once per second */
	optlen = sizeof(optval);
	optval = 1;
	if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_KEEPINTVL, &optval, optlen)))
		goto fail;

	/* Close after idle for 3 counts */
	optlen = sizeof(optval);
	optval = 3;
	if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_KEEPCNT, &optval, optlen)))
		goto fail;

	/* Wait 100 milliseconds for missing TCP segments */
	optlen = sizeof(optval);
	optval = 100;
	if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_REASSDL, &optval, optlen)))
		goto fail;



	passive = calloc(1, sizeof(struct passive_context));
	if (NULL == passive) {
		goto fail;
	}

	passive->loop = loop;
	passive->listener = listener;
	passive->verbose = cfg->verbose;
	passive->interface = cfg->interface;
	passive->extract = cfg->extract;
	memcpy(passive->content_types, cfg->content_types, sizeof(passive->content_types));

	memset(&sin, 0, sizeof(struct uinet_sockaddr_in));
	sin.sin_len = sizeof(struct uinet_sockaddr_in);
	sin.sin_family = UINET_AF_INET;
	sin.sin_addr = addr;
	sin.sin_port = htons(cfg->listen_port);
	error = uinet_sobind(listener, (struct uinet_sockaddr *)&sin);
	if (0 != error) {
		printf("bind failed\n");
		goto fail;
	}
	
	error = uinet_solisten(passive->listener, -1);
	if (0 != error)
		goto fail;

	if (passive->verbose) {
		char buf[32];

		printf("Listening on %s:%u\n", uinet_inet_ntoa(addr, buf, sizeof(buf)), cfg->listen_port);
	}

	ev_init(&passive->listen_watcher, accept_cb);
	ev_uinet_set(&passive->listen_watcher, soctx, EV_READ);
	passive->listen_watcher.data = passive;
	ev_uinet_start(loop, &passive->listen_watcher);

	return (passive);

fail:
	if (soctx) ev_uinet_detach(soctx);
	if (listener) uinet_soclose(listener);
	if (passive) free(passive);

	return (NULL);
}
Ejemplo n.º 3
0
static int
passive_start(struct uinet_demo_config *cfg, uinet_instance_t uinst, struct ev_loop *loop)
{
	struct uinet_demo_passive *passive = (struct uinet_demo_passive *)cfg;
	struct uinet_socket *listen_socket = NULL;
	struct ev_uinet_ctx *soctx = NULL;
	struct uinet_in_addr addr;
	int optlen, optval;
	int error;
	struct uinet_sockaddr_in sin;

	if (uinet_inet_pton(UINET_AF_INET, passive->listen_addr, &addr) <= 0) {
		printf("%s: Malformed address %s\n", passive->cfg.name, passive->listen_addr);
		error = UINET_EINVAL;
		goto fail;
	}

	error = uinet_socreate(passive->cfg.uinst, UINET_PF_INET, &listen_socket, UINET_SOCK_STREAM, 0);
	if (0 != error) {
		printf("%s: Listen socket creation failed (%d)\n", passive->cfg.name, error);
		goto fail;
	}

	soctx = ev_uinet_attach(listen_socket);
	if (NULL == soctx) {
		printf("%s: Failed to alloc libev socket context\n", passive->cfg.name);
		error = UINET_ENOMEM;
		goto fail;
	}
	
	if ((error = uinet_make_socket_passive(listen_socket))) {
		printf("%s: Failed to make listen socket passive (%d)\n", passive->cfg.name, error);
		goto fail;
	}

	if (passive->promisc) {
		if ((error = uinet_make_socket_promiscuous(listen_socket, NULL))) {
			printf("%s: Failed to make listen socket promiscuous (%d)\n", passive->cfg.name, error);
			goto fail;
		}
	}

	/* 
	 * The following settings will be inherited by all sockets created
	 * by this listen socket.
	 */

	/*
	 * Need to be non-blocking to work with the event system.
	 */
	uinet_sosetnonblocking(listen_socket, 1);

	/* Wait 5 seconds for connections to complete */
	optlen = sizeof(optval);
	optval = 5;
	if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_KEEPINIT, &optval, optlen))) {
		printf("%s: Failed to set TCP_KEEPINIT (%d)\n", passive->cfg.name, error);
		goto fail;
	}

	/* Begin counting down to close after 10 seconds of idle */
	optlen = sizeof(optval);
	optval = 10;
	if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_KEEPIDLE, &optval, optlen))) {
		printf("%s: Failed to set TCP_KEEPIDLE (%d)\n", passive->cfg.name, error);
		goto fail;
	}

	/* Count down to close once per second */
	optlen = sizeof(optval);
	optval = 1;
	if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_KEEPINTVL, &optval, optlen))) {
		printf("%s: Failed to set TCP_KEEPINTVL (%d)\n", passive->cfg.name, error);
		goto fail;
	}

	/* Close after idle for 3 counts */
	optlen = sizeof(optval);
	optval = 3;
	if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_KEEPCNT, &optval, optlen))) {
		printf("%s: Failed to set TCP_KEEPCNT (%d)\n", passive->cfg.name, error);
		goto fail;
	}

	/* Wait 100 milliseconds for missing TCP segments */
	optlen = sizeof(optval);
	optval = 100;
	if ((error = uinet_sosetsockopt(listen_socket, UINET_IPPROTO_TCP, UINET_TCP_REASSDL, &optval, optlen))) {
		printf("%s: Failed to set TCP_REASSDL (%d)\n", passive->cfg.name, error);
		goto fail;
	}


	passive->listen_socket = listen_socket;

	memset(&sin, 0, sizeof(struct uinet_sockaddr_in));
	sin.sin_len = sizeof(struct uinet_sockaddr_in);
	sin.sin_family = UINET_AF_INET;
	sin.sin_addr = addr;
	sin.sin_port = htons(passive->listen_port);
	error = uinet_sobind(listen_socket, (struct uinet_sockaddr *)&sin);
	if (0 != error) {
		printf("%s: Bind to %s:%u failed\n", passive->cfg.name,
		       passive->listen_addr, passive->listen_port);
		goto fail;
	}
	
	error = uinet_solisten(passive->listen_socket, -1);
	if (0 != error) {
		printf("%s: Listen on %s:%u failed\n", passive->cfg.name,
		       passive->listen_addr, passive->listen_port);
		goto fail;
	}

	if (passive->cfg.verbose)
		printf("%s: Listening on %s:%u\n", passive->cfg.name,
		       passive->listen_addr, passive->listen_port);

	ev_init(&passive->listen_watcher, passive_accept_cb);
	ev_uinet_set(&passive->listen_watcher, soctx, EV_READ);
	passive->listen_watcher.data = passive;
	ev_uinet_start(loop, &passive->listen_watcher);

	return (0);

fail:
	if (soctx) ev_uinet_detach(soctx);
	if (listen_socket) uinet_soclose(listen_socket);

	return (error);
}
Ejemplo n.º 4
0
int main (int argc, char **argv)
{
	int ch;
	char *progname = argv[0];
#define MIN_INTERFACES 1
#define MAX_INTERFACES 64
	struct interface_config interfaces[MAX_INTERFACES];
#define MIN_SERVERS 1
#define MAX_SERVERS 64	
	struct server_config servers[MAX_SERVERS];
	int num_interfaces = 0;
	int num_servers = 0;
	int interface_server_count = 0;
	int verbose = 0;
	int stats = 0;
	int tcp_stats_assigned = 0;
	unsigned int i;
	int error;
	struct uinet_in_addr tmpinaddr;
	int ifnetmap_count = 0;
	int ifpcap_count = 0;
	struct content_type *contype;

	memset(interfaces, 0, sizeof(interfaces));
	memset(servers, 0, sizeof(servers));

	for (i = 0; i < MAX_INTERFACES; i++) {
		interfaces[i].type = UINET_IFTYPE_NETMAP;
	}

	for (i = 0; i < MAX_SERVERS; i++) {
		servers[i].listen_port = -1;
	}

	while ((ch = getopt(argc, argv, "c:ehi:l:Pp:st:v")) != -1) {
		switch (ch) {
		case 'c':
#ifdef ENABLE_EXTRACT
			if (0 == interface_server_count) {
				printf("No listen address specified\n");
				return (1);
			} else if (MAX_CONTENT_TYPES == servers[num_servers - 1].num_content_types) {
				printf("Maximum number of content types per server is %u\n", MAX_CONTENT_TYPES);
				return (1);
			} else {
				contype = find_content_type(optarg, known_content_types);
				if (NULL == contype) {
					printf("Unknown content type %s\n", optarg);
					return (1);
				}
				servers[num_servers - 1].extract = 1;
				servers[num_servers - 1].content_types[servers[num_servers - 1].num_content_types] = contype;
				servers[num_servers - 1].num_content_types++;
			}
#else
			printf("Extract mode not supported.\n");
			return(1);
#endif
			break;
		case 'e':
#ifdef ENABLE_EXTRACT
			if (0 == num_interfaces) {
				printf("No interface specified\n");
				return (1);
			} else {
				servers[num_servers - 1].extract = 1;
			}
#else
			printf("Extract mode not supported.\n");
			return(1);
#endif
			break;
		case 'h':
			usage(progname);
			return (0);
		case 'i':
			if (MAX_INTERFACES == num_interfaces) {
				printf("Maximum number of interfaces is %u\n", MAX_INTERFACES);
				return (1);
			} else {
				interfaces[num_interfaces].ifname = optarg;
				interfaces[num_interfaces].cdom = num_interfaces + 1;
				num_interfaces++;
				interface_server_count = 0;
			}
			break;
		case 'l':
			if (0 == num_interfaces) {
				printf("No interface specified\n");
				return (1);
			} else if (MAX_SERVERS == num_servers) {
				printf("Maximum number of servers is %u\n", MAX_SERVERS);
				return (1);
			} else {
				servers[num_servers].listen_addr = optarg;
				servers[num_servers].interface = &interfaces[num_interfaces - 1];
				num_servers++;
				interface_server_count++;
			}
			break;
		case 'P':
			if (0 == num_interfaces) {
				printf("No interface specified\n");
				return (1);
			} else {
				interfaces[num_interfaces - 1].promisc = 1;
			}
			break;
		case 'p':
			if (0 == interface_server_count) {
				printf("No listen address specified\n");
				return (1);
			} else {
				servers[num_servers - 1].listen_port = strtoul(optarg, NULL, 10);
			}
			break;
		case 's':
			if (0 == num_interfaces) {
				printf("No interface specified\n");
				return (1);
			} else {
				interfaces[num_interfaces - 1].stats = 1;
			}
			break;
		case 't':
			if (0 == num_interfaces) {
				printf("No interface specified\n");
				return (1);
			} else if (0 == strcmp(optarg, "netmap")) {
				interfaces[num_interfaces - 1].type = UINET_IFTYPE_NETMAP;
			} else if (0 == strcmp(optarg, "pcap")) {
				interfaces[num_interfaces - 1].type = UINET_IFTYPE_PCAP;
			} else {
				printf("Unknown interface type %s\n", optarg);
				return (1);
			}
			break;
		case 'v':
			verbose++;
			break;
		default:
			printf("Unknown option \"%c\"\n", ch);
		case '?':
			usage(progname);
			return (1);
		}
	}
	argc -= optind;
	argv += optind;

	if (num_interfaces < MIN_INTERFACES) {
		printf("Specify at least %u interface%s\n", MIN_INTERFACES, MIN_INTERFACES == 1 ? "" : "s");
		return (1);
	}

	if (num_servers < MIN_SERVERS) {
		printf("Specify at least %u listen address%s\n", MIN_SERVERS, MIN_SERVERS == 1 ? "" : "es");
		return (1);
	}

	for (i = 0; i < num_servers; i++) {
		if (-1 == servers[i].listen_port) {
			printf("No listen port specified for interface %s, listen address %s\n",
			       servers[i].interface->ifname, servers[i].listen_addr);
			return (1);
		}

		if (servers[i].listen_port < 0 || servers[i].listen_port > 65535) {
			printf("Listen port for interface %s, listen address %s is out of range [0, 65535]\n",
			       servers[i].interface->ifname, servers[i].listen_addr);
			return (1);
		}

		if (0 == servers[i].listen_port)
			servers[i].interface->promisc = 1;

		if (uinet_inet_pton(UINET_AF_INET, servers[i].listen_addr, &tmpinaddr) <= 0) {
			printf("%s is not a valid listen address\n", servers[i].listen_addr);
			return (1);
		}

		if (tmpinaddr.s_addr == UINET_INADDR_ANY) {
			servers[i].addrany = 1;
			servers[i].interface->promisc = 1;
		}
	}
	
	
	uinet_init(1, 128*1024, 0);
	uinet_install_sighandlers();

	for (i = 0; i < num_interfaces; i++) {
		switch (interfaces[i].type) {
		case UINET_IFTYPE_NETMAP:
			interfaces[i].alias_prefix = "netmap";
			interfaces[i].instance = ifnetmap_count;
			ifnetmap_count++;
			break;
		case UINET_IFTYPE_PCAP:
			interfaces[i].alias_prefix = "pcap";
			interfaces[i].instance = ifpcap_count;
			ifpcap_count++;
			break;
		default:
			printf("Unknown interface type %d\n", interfaces[i].type);
			return (1);
			break;
		}

		if (interfaces[i].stats && !tcp_stats_assigned) {
			interfaces[i].do_tcpstats = 1;
			tcp_stats_assigned = 1;
		}

		snprintf(interfaces[i].alias, UINET_IF_NAMESIZE, "%s%d", interfaces[i].alias_prefix, interfaces[i].instance);

		if (verbose) {
			printf("Creating interface %s, Promiscuous INET %s, cdom=%u\n",
			       interfaces[i].alias, interfaces[i].promisc ? "enabled" : "disabled",
			       interfaces[i].promisc ? interfaces[i].cdom : 0);
		}

		error = uinet_ifcreate(interfaces[i].type, interfaces[i].ifname, interfaces[i].alias,
				       interfaces[i].promisc ? interfaces[i].cdom : 0,
				       0, NULL);
		if (0 != error) {
			printf("Failed to create interface %s (%d)\n", interfaces[i].alias, error);
		}

		interfaces[i].loop = ev_loop_new(EVFLAG_AUTO);
		if (NULL == interfaces[i].loop) {
			printf("Failed to create event loop interface %s\n", interfaces[i].alias);
			break;
		}
		
	}
	
		
	for (i = 0; i < num_servers; i++) {
		if (!servers[i].addrany) {
			if (verbose) {
				printf("Adding address %s to interface %s\n", servers[i].listen_addr, servers[i].interface->alias);
			}
			
			error = uinet_interface_add_alias(servers[i].interface->alias, servers[i].listen_addr, "", "");
			if (error) {
				printf("Adding alias %s to interface %s failed (%d)\n", servers[i].listen_addr, servers[i].interface->alias, error);
			}
		}
	}


	for (i = 0; i < num_servers; i++) {
		if (verbose) {
			printf("Creating passive server at %s:%d on interface %s\n",
			       servers[i].listen_addr, servers[i].listen_port,
			       servers[i].interface->alias);
		}

		servers[i].verbose = verbose;

		servers[i].passive = create_passive(servers[i].interface->loop, &servers[i]);
		if (NULL == servers[i].passive) {
			printf("Failed to create passive server at %s:%d on interface %s\n",
			       servers[i].listen_addr, servers[i].listen_port,
			       servers[i].interface->alias);
			break;
		}
	}


	for (i = 0; i < num_interfaces; i++) {
		if (verbose) {
			printf("Bringing up interface %s\n", interfaces[i].alias);
		}

		error = uinet_interface_up(interfaces[i].alias, 1, interfaces[i].promisc);
		if (0 != error) {
			printf("Failed to bring up interface %s (%d)\n", interfaces[i].alias, error);
		}

		if (verbose)
			printf("Creating interface thread for interface %s\n", interfaces[i].alias);

		interfaces[i].thread_create_result = pthread_create(&interfaces[i].thread, NULL,
								    interface_thread_start, &interfaces[i]);
	}

	for (i = 0; i < num_interfaces; i++) {
		if (0 == interfaces[i].thread_create_result)
			pthread_join(interfaces[i].thread, NULL);
	}

	uinet_shutdown(0);

	return (0);
}
Ejemplo n.º 5
0
static struct echo_context *
create_echo(struct ev_loop *loop, struct server_config *cfg)
{
	struct echo_context *echo = NULL;
	struct uinet_socket *listener = NULL;
	struct ev_uinet_ctx *soctx = NULL;
	struct uinet_in_addr addr;
	int optlen, optval;
	int error;
	struct uinet_sockaddr_in sin;

	if (uinet_inet_pton(UINET_AF_INET, cfg->listen_addr, &addr) <= 0) {
		printf("Malformed address %s\n", cfg->listen_addr);
		goto fail;
	}

	error = uinet_socreate(UINET_PF_INET, &listener, UINET_SOCK_STREAM, 0);
	if (0 != error) {
		printf("Listen socket creation failed (%d)\n", error);
		goto fail;
	}

	soctx = ev_uinet_attach(listener);
	if (NULL == soctx) {
		printf("Failed to alloc libev socket context\n");
		goto fail;
	}

	if (cfg->interface->promisc) {
		if ((error = uinet_make_socket_promiscuous(listener, cfg->interface->cdom))) {
			printf("Failed to make listen socket promiscuous (%d)\n", error);
			goto fail;
		}
	}

	uinet_sosetnonblocking(listener, 1);

	/* Set NODELAY on the listen socket so it will be set on all
	 * accepted sockets via inheritance.
	 */
	optlen = sizeof(optval);
	optval = 1;
	if ((error = uinet_sosetsockopt(listener, UINET_IPPROTO_TCP, UINET_TCP_NODELAY, &optval, optlen)))
		goto fail;

	echo = malloc(sizeof(struct echo_context));
	if (NULL == echo) {
		goto fail;
	}


	/* Listen on all VLANs */
	if ((error = uinet_setl2info2(listener, NULL, NULL, UINET_INL2I_TAG_ANY, NULL))) {
		printf("Listen socket L2 info set failed (%d)\n", error);
		goto fail;
	}

	echo->loop = loop;
	echo->listener = listener;
	echo->verbose = cfg->verbose;
	echo->listen_cdom = cfg->interface->cdom;

	memset(&sin, 0, sizeof(struct uinet_sockaddr_in));
	sin.sin_len = sizeof(struct uinet_sockaddr_in);
	sin.sin_family = UINET_AF_INET;
	sin.sin_addr = addr;
	sin.sin_port = htons(cfg->listen_port);
	error = uinet_sobind(listener, (struct uinet_sockaddr *)&sin);
	if (0 != error) {
		printf("bind failed\n");
		goto fail;
	}
	
	error = uinet_solisten(echo->listener, -1);
	if (0 != error)
		goto fail;

	if (echo->verbose) {
		char buf[32];

		printf("Listening on %s:%u\n", uinet_inet_ntoa(addr, buf, sizeof(buf)), cfg->listen_port);
	}

	ev_init(&echo->listen_watcher, accept_cb);
	ev_uinet_set(&echo->listen_watcher, soctx, EV_READ);
	echo->listen_watcher.data = echo;
	ev_uinet_start(loop, &echo->listen_watcher);

	return (echo);

fail:
	if (soctx) ev_uinet_detach(soctx);
	if (listener) uinet_soclose(listener);
	if (echo) free(echo);

	return (NULL);
}