Example #1
0
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;
			}
	}
}
Example #2
0
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;
}
Example #3
0
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;
}
Example #4
0
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);
}
Example #5
0
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;
        }


    }
}
Example #6
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);
}
Example #8
0
int WatcherNoticePipe::Open (void * arg)
{
    ev_io_set(&m_watcher, m_readFD, EV_READ);
    StartWatcher();
    return 0;
}
Example #9
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); }
  }
}