void client_state_machine(Client *client) { int r; Config *config = client->worker->config; start: //printf("state: %d\n", client->state); switch (client->state) { case CLIENT_START: client->worker->stats.req_started++; do { r = socket(config->saddr->ai_family, config->saddr->ai_socktype, config->saddr->ai_protocol); } while (-1 == r && errno == EINTR); if (-1 == r) { client->state = CLIENT_ERROR; strerror_r(errno, client->buffer, sizeof(client->buffer)); W_ERROR("socket() failed: %s (%d)", client->buffer, errno); goto start; } /* set non-blocking */ fcntl(r, F_SETFL, O_NONBLOCK | O_RDWR); ev_init(&client->sock_watcher, client_io_cb); ev_io_set(&client->sock_watcher, r, EV_WRITE); ev_io_start(client->worker->loop, &client->sock_watcher); if (!client_connect(client)) { client->state = CLIENT_ERROR; goto start; } else { client_set_events(client, EV_WRITE); return; } case CLIENT_CONNECTING: if (!client_connect(client)) { client->state = CLIENT_ERROR; goto start; } case CLIENT_WRITING: while (1) { r = write(client->sock_watcher.fd, &config->request[client->request_offset], config->request_size - client->request_offset); //printf("write(%d - %d = %d): %d\n", config->request_size, client->request_offset, config->request_size - client->request_offset, r); if (r == -1) { /* error */ if (errno == EINTR) continue; strerror_r(errno, client->buffer, sizeof(client->buffer)); W_ERROR("write() failed: %s (%d)", client->buffer, errno); client->state = CLIENT_ERROR; goto start; } else if (r != 0) { /* success */ client->request_offset += r; if (client->request_offset == config->request_size) { /* whole request was sent, start reading */ client->state = CLIENT_READING; client_set_events(client, EV_READ); } return; } else { /* disconnect */ client->state = CLIENT_END; goto start; } } case CLIENT_READING: while (1) { r = read(client->sock_watcher.fd, &client->buffer[client->buffer_offset], sizeof(client->buffer) - client->buffer_offset - 1); //printf("read(): %d, offset was: %d\n", r, client->buffer_offset); if (r == -1) { /* error */ if (errno == EINTR) continue; strerror_r(errno, client->buffer, sizeof(client->buffer)); W_ERROR("read() failed: %s (%d)", client->buffer, errno); client->state = CLIENT_ERROR; } else if (r != 0) { /* success */ client->bytes_received += r; client->buffer_offset += r; client->worker->stats.bytes_total += r; if (client->buffer_offset >= sizeof(client->buffer)) { /* too big response header */ client->state = CLIENT_ERROR; break; } client->buffer[client->buffer_offset] = '\0'; //printf("buffer:\n==========\n%s\n==========\n", client->buffer); if (!client_parse(client, r)) { client->state = CLIENT_ERROR; //printf("parser failed\n"); break; } else { if (client->state == CLIENT_END) goto start; else return; } } else { /* disconnect */ if (client->parser_state == PARSER_BODY && !client->keepalive && client->status_success && !client->chunked && client->content_length == -1) { client->success = 1; client->state = CLIENT_END; } else { client->state = CLIENT_ERROR; } goto start; } } case CLIENT_ERROR: //printf("client error\n"); client->worker->stats.req_error++; client->keepalive = 0; client->success = 0; client->state = CLIENT_END; case CLIENT_END: /* update worker stats */ client->worker->stats.req_done++; if (client->success) { client->worker->stats.req_success++; client->worker->stats.bytes_body += client->bytes_received - client->header_size; } else { client->worker->stats.req_failed++; } /* print progress every 10% done */ if (client->worker->id == 1 && client->worker->stats.req_done % client->worker->progress_interval == 0) { fprintf(stderr, "progress: %3d%% done\n", (int) (client->worker->stats.req_done * 100 / client->worker->stats.req_todo) ); } if (client->worker->stats.req_started == client->worker->stats.req_todo) { /* this worker has started all requests */ client->keepalive = 0; client_reset(client); if (client->worker->stats.req_done == client->worker->stats.req_todo) { /* this worker has finished all requests */ ev_unref(client->worker->loop); } } else { client_reset(client); goto start; } } }
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 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; }
void uv__io_set(uv__io_t* handle, uv__io_cb cb, int fd, int events) { ev_io_set(&handle->io_watcher, fd, events); uv__io_set_cb(handle, cb); }
void client_read_write(EV_P_ struct ev_io *io, int revents) { server_ctx_t *srv_ctx = (server_ctx_t *) ev_userdata(loop); client_ctx_t *cli_ctx = (client_ctx_t *) (((io_with_cctx_t*) io)->ctx); if (revents & EV_READ) { while (1) { if (cli_ctx->r_ctx.read_buff_length == cli_ctx->r_ctx.read_buff_pos) { char *new_buff = realloc(cli_ctx->r_ctx.read_buff, cli_ctx->r_ctx.read_buff_length + 1024); if (!new_buff) break; cli_ctx->r_ctx.read_buff = new_buff; cli_ctx->r_ctx.read_buff_length += 1024; } ssize_t readed = read(io->fd, &cli_ctx->r_ctx.read_buff[cli_ctx->r_ctx.read_buff_pos], cli_ctx->r_ctx.read_buff_length - cli_ctx->r_ctx.read_buff_pos); if (readed > 0) { cli_ctx->r_ctx.read_buff_pos += readed; for (; cli_ctx->r_ctx.parser_pos < cli_ctx->r_ctx.read_buff_pos - 1; cli_ctx->r_ctx.parser_pos++) { if ((cli_ctx->r_ctx.read_buff[cli_ctx->r_ctx.parser_pos] == '\r')&&(cli_ctx->r_ctx.read_buff[cli_ctx->r_ctx.parser_pos + 1] == '\n')) { if (cli_ctx->r_ctx.parser_pos - cli_ctx->r_ctx.prev_parser_pos > 0) on_client_message(loop, srv_ctx, cli_ctx, &cli_ctx->r_ctx.read_buff[cli_ctx->r_ctx.prev_parser_pos], cli_ctx->r_ctx.parser_pos - cli_ctx->r_ctx.prev_parser_pos + 2); cli_ctx->r_ctx.parser_pos++; cli_ctx->r_ctx.prev_parser_pos = cli_ctx->r_ctx.parser_pos + 1; } } if (cli_ctx->r_ctx.prev_parser_pos >= 1024) { size_t need_to_free = cli_ctx->r_ctx.prev_parser_pos / 1024 * 1024; size_t need_to_alloc = cli_ctx->r_ctx.read_buff_length - need_to_free; char *new_buf = (char *) malloc(need_to_alloc); if (!new_buf) break; memcpy(new_buf, &cli_ctx->r_ctx.read_buff[need_to_free], need_to_alloc); free(cli_ctx->r_ctx.read_buff); cli_ctx->r_ctx.read_buff = new_buf; cli_ctx->r_ctx.prev_parser_pos -= need_to_free; cli_ctx->r_ctx.parser_pos -= need_to_free; cli_ctx->r_ctx.read_buff_pos -= need_to_free; cli_ctx->r_ctx.read_buff_length = need_to_alloc; } } else if (readed < 0) { if (errno == EAGAIN) break; if (errno == EINTR) continue; return; } else { char time_buff[32]; time_t now = time(NULL); strftime(time_buff, sizeof (time_buff), "%Y-%m-%d %H:%M:%S %Z", localtime(&now)); char *addr = inet_ntoa(cli_ctx->client_addr.sin_addr); char uuid_buff[37]; uuid_unparse_lower(cli_ctx->uuid, (char *) &uuid_buff); printf("client closed connection %s:%hu %s at %s\n", addr, cli_ctx->client_addr.sin_port, &uuid_buff, &time_buff); char *disconnected_client_msg = server_client_disconnected(cli_ctx); for (ssize_t i = 0; i < srv_ctx->clients_count; i++) { if (uuid_compare(srv_ctx->clients[i]->uuid, cli_ctx->uuid) != 0) { send_message(loop, srv_ctx->clients[i]->uuid, disconnected_client_msg, strlen(disconnected_client_msg)); } } free(disconnected_client_msg); close_client(loop, cli_ctx); return; } } } if (revents & EV_WRITE) { write_ctx_t *w_ctx = &cli_ctx->w_ctx; message_buff_t *buffs = &w_ctx->buffs[0]; while (w_ctx->buffs_count > 0) { while (buffs[0].data_pos < buffs[0].data_length) { ssize_t writed = write(io->fd, &buffs[0].data[buffs->data_pos], buffs[0].data_length - buffs[0].data_pos); if (writed > 0) { buffs[0].data_pos += writed; } else { if (errno == EAGAIN) break; if (errno == EINTR) continue; break; } } if (buffs[0].data_pos == buffs[0].data_length) { free(buffs[0].data); memmove(&buffs[0], &buffs[1], sizeof (message_buff_t) * (w_ctx->buffs_count - 1)); w_ctx->buffs_count--; } else { break; } } if (w_ctx->buffs_count == 0) { ev_io *io = &cli_ctx->io.io; ev_io_stop(loop, io); ev_io_set(io, io->fd, EV_READ); ev_io_start(loop, io); cli_ctx->writing = 0; } } }
struct timeval * run_once(void) { int *cp, i, space; static struct timeval ta, ts, te, tv; gettimeofday(&ta, NULL); // Set up event watches: for (cp = pipes, i = 0; i < num_pipes; i++, cp += 2) { if (native) { #if NATIVE //if (ev_is_active (&evio [i])) // ev_io_stop (&evio [i]); ev_io_set (&io_blocks[i].io, cp [0], EV_READ); ev_io_start (EV_DEFAULT_UC_ &io_blocks[i].io); io_blocks[i].timer.repeat = 10. + drand48 (); ev_timer_again (EV_DEFAULT_UC_ &io_blocks[i].timer); #else abort (); #endif } else { event_set(&io_blocks[i].event, cp[0], EV_READ | EV_PERSIST, read_cb, &io_blocks[i]); if (set_prios) { event_priority_set(&io_blocks[i].event, drand48() * EV_MAXPRI); } if (timers) { tv.tv_sec = 10.; tv.tv_usec = drand48() * 1e6; } event_add(&io_blocks[i].event, timers ? &tv : 0); } } event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); // Make the chosen number of descriptors active: fired = 0; space = num_pipes / num_active; space = space * 2; for (i = 0; i < num_active; i++, fired++) { write(pipes[i * space + 1], "e", 1); } count = 0; writes = num_writes - fired; { int xcount = 0; gettimeofday(&ts, NULL); do { event_loop(EVLOOP_ONCE | EVLOOP_NONBLOCK); xcount++; } while (count != num_writes); gettimeofday(&te, NULL); //if (xcount != count) fprintf(stderr, "Xcount: %d, Rcount: %d\n", xcount, count); } timersub(&te, &ta, &ta); timersub(&te, &ts, &ts); fprintf(stdout, "%8ld %8ld\n", ta.tv_sec * 1000000L + ta.tv_usec, ts.tv_sec * 1000000L + ts.tv_usec); cp = pipes; for (int j = 0; j < num_pipes; j++, cp += 2) { if (native) { #if NATIVE ev_io_stop(EV_DEFAULT_UC_ &io_blocks[j].io); #endif } else { event_del(&io_blocks[j].event); event_set(&io_blocks[j].event, cp[0], EV_READ | EV_PERSIST, read_cb, &io_blocks[j]); } } return (&te); }
void server_generic_notify_write_disable(server_generic_client_t *client) { ev_io_stop(manager_event_loop, &client->evio); ev_io_set(&client->evio, (int) prelude_io_get_fd(client->fd), EV_READ); ev_io_start(manager_event_loop, &client->evio); }
int WatcherNoticePipe::Open (void * arg) { ev_io_set(&m_watcher, m_readFD, EV_READ); StartWatcher(); return 0; }
// This callback is called when data is readable on the unix socket. void evn_stream_priv_on_read(EV_P_ ev_io *w, int revents) { void* data; struct evn_exception error; int length; struct evn_stream* stream = (struct evn_stream*) w; char recv_data[EVN_MAX_RECV]; evn_debugs("EV_READ - stream->io.fd"); length = recv(stream->io.fd, &recv_data, EVN_MAX_RECV, 0); if (length < 0) { if (stream->on_error) { stream->on_error(EV_A_ stream, &error); } } else if (0 == length) { evn_debugs("received FIN"); // We no longer have data to read but we may still have data to write stream->ready_state = evn_WRITE_ONLY; if (stream->io.events & EV_WRITE) { int fd = stream->io.fd; ev_io_stop(EV_A_ &stream->io); ev_io_set(&stream->io, fd, EV_WRITE); ev_io_start(EV_A_ &stream->io); } else { ev_io_stop(EV_A_ &stream->io); } if (stream->oneshot) { evn_debugs("oneshot shot"); // TODO put on stack char data[stream->bufferlist->used]; if (stream->bufferlist->used) { evn_buffer* buffer = evn_bufferlist_concat(stream->bufferlist); if (stream->on_data) { stream->on_data(EV_A_ stream, buffer->data, buffer->used); } free(buffer); // does not free buffer->data, that's up to the user } } if (stream->on_end) { stream->on_end(EV_A_ stream); } // evn_stream_destroy(EV_A_ stream); } else if (length > 0) { if (stream->oneshot) { evn_debugs("adding to buffer"); // if (stream->on_progress) { stream->on_progress(EV_A_ stream, data, length); } // if time - stream->started_at > stream->max_wait; stream->timeout(); // if buffer->used > stream->max_size; stream->timeout(); evn_bufferlist_add(stream->bufferlist, &recv_data, length); return; } data = malloc(length); memcpy(data, &recv_data, length); if (stream->on_data) { stream->on_data(EV_A_ stream, recv_data, length); } } }