コード例 #1
0
ファイル: proxy.c プロジェクト: fbbs/fbbs
static bool data_received_callback(int fd, int bytes)
{
	connection_t *conn = connections + fd;
	while (bytes > 0) {
		uchar_t buf[4096];
		int rc = file_read(fd, buf,
				bytes >= sizeof(buf) ? sizeof(buf) : bytes);
		if (rc <= 0) {
			return false;
		} else {
			int received = conn->received;
			conn->received += rc;
			if (received < PARCEL_SIZE_LENGTH) {
				for (int i = received; i < PARCEL_SIZE_LENGTH
						&& i < conn->received; ++i) {
					conn->length |= (buf[i - received] << (i * 8));
				}
			}

			if (conn->received >= PARCEL_SIZE_LENGTH
					&& conn->received > conn->length) {
				return false;
			}

			if (conn->client && conn->remote_fd == REMOTE_NULL) {
				conn->remote_fd = assign_server(fd);
			}

			int remain = conn->received < PARCEL_SIZE_LENGTH
					? -1 : conn->length - received;
			if (valid_remote_fd(fd)) {
				file_write(conn->remote_fd, buf,
						remain > 0 && remain < rc ? remain : rc);
			}

			if (conn->received >= PARCEL_SIZE_LENGTH
					&& conn->received == conn->length) {
				conn->received = 0;
				conn->length = 0;
				if (!conn->client && valid_remote_fd(fd)) {
					connections[conn->remote_fd].remote_fd = REMOTE_NULL;
					conn->remote_fd = REMOTE_NULL;
				}
				if (conn->client && conn->remote_fd == REMOTE_BUSY) {
					parcel_t parcel;
					parcel_new(&parcel);
					parcel_write_bool(&parcel, true);
					parcel_flush(&parcel, fd);
					parcel_free(&parcel);
				}
				return true;
			}
		}
		bytes -= rc;
	}
	return bytes == 0;
}
コード例 #2
0
ファイル: backend.c プロジェクト: Chilledheart/haproxy
/* This function assigns a server to session <s> if required, and can add the
 * connection to either the assigned server's queue or to the proxy's queue.
 * If ->srv_conn is set, the session is first released from the server.
 * It may also be called with SN_DIRECT and/or SN_ASSIGNED though. It will
 * be called before any connection and after any retry or redispatch occurs.
 *
 * It is not allowed to call this function with a session in a queue.
 *
 * Returns :
 *
 *   SRV_STATUS_OK       if everything is OK.
 *   SRV_STATUS_NOSRV    if no server is available. objt_server(s->target) = NULL.
 *   SRV_STATUS_QUEUED   if the connection has been queued.
 *   SRV_STATUS_FULL     if the server(s) is/are saturated and the
 *                       connection could not be queued at the server's,
 *                       which may be NULL if we queue on the backend.
 *   SRV_STATUS_INTERNAL for other unrecoverable errors.
 *
 */
int assign_server_and_queue(struct session *s)
{
	struct pendconn *p;
	struct server *srv;
	int err;

	if (s->pend_pos)
		return SRV_STATUS_INTERNAL;

	err = SRV_STATUS_OK;
	if (!(s->flags & SN_ASSIGNED)) {
		struct server *prev_srv = objt_server(s->target);

		err = assign_server(s);
		if (prev_srv) {
			/* This session was previously assigned to a server. We have to
			 * update the session's and the server's stats :
			 *  - if the server changed :
			 *    - set TX_CK_DOWN if txn.flags was TX_CK_VALID
			 *    - set SN_REDISP if it was successfully redispatched
			 *    - increment srv->redispatches and be->redispatches
			 *  - if the server remained the same : update retries.
			 */

			if (prev_srv != objt_server(s->target)) {
				if ((s->txn.flags & TX_CK_MASK) == TX_CK_VALID) {
					s->txn.flags &= ~TX_CK_MASK;
					s->txn.flags |= TX_CK_DOWN;
				}
				s->flags |= SN_REDISP;
				prev_srv->counters.redispatches++;
				s->be->be_counters.redispatches++;
			} else {
				prev_srv->counters.retries++;
				s->be->be_counters.retries++;
			}
		}
	}

	switch (err) {
	case SRV_STATUS_OK:
		/* we have SN_ASSIGNED set */
		srv = objt_server(s->target);
		if (!srv)
			return SRV_STATUS_OK;   /* dispatch or proxy mode */

		/* If we already have a connection slot, no need to check any queue */
		if (s->srv_conn == srv)
			return SRV_STATUS_OK;

		/* OK, this session already has an assigned server, but no
		 * connection slot yet. Either it is a redispatch, or it was
		 * assigned from persistence information (direct mode).
		 */
		if ((s->flags & SN_REDIRECTABLE) && srv->rdr_len) {
			/* server scheduled for redirection, and already assigned. We
			 * don't want to go further nor check the queue.
			 */
			sess_change_server(s, srv); /* not really needed in fact */
			return SRV_STATUS_OK;
		}

		/* We might have to queue this session if the assigned server is full.
		 * We know we have to queue it into the server's queue, so if a maxqueue
		 * is set on the server, we must also check that the server's queue is
		 * not full, in which case we have to return FULL.
		 */
		if (srv->maxconn &&
		    (srv->nbpend || srv->served >= srv_dynamic_maxconn(srv))) {

			if (srv->maxqueue > 0 && srv->nbpend >= srv->maxqueue)
				return SRV_STATUS_FULL;

			p = pendconn_add(s);
			if (p)
				return SRV_STATUS_QUEUED;
			else
				return SRV_STATUS_INTERNAL;
		}

		/* OK, we can use this server. Let's reserve our place */
		sess_change_server(s, srv);
		return SRV_STATUS_OK;

	case SRV_STATUS_FULL:
		/* queue this session into the proxy's queue */
		p = pendconn_add(s);
		if (p)
			return SRV_STATUS_QUEUED;
		else
			return SRV_STATUS_INTERNAL;

	case SRV_STATUS_NOSRV:
		return err;

	case SRV_STATUS_INTERNAL:
		return err;

	default:
		return SRV_STATUS_INTERNAL;
	}
}