1 /*
2 
3    uWSGI zergpool
4 
5 */
6 
7 #include "../../uwsgi.h"
8 
9 extern struct uwsgi_server uwsgi;
10 
11 struct uwsgi_string_list *zergpool_socket_names;
12 
13 #define ZERGPOOL_EVENTS 64
14 
15 struct uwsgi_option zergpool_options[] = {
16 	{ "zergpool", required_argument, 0, "start a zergpool on specified address for specified address", uwsgi_opt_add_string_list, &zergpool_socket_names, 0},
17 	{ "zerg-pool", required_argument, 0, "start a zergpool on specified address for specified address", uwsgi_opt_add_string_list, &zergpool_socket_names, 0},
18 	{0, 0, 0, 0, 0, 0, 0},
19 };
20 
21 struct zergpool_socket {
22 	int fd;
23 	int *sockets;
24 	int num_sockets;
25 
26 	struct zergpool_socket *next;
27 };
28 
29 struct zergpool_socket *zergpool_sockets;
30 
zergpool_loop(int id,void * foobar)31 void zergpool_loop(int id, void *foobar) {
32 
33 	int i;
34 
35 	int zergpool_queue = event_queue_init();
36 
37 	void *events = event_queue_alloc(ZERGPOOL_EVENTS);
38 
39 	struct zergpool_socket *zps = zergpool_sockets;
40 	while(zps) {
41 		event_queue_add_fd_read(zergpool_queue, zps->fd);
42 		zps = zps->next;
43 	}
44 
45 	for(;;) {
46 		int nevents = event_queue_wait_multi(zergpool_queue, -1, events, ZERGPOOL_EVENTS);
47 
48 		for(i=0;i<nevents;i++) {
49 
50 			int interesting_fd = event_queue_interesting_fd(events, i);
51 
52 			zps = zergpool_sockets;
53 			while(zps) {
54 				if (zps->fd == interesting_fd) {
55 					uwsgi_manage_zerg(zps->fd, zps->num_sockets, zps->sockets);
56 				}
57 				zps = zps->next;
58 			}
59 		}
60 	}
61 }
62 
add_zergpool_socket(char * name,char * sockets)63 struct zergpool_socket *add_zergpool_socket(char *name, char *sockets) {
64 
65 	struct zergpool_socket *z_sock,*zps = zergpool_sockets;
66 
67 	if (!zps) {
68 		z_sock = uwsgi_calloc(sizeof(struct zergpool_socket));
69 		zergpool_sockets = z_sock;
70 	}
71 	else {
72 		while(zps) {
73 			if (!zps->next) {
74 				z_sock= uwsgi_calloc(sizeof(struct zergpool_socket));
75 				zps->next = z_sock;
76 				break;
77 			}
78 			zps = zps->next;
79 		}
80 	}
81 
82 
83 	// do not defer accept for zergpools
84 	if (uwsgi.no_defer_accept) {
85 		uwsgi.no_defer_accept = 0;
86 		z_sock->fd = bind_to_unix(name, uwsgi.listen_queue, uwsgi.chmod_socket, 0);
87 		uwsgi.no_defer_accept = 1;
88 	}
89 	else {
90 		z_sock->fd = bind_to_unix(name, uwsgi.listen_queue, uwsgi.chmod_socket, 0);
91 	}
92 
93 	char *sock_list = uwsgi_str(sockets);
94 	char *p, *ctx = NULL;
95 	uwsgi_foreach_token(sock_list, ",", p, ctx) {
96 		z_sock->num_sockets++;
97 	}
98 	free(sock_list);
99 	z_sock->sockets = uwsgi_calloc(sizeof(int) * (z_sock->num_sockets + 1));
100 
101 	sock_list = uwsgi_str(sockets);
102 	int pos = 0;
103 	ctx = NULL;
104 	uwsgi_foreach_token(sock_list, ",", p, ctx) {
105 		char *port = strchr(p, ':');
106 		char *sockname;
107 		if (!port) {
108 			z_sock->sockets[pos] = bind_to_unix(p, uwsgi.listen_queue, uwsgi.chmod_socket, uwsgi.abstract_socket);
109 			sockname = uwsgi_getsockname(z_sock->sockets[pos]);
110 			uwsgi_log("zergpool %s bound to UNIX socket %s (fd: %d)\n", name, sockname, z_sock->sockets[pos]);
111 		}
112 		else {
113 			char *gsn = generate_socket_name(p);
114 			z_sock->sockets[pos] = bind_to_tcp(gsn, uwsgi.listen_queue, strchr(gsn, ':'));
115 			sockname = uwsgi_getsockname(z_sock->sockets[pos]);
116 			uwsgi_log("zergpool %s bound to TCP socket %s (fd: %d)\n", name, sockname, z_sock->sockets[pos]);
117 		}
118 		pos++;
119 		free(sockname);
120 	}
121 	free(sock_list);
122 
123 	return z_sock;
124 }
125 
zergpool_init()126 int zergpool_init() {
127 
128 	if (!zergpool_socket_names) return 0;
129 
130 	struct uwsgi_string_list *zpsn = zergpool_socket_names;
131 	while(zpsn) {
132 		char *colon = strchr(zpsn->value, ':');
133 		if (!colon) {
134 			uwsgi_log("invalid zergpool syntax: %s\n", zpsn->value);
135 			exit(1);
136 		}
137 		*colon = 0;
138 		add_zergpool_socket(zpsn->value, colon+1);
139 		*colon = ':';
140 		zpsn = zpsn->next;
141 	}
142 
143 	if (register_gateway("uWSGI zergpool", zergpool_loop, NULL) == NULL) {
144 		uwsgi_log("unable to register the zergpool gateway\n");
145 		exit(1);
146 	}
147 
148 	return 0;
149 }
150 
151 
152 struct uwsgi_plugin zergpool_plugin = {
153 
154 	.name = "zergpool",
155 	.options = zergpool_options,
156 	.init = zergpool_init,
157 };
158