Browse Source

Continuing monitor server

Implementing a dummy stream response loop sending PyFCGI version
Yann Weber 4 years ago
parent
commit
6b9634c843
5 changed files with 151 additions and 41 deletions
  1. 1
    1
      include/conf.h
  2. 13
    9
      include/monitor.h
  3. 0
    5
      include/responder.h
  4. 126
    17
      src/monitor.c
  5. 11
    9
      src/responder.c

+ 1
- 1
include/conf.h View File

@@ -75,7 +75,7 @@ pyfcgi_conf_t PyFCGI_conf;
75 75
 
76 76
 #define PYFCGI_NAME "spawn-fcgi [OPTIONS] -- pyfcgi"
77 77
 
78
-#define PYFCGI_SHORT_OPT "Ce:E:Aw:W:m:ft:L:SPsvVh"
78
+#define PYFCGI_SHORT_OPT "Ce:E:Aw:W:m:ft:L:SPs:vVh"
79 79
 
80 80
 #define PYFCGI_LONG_OPT { \
81 81
 	{"config", required_argument, 0, 'C'},\

+ 13
- 9
include/monitor.h View File

@@ -36,6 +36,7 @@
36 36
 #include <arpa/inet.h>
37 37
 
38 38
 #define UNIX_SOCKPATH_MAX 108
39
+#define PYFCGI_MONITOR_STREAM_BACKLOG 5
39 40
 
40 41
 typedef struct pyfcgi_monitor_s pyfcgi_monitor_t;
41 42
 typedef union pyfcgi_monitor_addr_u pyfcgi_monitor_addr_t;
@@ -50,26 +51,28 @@ union pyfcgi_monitor_addr_u
50 51
 	struct sockaddr_un un;
51 52
 };
52 53
 
53
-/**@brief Local structure storing monitor process informations */
54 54
 struct pyfcgi_monitor_s
55 55
 {
56
-	/**@brief Socket fd */
57
-	int sock_serv;
58
-	/**@brief domain type & protocol */
59
-	int sock_args[3];
60
-	/**@brief Address to bind to */
56
+	int sockserv;
57
+	int sockargs[3];
61 58
 	pyfcgi_monitor_addr_t addr;
62 59
 };
63 60
 
64
-
65 61
 /**@brief Start the stats server monitoring server 
66 62
  * @return PID of the child process and -1 on error
67 63
  * @note When called the configuration has to be parsed */
68 64
 pid_t pyfcgi_spawn_monitor();
69 65
 
70
-void pyfcgi_monitor_init();
66
+/**@brief Main function for socket stats server
67
+ *
68
+ * Create the socket & bind to indicated address. If bind fails, sleep 30s, then
69
+ * exit, in order to retry the whole process
70
+ */
71 71
 void pyfcgi_monitor_loop();
72 72
 
73
+void pyfcgi_monitor_stream_loop();
74
+void pyfcgi_monitor_dgram_loop();
75
+
73 76
 /**@brief Check socket URL validity
74 77
  * @param const char* the URL to check
75 78
  * @return -1 if error else 0
@@ -95,6 +98,7 @@ int pyfcgi_monitor_parse_sock(const char*, int[3], pyfcgi_monitor_addr_t*);
95 98
  * @return 0 if no erro else -1
96 99
  * @todo add support for xxx://[IPV6]:port
97 100
  */
98
-int pyfcgi_monitor_parse_inet_addr(const char*, int, pyfcgi_monitor_addr_t*, int*);
101
+int pyfcgi_monitor_parse_inet_addr(const char*, int, pyfcgi_monitor_addr_t*,
102
+	int*);
99 103
 
100 104
 #endif

+ 0
- 5
include/responder.h View File

@@ -93,11 +93,6 @@ int pyfcgi_pool_state();
93 93
  */
94 94
 int pyfcgi_pool_idle(const struct timespec *timeout);
95 95
 
96
-/**@brief Exit after closing all stuff like semaphores
97
- * @ingroup work_master_proc
98
- */
99
-void clean_exit(int);
100
-
101 96
 /**@brief Handle signals and forward it to workers */
102 97
 void pool_sighandler(int signum);
103 98
 

+ 126
- 17
src/monitor.c View File

@@ -1,10 +1,28 @@
1 1
 #include "monitor.h"
2 2
 
3
+static pyfcgi_monitor_t pyfcgi_mon;
4
+
5
+static void clean_exit(int status)
6
+{
7
+	if(pyfcgi_mon.sockserv)
8
+	{
9
+		close(pyfcgi_mon.sockserv);
10
+	}
11
+	exit(status);
12
+}
3 13
 
4 14
 pid_t pyfcgi_spawn_monitor()
5 15
 {
6 16
 	pid_t res;
7 17
 
18
+	if(!PyFCGI_conf.mon_socket)
19
+	{
20
+		pyfcgi_log(LOG_ERR, "No socket url set but pyfcgi_spawn_monitor called !");
21
+		return -1;
22
+	}
23
+
24
+	memset(&pyfcgi_mon, 0, sizeof(pyfcgi_mon));
25
+
8 26
 	res = fork();
9 27
 	if(res == -1)
10 28
 	{
@@ -13,24 +31,119 @@ pid_t pyfcgi_spawn_monitor()
13 31
 		sleep(1);
14 32
 	}
15 33
 	if(!res)
16
-	{
34
+	{ //child process
17 35
 		pyfcgi_logger_set_ident("StatServ");
18
-		pyfcgi_monitor_init();
19 36
 		pyfcgi_monitor_loop();
20 37
 		pyfcgi_log(LOG_ALERT, "Monitor loop should never return but just did it...");
21
-		exit(PYFCGI_FATAL);
38
+		clean_exit(PYFCGI_FATAL);
22 39
 	}
23 40
 	return res;
24 41
 }
25 42
 
26
-void pyfcgi_monitor_init()
43
+
44
+void pyfcgi_monitor_loop()
27 45
 {
46
+	pyfcgi_monitor_addr_t addr;
47
+	int *sockargs;
48
+	socklen_t addrlen;
28 49
 
50
+	sockargs = pyfcgi_mon.sockargs;
51
+
52
+	if(pyfcgi_monitor_parse_sock(PyFCGI_conf.mon_socket, sockargs,
53
+		&addr) < 0)
54
+	{
55
+		pyfcgi_log(LOG_WARNING,
56
+			"Unable to parse socket URL, monitoring server not starting...");
57
+		free(PyFCGI_conf.mon_socket);
58
+		PyFCGI_conf.mon_socket = NULL;
59
+		clean_exit(PYFCGI_ERR);
60
+	}
61
+
62
+	if( (pyfcgi_mon.sockserv = socket(sockargs[0], sockargs[1],
63
+		sockargs[2])) < 0)
64
+	{
65
+		pyfcgi_log(LOG_ERR, "Unable to create socket : %s",
66
+			strerror(errno));
67
+		sleep(1);
68
+		clean_exit(PYFCGI_ERR);
69
+	}
70
+
71
+	if(sockargs[0] == AF_INET)
72
+	{
73
+		addrlen = sizeof(struct sockaddr_in);
74
+	}
75
+	else if(sockargs[0] == AF_INET6)
76
+	{
77
+		addrlen = sizeof(struct sockaddr_in6);
78
+	}
79
+	else
80
+	{
81
+		addrlen = sizeof(struct sockaddr_un);
82
+	}
83
+	
84
+	if(bind(pyfcgi_mon.sockserv, (struct sockaddr*)&addr, addrlen) < 0)
85
+	{
86
+		pyfcgi_log(LOG_ERR, "Unable to bind socket... Retrying in 10s");
87
+		close(pyfcgi_mon.sockserv);
88
+		sleep(30);
89
+		clean_exit(PYFCGI_ERR);
90
+	}
91
+	pyfcgi_log(LOG_INFO, "Listening on %s", PyFCGI_conf.mon_socket);
92
+	//bind successfull, sending to appropriate response loop
93
+	if(pyfcgi_mon.sockargs[1] == SOCK_DGRAM)
94
+	{
95
+		pyfcgi_monitor_dgram_loop();
96
+	}
97
+	else
98
+	{
99
+		pyfcgi_monitor_stream_loop();
100
+	}
29 101
 }
30 102
 
31
-void pyfcgi_monitor_loop()
103
+void pyfcgi_monitor_stream_loop(pyfcgi_monitor_addr_t addr_serv)
32 104
 {
105
+	pyfcgi_monitor_addr_t cliaddr;
106
+	socklen_t addrlen;
107
+	int sockcli;
108
+	char ipstr[64];
109
+	char name[] = "PYFCGI_"VERSION"\n";
33 110
 
111
+	addrlen = sizeof(cliaddr);
112
+	if(listen(pyfcgi_mon.sockserv, PYFCGI_MONITOR_STREAM_BACKLOG) < 0)
113
+	{
114
+		pyfcgi_log(LOG_ERR, "Unable to listen on socket : %s",
115
+			strerror(errno));
116
+		clean_exit(PYFCGI_ERR);
117
+	}
118
+
119
+	while( (sockcli = accept(pyfcgi_mon.sockserv,
120
+		(struct sockaddr*)&cliaddr, &addrlen)) >= 0)
121
+	{
122
+		pyfcgi_log(LOG_DEBUG, "New client");
123
+		if(!inet_ntop(pyfcgi_mon.sockargs[0], (void*)&cliaddr, ipstr, 64))
124
+		{
125
+			pyfcgi_log(LOG_WARNING,
126
+				"inet_ntop fails to represent client address : %s",
127
+				strerror(errno));
128
+			strcpy(ipstr, "XXX");
129
+		}
130
+		pyfcgi_log(LOG_INFO, "Sending stats to %s", ipstr);
131
+		
132
+		send(sockcli, name, strlen(name), 0);
133
+		close(sockcli);
134
+		
135
+		addrlen = sizeof(cliaddr);
136
+	}
137
+	pyfcgi_log(LOG_ERR, "Unable to accept new connection on socket : %s",
138
+		strerror(errno));
139
+}
140
+
141
+void pyfcgi_monitor_dgram_loop()
142
+{
143
+	pyfcgi_log(LOG_ERR, "Dgram server not implemented.... exiting server");
144
+	free(PyFCGI_conf.mon_socket);
145
+	PyFCGI_conf.mon_socket = NULL;
146
+	clean_exit(PYFCGI_ERR);
34 147
 }
35 148
 
36 149
 int pyfcgi_monitor_check_sock(const char* sockurl)
@@ -141,10 +254,9 @@ int pyfcgi_monitor_parse_sock(const char *sockurl, int sockargs[3],
141 254
 int pyfcgi_monitor_parse_inet_addr(const char* addr_str, int socktype,
142 255
 	pyfcgi_monitor_addr_t *listen_addr, int* domain)
143 256
 {
144
-	char *addr, *port, *ptr, *ipstr;
145
-	char v6str[64];
257
+	char *addr, *port, *ptr, ipstr[64];
146 258
 	struct addrinfo *infos, hints, *info;
147
-	short v4, v6, i;
259
+	short v4, v6;
148 260
 	int ret;
149 261
 
150 262
 	// initialize temporary address & port pointers
@@ -186,26 +298,23 @@ int pyfcgi_monitor_parse_inet_addr(const char* addr_str, int socktype,
186 298
 		{
187 299
 			memcpy(&listen_addr->in, info->ai_addr,
188 300
 				info->ai_addrlen);
189
-			ipstr = inet_ntoa(listen_addr->in.sin_addr);
190 301
 		}
191 302
 		else if(info->ai_family == AF_INET6)
192 303
 		{
193 304
 			memcpy(&listen_addr->in6, info->ai_addr,
194 305
 				info->ai_addrlen);
195
-			ptr = v6str;
196
-			for(i=0; i<16; i++)
197
-			{
198
-				ptr += snprintf(ptr, 4,
199
-					"%s%02X", ((i==0)?"":":"),
200
-					listen_addr->in6.sin6_addr.s6_addr[i]);
201
-			}
202
-			ipstr = v6str;
203 306
 		}
204 307
 		else
205 308
 		{
206 309
 			continue;
207 310
 		}
208 311
 		*domain = info->ai_family;
312
+		if(!inet_ntop(*domain, info->ai_addr, ipstr, 64))
313
+		{
314
+			pyfcgi_log(LOG_ERR, "Unable to format IP in string : %s",
315
+				strerror(errno));
316
+			strcpy(ipstr, "IP");
317
+		}
209 318
 		pyfcgi_log(LOG_DEBUG, "Listen addr resolved to %s(%s)",
210 319
 			info->ai_canonname,  ipstr);
211 320
 

+ 11
- 9
src/responder.c View File

@@ -18,6 +18,17 @@
18 18
  */
19 19
 #include "responder.h"
20 20
 
21
+/**@brief Exit after closing all stuff like semaphores
22
+ * @ingroup work_master_proc */
23
+static void clean_exit(int status)
24
+{
25
+	pyfcgi_IPC_close(IPC_WSTATE | IPC_WREQS | IPC_SEMST | IPC_SHMST);
26
+	//temporarly destroy everything....
27
+	pyfcgi_IPC_destroy(IPC_WSTATE | IPC_WREQS | IPC_SEMST | IPC_SHMST);
28
+	//pyfcgi_IPC_destroy(IPC_WSTATE);
29
+	exit(status);
30
+}
31
+
21 32
 void init_context()
22 33
 {
23 34
 	PyFCGI_conf.context.pid = getpid();
@@ -393,15 +404,6 @@ int pyfcgi_pool_idle(const struct timespec *timeout)
393 404
 	return 1; //idle
394 405
 }
395 406
 
396
-void clean_exit(int status)
397
-{
398
-	pyfcgi_IPC_close(IPC_WSTATE | IPC_WREQS | IPC_SEMST | IPC_SHMST);
399
-	//temporarly destroy everything....
400
-	pyfcgi_IPC_destroy(IPC_WSTATE | IPC_WREQS | IPC_SEMST | IPC_SHMST);
401
-	//pyfcgi_IPC_destroy(IPC_WSTATE);
402
-	exit(status);
403
-}
404
-
405 407
 void pool_sighandler(int signum)
406 408
 {
407 409
 	unsigned int i;

Loading…
Cancel
Save