Dillo v3.2.0
Loading...
Searching...
No Matches
main.c
Go to the documentation of this file.
1/*
2 Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
3 Copyright (C) 2020 Axel Beckert <abe@debian.org>
4 Copyright (C) 2023 Michal Grezl <walley@walley.org>
5 Copyright (C) 2025 Rodrigo Arias Mallo <rodarima@gmail.com>
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <errno.h> /* for ckd_write */
22#include <unistd.h> /* for ckd_write */
23#include <stdlib.h> /* for exit */
24#include <assert.h> /* for assert */
25#include <sys/stat.h> /* for umask */
26
27#include "dpid_common.h"
28#include "dpid.h"
29#include "dpi.h"
30#include "dpi_socket_dir.h"
31#include "misc_new.h"
32
33#include "../dlib/dlib.h"
34#include "../dpip/dpip.h"
35
36sigset_t mask_sigchld;
37
38/* fix for gcc 10 */
39
40enum {
42 dpid_srs_addrinuse /* dpid service request socket address already in use */
44
47fd_set sock_set;
52
53// end of fix
54
55
61static int start_filter_plugin(struct dp dpi_attr)
62{
63 int newsock, old_stdout=-1, old_stdin=-1;
64 socklen_t csz;
65 struct sockaddr_un clnt_addr;
66 pid_t pid;
67
68 csz = (socklen_t) sizeof(clnt_addr);
69
70 newsock = accept(dpi_attr.sock_fd, (struct sockaddr *) &clnt_addr, &csz);
71 if (newsock == -1)
72 ERRMSG("start_plugin", "accept", errno);
73
74 dup2(STDIN_FILENO, old_stdin);
75 if (dup2(newsock, STDIN_FILENO) == -1) {
76 ERRMSG("start_plugin", "dup2", errno);
77 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
78 exit(1);
79 }
80
81 dup2(STDOUT_FILENO, old_stdout);
82 if (dup2(newsock, STDOUT_FILENO) == -1) {
83 ERRMSG("start_plugin", "dup2", errno);
84 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
85 exit(1);
86 }
87 if ((pid = fork()) == -1) {
88 ERRMSG("main", "fork", errno);
89 return 0;
90 }
91 if (pid == 0) {
92 /* Child, start plugin */
93 if (execl(dpi_attr.path, dpi_attr.path, (char*)NULL) == -1) {
94 ERRMSG("start_plugin", "execl", errno);
95 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
96 exit(1);
97 }
98 }
99
100 /* Parent, Close sockets fix stdio and return pid */
101 if (dClose(newsock) == -1) {
102 ERRMSG("start_plugin", "close", errno);
103 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
104 exit(1);
105 }
106 dClose(STDIN_FILENO);
107 dClose(STDOUT_FILENO);
108 dup2(old_stdin, STDIN_FILENO);
109 dup2(old_stdout, STDOUT_FILENO);
110 return pid;
111}
112
113static void start_server_plugin(struct dp dpi_attr)
114{
115 if (dup2(dpi_attr.sock_fd, STDIN_FILENO) == -1) {
116 ERRMSG("start_plugin", "dup2", errno);
117 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
118 exit(1);
119 }
120 if (dClose(dpi_attr.sock_fd) == -1) {
121 ERRMSG("start_plugin", "close", errno);
122 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
123 exit(1);
124 }
125 if (execl(dpi_attr.path, dpi_attr.path, (char*)NULL) == -1) {
126 ERRMSG("start_plugin", "execl", errno);
127 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
128 exit(1);
129 }
130}
131
137static char *get_request(Dsh *sh)
138{
139 char *dpip_tag;
140
141 (void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
142 dpip_tag = a_Dpip_dsh_read_token(sh, 1);
143 (void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
144
145 return dpip_tag;
146}
147
153static int get_command(Dsh *sh, char *dpi_tag)
154{
155 char *cmd, *d_cmd;
156 int COMMAND;
157
158 if (dpi_tag == NULL) {
159 _ERRMSG("get_command", "dpid tag is NULL", 0);
160 return (-1);
161 }
162
163 cmd = a_Dpip_get_attr(dpi_tag, "cmd");
164
165 if (cmd == NULL) {
166 ERRMSG("get_command", "a_Dpip_get_attr", 0);
167 MSG_ERR(": dpid failed to parse cmd in %s\n", dpi_tag);
168 d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
169 "DpiError", "Failed to parse request");
170 a_Dpip_dsh_write_str(sh, 1, d_cmd);
171 dFree(d_cmd);
172 COMMAND = -1;
173 } else if (strcmp("auth", cmd) == 0) {
174 COMMAND = AUTH_CMD;
175 } else if (strcmp("DpiBye", cmd) == 0) {
176 COMMAND = BYE_CMD;
177 } else if (strcmp("check_server", cmd) == 0) {
178 COMMAND = CHECK_SERVER_CMD;
179 } else if (strcmp("register_all", cmd) == 0) {
180 COMMAND = REGISTER_ALL_CMD;
181 } else if (strcmp("register_service", cmd) == 0) {
182 COMMAND = REGISTER_SERVICE_CMD;
183 } else { /* Error unknown command */
184 COMMAND = UNKNOWN_CMD;
185 }
186
187 dFree(cmd);
188 return (COMMAND);
189}
190
194static int server_is_running(char *server_id)
195{
196 int i;
197
198 /* Search in the set of running servers */
199 for (i = 0; i < numdpis; i++) {
200 if (!dpi_attr_list[i].filter && dpi_attr_list[i].pid > 1 &&
201 strcmp(dpi_attr_list[i].id, server_id) == 0)
202 return 1;
203 }
204 return 0;
205}
206
207
211static int get_open_max(void)
212{
213#ifdef OPEN_MAX
214 return OPEN_MAX;
215#else
216 int ret = sysconf(_SC_OPEN_MAX);
217 if (ret < 0)
218 ret = 256;
219 return ret;
220#endif
221}
222
227int main(void)
228{
229 int i, n = 0, open_max;
230 int dpid_idle_timeout = 60 * 60; /* default, in seconds */
231 struct timeval select_timeout;
232 sigset_t mask_none;
233 fd_set selected_set;
234
235 dpi_attr_list = NULL;
236 services_list = NULL;
237 //daemon(0,0); /* Use 0,1 for feedback */
238 /* TODO: call setsid() ?? */
239
240 /* Allow read and write access, but only for the user.
241 * TODO: can this cause trouble with umount? */
242 umask(0077);
243 /* TODO: make dpid work on any directory. */
244 // chdir("/");
245
246 /* close inherited file descriptors */
247 open_max = get_open_max();
248 for (i = 3; i < open_max; i++)
249 dClose(i);
250
251 /* this sleep used to unmask a race condition */
252 // sleep(2);
253
255
256 /* Get list of available dpis */
258
259#if 0
260 /* Get name of socket directory */
261 dirname = a_Dpi_sockdir_file();
262 if ((sockdir = init_sockdir(dirname)) == NULL) {
263 ERRMSG("main", "init_sockdir", 0);
264 MSG_ERR("Failed to create socket directory\n");
265 exit(1);
266 }
267#endif
268
269 /* Init and get services list */
271
272 /* Remove any sockets that may have been leftover from a crash */
273 //cleanup();
274
275 /* Initialise sockets */
276 if ((numsocks = init_ids_srs_socket()) == -1) {
277 switch (dpi_errno) {
279 MSG_ERR("dpid refuses to start, possibly because:\n");
280 MSG_ERR("\t1) An instance of dpid is already running.\n");
281 MSG_ERR("\t2) A previous dpid didn't clean up on exit.\n");
282 exit(1);
283 default:
284 //ERRMSG("main", "init_srs_socket failed", 0);
285 ERRMSG("main", "init_ids_srs_socket failed", 0);
286 exit(1);
287 }
288 }
292
293 (void) sigemptyset(&mask_sigchld);
294 (void) sigaddset(&mask_sigchld, SIGCHLD);
295 (void) sigemptyset(&mask_none);
296 (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
297
298 printf("dpid started (found %d dpis)\n", numdpis);
299/* Start main loop */
300 while (1) {
301 do {
302 (void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
303 if (caught_sigchld) {
305 caught_sigchld = 0;
306 }
307 (void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
308 select_timeout.tv_sec = dpid_idle_timeout;
309 select_timeout.tv_usec = 0;
310 selected_set = sock_set;
311 n = select(FD_SETSIZE, &selected_set, NULL, NULL, &select_timeout);
312 if (n == 0) { /* select timed out, try to exit */
313 /* BUG: This is a workaround for dpid not to exit when the
314 * downloads server is active. The proper way to handle it is with
315 * a dpip command that asks the server whether it's busy.
316 * Note: the cookies server may lose session info too. */
317 if (server_is_running("downloads"))
318 continue;
319
321 //cleanup();
322 exit(0);
323 }
324 } while (n == -1 && errno == EINTR);
325
326 if (n == -1) {
327 ERRMSG("main", "select", errno);
328 exit(1);
329 }
330 /* If the service req socket is selected then service the req. */
331 if (FD_ISSET(srs_fd, &selected_set)) {
332 int sock_fd;
333 socklen_t sin_sz;
334 struct sockaddr_in sin;
335 char *req = NULL;
336
337 --n;
338 assert(n >= 0);
339 sin_sz = (socklen_t) sizeof(sin);
340 sock_fd = accept(srs_fd, (struct sockaddr *)&sin, &sin_sz);
341 if (sock_fd == -1) {
342 ERRMSG("main", "accept", errno);
343 MSG_ERR("accept on srs socket failed\n");
344 MSG_ERR("service pending connections, and continue\n");
345 } else {
346 int command;
347 Dsh *sh;
348
349 sh = a_Dpip_dsh_new(sock_fd, sock_fd, 1024);
350read_next:
351 req = get_request(sh);
352 command = get_command(sh, req);
353 switch (command) {
354 case AUTH_CMD:
355 if (a_Dpip_check_auth(req) != -1) {
356 dFree(req);
357 goto read_next;
358 }
359 break;
360 case BYE_CMD:
362 //cleanup();
363 exit(0);
364 break;
365 case CHECK_SERVER_CMD:
366 send_sockport(sock_fd, req, dpi_attr_list);
367 break;
368 case REGISTER_ALL_CMD:
370 break;
371 case UNKNOWN_CMD:
372 {
373 char *d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
374 "DpiError", "Unknown command");
375 (void) CKD_WRITE(sock_fd, d_cmd);
376 dFree(d_cmd);
377 ERRMSG("main", "Unknown command", 0);
378 MSG_ERR(" for request: %s\n", req);
379 break;
380 }
381 case -1:
382 _ERRMSG("main", "get_command failed", 0);
383 break;
384 }
385 if (req)
386 free(req);
389 }
390 }
391
392 /* While there's a request on one of the plugin sockets
393 * find the matching plugin and start it. */
394 for (i = 0; n > 0 && i < numdpis; i++) {
395 if (FD_ISSET(dpi_attr_list[i].sock_fd, &selected_set)) {
396 --n;
397 assert(n >= 0);
398
399 if (dpi_attr_list[i].filter) {
400 /* start a dpi filter plugin and continue watching its socket
401 * for new connections */
402 (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
404 } else {
405 /* start a dpi server plugin but don't wait for new connections
406 * on its socket */
407 numsocks--;
408 assert(numsocks >= 0);
409 FD_CLR(dpi_attr_list[i].sock_fd, &sock_set);
410 if ((dpi_attr_list[i].pid = fork()) == -1) {
411 ERRMSG("main", "fork", errno);
412 /* exit(1); */
413 } else if (dpi_attr_list[i].pid == 0) {
414 /* child */
415 (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
417 }
418 }
419 }
420 }
421 }
422}
static Dsh * sh
Definition datauri.c:39
void dFree(void *mem)
Definition dlib.c:68
int dClose(int fd)
Close a FD handling EINTR.
Definition dlib.c:951
volatile sig_atomic_t caught_sigchld
Definition downloads.cc:218
@ REGISTER_SERVICE_CMD
Definition dpi.h:35
@ UNKNOWN_CMD
Definition dpi.h:30
@ REGISTER_ALL_CMD
Definition dpi.h:34
@ BYE_CMD
Definition dpi.h:32
@ AUTH_CMD
Definition dpi.h:31
@ CHECK_SERVER_CMD
Definition dpi.h:33
char * init_sockdir(char *dpi_socket_dir)
char * a_Dpi_sockdir_file(void)
Definition dpi.c:34
void send_sockport(int sock_fd, char *dpi_tag, struct dp *dpi_attr_list)
Definition dpid.c:883
int init_all_dpi_sockets(struct dp *dpi_attr_list)
Definition dpid.c:686
int register_all_cmd(void)
Definition dpid.c:826
int register_all(struct dp **attlist)
Definition dpid.c:348
int init_ids_srs_socket(void)
Definition dpid.c:638
void est_dpi_sigchld(void)
Definition dpid.c:732
void handle_sigchld(void)
Definition dpid.c:709
void stop_active_dpis(struct dp *dpi_attr_list, int numdpis)
Definition dpid.c:763
void est_dpi_terminator(void)
Definition dpid.c:118
int fill_services_list(struct dp *attlist, int numdpis, Dlist **services_list)
Definition dpid.c:452
#define CKD_WRITE(fd, msg)
Definition dpid_common.h:37
#define MSG_ERR(...)
Definition dpid_common.h:23
#define _ERRMSG(CALLER, CALLED, ERR)
Definition dpid_common.h:31
#define ERRMSG(CALLER, CALLED, ERR)
Definition dpid_common.h:29
void a_Dpip_dsh_free(Dsh *dsh)
Free the SockHandler structure.
Definition dpip.c:525
char * a_Dpip_build_cmd(const char *format,...)
Printf like function for building dpip commands.
Definition dpip.c:83
int a_Dpip_dsh_write_str(Dsh *dsh, int flush, const char *str)
Convenience function.
Definition dpip.c:374
char * a_Dpip_get_attr(const char *tag, const char *attrname)
Task: given a tag and an attribute name, return its value.
Definition dpip.c:192
char * a_Dpip_dsh_read_token(Dsh *dsh, int blocking)
Return a newlly allocated string with the next dpip token in the socket.
Definition dpip.c:493
void a_Dpip_dsh_close(Dsh *dsh)
Close this socket for reading and writing.
Definition dpip.c:504
int a_Dpip_check_auth(const char *auth_tag)
Check whether the given 'auth' string equals what dpid saved.
Definition dpip.c:201
Dsh * a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
Create and initialize a dpip socket handler.
Definition dpip.c:247
enum @2 dpi_errno
static int get_open_max(void)
Get MAX open FD limit (yes, it's tricky –Jcid).
Definition main.c:211
Dlist * services_list
Definition main.c:49
static int get_command(Dsh *sh, char *dpi_tag)
Definition main.c:153
char * srs_name
Definition main.c:45
static void start_server_plugin(struct dp dpi_attr)
Definition main.c:113
static int server_is_running(char *server_id)
Check whether a dpi server is running.
Definition main.c:194
int main(void)
Definition main.c:227
@ no_errors
Definition main.c:41
@ dpid_srs_addrinuse
Definition main.c:42
int numdpis
Definition main.c:46
int numsocks
Definition main.c:50
fd_set sock_set
Definition main.c:47
static char * get_request(Dsh *sh)
Definition main.c:137
struct dp * dpi_attr_list
Definition main.c:48
static int start_filter_plugin(struct dp dpi_attr)
Start a dpi filter plugin after accepting the pending connection \Return.
Definition main.c:61
int srs_fd
Definition main.c:51
sigset_t mask_sigchld
Definition main.c:36
Definition dlib.h:131
Dpip socket handler type.
Definition dpip.h:31
Definition dpid.h:35
char * path
Definition dpid.h:37
int sock_fd
Definition dpid.h:38