static void mowgli_linebuf_write_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { mowgli_linebuf_t *linebuf = (mowgli_linebuf_t *) userdata; mowgli_linebuf_buf_t *buffer = &(linebuf->writebuf); int ret; if ((ret = mowgli_vio_write(linebuf->vio, buffer->buffer, buffer->buflen)) <= 0) if (linebuf->vio->error.code != MOWGLI_VIO_ERR_NONE) /* If we have a genuine error, we shouldn't come back to this func * Otherwise we'll try again. */ if (ret != 0) { mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); mowgli_log("mowgli_vio_write returned error [%ld]: %s", linebuf->vio->error.code, linebuf->vio->error.string); return; } buffer->buflen -= ret; /* Anything else to write? */ if (buffer->buflen == 0) { if (!mowgli_vio_hasflag(linebuf->vio, MOWGLI_VIO_FLAGS_NEEDWRITE)) mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, NULL); if ((linebuf->flags & MOWGLI_LINEBUF_SHUTTING_DOWN) != 0) mowgli_linebuf_do_shutdown(linebuf); } else { mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); } }
/* Detach the linebuf instance from the eventloop */ void mowgli_linebuf_detach_from_eventloop(mowgli_linebuf_t *linebuf) { return_if_fail(linebuf != NULL); return_if_fail(linebuf->eventloop != NULL); mowgli_pollable_setselect(linebuf->eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_READ, NULL); mowgli_pollable_setselect(linebuf->eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_WRITE, NULL); mowgli_vio_eventloop_detach(linebuf->vio); linebuf->eventloop = NULL; }
void mowgli_helper_set_read_cb(mowgli_eventloop_t *eventloop, mowgli_eventloop_helper_proc_t *helper, mowgli_eventloop_io_cb_t *read_fn) { return_if_fail(eventloop != NULL); return_if_fail(helper != NULL); if (read_fn == NULL) mowgli_pollable_setselect(eventloop, helper->pfd, MOWGLI_EVENTLOOP_IO_READ, NULL); helper->read_function = read_fn; mowgli_pollable_setselect(eventloop, helper->pfd, MOWGLI_EVENTLOOP_IO_READ, mowgli_helper_io_trampoline); }
void mowgli_linebuf_write(mowgli_linebuf_t *linebuf, const char *data, int len) { char *ptr = linebuf->writebuf.buffer + linebuf->writebuf.buflen; return_if_fail(len > 0); return_if_fail(data != NULL); if (linebuf->flags & MOWGLI_LINEBUF_SHUTTING_DOWN) return; if (linebuf->writebuf.buflen + len + linebuf->endl_len > linebuf->writebuf.maxbuflen) { linebuf->flags |= MOWGLI_LINEBUF_ERR_WRITEBUF_FULL; mowgli_linebuf_error(linebuf->vio); return; } memcpy((void *) ptr, data, len); memcpy((void *) (ptr + len), linebuf->endl, linebuf->endl_len); linebuf->writebuf.buflen += len + linebuf->endl_len; /* Schedule our write */ mowgli_pollable_setselect(linebuf->eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); }
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; }
/* Attach the linebuf instance to the eventloop -- socket must be created first with VIO instance! */ void mowgli_linebuf_attach_to_eventloop(mowgli_linebuf_t *linebuf, mowgli_eventloop_t *eventloop) { return_if_fail(eventloop != NULL); return_if_fail(linebuf != NULL); return_if_fail(linebuf->vio != NULL); return_if_fail((linebuf->vio->flags & MOWGLI_VIO_FLAGS_ISCLOSED) == 0); #ifdef NOTYET mowgli_vio_eventloop_attach(linebuf->vio, eventloop, &linebuf_evops); #else mowgli_vio_eventloop_attach(linebuf->vio, eventloop, NULL); #endif mowgli_pollable_setselect(eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_READ, mowgli_linebuf_read_data); mowgli_pollable_setselect(eventloop, linebuf->vio->io.e, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); linebuf->eventloop = eventloop; }
static void mowgli_linebuf_read_data(mowgli_eventloop_t *eventloop, mowgli_eventloop_io_t *io, mowgli_eventloop_io_dir_t dir, void *userdata) { mowgli_linebuf_t *linebuf = (mowgli_linebuf_t *) userdata; mowgli_linebuf_buf_t *buffer = &(linebuf->readbuf); void *bufpos; size_t offset; int ret; if (buffer->maxbuflen - buffer->buflen == 0) { linebuf->flags |= MOWGLI_LINEBUF_ERR_READBUF_FULL; mowgli_linebuf_error(linebuf->vio); return; } bufpos = buffer->buffer + buffer->buflen; offset = buffer->maxbuflen - buffer->buflen + 1; if ((ret = mowgli_vio_read(linebuf->vio, bufpos, offset)) <= 0) { if (linebuf->vio->error.type == MOWGLI_VIO_ERR_NONE) return; /* Let's never come back here */ mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_READ, NULL); mowgli_linebuf_do_shutdown(linebuf); return; } /* Le sigh -- stupid edge-triggered interfaces */ if (mowgli_vio_hasflag(linebuf->vio, MOWGLI_VIO_FLAGS_NEEDREAD)) mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_READ, mowgli_linebuf_read_data); /* Do we want a write for SSL? */ if (mowgli_vio_hasflag(linebuf->vio, MOWGLI_VIO_FLAGS_NEEDWRITE)) mowgli_pollable_setselect(eventloop, io, MOWGLI_EVENTLOOP_IO_WRITE, mowgli_linebuf_write_data); buffer->buflen += ret; mowgli_linebuf_process(linebuf); }
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_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); }