process: associate open connections with clients

This commit is contained in:
Justin Maggard 2014-06-09 18:48:49 -07:00
parent e9a653d6e8
commit a46a8e5e89
5 changed files with 102 additions and 16 deletions

View File

@ -93,6 +93,7 @@ struct client_cache_s {
unsigned char mac[6]; unsigned char mac[6];
struct client_type_s *type; struct client_type_s *type;
time_t age; time_t age;
int connections;
}; };
extern struct client_type_s client_types[]; extern struct client_type_s client_types[];

View File

@ -372,7 +372,7 @@ rescan:
#if USE_FORK #if USE_FORK
scanning = 1; scanning = 1;
sqlite3_close(db); sqlite3_close(db);
*scanner_pid = process_fork(); *scanner_pid = fork();
open_db(&db); open_db(&db);
if (*scanner_pid == 0) /* child (scanner) process */ if (*scanner_pid == 0) /* child (scanner) process */
{ {
@ -969,6 +969,13 @@ init(int argc, char **argv)
DPRINTF(E_FATAL, L_GENERAL, "Failed to switch to uid '%d'. [%s] EXITING.\n", DPRINTF(E_FATAL, L_GENERAL, "Failed to switch to uid '%d'. [%s] EXITING.\n",
uid, strerror(errno)); uid, strerror(errno));
children = calloc(runtime_vars.max_connections, sizeof(struct child));
if (!children)
{
DPRINTF(E_ERROR, L_GENERAL, "Allocation failed\n");
return 1;
}
return 0; return 0;
} }
@ -1285,7 +1292,10 @@ main(int argc, char **argv)
shutdown: shutdown:
/* kill the scanner */ /* kill the scanner */
if (scanning && scanner_pid) if (scanning && scanner_pid)
kill(scanner_pid, 9); kill(scanner_pid, SIGKILL);
/* kill other child processes */
process_reap_children();
/* close out open sockets */ /* close out open sockets */
while (upnphttphead.lh_first != NULL) while (upnphttphead.lh_first != NULL)

View File

@ -43,10 +43,47 @@
#include "config.h" #include "config.h"
#include "log.h" #include "log.h"
static int number_of_children = 0; struct child *children = NULL;
int number_of_children = 0;
static void
add_process_info(pid_t pid, struct client_cache_s *client)
{
struct child *child;
int i;
for (i = 0; i < runtime_vars.max_connections; i++)
{
child = children+i;
if (child->pid)
continue;
child->pid = pid;
child->client = client;
child->age = time(NULL);
break;
}
}
static inline void
remove_process_info(pid_t pid)
{
struct child *child;
int i;
for (i = 0; i < runtime_vars.max_connections; i++)
{
child = children+i;
if (child->pid != pid)
continue;
child->pid = 0;
if (child->client)
child->client->connections--;
break;
}
}
pid_t pid_t
process_fork(void) process_fork(struct client_cache_s *client)
{ {
if (number_of_children >= runtime_vars.max_connections) if (number_of_children >= runtime_vars.max_connections)
{ {
@ -58,7 +95,13 @@ process_fork(void)
pid_t pid = fork(); pid_t pid = fork();
if (pid > 0) if (pid > 0)
++number_of_children; {
number_of_children++;
if (client)
client->connections++;
add_process_info(pid, client);
}
return pid; return pid;
} }
@ -76,7 +119,8 @@ process_handle_child_termination(int signal)
else else
break; break;
} }
--number_of_children; number_of_children--;
remove_process_info(pid);
} }
} }
@ -87,7 +131,7 @@ process_daemonize(void)
#ifndef USE_DAEMON #ifndef USE_DAEMON
int i; int i;
switch(process_fork()) switch(fork())
{ {
/* fork error */ /* fork error */
case -1: case -1:
@ -157,3 +201,17 @@ process_check_if_running(const char *fname)
return 0; return 0;
} }
void
process_reap_children(void)
{
struct child *child;
int i;
for (i = 0; i < runtime_vars.max_connections; i++)
{
child = children+i;
if (child->pid)
kill(child->pid, SIGKILL);
}
}

View File

@ -30,6 +30,16 @@
#define __PROCESS_H__ #define __PROCESS_H__
#include <unistd.h> #include <unistd.h>
#include "clients.h"
struct child {
pid_t pid;
time_t age;
struct client_cache_s *client;
};
extern struct child *children;
extern int number_of_children;
/** /**
* Fork a new child (just like fork()) but keep track of how many childs are * Fork a new child (just like fork()) but keep track of how many childs are
@ -37,7 +47,7 @@
* @return -1 if it couldn't fork, 0 in the child process, the pid of the * @return -1 if it couldn't fork, 0 in the child process, the pid of the
* child process in the parent process. * child process in the parent process.
*/ */
pid_t process_fork(void); pid_t process_fork(struct client_cache_s *client);
/** /**
* Handler to be called upon receiving SIGCHLD. This signal is received by the * Handler to be called upon receiving SIGCHLD. This signal is received by the
@ -63,4 +73,9 @@ int process_daemonize(void);
*/ */
int process_check_if_running(const char *fname); int process_check_if_running(const char *fname);
/**
* Kill all child processes
*/
void process_reap_children(void);
#endif // __PROCESS_H__ #endif // __PROCESS_H__

View File

@ -83,8 +83,7 @@
#include "sendfile.h" #include "sendfile.h"
//#define MAX_BUFFER_SIZE 4194304 // 4MB -- Too much? #define MAX_BUFFER_SIZE 2147483647
#define MAX_BUFFER_SIZE 2147483647 // 2GB -- Too much?
#define MIN_BUFFER_SIZE 65536 #define MIN_BUFFER_SIZE 65536
#include "icons.c" #include "icons.c"
@ -615,17 +614,20 @@ SendResp_presentation(struct upnphttp * h)
strcatf(&str, strcatf(&str,
"<h3>Connected clients</h3>" "<h3>Connected clients</h3>"
"<table border=1 cellpadding=10>" "<table border=1 cellpadding=10>"
"<tr><td>ID</td><td>Type</td><td>IP Address</td><td>HW Address</td></tr>"); "<tr><td>ID</td><td>Type</td><td>IP Address</td><td>HW Address</td><td>Connections</td></tr>");
for (i = 0; i < CLIENT_CACHE_SLOTS; i++) for (i = 0; i < CLIENT_CACHE_SLOTS; i++)
{ {
if (!clients[i].addr.s_addr) if (!clients[i].addr.s_addr)
continue; continue;
strcatf(&str, "<tr><td>%d</td><td>%s</td><td>%s</td><td>%02X:%02X:%02X:%02X:%02X:%02X</td></tr>", strcatf(&str, "<tr><td>%d</td><td>%s</td><td>%s</td><td>%02X:%02X:%02X:%02X:%02X:%02X</td><td>%d</td></tr>",
i, clients[i].type->name, inet_ntoa(clients[i].addr), i, clients[i].type->name, inet_ntoa(clients[i].addr),
clients[i].mac[0], clients[i].mac[1], clients[i].mac[2], clients[i].mac[0], clients[i].mac[1], clients[i].mac[2],
clients[i].mac[3], clients[i].mac[4], clients[i].mac[5]); clients[i].mac[3], clients[i].mac[4], clients[i].mac[5], clients[i].connections);
} }
strcatf(&str, "</table></BODY></HTML>\r\n"); strcatf(&str, "</table>");
strcatf(&str, "<br>%d connection%s currently open<br>", number_of_children, (number_of_children == 1 ? "" : "s"));
strcatf(&str, "</BODY></HTML>\r\n");
BuildResp_upnphttp(h, str.data, str.off); BuildResp_upnphttp(h, str.data, str.off);
SendResp_upnphttp(h); SendResp_upnphttp(h);
@ -1633,7 +1635,7 @@ SendResp_resizedimg(struct upnphttp * h, char * object)
#if USE_FORK #if USE_FORK
pid_t newpid = 0; pid_t newpid = 0;
newpid = process_fork(); newpid = process_fork(h->req_client);
if( newpid > 0 ) if( newpid > 0 )
{ {
CloseSocket_upnphttp(h); CloseSocket_upnphttp(h);
@ -1875,7 +1877,7 @@ SendResp_dlnafile(struct upnphttp *h, char *object)
sqlite3_free_table(result); sqlite3_free_table(result);
} }
#if USE_FORK #if USE_FORK
newpid = process_fork(); newpid = process_fork(h->req_client);
if( newpid > 0 ) if( newpid > 0 )
{ {
CloseSocket_upnphttp(h); CloseSocket_upnphttp(h);