idleTime, timeout (0) sets immediate timeout; -1 disabled timeout.
[yazpp-moved-to-github.git] / src / yaz-proxy-main.cpp
1 /*
2  * Copyright (c) 1998-2004, Index Data.
3  * See the file LICENSE for details.
4  * 
5  * $Id: yaz-proxy-main.cpp,v 1.27 2004-01-05 11:31:04 adam Exp $
6  */
7
8 #include <signal.h>
9 #include <unistd.h>
10 #include <pwd.h>
11 #include <sys/types.h>
12
13 #include <yaz/log.h>
14 #include <yaz/options.h>
15
16 #include <yaz++/socket-manager.h>
17 #include <yaz++/pdu-assoc.h>
18 #include <yaz++/proxy.h>
19
20 void usage(char *prog)
21 {
22     fprintf (stderr, "%s: [-c config] [-l log] [-a log] [-v level] [-t target] "
23              "[-u uid] [-p pidfile] @:port\n", prog);
24     exit (1);
25 }
26
27 static char *pid_fname = 0;
28 static char *uid = 0;
29 static char *log_file = 0;
30 static int debug = 0;
31
32 int args(Yaz_Proxy *proxy, int argc, char **argv)
33 {
34     char *addr = 0;
35     char *arg;
36     char *prog = argv[0];
37     int ret;
38
39     while ((ret = options("o:a:t:v:c:u:i:m:l:T:p:U:X",
40                           argv, argc, &arg)) != -2)
41     {
42         int err;
43         switch (ret)
44         {
45         case 0:
46             if (addr)
47             {
48                 usage(prog);
49                 return 1;
50             }
51             addr = arg;
52             break;
53         case 'c':
54             err = proxy->set_config(arg);
55             if (err == -2)
56             {
57                 fprintf(stderr, "Config file support not enabled (proxy not compiled with libxml2 support)\n");
58                 exit(1);
59             }
60             else if (err == -1)
61             {
62                 fprintf(stderr, "Bad or missing file %s\n", arg);
63                 exit(1);
64             }
65             break;
66         case 'a':
67             proxy->set_APDU_log(arg);
68             break;
69         case 't':
70             proxy->set_default_target(arg);
71             break;
72         case 'U':
73             proxy->set_proxy_authentication(arg);
74             break;
75         case 'o':
76             proxy->option("optimize", arg);
77             break;
78         case 'v':
79             yaz_log_init_level (yaz_log_mask_str(arg));
80             break;
81         case 'l':
82             yaz_log_init_file (arg);
83             log_file = xstrdup(arg);
84             break;
85         case 'm':
86             proxy->set_max_clients(atoi(arg));
87             break;
88         case 'i':
89             proxy->set_client_idletime(atoi(arg));
90             break;
91         case 'T':
92             proxy->set_target_idletime(atoi(arg));
93             break;
94         case 'X':
95             debug = 1;
96             break;
97         case 'p':
98             if (!pid_fname)
99                 pid_fname = xstrdup(arg);
100             break;
101         case 'u':
102             if (!uid)
103                 uid = xstrdup(arg);
104             break;
105         default:
106             usage(prog);
107             return 1;
108         }
109     }
110     if (addr)
111     {
112         yaz_log(LOG_LOG, "0 Starting proxy " VERSION );
113         if (proxy->server(addr))
114         {
115             yaz_log(LOG_FATAL|LOG_ERRNO, "listen %s", addr);
116             exit(1);
117         }
118     }
119     else
120     {
121         usage(prog);
122         return 1;
123     }
124     return 0;
125 }
126
127 static Yaz_Proxy *static_yaz_proxy = 0;
128 static void sighup_handler(int num)
129 {
130     signal(SIGHUP, sighup_handler);
131     if (static_yaz_proxy)
132         static_yaz_proxy->reconfig();
133 }
134
135
136 static void child_run(Yaz_SocketManager *m)
137 {
138     yaz_log(LOG_LOG, "0 proxy pid=%ld", (long) getpid());
139     if (pid_fname)
140     {
141         FILE *f = fopen(pid_fname, "w");
142         if (!f)
143         {
144             yaz_log(LOG_ERRNO|LOG_FATAL, "Couldn't create %s", pid_fname);
145             exit(0);
146         }
147         fprintf(f, "%ld", (long) getpid());
148         fclose(f);
149         xfree(pid_fname);
150     }
151     if (uid)
152     {
153         struct passwd *pw;
154
155         if (!(pw = getpwnam(uid)))
156         {
157             yaz_log(LOG_FATAL, "%s: Unknown user", uid);
158             exit(3);
159         }
160         if (log_file)
161         {
162             chown(log_file, pw->pw_uid,  pw->pw_gid);
163             xfree(log_file);
164         }
165
166         if (setuid(pw->pw_uid) < 0)
167         {
168             yaz_log(LOG_FATAL|LOG_ERRNO, "setuid");
169             exit(4);
170         }
171         xfree(uid);
172     }
173
174     while (m->processEvent() > 0)
175         ;
176
177     exit (0);
178 }
179
180 int main(int argc, char **argv)
181 {
182     int cont = 1;
183     static int mk_pid = 0;
184     Yaz_SocketManager mySocketManager;
185     Yaz_Proxy proxy(new Yaz_PDU_Assoc(&mySocketManager));
186
187     static_yaz_proxy = &proxy;
188
189     signal(SIGHUP, sighup_handler);
190
191     args(&proxy, argc, argv);
192
193     if (debug)
194     {
195         child_run(&mySocketManager);
196         exit(0);
197     }
198     while (cont)
199     {
200         pid_t p = fork();
201         if (p == (pid_t) -1)
202         {
203             yaz_log(LOG_FATAL|LOG_ERRNO, "fork");
204             exit(1);
205         }
206         else if (p == 0)
207         {
208             child_run(&mySocketManager);
209         }
210         pid_t p1;
211         int status;
212         p1 = wait(&status);
213         if (p1 != p)
214         {
215             yaz_log(LOG_FATAL, "p1=%d != p=%d", p1, p);
216             exit(1);
217         }
218         if (WIFSIGNALED(status))
219         {
220             switch(WTERMSIG(status)) {
221             case SIGILL:
222                 yaz_log(LOG_WARN, "Received SIGILL from child %ld", (long) p);
223                 cont = 1;
224                 break;
225             case SIGABRT:
226                 yaz_log(LOG_WARN, "Received SIGABRT from child %ld", (long) p);
227                 cont = 1;
228                 break ;
229             case SIGSEGV:
230                 yaz_log(LOG_WARN, "Received SIGSEGV from child %ld", (long) p);
231                 cont = 1;
232                 break;
233             case SIGTERM:
234                 yaz_log(LOG_LOG, "Received SIGTERM from child %ld",
235                         WTERMSIG(status), (long) p);
236                 cont = 0;
237                 break;
238             default:
239                 yaz_log(LOG_WARN, "Received SIG %d from child %ld",
240                         WTERMSIG(status), (long) p);
241                 cont = 0;
242             }
243         }
244         else if (status == 0)
245             cont = 0;
246         else
247         {
248             yaz_log(LOG_LOG, "Exit %d from child %ld", status, (long) p);
249             cont = 1;
250         }
251         if (cont)
252             sleep(1);
253     }
254     exit (0);
255     return 0;
256 }