void li_connection_start(liConnection *con, liSocketAddress remote_addr, int s, liServerSocket *srv_sock) { LI_FORCE_ASSERT(NULL == con->con_sock.data); con->srv_sock = srv_sock; con->state = LI_CON_STATE_REQUEST_START; con->mainvr->ts_started = con->ts_started = li_cur_ts(con->wrk); con->info.remote_addr = remote_addr; li_sockaddr_to_string(remote_addr, con->info.remote_addr_str, FALSE); con->info.local_addr = li_sockaddr_dup(srv_sock->local_addr); li_sockaddr_to_string(con->info.local_addr, con->info.local_addr_str, FALSE); con->info.aborted = FALSE; li_stream_init(&con->in, &con->wrk->loop, _connection_http_in_cb); li_stream_init(&con->out, &con->wrk->loop, _connection_http_out_cb); con->info.req = &con->in; con->info.resp = &con->out; li_connection_update_io_wait(con); if (srv_sock->new_cb) { if (!srv_sock->new_cb(con, s)) { li_connection_error(con); return; } } else { simple_tcp_new(con, s); } LI_FORCE_ASSERT(NULL != con->con_sock.raw_in || NULL != con->con_sock.raw_out); li_chunkqueue_use_limit(con->con_sock.raw_in->out, LI_CONNECTION_DEFAULT_CHUNKQUEUE_LIMIT); li_chunkqueue_use_limit(con->con_sock.raw_out->out, LI_CONNECTION_DEFAULT_CHUNKQUEUE_LIMIT); li_stream_connect(&con->out, con->con_sock.raw_out); li_stream_connect(con->con_sock.raw_in, &con->in); li_chunk_parser_init(&con->req_parser_ctx.chunk_ctx, con->con_sock.raw_in->out); }
static void memcached_io_cb(liEventBase *watcher, int events) { liMemcachedCon *con = LI_CONTAINER_OF(li_event_io_from(watcher), liMemcachedCon, con_watcher); if (1 == g_atomic_int_get(&con->refcount) && li_event_active(&con->con_watcher)) { memcached_stop_io(con); return; } if (-1 == con->fd) { memcached_connect(con); return; } li_memcached_con_acquire(con); /* make sure con isn't freed in the middle of something */ if (events & LI_EV_WRITE) { int i; ssize_t written, len; gchar *data; send_item *si; si = g_queue_peek_head(&con->out); for (i = 0; si && (i < 10); i++) { /* don't send more than 10 chunks */ data = si->buf->addr + si->pos; len = si->len; written = write(li_event_io_fd(&con->con_watcher), data, len); if (written < 0) { switch (errno) { case EINTR: continue; case EAGAIN: #if EWOULDBLOCK != EAGAIN case EWOULDBLOCK: #endif goto write_eagain; default: /* Fatal error, connection has to be closed */ g_clear_error(&con->err); g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Couldn't write socket '%s': %s", li_sockaddr_to_string(con->addr, con->tmpstr, TRUE)->str, g_strerror(errno)); close_con(con); goto out; } } else { si->pos += written; si->len -= written; if (0 == si->len) { send_queue_item_free(si); g_queue_pop_head(&con->out); si = g_queue_peek_head(&con->out); } } } write_eagain: send_queue_clean(&con->out); } if (events & LI_EV_READ) { do { handle_read(con); } while (con->remaining && con->remaining->used > 0); } out: memcached_update_io(con); li_memcached_con_release(con); }
static liHandlerResult proxy_statemachine(liVRequest *vr, proxy_connection *pcon) { liPlugin *p = pcon->ctx->plugin; switch (pcon->state) { case SS_WAIT_FOR_REQUEST: /* do *not* wait until we have all data */ pcon->state = SS_CONNECT; /* fall through */ case SS_CONNECT: do { pcon->fd = socket(pcon->ctx->socket.addr->plain.sa_family, SOCK_STREAM, 0); } while (-1 == pcon->fd && errno == EINTR); if (-1 == pcon->fd) { if (errno == EMFILE) { li_server_out_of_fds(vr->wrk->srv); } VR_ERROR(vr, "Couldn't open socket: %s", g_strerror(errno)); return LI_HANDLER_ERROR; } li_fd_init(pcon->fd); ev_io_set(&pcon->fd_watcher, pcon->fd, EV_READ | EV_WRITE); ev_io_start(vr->wrk->loop, &pcon->fd_watcher); /* fall through */ case SS_CONNECTING: if (-1 == connect(pcon->fd, &pcon->ctx->socket.addr->plain, pcon->ctx->socket.len)) { switch (errno) { case EINPROGRESS: case EALREADY: case EINTR: pcon->state = SS_CONNECTING; return LI_HANDLER_GO_ON; case EAGAIN: /* backend overloaded */ proxy_close(vr, p); li_vrequest_backend_overloaded(vr); return LI_HANDLER_GO_ON; case EISCONN: break; default: VR_ERROR(vr, "Couldn't connect to '%s': %s", li_sockaddr_to_string(pcon->ctx->socket, vr->wrk->tmp_str, TRUE)->str, g_strerror(errno)); proxy_close(vr, p); li_vrequest_backend_dead(vr); return LI_HANDLER_GO_ON; } } pcon->state = SS_CONNECTED; /* prepare stream */ proxy_send_headers(vr, pcon); /* fall through */ case SS_CONNECTED: proxy_forward_request(vr, pcon); break; case SS_DONE: break; } return LI_HANDLER_GO_ON; }
static void memcached_connect(liMemcachedCon *con) { int s; struct sockaddr addr; socklen_t len; li_tstamp now = li_event_now(li_event_get_loop(&con->con_watcher)); if (-1 != con->fd) return; s = li_event_io_fd(&con->con_watcher); if (-1 == s) { /* reconnect limit */ if (now < con->last_con_start + 1) { if (con->err) { con->err->code = LI_MEMCACHED_DISABLED; } else { g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_DISABLED, "Disabled right now"); } return; } con->last_con_start = now; do { s = socket(con->addr.addr->plain.sa_family, SOCK_STREAM, 0); } while (-1 == s && errno == EINTR); if (-1 == s) { g_clear_error(&con->err); g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Couldn't open socket: %s", g_strerror(errno)); return; } li_fd_init(s); li_event_io_set_fd(&con->con_watcher, s); if (-1 == connect(s, &con->addr.addr->plain, con->addr.len)) { switch (errno) { case EINPROGRESS: case EALREADY: case EINTR: memcached_start_io(con); li_event_io_add_events(&con->con_watcher, LI_EV_READ | LI_EV_WRITE); break; case EISCONN: break; default: g_clear_error(&con->err); g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Couldn't connect to '%s': %s", li_sockaddr_to_string(con->addr, con->tmpstr, TRUE)->str, g_strerror(errno)); close(s); li_event_io_set_fd(&con->con_watcher, -1); break; } } else { /* connect succeeded */ con->fd = s; g_clear_error(&con->err); memcached_update_io(con); } return; } /* create new connection: * see http://www.cyberconf.org/~cynbe/ref/nonblocking-connects.html */ /* Check to see if we can determine our peer's address. */ len = sizeof(addr); if (getpeername(s, &addr, &len) == -1) { /* connect failed; find out why */ int err; len = sizeof(err); #ifdef SO_ERROR if (-1 == getsockopt(s, SOL_SOCKET, SO_ERROR, (void*)&err, &len)) { err = errno; } #else { char ch; errno = 0; read(s, &ch, 1); err = errno; } #endif g_clear_error(&con->err); g_set_error(&con->err, LI_MEMCACHED_ERROR, LI_MEMCACHED_CONNECTION, "Couldn't connect socket to '%s': %s", li_sockaddr_to_string(con->addr, con->tmpstr, TRUE)->str, g_strerror(err)); close(s); memcached_stop_io(con); li_event_io_set_fd(&con->con_watcher, -1); } else { /* connect succeeded */ con->fd = s; g_clear_error(&con->err); memcached_update_io(con); } }
static liHandlerResult fastcgi_statemachine(liVRequest *vr, fastcgi_connection *fcon) { liPlugin *p = fcon->ctx->plugin; switch (fcon->state) { case FS_WAIT_FOR_REQUEST: /* wait until we have either all data or the cqlimit is full */ if (-1 == vr->request.content_length || vr->request.content_length != vr->in->length) { if (0 != li_chunkqueue_limit_available(vr->in)) return LI_HANDLER_GO_ON; } fcon->state = FS_CONNECT; /* fall through */ case FS_CONNECT: do { fcon->fd = socket(fcon->ctx->socket.addr->plain.sa_family, SOCK_STREAM, 0); } while (-1 == fcon->fd && errno == EINTR); if (-1 == fcon->fd) { if (errno == EMFILE) { li_server_out_of_fds(vr->wrk->srv); } else if (errno != g_atomic_int_get(&fcon->ctx->last_errno)) { g_atomic_int_set(&fcon->ctx->last_errno, errno); VR_ERROR(vr, "Couldn't open socket: %s", g_strerror(errno)); } return LI_HANDLER_ERROR; } li_fd_init(fcon->fd); ev_io_set(&fcon->fd_watcher, fcon->fd, EV_READ | EV_WRITE); ev_io_start(vr->wrk->loop, &fcon->fd_watcher); /* fall through */ case FS_CONNECTING: if (-1 == connect(fcon->fd, &fcon->ctx->socket.addr->plain, fcon->ctx->socket.len)) { switch (errno) { case EINPROGRESS: case EALREADY: case EINTR: fcon->state = FS_CONNECTING; return LI_HANDLER_GO_ON; case EAGAIN: /* backend overloaded */ fastcgi_close(vr, p); li_vrequest_backend_overloaded(vr); return LI_HANDLER_GO_ON; case EISCONN: break; default: if (errno != g_atomic_int_get(&fcon->ctx->last_errno)) { g_atomic_int_set(&fcon->ctx->last_errno, errno); VR_ERROR(vr, "Couldn't connect to '%s': %s", li_sockaddr_to_string(fcon->ctx->socket, vr->wrk->tmp_str, TRUE)->str, g_strerror(errno)); } fastcgi_close(vr, p); li_vrequest_backend_dead(vr); return LI_HANDLER_GO_ON; } } g_atomic_int_set(&fcon->ctx->last_errno, 0); fcon->state = FS_CONNECTED; /* prepare stream */ fastcgi_send_begin(fcon); fastcgi_send_env(vr, fcon); /* fall through */ case FS_CONNECTED: fastcgi_forward_request(vr, fcon); break; case FS_DONE: break; } return LI_HANDLER_GO_ON; }