/* Set up a helper connection to parent using getenv() */ mowgli_eventloop_helper_proc_t * mowgli_helper_setup(mowgli_eventloop_t *eventloop) { mowgli_eventloop_helper_proc_t *helper; const char *env_io_fd; env_io_fd = getenv("IO_FD"); /* this shouldn't be a hard-fail because some idiot may run the helper from * the cmdline. allow the helper to error out gracefully if not spawned as * a helper. */ if (env_io_fd == NULL) return NULL; helper = mowgli_alloc(sizeof(mowgli_eventloop_helper_proc_t)); helper->type.type = MOWGLI_EVENTLOOP_TYPE_HELPER; helper->eventloop = eventloop; helper->fd = atoi(env_io_fd); helper->pfd = mowgli_pollable_create(helper->eventloop, helper->fd, helper); mowgli_pollable_set_nonblocking(helper->pfd, true); return helper; }
u_link_origin *u_link_origin_create_from_fd(mowgli_eventloop_t *ev, int fd) { const char *operation; u_link_origin *origin = NULL; /* Set the fd to be close-on-exec. All listening sockets will be closed when * we upgrade. This may cause some slight disturbance for users currently * connecting, but this is acceptable. */ operation = "set close-on-exec"; if (set_cloexec(fd) < 0) goto error; u_log(LG_DEBUG, "u_link_origin_create_from_fd: %d", fd); origin = malloc(sizeof(*origin)); operation = "create pollable"; if (!(origin->poll = mowgli_pollable_create(ev, fd, origin))) { errno = -EINVAL; /* XXX */ goto error; } mowgli_node_add(origin, &origin->n, &all_origins); mowgli_pollable_setselect(ev, origin->poll, MOWGLI_EVENTLOOP_IO_READ, accept_ready); return origin; error: u_perror(operation); free(origin); return NULL; }
mowgli_eventloop_helper_proc_t * mowgli_helper_spawn(mowgli_eventloop_t *eventloop, const char *path, char *const argv[]) { mowgli_eventloop_helper_proc_t *helper; int io_fd[2]; char buf[64]; return_val_if_fail(eventloop != NULL, NULL); return_val_if_fail(path != NULL, NULL); helper = mowgli_alloc(sizeof(mowgli_eventloop_helper_proc_t)); helper->type.type = MOWGLI_EVENTLOOP_TYPE_HELPER; helper->eventloop = eventloop; socketpair(AF_UNIX, SOCK_STREAM, 0, io_fd); /* set up helper/child fd mapping */ helper->fd = io_fd[0]; /* make pollables and make them non-blocking */ helper->pfd = mowgli_pollable_create(eventloop, helper->fd, helper); snprintf(buf, sizeof buf, "%d", io_fd[1]); setenv("IO_FD", buf, 1); /* Spawn helper process using mowgli_process_spawn(), helper will get * IO_FD mapping from getenv(). Ugly hack, but it works... * --nenolod */ helper->child = mowgli_process_spawn(path, argv); if (helper->child == NULL) { mowgli_pollable_destroy(eventloop, helper->pfd); close(io_fd[0]); close(io_fd[1]); mowgli_free(helper); return NULL; } close(io_fd[1]); return helper; }
int main(void) { mowgli_eventloop_t *evloop = mowgli_eventloop_create(); mowgli_dns_t *dns = mowgli_dns_create(evloop, MOWGLI_DNS_TYPE_ASYNC); mowgli_eventloop_pollable_t *stdin_pollable = mowgli_pollable_create(evloop, STDIN_FILENO, dns); mowgli_pollable_set_nonblocking(stdin_pollable, true); mowgli_pollable_setselect(evloop, stdin_pollable, MOWGLI_EVENTLOOP_IO_READ, read_data); mowgli_eventloop_run(evloop); mowgli_eventloop_destroy(evloop); return 0; }
mowgli_eventloop_helper_proc_t * mowgli_helper_create(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_start_fn_t *start_fn, const char *helpername, void *userdata) { mowgli_eventloop_helper_proc_t *helper; mowgli_helper_create_req_t child; int io_fd[2]; return_val_if_fail(eventloop != NULL, NULL); return_val_if_fail(start_fn != NULL, NULL); child.start_fn = start_fn; child.userdata = userdata; helper = mowgli_alloc(sizeof(mowgli_eventloop_helper_proc_t)); helper->type.type = MOWGLI_EVENTLOOP_TYPE_HELPER; helper->eventloop = eventloop; socketpair(AF_UNIX, SOCK_STREAM, 0, io_fd); /* set up helper/child fd mapping */ helper->fd = io_fd[0]; child.fd = io_fd[1]; /* make pollables and make them non-blocking */ helper->pfd = mowgli_pollable_create(eventloop, helper->fd, helper); mowgli_pollable_set_nonblocking(helper->pfd, true); /* spawn helper process using mowgli_process_clone() */ helper->child = mowgli_process_clone((mowgli_process_start_fn_t) mowgli_helper_trampoline, helpername, &child); if (helper->child == NULL) { mowgli_pollable_destroy(eventloop, helper->pfd); close(io_fd[0]); close(io_fd[1]); mowgli_free(helper); return NULL; } close(child.fd); return helper; }
static void mowgli_helper_trampoline(mowgli_helper_create_req_t *req) { mowgli_eventloop_helper_proc_t *helper; #ifndef _WIN32 int i, x; #endif return_if_fail(req != NULL); return_if_fail(req->start_fn != NULL); helper = mowgli_alloc(sizeof(mowgli_eventloop_helper_proc_t)); helper->type.type = MOWGLI_EVENTLOOP_TYPE_HELPER; helper->fd = req->fd; #ifndef _WIN32 for (i = 0; i < 1024; i++) { if (i != req->fd) close(i); } x = open("/dev/null", O_RDWR); for (i = 0; i < 2; i++) { if (req->fd != i) dup2(x, i); } if (x > 2) close(x); #endif helper->eventloop = mowgli_eventloop_create(); helper->pfd = mowgli_pollable_create(helper->eventloop, helper->fd, helper); helper->userdata = req->userdata; mowgli_pollable_set_nonblocking(helper->pfd, true); req->start_fn(helper, helper->userdata); }
mowgli_eventloop_pollable_t* irc_connect(const char * host, const char * port) { mowgli_eventloop_pollable_t* out; mowgli_descriptor_t fd; struct addrinfo hints, *res; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; getaddrinfo(host, port, &hints, &res); fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); connect(fd, res->ai_addr, res->ai_addrlen); out = mowgli_pollable_create(base_eventloop, fd, NULL); mowgli_pollable_set_nonblocking(out, true); mowgli_pollable_setselect(base_eventloop, out, MOWGLI_EVENTLOOP_POLL_READ, irc_read); return out; }
static int linux_prepare(mowgli_eventloop_t *eventloop, mowgli_config_file_entry_t *entry) { mowgli_eventloop_pollable_t *pollable; mowgli_config_file_entry_t *ce; char *interface = NULL; int fd; int ifindex = 0; bool promisc; MOWGLI_ITER_FOREACH(ce, entry) { if (!strcasecmp(ce->varname, "interface")) interface = strdup(ce->vardata); if (!strcasecmp(ce->varname, "promisc")) promisc = true; } fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_IP)); if (fd < 0) return; if (interface) { struct sockaddr_ll sll; struct ifreq ethreq = {}; mowgli_strlcpy(ethreq.ifr_name, interface, IFNAMSIZ); ioctl(fd, SIOCGIFINDEX, ðreq); DPRINTF("ifindex for %s: %d\n", interface, ethreq.ifr_ifindex); ifindex = ethreq.ifr_ifindex; sll.sll_family = AF_PACKET; sll.sll_protocol = htons(ETH_P_IP); sll.sll_ifindex = ifindex; if (bind(fd, (struct sockaddr *) &sll, sizeof sll) < 0) { DPRINTF("unable to bind(2) to interface '%s' (index %d): %s\n", interface, ifindex, strerror(errno)); goto out; } DPRINTF("bound to interface '%s'\n", interface); } if (promisc) { struct packet_mreq mr; mr.mr_ifindex = ifindex; mr.mr_type = PACKET_MR_PROMISC; if (setsockopt(fd, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr, sizeof mr) < 0) { DPRINTF("unable to add packet membership for fd=%d\n", fd); goto out; } DPRINTF("enabled promisc mode for fd=%d\n", fd); } out: DPRINTF("opened raw packet socket as fd=%d\n", fd); pollable = mowgli_pollable_create(eventloop, fd, NULL); mowgli_pollable_setselect(eventloop, pollable, MOWGLI_EVENTLOOP_IO_READ, linux_handle); }