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); }
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); }
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); }
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); }
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); }