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
 
75
 
76
 #define PYFCGI_NAME "spawn-fcgi [OPTIONS] -- pyfcgi"
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
 #define PYFCGI_LONG_OPT { \
80
 #define PYFCGI_LONG_OPT { \
81
 	{"config", required_argument, 0, 'C'},\
81
 	{"config", required_argument, 0, 'C'},\

+ 13
- 9
include/monitor.h View File

36
 #include <arpa/inet.h>
36
 #include <arpa/inet.h>
37
 
37
 
38
 #define UNIX_SOCKPATH_MAX 108
38
 #define UNIX_SOCKPATH_MAX 108
39
+#define PYFCGI_MONITOR_STREAM_BACKLOG 5
39
 
40
 
40
 typedef struct pyfcgi_monitor_s pyfcgi_monitor_t;
41
 typedef struct pyfcgi_monitor_s pyfcgi_monitor_t;
41
 typedef union pyfcgi_monitor_addr_u pyfcgi_monitor_addr_t;
42
 typedef union pyfcgi_monitor_addr_u pyfcgi_monitor_addr_t;
50
 	struct sockaddr_un un;
51
 	struct sockaddr_un un;
51
 };
52
 };
52
 
53
 
53
-/**@brief Local structure storing monitor process informations */
54
 struct pyfcgi_monitor_s
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
 	pyfcgi_monitor_addr_t addr;
58
 	pyfcgi_monitor_addr_t addr;
62
 };
59
 };
63
 
60
 
64
-
65
 /**@brief Start the stats server monitoring server 
61
 /**@brief Start the stats server monitoring server 
66
  * @return PID of the child process and -1 on error
62
  * @return PID of the child process and -1 on error
67
  * @note When called the configuration has to be parsed */
63
  * @note When called the configuration has to be parsed */
68
 pid_t pyfcgi_spawn_monitor();
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
 void pyfcgi_monitor_loop();
71
 void pyfcgi_monitor_loop();
72
 
72
 
73
+void pyfcgi_monitor_stream_loop();
74
+void pyfcgi_monitor_dgram_loop();
75
+
73
 /**@brief Check socket URL validity
76
 /**@brief Check socket URL validity
74
  * @param const char* the URL to check
77
  * @param const char* the URL to check
75
  * @return -1 if error else 0
78
  * @return -1 if error else 0
95
  * @return 0 if no erro else -1
98
  * @return 0 if no erro else -1
96
  * @todo add support for xxx://[IPV6]:port
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
 #endif
104
 #endif

+ 0
- 5
include/responder.h View File

93
  */
93
  */
94
 int pyfcgi_pool_idle(const struct timespec *timeout);
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
 /**@brief Handle signals and forward it to workers */
96
 /**@brief Handle signals and forward it to workers */
102
 void pool_sighandler(int signum);
97
 void pool_sighandler(int signum);
103
 
98
 

+ 126
- 17
src/monitor.c View File

1
 #include "monitor.h"
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
 pid_t pyfcgi_spawn_monitor()
14
 pid_t pyfcgi_spawn_monitor()
5
 {
15
 {
6
 	pid_t res;
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
 	res = fork();
26
 	res = fork();
9
 	if(res == -1)
27
 	if(res == -1)
10
 	{
28
 	{
13
 		sleep(1);
31
 		sleep(1);
14
 	}
32
 	}
15
 	if(!res)
33
 	if(!res)
16
-	{
34
+	{ //child process
17
 		pyfcgi_logger_set_ident("StatServ");
35
 		pyfcgi_logger_set_ident("StatServ");
18
-		pyfcgi_monitor_init();
19
 		pyfcgi_monitor_loop();
36
 		pyfcgi_monitor_loop();
20
 		pyfcgi_log(LOG_ALERT, "Monitor loop should never return but just did it...");
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
 	return res;
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
 int pyfcgi_monitor_check_sock(const char* sockurl)
149
 int pyfcgi_monitor_check_sock(const char* sockurl)
141
 int pyfcgi_monitor_parse_inet_addr(const char* addr_str, int socktype,
254
 int pyfcgi_monitor_parse_inet_addr(const char* addr_str, int socktype,
142
 	pyfcgi_monitor_addr_t *listen_addr, int* domain)
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
 	struct addrinfo *infos, hints, *info;
258
 	struct addrinfo *infos, hints, *info;
147
-	short v4, v6, i;
259
+	short v4, v6;
148
 	int ret;
260
 	int ret;
149
 
261
 
150
 	// initialize temporary address & port pointers
262
 	// initialize temporary address & port pointers
186
 		{
298
 		{
187
 			memcpy(&listen_addr->in, info->ai_addr,
299
 			memcpy(&listen_addr->in, info->ai_addr,
188
 				info->ai_addrlen);
300
 				info->ai_addrlen);
189
-			ipstr = inet_ntoa(listen_addr->in.sin_addr);
190
 		}
301
 		}
191
 		else if(info->ai_family == AF_INET6)
302
 		else if(info->ai_family == AF_INET6)
192
 		{
303
 		{
193
 			memcpy(&listen_addr->in6, info->ai_addr,
304
 			memcpy(&listen_addr->in6, info->ai_addr,
194
 				info->ai_addrlen);
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
 		else
307
 		else
205
 		{
308
 		{
206
 			continue;
309
 			continue;
207
 		}
310
 		}
208
 		*domain = info->ai_family;
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
 		pyfcgi_log(LOG_DEBUG, "Listen addr resolved to %s(%s)",
318
 		pyfcgi_log(LOG_DEBUG, "Listen addr resolved to %s(%s)",
210
 			info->ai_canonname,  ipstr);
319
 			info->ai_canonname,  ipstr);
211
 
320
 

+ 11
- 9
src/responder.c View File

18
  */
18
  */
19
 #include "responder.h"
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
 void init_context()
32
 void init_context()
22
 {
33
 {
23
 	PyFCGI_conf.context.pid = getpid();
34
 	PyFCGI_conf.context.pid = getpid();
393
 	return 1; //idle
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
 void pool_sighandler(int signum)
407
 void pool_sighandler(int signum)
406
 {
408
 {
407
 	unsigned int i;
409
 	unsigned int i;

Loading…
Cancel
Save