void echo_client_wcb_send(EV_P_ ev_io *w, int tev) { int sent_nb; echo_client_t *c = aux_memberof(echo_client_t, wev_send, w); sent_nb = aux_unix_send(w->fd, c->to_send_beg, c->to_send_size); /* sent_nb = aux_unix_send(w->fd, OUTPUT, sizeof(OUTPUT) - 1); */ /* fprintf(stderr, "sent %d bytes (%d: %s)\n", sent_nb, errno, strerror(errno)); */ if (0 > sent_nb) { if (EAGAIN == errno) { return; } fprintf(stderr, "send error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); echo_client_del(c); return; } c->to_send_beg += sent_nb; c->to_send_size -= sent_nb; if (c->to_send_size > 0) { return; } ev_io_stop(loop, &c->wev_send); }
static void ugh_subreq_wcb_connect(EV_P_ ev_io *w, int tev) { ugh_subreq_t *r = aux_memberof(ugh_subreq_t, wev_connect, w); if (EV_READ & tev) { int optval = 0; socklen_t optlen = sizeof(optval); if (0 > getsockopt(w->fd, SOL_SOCKET, SO_ERROR, &optval, &optlen)) { optval = errno; } ugh_subreq_del(r, UGH_UPSTREAM_FT_ERROR, optval); return; } ev_io_stop(loop, &r->wev_connect); ev_timer_stop(loop, &r->wev_timeout_connect); r->connection_time = ev_now(loop) - r->response_time; ev_io_start(loop, &r->wev_send); }
void echo_server_wcb_accept(EV_P_ ev_io *w, int tev) { int sd, rc; struct sockaddr_in addr; socklen_t addrlen; echo_server_t *s = aux_memberof(echo_server_t, wev_accept, w); addrlen = sizeof(addr); pthread_mutex_lock(&accept_mtx); sd = accept(w->fd, (struct sockaddr *) &addr, &addrlen); pthread_mutex_unlock(&accept_mtx); /* fprintf(stderr, "accept in thread=%d fd=%d (%d: %s)\n", (int) pthread_self(), sd, errno, strerror(errno)); */ if (0 > sd) { return; } if (0 > (rc = aux_set_nonblk(sd, 1))) { return; } #if 0 if (0 > (rc = aux_set_sckopt(sd, IPPROTO_TCP, TCP_NODELAY, 1))) { fprintf(stderr, "sockopt TCP_NODELAY error\n"); } #endif echo_client_add(s, sd, &addr); }
void wcb_recv(EV_P_ ev_io *w, int tev) { client_t *c = aux_memberof(client_t, wev_recv, w); char buf [4096]; int nb = aux_unix_recv(w->fd, buf, 4096); double time = ev_now(loop) - c->ts; times_sum += time; times_count++; if (times_max < time) times_max = time; if (times_min > time) times_min = time; /* fprintf(stderr, "recv fd=%d %f (%d bytes) %.*s\n", w->fd, ev_now(loop) - c->ts, nb, nb, buf); */ /* if (nb != 57) fprintf(stderr, "recv error %d bytes\n", nb); */ if (0 > nb) { if (errno == EAGAIN) { return; } fprintf(stderr, "recv error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); client_del(c); return; } }
void wcb_send(EV_P_ ev_io *w, int tev) { client_t *c = aux_memberof(client_t, wev_send, w); for (; c->to_send; c->to_send--) { int rc = client_send(c); if (0 > rc) return; } ev_io_stop(loop, &c->wev_send); }
void wcb_timeout(EV_P_ ev_timer *w, int tev) { client_t *c = aux_memberof(client_t, wev_timeout, w); c->to_send++; ev_io_start(loop, &c->wev_send); #if 0 int rc = client_send(c); if (0 > rc) return; #endif }
static void ugh_subreq_wcb_send(EV_P_ ev_io *w, int tev) { int rc; ugh_subreq_t *r = aux_memberof(ugh_subreq_t, wev_send, w); /* errno = 0; */ rc = aux_unix_send(w->fd, r->b_send.data + r->b_send.rpos, r->b_send.wpos - r->b_send.rpos); log_debug("subreq send: %d: %.*s", rc, (int) (r->b_send.wpos - r->b_send.rpos), r->b_send.data + r->b_send.rpos); if (0 > rc) { log_warn("send error %.*s%s%.*s (%d: %s)", (int) r->u.uri.size, r->u.uri.data, r->u.args.size ? "?" : "", (int) r->u.args.size, r->u.args.data, errno, aux_strerror(errno)); ugh_subreq_del(r, UGH_UPSTREAM_FT_ERROR); return; } /* log_debug("send %d bytes", rc); */ if (0 == rc) { return; } if (UGH_TIMEOUT_ONCE == r->timeout_type) { ev_timer_again(loop, &r->wev_timeout); } r->b_send.rpos += rc; if (r->b_send.rpos == r->b_send.wpos) { ev_io_stop(loop, &r->wev_send); ev_io_start(loop, &r->wev_recv); return; } }
void wcb_connect(EV_P_ ev_io *w, int tev) { client_t *c = aux_memberof(client_t, wev_connect, w); if (EV_READ & tev) { fprintf(stderr, "conn error fd=%d\n", w->fd); client_del(c); return; } #if 0 int rc = client_send(c); if (0 > rc) return; #endif c->to_send = 1; ev_io_stop(loop, &c->wev_connect); ev_io_start(loop, &c->wev_send); ev_io_start(loop, &c->wev_recv); }
static void ugh_subreq_wcb_connect(EV_P_ ev_io *w, int tev) { ugh_subreq_t *r = aux_memberof(ugh_subreq_t, wev_connect, w); if (EV_READ & tev) { int optval = 0; socklen_t optlen = sizeof(optval); if (0 > getsockopt(w->fd, SOL_SOCKET, SO_ERROR, &optval, &optlen)) { optval = errno; } log_warn("conn error %.*s%s%.*s (%d: %s)", (int) r->u.uri.size, r->u.uri.data, r->u.args.size ? "?" : "", (int) r->u.args.size, r->u.args.data, optval, aux_strerror(optval)); ugh_subreq_del(r, UGH_UPSTREAM_FT_ERROR); return; } ev_io_stop(loop, &r->wev_connect); ev_io_start(loop, &r->wev_send); }
void ugh_wcb_silent(EV_P_ ev_timer *w, int tev) { if (0 != aux_terminate) { ev_timer_stop(EV_A_ w); ev_break(EV_A_ EVBREAK_ALL); return; } if (0 != aux_rotatelog) { ugh_daemon_t *d; aux_rotatelog = 0; d = aux_memberof(ugh_daemon_t, wev_silent, w); if (-1 == log_rotate(d->cfg.log_error)) { log_warn("log_rotate(%s) (%d: %s)", d->cfg.log_error, errno, aux_strerror(errno)); } } }
static void ugh_subreq_wcb_recv(EV_P_ ev_io *w, int tev) { ugh_subreq_t *r = aux_memberof(ugh_subreq_t, wev_recv, w); /* errno = 0; */ int nb = aux_unix_recv(w->fd, r->buf_recv.data, r->buf_recv.size); log_debug("subreq recv: %d: %.*s", nb, nb, r->buf_recv.data); if (0 == nb) { if (r->content_length != UGH_RESPONSE_CLOSE_AFTER_BODY) { /* * NOTE: recv(2) will never fail with EPIPE, so I'm using it here * to get meaningful error message in ugh_subreq_del' */ log_warn("upstream prematurely closed connection"); ugh_subreq_del(r, UGH_UPSTREAM_FT_ERROR, EPIPE); } else { ugh_subreq_del(r, UGH_UPSTREAM_FT_OFF, 0); } return; } if (0 > nb) { if (EAGAIN == errno) { if (UGH_TIMEOUT_ONCE == r->timeout_type) { ev_timer_again(loop, &r->wev_timeout); } return; } ugh_subreq_del(r, UGH_UPSTREAM_FT_ERROR, errno); return; } r->buf_recv.data += nb; r->buf_recv.size -= nb; if (UGH_TIMEOUT_ONCE == r->timeout_type) { ev_timer_again(loop, &r->wev_timeout); } if (NULL == r->body.data) { int status = ugh_parser_subreq(r, r->buf_recv.data - nb, nb); if (UGH_AGAIN == status) { return; } if (UGH_ERROR == status) { ugh_subreq_del(r, UGH_UPSTREAM_FT_INVALID_HEADER, 0); return; } ugh_header_t *hdr_content_length = ugh_subreq_header_get_nt(r, "Content-Length"); if (0 != hdr_content_length->value.size) { r->content_length = atoi(hdr_content_length->value.data); if (r->content_length > r->buf_recv.size + (r->buf_recv.data - r->request_end)) { r->body.data = aux_pool_nalloc(r->c->pool, r->content_length); r->body.size = r->buf_recv.data - r->request_end; memcpy(r->body.data, r->request_end, r->body.size); r->buf_recv.data = r->body.data + r->body.size; r->buf_recv.size = r->content_length - r->body.size; } else { r->body.data = r->request_end; r->body.size = r->buf_recv.data - r->request_end; } } else { ugh_header_t *hdr_transfer_encoding = ugh_subreq_header_get_nt(r, "Transfer-Encoding"); if (7 == hdr_transfer_encoding->value.size && 0 == strncmp(hdr_transfer_encoding->value.data, "chunked", 7)) { r->content_length = UGH_RESPONSE_CHUNKED; r->chunk_body_size = UGH_CHUNKS_BUF; r->body.data = aux_pool_nalloc(r->c->pool, r->chunk_body_size); r->body.size = 0; char *next_chunk = r->request_end; for (;;) { status = ugh_parser_chunks(r, next_chunk, r->buf_recv.data - next_chunk); if (UGH_AGAIN == status) { r->buf_recv.size += r->buf_recv.data - r->request_end; r->buf_recv.data = r->request_end; r->chunk_start = 0; return; } if (UGH_ERROR == status) { ugh_subreq_del(r, UGH_UPSTREAM_FT_INVALID_HEADER, 0); return; } if (0 == r->chunk_size) { ugh_subreq_del(r, UGH_UPSTREAM_FT_OFF, 0); return; } size_t recv_len = r->buf_recv.data - r->chunk_start; if (r->chunk_size > recv_len) { ugh_subreq_copy_chunk(r, r->chunk_start, recv_len); r->chunk_size -= recv_len; r->buf_recv.size += r->buf_recv.data - r->request_end; r->buf_recv.data = r->request_end; r->chunk_start = r->buf_recv.data; break; } else { ugh_subreq_copy_chunk(r, r->chunk_start, r->chunk_size); next_chunk = r->chunk_start + r->chunk_size; r->chunk_size = 0; r->chunk_start = 0; } } } else /* http/1.0 close after body response */ { r->content_length = UGH_RESPONSE_CLOSE_AFTER_BODY; r->body.data = r->request_end; r->body.size = r->buf_recv.data - r->request_end; if (r->buf_recv.size == 0) { char *old_body = r->body.data; r->body.data = aux_pool_nalloc(r->c->pool, r->body.size * 2); memcpy(r->body.data, old_body, r->body.size); r->buf_recv.data = r->body.data + r->body.size; r->buf_recv.size = r->body.size; } } } } else if (r->content_length == UGH_RESPONSE_CHUNKED) { for (;;) { char *next_chunk = r->buf_recv.data - nb; if (r->chunk_start) { size_t recv_len = r->buf_recv.data - r->chunk_start; if (r->chunk_size > recv_len) { ugh_subreq_copy_chunk(r, r->chunk_start, recv_len); r->chunk_size -= recv_len; r->buf_recv.data -= nb; r->buf_recv.size += nb; r->chunk_start = r->buf_recv.data; break; } else { ugh_subreq_copy_chunk(r, r->chunk_start, r->chunk_size); next_chunk = r->chunk_start + r->chunk_size; r->chunk_size = 0; } } int status = ugh_parser_chunks(r, next_chunk, r->buf_recv.data - next_chunk); if (UGH_AGAIN == status) { r->buf_recv.data -= nb; r->buf_recv.size += nb; r->chunk_start = 0; return; } if (UGH_ERROR == status) { ugh_subreq_del(r, UGH_UPSTREAM_FT_INVALID_HEADER, 0); return; } if (0 == r->chunk_size) { ugh_subreq_del(r, UGH_UPSTREAM_FT_OFF, 0); } } } else if (r->content_length == UGH_RESPONSE_CLOSE_AFTER_BODY) { r->body.size += nb; if (r->buf_recv.size == 0) { char *old_body = r->body.data; r->body.data = aux_pool_nalloc(r->c->pool, r->body.size * 2); memcpy(r->body.data, old_body, r->body.size); r->buf_recv.data = r->body.data + r->body.size; r->buf_recv.size = r->body.size; } } else { r->body.size += nb; } if (r->body.size == r->content_length) { uint32_t ft_type = UGH_UPSTREAM_FT_OFF; switch (r->status) { case 400: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 401: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 402: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 403: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 404: ft_type = UGH_UPSTREAM_FT_HTTP_404; break; case 405: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 406: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 407: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 408: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 409: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 410: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 411: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 412: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 413: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 414: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 415: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 416: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 417: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 500: ft_type = UGH_UPSTREAM_FT_HTTP_500; break; case 501: ft_type = UGH_UPSTREAM_FT_HTTP_5XX; break; case 502: ft_type = UGH_UPSTREAM_FT_HTTP_502; break; case 503: ft_type = UGH_UPSTREAM_FT_HTTP_503; break; case 504: ft_type = UGH_UPSTREAM_FT_HTTP_504; break; case 505: ft_type = UGH_UPSTREAM_FT_HTTP_5XX; break; case 506: ft_type = UGH_UPSTREAM_FT_HTTP_5XX; break; case 507: ft_type = UGH_UPSTREAM_FT_HTTP_5XX; break; } ugh_subreq_del(r, ft_type, 0); } }
void echo_client_wcb_recv(EV_P_ ev_io *w, int tev) { int nb; echo_client_t *c = aux_memberof(echo_client_t, wev_recv, w); int rem_size = c->to_send + TO_SEND_SIZE - (c->to_send_beg + c->to_send_size); if (rem_size < 32) { /* fprintf(stderr, "rem_size=%d, c->to_send_size=%u, fd=%d\n", rem_size, (unsigned) c->to_send_size, w->fd); */ memcpy(c->to_send, c->to_send_beg, c->to_send_size); c->to_send_beg = c->to_send; rem_size = TO_SEND_SIZE - c->to_send_size; /* fprintf(stderr, "rem_size=%d\n", rem_size); */ } nb = aux_unix_recv(w->fd, c->to_send_beg + c->to_send_size, rem_size); /* fprintf(stderr, "recv %d bytes (%d: %s) %.*s\n", nb, errno, strerror(errno), nb, buf); */ if (0 > nb) { if (EAGAIN == errno) { ev_timer_again(loop, &c->wev_timeout); return; } fprintf(stderr, "recv error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); echo_client_del(c); return; } if (0 == nb) { /* fprintf(stderr, "recv done fd=%d\n", w->fd); */ /* echo_client_del(c); */ return; } c->to_send_size += nb; int sent_nb; sent_nb = aux_unix_send(w->fd, c->to_send_beg, c->to_send_size); /* nb = aux_unix_send(w->fd, OUTPUT, sizeof(OUTPUT) - 1); */ /* fprintf(stderr, "sent %d bytes (%d: %s)\n", nb, errno, strerror(errno)); */ if (0 > sent_nb) { if (EAGAIN == errno) { ev_io_start(loop, &c->wev_send); return; } fprintf(stderr, "send error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); echo_client_del(c); return; } c->to_send_beg += sent_nb; c->to_send_size -= sent_nb; if (c->to_send_size > 0) { ev_io_start(loop, &c->wev_send); return; } #if 0 nb = aux_unix_send(w->fd, buf, nb); /* fprintf(stderr, "sent %d bytes (%d: %s)\n", nb, errno, strerror(errno)); */ if (0 > nb) { fprintf(stderr, "send error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); echo_client_del(c); return; } ev_timer_again(loop, &c->wev_timeout); #endif }
static void ugh_client_wcb_timeout(EV_P_ ev_timer *w, int tev) { ugh_client_t *c = aux_memberof(ugh_client_t, wev_timeout, w); ugh_client_del(c); }
static void ugh_client_wcb_send(EV_P_ ev_io *w, int tev) { int rc; ugh_client_t *c = aux_memberof(ugh_client_t, wev_send, w); if (0 == c->buf_send.size) { ugh_client_del(c); return; } if (NULL == c->iov) { c->iov_num = ugh_module_handles_size + 1; c->iov = aux_pool_malloc(c->pool, c->iov_num * sizeof(c->iov[0])); if (NULL == c->iov) { ugh_client_del(c); return; } c->iov[0].iov_base = c->buf_send.data; c->iov[0].iov_len = c->buf_send.size; size_t i; for (i = 0; i < c->iov_num - 1; ++i) { c->iov[i+1].iov_base = c->bufs[i].data; c->iov[i+1].iov_len = c->bufs[i].size; } } rc = writev(w->fd, c->iov, c->iov_num); log_debug("client send: %d: %.*s", rc, (int) c->iov[0].iov_len, (char *) c->iov[0].iov_base); if (0 > rc) { log_warn("err writev(%d,%d) (%d: %s)", w->fd, rc, errno, aux_strerror(errno)); ugh_client_del(c); return; } /* log_debug("end writev(%d,%d)", w->fd, rc); */ if (0 == rc) { return; } size_t i; for (i = 0; i < c->iov_num; ++i) { if (rc < c->iov[i].iov_len) { c->iov[i].iov_base += rc; c->iov[i].iov_len -= rc; c->iov += i; c->iov_num -= i; /* TODO send timeout */ return; } rc -= c->iov[i].iov_len; } ugh_client_del(c); }
static void ugh_subreq_wcb_timeout_connect(EV_P_ ev_timer *w, int tev) { ugh_subreq_t *r = aux_memberof(ugh_subreq_t, wev_timeout_connect, w); ugh_subreq_del(r, UGH_UPSTREAM_FT_TIMEOUT_CONNECT, 0); }
void echo_client_wcb_timeout(EV_P_ ev_timer *w, int tev) { echo_client_t *c = aux_memberof(echo_client_t, wev_timeout, w); echo_client_del(c); }
static void ugh_client_wcb_recv(EV_P_ ev_io *w, int tev) { int nb; ugh_client_t *c = aux_memberof(ugh_client_t, wev_recv, w); nb = aux_unix_recv(w->fd, c->buf_recv.data, c->buf_recv.size); log_debug("client recv: %d: %.*s", nb, nb, c->buf_recv.data); if (0 == nb) { ugh_client_del(c); return; } if (0 > nb) { if (EAGAIN == errno) { ev_timer_again(loop, &c->wev_timeout); return; } ugh_client_del(c); return; } c->buf_recv.data += nb; c->buf_recv.size -= nb; ev_timer_again(loop, &c->wev_timeout); if (NULL == c->request_end) { int status = ugh_parser_client(c, c->buf_recv.data - nb, nb); if (UGH_AGAIN == status) { return; } if (UGH_HTTP_BAD_REQUEST <= status) { ugh_client_send(c, status); return; } if (UGH_HTTP_POST == c->method) { ugh_header_t *hdr_content_length = ugh_client_header_get_nt(c, "Content-Length"); if (0 != hdr_content_length->value.size) { c->content_length = atoi(hdr_content_length->value.data); if (c->content_length > (c->buf_recv.size + (c->buf_recv.data - c->request_end))) { c->body.data = aux_pool_nalloc(c->pool, c->content_length); c->body.size = c->buf_recv.data - c->request_end; memcpy(c->body.data, c->request_end, c->body.size); c->buf_recv.data = c->body.data + c->body.size; c->buf_recv.size = c->content_length - c->body.size; } else { c->body.data = c->request_end; c->body.size = c->buf_recv.data - c->request_end; } if (c->body.size < c->content_length) { return; } } } } else if (UGH_HTTP_POST == c->method) { c->body.size += nb; if (c->body.size < c->content_length) { return; } } ev_io_stop(loop, &c->wev_recv); ev_timer_stop(loop, &c->wev_timeout); #if 1 /* prepare post args */ ugh_header_t *hdr_content_type = ugh_client_header_get_nt(c, "Content-Type"); if (sizeof("application/x-www-form-urlencoded") - 1 == hdr_content_type->value.size && 0 == strncmp(hdr_content_type->value.data, "application/x-www-form-urlencoded", hdr_content_type->value.size)) { ugh_parser_client_body(c, c->body.data, c->body.size); } #endif #if 1 /* UGH_CORO ENABLE */ c->stack = aux_pool_malloc(c->pool, UGH_CORO_STACK); if (NULL == c->stack) { ugh_client_send(c, UGH_HTTP_INTERNAL_SERVER_ERROR); return; } coro_create(&c->ctx, ugh_client_ccb_handle, c, c->stack, UGH_CORO_STACK, &ctx_main); is_main_coro = 0; coro_transfer(&ctx_main, &c->ctx); is_main_coro = 1; #endif #if 0 /* UGH_CORO DISABLE */ ugh_client_ccb_handle(c); #endif }