rstatus_t server_connect(struct context *ctx, struct server *server, struct conn *conn) { rstatus_t status; ASSERT(!conn->client && !conn->proxy); if (conn->sd > 0) { /* already connected on server connection */ return DN_OK; } log_debug(LOG_VVERB, "connect to server '%.*s'", server->pname.len, server->pname.data); conn->sd = socket(conn->family, SOCK_STREAM, 0); if (conn->sd < 0) { log_error("socket for server '%.*s' failed: %s", server->pname.len, server->pname.data, strerror(errno)); status = DN_ERROR; goto error; } status = dn_set_nonblocking(conn->sd); if (status != DN_OK) { log_error("set nonblock on s %d for server '%.*s' failed: %s", conn->sd, server->pname.len, server->pname.data, strerror(errno)); goto error; } if (server->pname.data[0] != '/') { status = dn_set_tcpnodelay(conn->sd); if (status != DN_OK) { log_warn("set tcpnodelay on s %d for server '%.*s' failed, ignored: %s", conn->sd, server->pname.len, server->pname.data, strerror(errno)); } } status = event_add_conn(ctx->evb, conn); if (status != DN_OK) { log_error("event add conn s %d for server '%.*s' failed: %s", conn->sd, server->pname.len, server->pname.data, strerror(errno)); goto error; } ASSERT(!conn->connecting && !conn->connected); status = connect(conn->sd, conn->addr, conn->addrlen); if (status != DN_OK) { if (errno == EINPROGRESS) { conn->connecting = 1; log_debug(LOG_DEBUG, "connecting on s %d to server '%.*s'", conn->sd, server->pname.len, server->pname.data); return DN_OK; } log_error("connect on s %d to server '%.*s' failed: %s", conn->sd, server->pname.len, server->pname.data, strerror(errno)); goto error; } ASSERT(!conn->connecting); conn->connected = 1; log_debug(LOG_INFO, "connected on s %d to server '%.*s'", conn->sd, server->pname.len, server->pname.data); return DN_OK; error: conn->err = errno; return status; }
static rstatus_t proxy_listen(struct context *ctx, struct conn *p) { rstatus_t status; struct server_pool *pool = p->owner; ASSERT(p->proxy); p->sd = socket(p->family, SOCK_STREAM, 0); if (p->sd < 0) { log_error("socket failed: %s", strerror(errno)); return DN_ERROR; } status = proxy_reuse(p); if (status < 0) { log_error("reuse of addr '%.*s' for listening on p %d failed: %s", pool->addrstr.len, pool->addrstr.data, p->sd, strerror(errno)); return DN_ERROR; } status = bind(p->sd, p->addr, p->addrlen); if (status < 0) { log_error("bind on p %d to addr '%.*s' failed: %s", p->sd, pool->addrstr.len, pool->addrstr.data, strerror(errno)); return DN_ERROR; } status = listen(p->sd, pool->backlog); if (status < 0) { log_error("listen on p %d on addr '%.*s' failed: %s", p->sd, pool->addrstr.len, pool->addrstr.data, strerror(errno)); return DN_ERROR; } status = dn_set_nonblocking(p->sd); if (status < 0) { log_error("set nonblock on p %d on addr '%.*s' failed: %s", p->sd, pool->addrstr.len, pool->addrstr.data, strerror(errno)); return DN_ERROR; } status = event_add_conn(ctx->evb, p); if (status < 0) { log_error("event add conn p %d on addr '%.*s' failed: %s", p->sd, pool->addrstr.len, pool->addrstr.data, strerror(errno)); return DN_ERROR; } status = event_del_out(ctx->evb, p); if (status < 0) { log_error("event del out p %d on addr '%.*s' failed: %s", p->sd, pool->addrstr.len, pool->addrstr.data, strerror(errno)); return DN_ERROR; } return DN_OK; }
static rstatus_t proxy_accept(struct context *ctx, struct conn *p) { rstatus_t status; struct conn *c; int sd; ASSERT(p->proxy && !p->client); ASSERT(p->sd > 0); ASSERT(p->recv_active && p->recv_ready); for (;;) { sd = accept(p->sd, NULL, NULL); if (sd < 0) { if (errno == EINTR) { log_debug(LOG_VERB, "accept on p %d not ready - eintr", p->sd); continue; } if (errno == EAGAIN || errno == EWOULDBLOCK) { log_debug(LOG_VERB, "accept on p %d not ready - eagain", p->sd); p->recv_ready = 0; return DN_OK; } /* * FIXME: On EMFILE or ENFILE mask out IN event on the proxy; mask * it back in when some existing connection gets closed */ log_error("accept on p %d failed: %s", p->sd, strerror(errno)); return DN_ERROR; } break; } c = conn_get(p->owner, true, p->data_store); if (c == NULL) { log_error("get conn for c %d from p %d failed: %s", sd, p->sd, strerror(errno)); status = close(sd); if (status < 0) { log_error("close c %d failed, ignored: %s", sd, strerror(errno)); } return DN_ENOMEM; } c->sd = sd; stats_pool_incr(ctx, c->owner, client_connections); status = dn_set_nonblocking(c->sd); if (status < 0) { log_error("set nonblock on c %d from p %d failed: %s", c->sd, p->sd, strerror(errno)); c->close(ctx, c); return status; } if (p->family == AF_INET || p->family == AF_INET6) { status = dn_set_tcpnodelay(c->sd); if (status < 0) { log_warn("set tcpnodelay on c %d from p %d failed, ignored: %s", c->sd, p->sd, strerror(errno)); } } status = event_add_conn(ctx->evb, c); if (status < 0) { log_error("event add conn from p %d failed: %s", p->sd, strerror(errno)); c->close(ctx, c); return status; } log_debug(LOG_NOTICE, "accepted c %d on p %d from '%s'", c->sd, p->sd, dn_unresolve_peer_desc(c->sd)); return DN_OK; }
static rstatus_t dnode_listen(struct context *ctx, struct conn *p) { rstatus_t status; struct server_pool *pool = p->owner; ASSERT(p->dnode_server); p->sd = socket(p->family, SOCK_STREAM, 0); if (p->sd < 0) { log_error("dyn: socket failed: %s", strerror(errno)); return DN_ERROR; } status = dnode_reuse(p); if (status < 0) { log_error("dyn: reuse of addr '%.*s' for listening on p %d failed: %s", pool->d_addrstr.len, pool->d_addrstr.data, p->sd, strerror(errno)); return DN_ERROR; } status = bind(p->sd, p->addr, p->addrlen); if (status < 0) { log_error("dyn: bind on p %d to addr '%.*s' failed: %s", p->sd, pool->addrstr.len, pool->addrstr.data, strerror(errno)); return DN_ERROR; } status = listen(p->sd, pool->backlog); if (status < 0) { log_error("dyn: listen on p %d on addr '%.*s' failed: %s", p->sd, pool->d_addrstr.len, pool->d_addrstr.data, strerror(errno)); return DN_ERROR; } status = dn_set_nonblocking(p->sd); if (status < 0) { log_error("dyn: set nonblock on p %d on addr '%.*s' failed: %s", p->sd, pool->d_addrstr.len, pool->d_addrstr.data, strerror(errno)); return DN_ERROR; } log_debug(LOG_INFO, "dyn: e %d with nevent %d", ctx->evb->ep, ctx->evb->nevent); status = event_add_conn(ctx->evb, p); if (status < 0) { log_error("dyn: event add conn p %d on addr '%.*s' failed: %s", p->sd, pool->d_addrstr.len, pool->d_addrstr.data, strerror(errno)); return DN_ERROR; } status = event_del_out(ctx->evb, p); if (status < 0) { log_error("dyn: event del out p %d on addr '%.*s' failed: %s", strerror(errno)); return DN_ERROR; } return DN_OK; }