SWITCH_DECLARE(char *) switch_limit_status(const char *backend) { switch_limit_interface_t *limit = NULL; char *status = NULL; /* locate impl, call appropriate func */ if (!(limit = get_backend(backend))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend); switch_goto_status(strdup("-ERR"), end); } status = limit->status(); end: release_backend(limit); return status; }
SWITCH_DECLARE(switch_status_t) switch_limit_reset(const char *backend) { switch_limit_interface_t *limit = NULL; int status = SWITCH_STATUS_SUCCESS; /* locate impl, call appropriate func */ if (!(limit = get_backend(backend))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend); switch_goto_status(SWITCH_STATUS_GENERR, end); } status = limit->reset(); end: release_backend(limit); return status; }
SWITCH_DECLARE(int) switch_limit_usage(const char *backend, const char *realm, const char *resource, uint32_t *rcount) { switch_limit_interface_t *limit = NULL; int usage = 0; /* locate impl, call appropriate func */ if (!(limit = get_backend(backend))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend); goto end; } usage = limit->usage(realm, resource, rcount); end: release_backend(limit); return usage; }
SWITCH_DECLARE(switch_status_t) switch_limit_release(const char *backend, switch_core_session_t *session, const char *realm, const char *resource) { switch_limit_interface_t *limit = NULL; int status = SWITCH_STATUS_SUCCESS; /* locate impl, call appropriate func */ if (!(limit = get_backend(backend))) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend); switch_goto_status(SWITCH_STATUS_GENERR, end); } status = limit->release(session, realm, resource); end: release_backend(limit); return status; }
SWITCH_DECLARE(switch_status_t) switch_limit_incr(const char *backend, switch_core_session_t *session, const char *realm, const char *resource, const int max, const int interval) { switch_limit_interface_t *limit = NULL; switch_channel_t *channel = NULL; int status = SWITCH_STATUS_SUCCESS; if (session) { channel = switch_core_session_get_channel(session); } /* locate impl, call appropriate func */ if (!(limit = get_backend(backend))) { switch_limit_log(session, SWITCH_LOG_ERROR, "Limit subsystem %s not found!\n", backend); switch_goto_status(SWITCH_STATUS_GENERR, end); } switch_limit_log(session, SWITCH_LOG_INFO, "incr called: %s_%s max:%d, interval:%d\n", realm, resource, max, interval); if ((status = limit->incr(session, realm, resource, max, interval)) == SWITCH_STATUS_SUCCESS) { if (session) { /* race condition? what if another leg is doing the same thing? */ const char *existing = switch_channel_get_variable(channel, LIMIT_BACKEND_VARIABLE); if (existing) { if (!strstr(existing, backend)) { switch_channel_set_variable_printf(channel, LIMIT_BACKEND_VARIABLE, "%s,%s", existing, backend); } } else { switch_channel_set_variable(channel, LIMIT_BACKEND_VARIABLE, backend); switch_core_event_hook_add_state_change(session, limit_state_handler); } } } release_backend(limit); end: return status; }
static void ev_handler(struct ns_connection *nc, int ev, void *ev_data) { struct conn_data *conn = (struct conn_data *) nc->user_data; const time_t now = time(NULL); #ifdef DEBUG write_log("%d conn=%p nc=%p ev=%d ev_data=%p bec=%p bec_nc=%p\n", now, conn, nc, ev, ev_data, conn != NULL ? conn->be_conn : NULL, conn != NULL && conn->be_conn != NULL ? conn->be_conn->nc : NULL); #endif if (conn == NULL) { if (ev == NS_ACCEPT) { conn = calloc(1, sizeof(*conn)); if (conn == NULL) { send_http_err(nc, s_error_500); } else { memset(conn, 0, sizeof(*conn)); nc->user_data = conn; conn->client.nc = nc; conn->client.body_len = -1; conn->backend.body_len = -1; conn->last_activity = now; } return; } else { nc->flags |= NSF_CLOSE_IMMEDIATELY; return; } } if (ev != NS_POLL) conn->last_activity = now; switch (ev) { case NS_HTTP_REQUEST: { /* From client */ assert(conn != NULL); assert(conn->be_conn == NULL); struct http_message *hm = (struct http_message *) ev_data; conn->client.flags.keep_alive = is_keep_alive(hm); if (!connect_backend(conn, hm)) { respond_with_error(conn, s_error_500); break; } if (conn->backend.nc == NULL) { /* This is a redirect, we're done. */ conn->client.nc->flags |= NSF_SEND_AND_CLOSE; break; } forward(conn, hm, &conn->client, &conn->backend); break; } case NS_CONNECT: { /* To backend */ assert(conn != NULL); assert(conn->be_conn != NULL); int status = *(int *) ev_data; if (status != 0) { write_log("Error connecting to %s: %d (%s)\n", conn->be_conn->be->host_port, status, strerror(status)); /* TODO(lsm): mark backend as defunct, try it later on */ respond_with_error(conn, s_error_500); conn->be_conn->nc = NULL; release_backend(conn); break; } break; } case NS_HTTP_REPLY: { /* From backend */ assert(conn != NULL); struct http_message *hm = (struct http_message *) ev_data; conn->backend.flags.keep_alive = s_backend_keepalive && is_keep_alive(hm); forward(conn, hm, &conn->backend, &conn->client); release_backend(conn); if (!conn->client.flags.keep_alive) { conn->client.nc->flags |= NSF_SEND_AND_CLOSE; } else { #ifdef DEBUG write_log("conn=%p remains open\n", conn); #endif } break; } case NS_POLL: { assert(conn != NULL); if (now - conn->last_activity > CONN_IDLE_TIMEOUT && conn->backend.nc == NULL /* not waiting for backend */) { #ifdef DEBUG write_log("conn=%p has been idle for too long\n", conn); conn->client.nc->flags |= NSF_SEND_AND_CLOSE; #endif } break; } case NS_CLOSE: { assert(conn != NULL); if (nc == conn->client.nc) { #ifdef DEBUG write_log("conn=%p nc=%p client closed, body_sent=%d\n", conn, nc, conn->backend.body_sent); #endif conn->client.nc = NULL; if (conn->backend.nc != NULL) { conn->backend.nc->flags |= NSF_CLOSE_IMMEDIATELY; } } else if (nc == conn->backend.nc) { #ifdef DEBUG write_log("conn=%p nc=%p backend closed\n", conn, nc); #endif conn->backend.nc = NULL; if (conn->client.nc != NULL && (conn->backend.body_len < 0 || conn->backend.body_sent < conn->backend.body_len)) { write_log("Backend %s disconnected.\n", conn->be_conn->be->host_port); respond_with_error(conn, s_error_500); } } if (conn->client.nc == NULL && conn->backend.nc == NULL) { free(conn); } break; } } }