annotate dpid/main.c @ 1382:7faa2c7a544f

Switch the DPI framework from Unix sockets to Internet sockets Initially meant for MINIX, but in the process several bugs were fixed, the code restructured, added more error handling and improved in general. In the future we may go back to UDS, but the cleanup gains will remain.
author Jorge Arellano Cid <jcid@dillo.org>
date Sun, 01 Nov 2009 16:31:36 -0300
parents b912173aecd1
children 16cf380cd04c
rev   line source
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
1 /*
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
2 Copyright (C) 2003 Ferdi Franceschini <ferdif@optusnet.com.au>
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
3
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
4 This program is free software; you can redistribute it and/or modify
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
5 it under the terms of the GNU General Public License as published by
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
6 the Free Software Foundation; either version 3 of the License, or
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
7 (at your option) any later version.
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
8
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
9 This program is distributed in the hope that it will be useful,
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
12 GNU General Public License for more details.
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
13
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
14 You should have received a copy of the GNU General Public License
972
d7dbd3dcfa38 Updated the GPL copyright note in the source files
Detlef Riekenberg <wine.dev@web.de>
parents: 368
diff changeset
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
16 */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
17
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
18 #include <errno.h> /* for ckd_write */
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
19 #include <unistd.h> /* for ckd_write */
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
20 #include <stdlib.h> /* for exit */
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
21 #include <assert.h> /* for assert */
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
22 #include <sys/stat.h> /* for umask */
1223
a09dbf132be6 Remove system includes for dpid
Jorge Arellano Cid <jcid@dillo.org>
parents: 972
diff changeset
23
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
24 #include "dpid_common.h"
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
25 #include "dpid.h"
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
26 #include "dpi.h"
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
27 #include "dpi_socket_dir.h"
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
28 #include "misc_new.h"
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
29 #include "../dpip/dpip.h"
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
30
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
31 sigset_t mask_sigchld;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
32
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
33
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
34 /* Start a dpi filter plugin after accepting the pending connection
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
35 * \Return
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
36 * \li Child process ID on success
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
37 * \li 0 on failure
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
38 */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
39 static int start_filter_plugin(struct dp dpi_attr)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
40 {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
41 int newsock, old_stdout=-1, old_stdin=-1;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
42 socklen_t csz;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
43 struct sockaddr_un clnt_addr;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
44 pid_t pid;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
45
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
46 csz = (socklen_t) sizeof(clnt_addr);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
47
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
48 newsock = accept(dpi_attr.sock_fd, (struct sockaddr *) &clnt_addr, &csz);
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
49 if (newsock == -1)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
50 ERRMSG("start_plugin", "accept", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
51
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
52 dup2(STDIN_FILENO, old_stdin);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
53 if (dup2(newsock, STDIN_FILENO) == -1) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
54 ERRMSG("start_plugin", "dup2", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
55 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
56 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
57 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
58
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
59 dup2(STDOUT_FILENO, old_stdout);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
60 if (dup2(newsock, STDOUT_FILENO) == -1) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
61 ERRMSG("start_plugin", "dup2", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
62 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
63 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
64 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
65 if ((pid = fork()) == -1) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
66 ERRMSG("main", "fork", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
67 return 0;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
68 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
69 if (pid == 0) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
70 /* Child, start plugin */
1230
60fb2b1b6220 Cast NULL sentinel to (char*) for execl (fix for LP64 arch).
Jorge Arellano Cid <jcid@dillo.org>
parents: 1223
diff changeset
71 if (execl(dpi_attr.path, dpi_attr.path, (char*)NULL) == -1) {
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
72 ERRMSG("start_plugin", "execl", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
73 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
74 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
75 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
76 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
77
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
78 /* Parent, Close sockets fix stdio and return pid */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
79 if (a_Misc_close_fd(newsock) == -1) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
80 ERRMSG("start_plugin", "close", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
81 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
82 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
83 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
84 a_Misc_close_fd(STDIN_FILENO);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
85 a_Misc_close_fd(STDOUT_FILENO);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
86 dup2(old_stdin, STDIN_FILENO);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
87 dup2(old_stdout, STDOUT_FILENO);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
88 return pid;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
89 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
90
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
91 static void start_server_plugin(struct dp dpi_attr)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
92 {
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
93 if (dup2(dpi_attr.sock_fd, STDIN_FILENO) == -1) {
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
94 ERRMSG("start_plugin", "dup2", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
95 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
96 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
97 }
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
98 if (a_Misc_close_fd(dpi_attr.sock_fd) == -1) {
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
99 ERRMSG("start_plugin", "close", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
100 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
101 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
102 }
1230
60fb2b1b6220 Cast NULL sentinel to (char*) for execl (fix for LP64 arch).
Jorge Arellano Cid <jcid@dillo.org>
parents: 1223
diff changeset
103 if (execl(dpi_attr.path, dpi_attr.path, (char*)NULL) == -1) {
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
104 ERRMSG("start_plugin", "execl", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
105 MSG_ERR("ERROR in child proc for %s\n", dpi_attr.path);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
106 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
107 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
108 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
109
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
110 /*!
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
111 * Read service request from sock
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
112 * \Return
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
113 * pointer to dynamically allocated request tag
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
114 */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
115 static char *get_request(int sock)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
116 {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
117 char *req, buf[10];
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
118 size_t buflen;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
119 size_t rqsz;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
120 ssize_t rdln;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
121
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
122 req = NULL;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
123 buf[0] = '\0';
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
124 buflen = sizeof(buf) / sizeof(buf[0]);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
125
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
126 (void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
127 for (rqsz = 0; (rdln = read(sock, buf, buflen)) != 0; rqsz += rdln) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
128 if (rdln == -1)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
129 break;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
130 req = (char *) realloc(req, rqsz + rdln + 1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
131 if (rqsz == 0)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
132 req[0] = '\0';
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
133 strncat(req, buf, (size_t) rdln);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
134 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
135 (void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
136 if (rdln == -1) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
137 ERRMSG("get_request", "read", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
138 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
139
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
140 return (req);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
141 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
142
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
143 /*!
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
144 * Get value of cmd field in dpi_tag
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
145 * \Return
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
146 * command code on success, -1 on failure
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
147 */
335
4a6db4341660 - Made several cleanups according to compiler warnings with "-W -Wall".
jcid
parents: 84
diff changeset
148 static int get_command(int sock, char *dpi_tag)
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
149 {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
150 char *cmd, *d_cmd;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
151 int COMMAND;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
152
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
153 if (dpi_tag == NULL) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
154 _ERRMSG("get_command", "dpid tag is NULL", 0);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
155 return (-1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
156 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
157
1236
b912173aecd1 Added a_Dpip_get_attr_l() to DPIP's API
Jorge Arellano Cid <jcid@dillo.org>
parents: 1230
diff changeset
158 cmd = a_Dpip_get_attr(dpi_tag, "cmd");
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
159
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
160 if (cmd == NULL) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
161 ERRMSG("get_command", "a_Dpip_get_attr", 0);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
162 MSG_ERR(": dpid failed to parse cmd in %s\n", dpi_tag);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
163 d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
164 "DpiError", "Failed to parse request");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
165 (void) CKD_WRITE(sock, d_cmd);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
166 dFree(d_cmd);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
167 COMMAND = -1;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
168 } else if (strcmp("DpiBye", cmd) == 0) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
169 COMMAND = BYE_CMD;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
170 } else if (strcmp("check_server", cmd) == 0) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
171 COMMAND = CHECK_SERVER_CMD;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
172 } else if (strcmp("register_all", cmd) == 0) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
173 COMMAND = REGISTER_ALL_CMD;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
174 } else if (strcmp("register_service", cmd) == 0) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
175 COMMAND = REGISTER_SERVICE_CMD;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
176 } else { /* Error unknown command */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
177 COMMAND = UNKNOWN_CMD;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
178 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
179
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
180 dFree(cmd);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
181 return (COMMAND);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
182 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
183
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
184 /*
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
185 * Check whether a dpi server is running
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
186 */
84
03f9a7877a2e Implemented the SELECT element in FORMS!
jcid
parents: 67
diff changeset
187 static int server_is_running(char *server_id)
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
188 {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
189 int i;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
190
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
191 /* Search in the set of running servers */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
192 for (i = 0; i < numdpis; i++) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
193 if (!dpi_attr_list[i].filter && dpi_attr_list[i].pid > 1 &&
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
194 strcmp(dpi_attr_list[i].id, server_id) == 0)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
195 return 1;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
196 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
197 return 0;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
198 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
199
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
200
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
201 /*
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
202 * Get MAX open FD limit (yes, it's tricky --Jcid).
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
203 */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
204 static int get_open_max(void)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
205 {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
206 #ifdef OPEN_MAX
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
207 return OPEN_MAX;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
208 #else
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
209 int ret = sysconf(_SC_OPEN_MAX);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
210 if (ret < 0)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
211 ret = 256;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
212 return ret;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
213 #endif
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
214 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
215
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
216 /*! \todo
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
217 * \li Add a dpid_idle_timeout variable to dpidrc
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
218 * \bug Infinite loop if plugin crashes before it accepts a connection
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
219 */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
220 int main(void)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
221 {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
222 int i, n = 0, open_max;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
223 int dpid_idle_timeout = 60 * 60; /* default, in seconds */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
224 struct timeval select_timeout;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
225 sigset_t mask_none;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
226 fd_set selected_set;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
227
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
228 dpi_attr_list = NULL;
67
ec671a7ea6e2 - * Improved the dpi framework. Now dpi-programs can be specified in dpidrc,
jcid
parents: 0
diff changeset
229 services_list = NULL;
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
230 //daemon(0,0); /* Use 0,1 for feedback */
368
2242da885677 - s/todo:/TODO:/g
jcid
parents: 335
diff changeset
231 /* TODO: call setsid() ?? */
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
232
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
233 /* Allow read and write access, but only for the user.
368
2242da885677 - s/todo:/TODO:/g
jcid
parents: 335
diff changeset
234 * TODO: can this cause trouble with umount? */
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
235 umask(0077);
368
2242da885677 - s/todo:/TODO:/g
jcid
parents: 335
diff changeset
236 /* TODO: make dpid work on any directory. */
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
237 // chdir("/");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
238
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
239 /* close inherited file descriptors */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
240 open_max = get_open_max();
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
241 for (i = 3; i < open_max; i++)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
242 a_Misc_close_fd(i);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
243
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
244 /* this sleep used to unmask a race condition */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
245 // sleep(2);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
246
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
247 dpi_errno = no_errors;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
248
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
249 /* Get list of available dpis */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
250 numdpis = register_all(&dpi_attr_list);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
251
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
252 #if 0
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
253 /* Get name of socket directory */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
254 dirname = a_Dpi_sockdir_file();
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
255 if ((sockdir = init_sockdir(dirname)) == NULL) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
256 ERRMSG("main", "init_sockdir", 0);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
257 MSG_ERR("Failed to create socket directory\n");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
258 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
259 }
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
260 #endif
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
261
67
ec671a7ea6e2 - * Improved the dpi framework. Now dpi-programs can be specified in dpidrc,
jcid
parents: 0
diff changeset
262 /* Init and get services list */
ec671a7ea6e2 - * Improved the dpi framework. Now dpi-programs can be specified in dpidrc,
jcid
parents: 0
diff changeset
263 fill_services_list(dpi_attr_list, numdpis, &services_list);
ec671a7ea6e2 - * Improved the dpi framework. Now dpi-programs can be specified in dpidrc,
jcid
parents: 0
diff changeset
264
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
265 /* Remove any sockets that may have been leftover from a crash */
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
266 //cleanup();
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
267
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
268 /* Initialise sockets */
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
269 if ((numsocks = init_ids_srs_socket()) == -1) {
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
270 switch (dpi_errno) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
271 case dpid_srs_addrinuse:
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
272 MSG_ERR("dpid refuses to start, possibly because:\n");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
273 MSG_ERR("\t1) An instance of dpid is already running.\n");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
274 MSG_ERR("\t2) A previous dpid didn't clean up on exit.\n");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
275 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
276 default:
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
277 //ERRMSG("main", "init_srs_socket failed", 0);
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
278 ERRMSG("main", "init_ids_srs_socket failed", 0);
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
279 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
280 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
281 }
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
282 numsocks = init_all_dpi_sockets(dpi_attr_list);
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
283 //est_terminator(); /* Do we still want to clean up on an abnormal exit? */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
284 est_dpi_sigchld();
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
285
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
286 (void) sigemptyset(&mask_sigchld);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
287 (void) sigaddset(&mask_sigchld, SIGCHLD);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
288 (void) sigemptyset(&mask_none);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
289 (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
290
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
291 printf("dpid started\n");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
292 /* Start main loop */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
293 while (1) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
294 do {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
295 (void) sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
296 if (caught_sigchld) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
297 handle_sigchld();
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
298 caught_sigchld = 0;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
299 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
300 (void) sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
301 select_timeout.tv_sec = dpid_idle_timeout;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
302 select_timeout.tv_usec = 0;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
303 selected_set = sock_set;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
304 n = select(FD_SETSIZE, &selected_set, NULL, NULL, &select_timeout);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
305 if (n == 0) { /* select timed out, try to exit */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
306 /* BUG: This is a workaround for dpid not to exit when the
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
307 * downloads server is active. The proper way to handle it is with
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
308 * a dpip command that asks the server whether it's busy.
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
309 * Note: the cookies server may lose session info too. */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
310 if (server_is_running("downloads"))
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
311 continue;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
312
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
313 stop_active_dpis(dpi_attr_list, numdpis);
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
314 //cleanup();
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
315 exit(0);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
316 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
317 } while (n == -1 && errno == EINTR);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
318
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
319 if (n == -1) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
320 ERRMSG("main", "select", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
321 exit(1);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
322 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
323 /* If the service req socket is selected then service the req. */
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
324 if (FD_ISSET(srs_fd, &selected_set)) {
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
325 int sock_fd;
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
326 socklen_t sin_sz;
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
327 struct sockaddr_in sin;
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
328 char *req = NULL;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
329
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
330 --n;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
331 assert(n >= 0);
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
332 sin_sz = (socklen_t) sizeof(sin);
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
333 sock_fd = accept(srs_fd, (struct sockaddr *)&sin, &sin_sz);
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
334 if (sock_fd == -1) {
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
335 ERRMSG("main", "accept", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
336 MSG_ERR("accept on srs socket failed\n");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
337 MSG_ERR("service pending connections, and continue\n");
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
338 } else {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
339 int command;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
340
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
341 req = get_request(sock_fd);
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
342 command = get_command(sock_fd, req);
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
343 switch (command) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
344 case BYE_CMD:
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
345 stop_active_dpis(dpi_attr_list, numdpis);
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
346 //cleanup();
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
347 exit(0);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
348 break;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
349 case CHECK_SERVER_CMD:
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
350 send_sockport(sock_fd, req, dpi_attr_list);
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
351 break;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
352 case REGISTER_ALL_CMD:
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
353 register_all_cmd();
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
354 break;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
355 case UNKNOWN_CMD:
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
356 {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
357 char *d_cmd = a_Dpip_build_cmd("cmd=%s msg=%s",
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
358 "DpiError", "Unknown command");
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
359 (void) CKD_WRITE(sock_fd, d_cmd);
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
360 dFree(d_cmd);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
361 ERRMSG("main", "Unknown command", 0);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
362 MSG_ERR(" for request: %s\n", req);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
363 break;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
364 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
365 case -1:
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
366 _ERRMSG("main", "get_command failed", 0);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
367 break;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
368 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
369 if (req)
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
370 free(req);
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
371 a_Misc_close_fd(sock_fd);
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
372 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
373 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
374
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
375 /* While there's a request on one of the plugin sockets
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
376 * find the matching plugin and start it. */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
377 for (i = 0; n > 0 && i < numdpis; i++) {
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
378 if (FD_ISSET(dpi_attr_list[i].sock_fd, &selected_set)) {
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
379 --n;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
380 assert(n >= 0);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
381
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
382 if (dpi_attr_list[i].filter) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
383 /* start a dpi filter plugin and continue watching its socket
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
384 * for new connections */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
385 (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
386 start_filter_plugin(dpi_attr_list[i]);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
387 } else {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
388 /* start a dpi server plugin but don't wait for new connections
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
389 * on its socket */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
390 numsocks--;
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
391 assert(numsocks >= 0);
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
392 FD_CLR(dpi_attr_list[i].sock_fd, &sock_set);
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
393 if ((dpi_attr_list[i].pid = fork()) == -1) {
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
394 ERRMSG("main", "fork", errno);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
395 /* exit(1); */
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
396 } else if (dpi_attr_list[i].pid == 0) {
1382
7faa2c7a544f Switch the DPI framework from Unix sockets to Internet sockets
Jorge Arellano Cid <jcid@dillo.org>
parents: 1236
diff changeset
397 /* child */
0
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
398 (void) sigprocmask(SIG_SETMASK, &mask_none, NULL);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
399 start_server_plugin(dpi_attr_list[i]);
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
400 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
401 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
402 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
403 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
404 }
6ee11bf9e3ea Initial revision
jcid
parents:
diff changeset
405 }