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; }
/* 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; } }