static inline void handler_process_request(Handler *handler, int id, int fd, Connection *conn, bstring payload) { int rc = 0; if(conn == NULL) { debug("Ident %d (fd %d) is no longer connected.", id, fd); Handler_notify_leave(handler, id); } else { if(blength(payload) == 0) { rc = Register_disconnect(fd); check(rc != -1, "Register disconnect failed for: %d", fd); } else { int raw = conn->type != CONN_TYPE_MSG || handler->raw; rc = deliver_payload(raw, fd, conn, payload); check(rc != -1, "Failed to deliver to connection %d on socket %d", id, fd); } } return; error: Register_disconnect(fd); // return ignored return; }
static inline void handler_process_extended_request(int fd, Connection *conn, bstring payload) { char *x; tns_value_t *data = NULL; darray_t *l = NULL; data = tns_parse(bdata(payload),blength(payload),&x); check((x-bdata(payload))==blength(payload), "Invalid extended response: extra data after tnetstring."); check(data->type==tns_tag_list, "Invalid extended response: not a list."); l = data->value.list; check(darray_end(l)==2, "Invalid extended response: odd number of elements in list."); tns_value_t *key=darray_get(l,0); check(key->type==tns_tag_string, "Invalid extended response: key is not a string"); check(key->value.string != NULL,, "Invalid extended response: key is NULL"); if(!bstrcmp(key->value.string, &XREQ_CTL)) { check (0 == handler_process_control_request(conn, data), "Control request processing returned non-zero: %s", bdata(key->value.string)); } else { check (0 == dispatch_extended_request(conn, key->value.string, data), "Extended request dispatch returned non-zero: %s",bdata(key->value.string)); } return; error: tns_value_destroy(data); Register_disconnect(fd); // return ignored return; }
static int handler_process_control_request(Connection *conn, tns_value_t *data) { tns_value_t *args = darray_get(data->value.list, 1); check(args->type==tns_tag_dict, "Invalid control response: not a dict."); hnode_t *n = hash_lookup(args->value.dict, &KEEP_ALIVE); if(n != NULL) { Register_ping(IOBuf_fd(conn->iob)); } n = hash_lookup(args->value.dict, &CREDITS); if(n != NULL) { tns_value_t *credits = (tns_value_t *)hnode_get(n); conn->sendCredits += credits->value.number; taskwakeup(&conn->uploadRendez); } n = hash_lookup(args->value.dict, &CANCEL); if(n != NULL && !conn->closing) { Register_disconnect(IOBuf_fd(conn->iob)); taskwakeup(&conn->uploadRendez); } tns_value_destroy(data); return 0; error: return -1; }
int Register_cleanout() { int i = 0; int nkilled = 0; int nscanned = 0; time_t now = THE_CURRENT_TIME_IS; int min_ping = Setting_get_int("limits.min_ping", DEFAULT_MIN_PING); int min_write_rate = Setting_get_int("limits.min_write_rate", DEFAULT_MIN_READ_RATE); int min_read_rate = Setting_get_int("limits.min_read_rate", DEFAULT_MIN_WRITE_RATE); int kill_limit = Setting_get_int("limits.kill_limit", DEFAULT_KILL_LIMIT); for(i = 0, nscanned = 0; i < darray_max(REGISTRATIONS) && nscanned < NUM_REG_FD; i++) { Registration *reg = darray_get(REGISTRATIONS, i); if(Register_valid(reg)) { nscanned++; // avoid scanning the whole array if we've found them all int last_ping = ZERO_OR_DELTA(now, reg->last_ping); off_t read_rate = reg->bytes_read / (ZERO_OR_DELTA(now, reg->last_read) + 1); off_t write_rate = reg->bytes_written / (ZERO_OR_DELTA(now, reg->last_write) + 1); int should_kill = 0; debug("Checking fd=%d:conn_id=%d against last_ping: %d, read_rate: %d, write_rate: %d", i, reg->id, last_ping, read_rate, write_rate); // these are weighted so they are not if-else statements if(min_ping != 0 && last_ping > min_ping) { debug("Connection fd=%d:conn_id=%d over limits.min_ping time: %d < %d", i, reg->id, min_ping, last_ping); should_kill++; } if(min_read_rate != 0 && read_rate < min_read_rate) { debug("Connection fd=%d:conn_id=%d read rate lower than allowed: %d < %d", i, reg->id, read_rate, min_read_rate); should_kill++; } if(min_write_rate != 0 && write_rate < min_write_rate) { debug("Connection fd=%d:conn_id=%d write rate lower than allowed: %d < %d", i, reg->id, write_rate, min_write_rate); should_kill++; } if(should_kill > kill_limit) { nkilled++; Register_disconnect(i); } } } if(nkilled) { log_warn("Killed %d connections according to min_ping: %d, min_write_rate: %d, min_read_rate: %d", nkilled, min_ping, min_write_rate, min_read_rate); } return nkilled; }
static inline int close_or_error(Connection *conn, int next) { IOBuf_destroy(conn->proxy_iob); conn->proxy_iob = NULL; check_debug(Register_disconnect(IOBuf_fd(conn->iob)) != -1, "Register disconnect didn't work for %d", IOBuf_fd(conn->iob)); error: // fallthrough on purpose return next; }
static inline void handler_process_request(Handler *handler, int id, int fd, Connection *conn, bstring payload) { int rc = 0; check(conn != NULL, "You can't pass NULL conn to this anymore."); if(blength(payload) == 0) { rc = Connection_deliver_raw(conn,NULL); check(rc != -1, "Register disconnect failed for: %d", fd); } else { int raw = conn->type != CONN_TYPE_MSG || handler->raw; rc = deliver_payload(raw, fd, conn, payload); check(rc != -1, "Failed to deliver to connection %d on socket %d", id, fd); } return; error: Register_disconnect(fd); // return ignored return; }
int Register_connect(int fd, Connection* data) { check(fd < MAX_REGISTERED_FDS, "FD given to register is greater than max."); check(data != NULL, "data can't be NULL"); Registration *reg = darray_get(REGISTRATIONS, fd); if(reg == NULL) { reg = darray_new(REGISTRATIONS); check(reg != NULL, "Failed to allocate a new registration."); // we only set this here since they stay in list forever rather than recycle darray_set(REGISTRATIONS, fd, reg); darray_attach(REGISTRATIONS, reg); } if(Register_valid(reg)) { // force them to exit int rc = Register_disconnect(fd); check(rc != -1, "Weird error trying to disconnect. Tell Zed."); tasksignal(reg->task, SIGINT); } reg->data = data; reg->last_ping = THE_CURRENT_TIME_IS; reg->fd = fd; reg->task = taskself(); reg->id = UINT32_MAX; // start off with an invalid conn_id // keep track of the number of registered things we're tracking NUM_REG_FD++; return 0; error: return -1; }
void fake_conn_close(Connection *conn) { assert(conn && conn->iob && "Invalid connection."); Register_disconnect(conn->iob->fd); Connection_destroy(conn); }