コード例 #1
0
ファイル: connection.c プロジェクト: angel1991521/lighttpd2
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);
}
コード例 #2
0
ファイル: memcached.c プロジェクト: AlexShiLucky/lighttpd2
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);
}
コード例 #3
0
ファイル: mod_proxy.c プロジェクト: soarpenguin/lighttpd2
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;
}
コード例 #4
0
ファイル: memcached.c プロジェクト: AlexShiLucky/lighttpd2
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);
	}
}
コード例 #5
0
ファイル: mod_fastcgi.c プロジェクト: soarpenguin/lighttpd2
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;
}