Example #1
0
static void li_memcached_con_free(liMemcachedCon* con) {
	if (!con) return;

	if (-1 != li_event_io_fd(&con->con_watcher)) {
		close(li_event_io_fd(&con->con_watcher));
		li_event_clear(&con->con_watcher);
		con->fd = -1;
	}

	send_queue_reset(&con->out);
	cancel_all_requests(con);

	li_buffer_release(con->buf);
	li_buffer_release(con->line);
	li_buffer_release(con->remaining);
	li_buffer_release(con->data);
	reset_item(&con->curitem);

	li_sockaddr_clear(&con->addr);
	g_string_free(con->tmpstr, TRUE);

	g_clear_error(&con->err);

	g_slice_free(liMemcachedCon, con);
}
Example #2
0
static void proxy_connection_new(liVRequest *vr, liBackendConnection *bcon, proxy_context *ctx) {
	proxy_connection* scon = g_slice_new0(proxy_connection);
	liIOStream *iostream;
	liStream *outplug;
	liStream *http_out;

	proxy_context_acquire(ctx);
	scon->ctx = ctx;
	scon->bcon = bcon;
	iostream = li_iostream_new(vr->wrk, li_event_io_fd(&bcon->watcher), proxy_io_cb, scon);

	/* insert proxy header before actual data */
	outplug = li_stream_plug_new(&vr->wrk->loop);

	li_stream_connect(outplug, &iostream->stream_out);

	proxy_send_headers(vr, outplug->out);
	li_stream_notify_later(outplug);

	http_out = li_stream_http_response_handle(&iostream->stream_in, vr, TRUE, FALSE);

	li_vrequest_handle_indirect(vr, NULL);
	li_vrequest_indirect_connect(vr, outplug, http_out);

	li_iostream_release(iostream);
	li_stream_release(outplug);
	li_stream_release(http_out);
}
Example #3
0
static void close_con(liMemcachedCon *con) {
	if (con->line) con->line->used = 0;
	if (con->remaining) con->remaining->used = 0;
	if (con->data) con->data->used = 0;
	if (con->buf) con->buf->used = 0;
	reset_item(&con->curitem);
	send_queue_reset(&con->out);

	memcached_stop_io(con);
	close(li_event_io_fd(&con->con_watcher));
	con->fd = -1;
	li_event_io_set_fd(&con->con_watcher, -1);
	con->cur_req = NULL;
	cancel_all_requests(con);
	memcached_connect(con);
}
Example #4
0
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);
}
Example #5
0
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);
	}
}
Example #6
0
static void angel_connection_io_cb(liEventBase *watcher, int events) {
	liAngelConnection *acon = LI_CONTAINER_OF(li_event_io_from(watcher), liAngelConnection, fd_watcher);

	if (events | LI_EV_WRITE) {
		GString *out_str;
		int i;
		ssize_t written, len;
		gchar *data;
		gboolean out_queue_empty;
		angel_connection_send_item_t *send_item;
		int fd = li_event_io_fd(&acon->fd_watcher);

		g_mutex_lock(acon->mutex);
			send_item = g_queue_peek_head(acon->out);
		g_mutex_unlock(acon->mutex);

		for (i = 0; send_item && (i < 10); i++) { /* don't send more than 10 chunks */
			switch (send_item->type) {
			case ANGEL_CONNECTION_ITEM_GSTRING:
				out_str = send_item->value.string.buf;
				written = send_item->value.string.pos;
				data = out_str->str + written;
				len = out_str->len - written;
				while (len > 0) {
					written = write(fd, 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 */
							li_event_clear(&acon->out_notify_watcher);
							li_event_clear(&acon->fd_watcher);
							acon->close_cb(acon, NULL); /* TODO: set err */
							return;
						}
					} else {
						data += written;
						len -= written;
						send_item->value.string.pos += written;
					}
				}
				break;

			case ANGEL_CONNECTION_ITEM_FDS:
				while (send_item->value.fds.pos < send_item->value.fds.fds->len) {
					switch (li_send_fd(fd, g_array_index(send_item->value.fds.fds, int, send_item->value.fds.pos))) {
					case  0:
						send_item->value.fds.pos++;
						continue;
					case -1: /* Fatal error, connection has to be closed */
						li_event_clear(&acon->out_notify_watcher);
						li_event_clear(&acon->fd_watcher);
						acon->close_cb(acon, NULL); /* TODO: set err */
						return;
					case -2: goto write_eagain;
					}
				}
				break;
			}

			g_mutex_lock(acon->mutex);
				send_queue_clean(acon->out);
				send_item = g_queue_peek_head(acon->out);
			g_mutex_unlock(acon->mutex);
		}

write_eagain:
		g_mutex_lock(acon->mutex);
		send_queue_clean(acon->out);
		out_queue_empty = (0 == acon->out->length);
		g_mutex_unlock(acon->mutex);

		if (out_queue_empty) li_event_io_rem_events(&acon->fd_watcher, LI_EV_WRITE);
	}