static void * libev_ctx_add(void *ctx, const verto_ev *ev, verto_ev_flag *flags) { ev_io *iow = NULL; ev_timer *timerw = NULL; ev_idle *idlew = NULL; ev_signal *signalw = NULL; ev_child *childw = NULL; ev_tstamp interval; int events = EV_NONE; *flags |= VERTO_EV_FLAG_PERSIST; switch (verto_get_type(ev)) { case VERTO_EV_TYPE_IO: if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_READ) events |= EV_READ; if (verto_get_flags(ev) & VERTO_EV_FLAG_IO_WRITE) events |= EV_WRITE; setuptype(io, ev, libev_callback, verto_get_fd(ev), events); case VERTO_EV_TYPE_TIMEOUT: interval = ((ev_tstamp) verto_get_interval(ev)) / 1000.0; setuptype(timer, ev, libev_callback, interval, interval); case VERTO_EV_TYPE_IDLE: setuptype(idle, ev, libev_callback); case VERTO_EV_TYPE_SIGNAL: setuptype(signal, ev, libev_callback, verto_get_signal(ev)); case VERTO_EV_TYPE_CHILD: *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */ setuptype(child, ev, libev_callback, verto_get_proc(ev), 0); default: return NULL; /* Not supported */ } }
static void * libevent_ctx_add(void *ctx, const verto_ev *ev, verto_ev_flag *flags) { struct event *priv = NULL; struct timeval *timeout = NULL; struct timeval tv; int libeventflags = 0; if (*flags & VERTO_EV_FLAG_PERSIST) libeventflags |= EV_PERSIST; switch (verto_get_type(ev)) { case VERTO_EV_TYPE_IO: if (*flags & VERTO_EV_FLAG_IO_READ) libeventflags |= EV_READ; if (*flags & VERTO_EV_FLAG_IO_WRITE) libeventflags |= EV_WRITE; priv = event_new(ctx, verto_get_fd(ev), libeventflags, libevent_callback, (void *) ev); break; case VERTO_EV_TYPE_TIMEOUT: timeout = &tv; tv.tv_sec = verto_get_interval(ev) / 1000; tv.tv_usec = verto_get_interval(ev) % 1000 * 1000; priv = event_new(ctx, -1, EV_TIMEOUT | libeventflags, libevent_callback, (void *) ev); break; case VERTO_EV_TYPE_SIGNAL: priv = event_new(ctx, verto_get_signal(ev), EV_SIGNAL | libeventflags, libevent_callback, (void *) ev); break; case VERTO_EV_TYPE_IDLE: case VERTO_EV_TYPE_CHILD: default: return NULL; /* Not supported */ } if (!priv) return NULL; if (*flags & VERTO_EV_FLAG_PRIORITY_HIGH) event_priority_set(priv, 0); else if (*flags & VERTO_EV_FLAG_PRIORITY_MEDIUM) event_priority_set(priv, 1); else if (*flags & VERTO_EV_FLAG_PRIORITY_LOW) event_priority_set(priv, 2); event_add(priv, timeout); return priv; }
static void cb(verto_ctx *ctx, verto_ev *ev) { unsigned char buff[DATALEN]; int fd = 0; ssize_t bytes = 0; fd = verto_get_fd(ev); assert(fd == fds[0]); bytes = read(fd, buff, DATALEN); if (callcount++ == 0) { assert(bytes == DATALEN); close(fds[1]); fds[1] = -1; } else { assert(bytes != DATALEN); close(fd); fds[0] = -1; verto_del(ev); verto_break(ctx); } }
static verto_mod_ev * glib_ctx_add(verto_mod_ctx *ctx, const verto_ev *ev, verto_ev_flag *flags) { verto_mod_ev *evpriv = NULL; verto_ev_type type = verto_get_type(ev); *flags |= verto_get_flags(ev) & VERTO_EV_FLAG_PERSIST; *flags |= verto_get_flags(ev) & VERTO_EV_FLAG_IO_CLOSE_FD; switch (type) { case VERTO_EV_TYPE_IO: evpriv = g_source_new(&funcs, sizeof(GIOSource)); if (evpriv) { ((GIOSource*) evpriv)->fd.fd = verto_get_fd(ev); ((GIOSource*) evpriv)->autoclose = *flags & VERTO_EV_FLAG_IO_CLOSE_FD; g_source_add_poll(evpriv, &((GIOSource*) evpriv)->fd); } break; case VERTO_EV_TYPE_TIMEOUT: evpriv = g_timeout_source_new(verto_get_interval(ev)); break; case VERTO_EV_TYPE_IDLE: evpriv = g_idle_source_new(); break; case VERTO_EV_TYPE_CHILD: evpriv = g_child_watch_source_new(verto_get_proc(ev)); break; case VERTO_EV_TYPE_SIGNAL: /* While glib has signal support in >=2.29, it does not support many common signals (like USR*). Therefore, signal support is disabled until they support them (should be soonish) */ #if GLIB_MAJOR_VERSION >= 999 #if GLIB_MINOR_VERSION >= 29 #ifdef G_OS_UNIX /* Not supported on Windows */ evpriv = g_unix_signal_source_new(verto_get_signal(ev)); break; #endif #endif /* GLIB_MINOR_VERSION >= 29 */ #endif /* GLIB_MAJOR_VERSION >= 2 */ default: return NULL; /* Not supported */ } if (!evpriv) goto error; if (type == VERTO_EV_TYPE_IO) g_source_set_callback(evpriv, (GSourceFunc) glib_callback_io, (void *) ev, NULL); else if (type == VERTO_EV_TYPE_CHILD) g_source_set_callback(evpriv, (GSourceFunc) glib_callback_child, (void *) ev, NULL); else g_source_set_callback(evpriv, glib_callback, (void *) ev, NULL); glib_ctx_set_flags(ctx, ev, evpriv); g_source_set_can_recurse(evpriv, FALSE); if (g_source_attach(evpriv, ctx->context) == 0) goto error; return evpriv; error: if (evpriv) { g_source_destroy(evpriv); g_source_unref(evpriv); } return NULL; }
static void * glib_ctx_add(void *ctx, const verto_ev *ev, verto_ev_flag *flags) { glib_ev *gev = NULL; GIOCondition cond = 0; verto_ev_type type = verto_get_type(ev); gev = g_new0(glib_ev, 1); if (!gev) return NULL; switch (type) { case VERTO_EV_TYPE_IO: #ifdef WIN32 gev->chan = g_io_channel_win32_new_socket(verto_get_fd(ev)); #else gev->chan = g_io_channel_unix_new(verto_get_fd(ev)); #endif if (!gev->chan) goto error; g_io_channel_set_close_on_unref(gev->chan, FALSE); if (*flags & VERTO_EV_FLAG_IO_READ) cond |= G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL; if (*flags & VERTO_EV_FLAG_IO_WRITE) cond |= G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL; gev->src = g_io_create_watch(gev->chan, cond); break; case VERTO_EV_TYPE_TIMEOUT: gev->src = g_timeout_source_new(verto_get_interval(ev)); break; case VERTO_EV_TYPE_IDLE: gev->src = g_idle_source_new(); break; case VERTO_EV_TYPE_CHILD: gev->src = g_child_watch_source_new(verto_get_proc(ev)); *flags &= ~VERTO_EV_FLAG_PERSIST; /* Child events don't persist */ break; case VERTO_EV_TYPE_SIGNAL: #if GLIB_MAJOR_VERSION >= 2 #if GLIB_MINOR_VERSION >= 29 #ifdef G_OS_UNIX /* Not supported on Windows */ gev->src = g_unix_signal_source_new(verto_get_signal(ev)); break; #endif #endif /* GLIB_MINOR_VERSION >= 29 */ #endif /* GLIB_MAJOR_VERSION >= 2 */ default: return NULL; /* Not supported */ } if (!gev->src) goto error; if (type == VERTO_EV_TYPE_IO) g_source_set_callback(gev->src, (GSourceFunc) glib_callback_io, (void *) ev, NULL); else if (type == VERTO_EV_TYPE_CHILD) g_source_set_callback(gev->src, (GSourceFunc) glib_callback_child, (void *) ev, NULL); else g_source_set_callback(gev->src, glib_callback, (void *) ev, NULL); if (*flags & VERTO_EV_FLAG_PRIORITY_HIGH) g_source_set_priority(gev->src, G_PRIORITY_HIGH); else if (*flags & VERTO_EV_FLAG_PRIORITY_MEDIUM) g_source_set_priority(gev->src, G_PRIORITY_DEFAULT_IDLE); else if (*flags & VERTO_EV_FLAG_PRIORITY_LOW) g_source_set_priority(gev->src, G_PRIORITY_LOW); g_source_set_can_recurse(gev->src, FALSE); if (g_source_attach(gev->src, ((glib_ev_ctx*) ctx)->context) == 0) goto error; return gev; error: if (gev) { if (gev->chan) g_io_channel_unref(gev->chan); if (gev->src) { g_source_destroy(gev->src); g_source_unref(gev->src); } g_free(gev); } return NULL; }
void accept_sock_conn(verto_ctx *vctx, verto_ev *ev) { struct gp_conn *conn = NULL; int listen_fd; int fd = -1; int ret; conn = calloc(1, sizeof(struct gp_conn)); if (!conn) { ret = ENOMEM; goto done; } conn->sock_ctx = verto_get_private(ev); conn->us.sd = -1; listen_fd = verto_get_fd(ev); fd = accept(listen_fd, (struct sockaddr *)&conn->us.sock_addr, &conn->us.sock_addr_len); if (fd == -1) { ret = errno; if (ret == EINTR) { /* let the event loop retry later */ return; } goto done; } conn->us.sd = fd; ret = set_status_flags(fd, O_NONBLOCK); if (ret) { GPDEBUG("Failed to set O_NONBLOCK on %d!\n", fd); goto done; } ret = set_fd_flags(fd, FD_CLOEXEC); if (ret) { GPDEBUG("Failed to set FD_CLOEXEC on %d!\n", fd); goto done; } ret = get_peercred(fd, conn); if (ret) { goto done; } GPDEBUG("Client connected (fd = %d)", fd); if (conn->creds.type & CRED_TYPE_UNIX) { GPDEBUG(" (pid = %d) (uid = %d) (gid = %d)", conn->creds.ucred.pid, conn->creds.ucred.uid, conn->creds.ucred.gid); } if (conn->creds.type & CRED_TYPE_SELINUX) { GPDEBUG(" (context = %s)", SELINUX_context_str(conn->selinux_ctx)); } GPDEBUG("\n"); gp_setup_reader(vctx, conn); ret = 0; done: if (ret) { GPERROR("Error connecting client: (%d:%s)", ret, gp_strerror(ret)); gp_conn_free(conn); } }
static void gp_socket_write(verto_ctx *vctx, verto_ev *ev) { struct gp_buffer *wbuf; struct iovec iov[2]; uint32_t size; ssize_t wn; int vecs; int fd; fd = verto_get_fd(ev); wbuf = verto_get_private(ev); vecs = 0; if (wbuf->pos == 0) { /* first write, send the buffer size as packet header */ size = wbuf->size | FRAGMENT_BIT; size = htonl(size); iov[0].iov_base = &size; iov[0].iov_len = sizeof(size); vecs = 1; } iov[vecs].iov_base = wbuf->data + wbuf->pos; iov[vecs].iov_len = wbuf->size - wbuf->pos; vecs++; errno = 0; wn = writev(fd, iov, vecs); if (wn == -1) { if (errno == EAGAIN || errno == EINTR) { /* try again later */ gp_socket_schedule_write(vctx, wbuf); } else { /* error on socket, close and release it */ gp_conn_free(wbuf->conn); gp_buffer_free(wbuf); } return; } if (vecs == 2) { if (wn < sizeof(size)) { /* don't bother trying to handle sockets that can't * buffer even 4 bytes */ gp_conn_free(wbuf->conn); gp_buffer_free(wbuf); return; } wn -= sizeof(size); } wbuf->pos += wn; if (wbuf->size > wbuf->pos) { /* short write, reschedule */ gp_socket_schedule_write(vctx, wbuf); } else { /* now setup again the reader */ gp_setup_reader(vctx, wbuf->conn); /* all done, free write context */ gp_buffer_free(wbuf); } }
static void gp_socket_read(verto_ctx *vctx, verto_ev *ev) { struct gp_buffer *rbuf; uint32_t size; bool header = false; size_t rn; int ret; int fd; fd = verto_get_fd(ev); rbuf = verto_get_private(ev); if (rbuf->data == NULL) { header = true; /* new connection, need to read length first */ rn = read(fd, &size, sizeof(uint32_t)); if (rn == -1) { if (errno == EAGAIN || errno == EINTR) { /* spin again */ ret = EAGAIN; } else { ret = EIO; } goto done; } if (rn != sizeof(uint32_t)) { /* client closed, * or we didn't get even 4 bytes, * close conn, not worth trying 1 byte reads at this time */ ret = EIO; goto done; } /* allocate buffer for receiving data */ rbuf->size = ntohl(size); /* FIXME: need to support multiple fragments */ /* for now just make sure we have the last fragment bit * then remove it */ if (rbuf->size & FRAGMENT_BIT) { rbuf->size &= ~FRAGMENT_BIT; } else { ret = EIO; goto done; } if (rbuf->size > MAX_RPC_SIZE) { /* req too big close conn. */ ret = EIO; goto done; } rbuf->data = malloc(rbuf->size); if (!rbuf->data) { ret = ENOMEM; goto done; } } errno = 0; rn = read(fd, rbuf->data + rbuf->pos, rbuf->size - rbuf->pos); if (rn == -1) { if (errno == EAGAIN || errno == EINTR) { /* spin again */ ret = EAGAIN; } else { ret = EIO; } goto done; } if (rn == 0) { if (!header) { /* client closed before the buffer was fully read */ ret = EIO; } else { ret = EAGAIN; } goto done; } rbuf->pos += rn; if (rbuf->pos == rbuf->size) { /* got all data, hand over packet */ ret = gp_query_new(rbuf->conn->sock_ctx->gpctx->workers, rbuf->conn, rbuf->data, rbuf->size); if (ret != 0) { /* internal error, not much we can do */ goto done; } /* we successfully handed over the data */ rbuf->data = NULL; gp_buffer_free(rbuf); return; } ret = EAGAIN; done: switch (ret) { case EAGAIN: gp_socket_schedule_read(vctx, rbuf); return; default: gp_conn_free(rbuf->conn); gp_buffer_free(rbuf); } }