/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ /* Cherokee * * Authors: * Alvaro Lopez Ortega * * Copyright (C) 2001-2007 Alvaro Lopez Ortega * * This program is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA */ #include "common-internal.h" #include "connection_info.h" #include "connection-protected.h" #include "thread.h" #include "server-protected.h" #include "handler_file.h" ret_t cherokee_connection_info_new (cherokee_connection_info_t **info) { CHEROKEE_NEW_STRUCT(n, connection_info); INIT_LIST_HEAD(&n->list_entry); cherokee_buffer_init (&n->id); cherokee_buffer_init (&n->phase); cherokee_buffer_init (&n->request); cherokee_buffer_init (&n->rx); cherokee_buffer_init (&n->tx); cherokee_buffer_init (&n->total_size); cherokee_buffer_init (&n->ip); cherokee_buffer_init (&n->percent); cherokee_buffer_init (&n->handler); cherokee_buffer_init (&n->icon); *info = n; return ret_ok; } ret_t cherokee_connection_info_free (cherokee_connection_info_t *info) { cherokee_buffer_mrproper (&info->id); cherokee_buffer_mrproper (&info->phase); cherokee_buffer_mrproper (&info->request); cherokee_buffer_mrproper (&info->rx); cherokee_buffer_mrproper (&info->tx); cherokee_buffer_mrproper (&info->total_size); cherokee_buffer_mrproper (&info->ip); cherokee_buffer_mrproper (&info->percent); cherokee_buffer_mrproper (&info->handler); cherokee_buffer_mrproper (&info->icon); free (info); return ret_ok; } ret_t cherokee_connection_info_fill_up (cherokee_connection_info_t *info, cherokee_connection_t *conn) { ret_t ret; const char *handler_name = NULL; cherokee_icons_t *icons = CONN_SRV(conn)->icons; cherokee_connection_phase_t phase; /* ID */ cherokee_buffer_add_va (&info->id, "%lu", conn->id); /* Phase */ switch (conn->phase) { case phase_nothing: phase = phase_nothing; cherokee_buffer_add_str (&info->phase, "Unknown"); break; case phase_switching_headers: phase = phase_switching_headers; cherokee_buffer_add_str (&info->phase, "Switching headers"); break; case phase_tls_handshake: phase = phase_tls_handshake; cherokee_buffer_add_str (&info->phase, "TLS Handshake"); break; case phase_reading_header: phase = phase_reading_header; cherokee_buffer_add_str (&info->phase, "Reading header"); break; case phase_processing_header: phase = phase_processing_header; cherokee_buffer_add_str (&info->phase, "Processing headers"); break; case phase_read_post: phase = phase_read_post; cherokee_buffer_add_str (&info->phase, "Reading Post"); break; case phase_setup_connection: phase = phase_setup_connection; cherokee_buffer_add_str (&info->phase, "Setting up connection"); break; case phase_init: phase = phase_init; cherokee_buffer_add_str (&info->phase, "Initializing"); break; case phase_add_headers: phase = phase_add_headers; cherokee_buffer_add_str (&info->phase, "Adding headers"); break; case phase_send_headers: phase = phase_send_headers; cherokee_buffer_add_str (&info->phase, "Sending headers"); break; case phase_steping: phase = phase_steping; cherokee_buffer_add_str (&info->phase, "Sending body"); break; case phase_lingering: phase = phase_lingering; cherokee_buffer_add_str (&info->phase, "Closing"); break; default: SHOULDNT_HAPPEN; } /* From */ if (conn->socket.socket > 0) { cherokee_buffer_ensure_size (&info->ip, CHE_INET_ADDRSTRLEN + 1); cherokee_socket_ntop (&conn->socket, info->ip.buf, info->ip.size - 1); } /* Request */ if (! cherokee_buffer_is_empty (&conn->request_original)) { cherokee_buffer_add_buffer (&info->request, &conn->request_original); } else if (! cherokee_buffer_is_empty (&conn->request)) { cherokee_buffer_add_buffer (&info->request, &conn->request); } /* Transference */ cherokee_buffer_add_va (&info->rx, FMT_OFFSET, (CST_OFFSET)conn->rx); cherokee_buffer_add_va (&info->tx, FMT_OFFSET, (CST_OFFSET)conn->tx); /* Handler */ if (conn->handler != NULL) { cherokee_module_get_name (MODULE(conn->handler), &handler_name); if (handler_name) cherokee_buffer_add (&info->handler, handler_name, strlen(handler_name)); } /* Total size */ if (handler_name && !strcmp (handler_name, "file")) { char *point; double percent; cherokee_handler_file_t *file = HDL_FILE(conn->handler); /* File size */ cherokee_buffer_add_va (&info->total_size, FMT_OFFSET, (CST_OFFSET)file->info->st_size); /* Percent */ percent = (CST_OFFSET)conn->tx * (double)100 / (CST_OFFSET)file->info->st_size; cherokee_buffer_add_va (&info->percent, "%f", percent); point = strchr (info->percent.buf, '.'); if (point != NULL) cherokee_buffer_drop_endding (&info->percent, (info->percent.buf + info->percent.len) - (point + 2)); } /* Local icon */ if ((icons != NULL) && (!cherokee_buffer_is_empty (&info->request))) { char *tmp; cherokee_buffer_t *icon; cherokee_buffer_t name = CHEROKEE_BUF_INIT; cherokee_buffer_add_buffer (&name, &info->request); tmp = strchr (name.buf, '?'); if (tmp != NULL) cherokee_buffer_drop_endding (&name, (name.buf + name.len) - tmp); tmp = strrchr (name.buf, '/'); if (tmp != NULL) cherokee_buffer_move_to_begin (&name, tmp - name.buf); ret = cherokee_icons_get_icon (icons, &name, &icon); if (ret == ret_ok) cherokee_buffer_add_buffer (&info->icon, icon); cherokee_buffer_mrproper (&name); } return ret_ok; } ret_t cherokee_connection_info_list_thread (cherokee_list_t *list, void *_thread, cherokee_handler_t *self_handler) { ret_t ret; cherokee_list_t *i; cherokee_boolean_t locked = false; cherokee_thread_t *thread = THREAD(_thread); /* Does it has active connections? */ if (thread->active_list_num <= 0) return ret_not_found; /* If it tries to adquire the thread ownership of the thread * which is already calling this function it will generate * a deadlock situation. Check it before lock. */ if ((self_handler != NULL) && (HANDLER_THREAD(self_handler) != thread)) { /* Adquire the ownership of the thread */ CHEROKEE_MUTEX_LOCK (&thread->ownership); locked = true; } /* Process each connection */ list_for_each (i, &thread->active_list) { CHEROKEE_NEW(n,connection_info); cherokee_connection_info_fill_up (n, CONN(i)); cherokee_list_add (LIST(n), list); } ret = ret_ok; if (cherokee_list_empty (list)) ret = ret_not_found; /* Release it */ if (locked) CHEROKEE_MUTEX_UNLOCK (&thread->ownership); return ret; } ret_t cherokee_connection_info_list_server (cherokee_list_t *list, cherokee_server_t *server, cherokee_handler_t *self) { cherokee_list_t *i; cherokee_connection_info_list_thread (list, server->main_thread, self); list_for_each (i, &server->thread_list) { cherokee_connection_info_list_thread (list, i, self); } if (cherokee_list_empty (list)) return ret_not_found; return ret_ok; }