16a7f2aa80cd7bd40e1029144605280ff3babe49
[strongswan.git] / src / starter / invokecharon.c
1 /* strongSwan charon launcher
2 * Copyright (C) 2001-2002 Mathieu Lafon - Arkoon Network Security
3 * Copyright (C) 2006 Martin Willi - Hochschule fuer Technik Rapperswil
4 *
5 * Ported from invokepluto.c to fit charons needs.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2 of the License, or (at your
10 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 * for more details.
16 *
17 * RCSID $Id$
18 */
19
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27
28 #include <freeswan.h>
29
30 #include "../pluto/constants.h"
31 #include "../pluto/defs.h"
32 #include "../pluto/log.h"
33
34 #include "confread.h"
35 #include "invokecharon.h"
36 #include "files.h"
37
38 static int _charon_pid = 0;
39 static int _stop_requested;
40
41 pid_t
42 starter_charon_pid(void)
43 {
44 return _charon_pid;
45 }
46
47 void
48 starter_charon_sigchild(pid_t pid)
49 {
50 if (pid == _charon_pid)
51 {
52 _charon_pid = 0;
53 if (!_stop_requested)
54 {
55 plog("charon has died -- restart scheduled (%dsec)"
56 , CHARON_RESTART_DELAY);
57 alarm(CHARON_RESTART_DELAY); // restart in 5 sec
58 }
59 unlink(CHARON_PID_FILE);
60 }
61 }
62
63 int
64 starter_stop_charon (void)
65 {
66 int i;
67 pid_t pid = _charon_pid;
68
69 if (pid)
70 {
71 _stop_requested = 1;
72
73 /* be more and more aggressive */
74 for (i = 0; i < 50 && (pid = _charon_pid) != 0; i++)
75 {
76 if (i == 0)
77 {
78 kill(pid, SIGINT);
79 }
80 else if (i < 40)
81 {
82 kill(pid, SIGTERM);
83 }
84 else if (i == 40)
85 {
86 kill(pid, SIGKILL);
87 plog("starter_stop_charon(): charon does not respond, sending KILL");
88 }
89 else
90 {
91 kill(pid, SIGKILL);
92 }
93 usleep(200000); /* sleep for 200 ms */
94 }
95 if (_charon_pid == 0)
96 {
97 plog("charon stopped after %d ms", 200*i);
98 return 0;
99 }
100 plog("starter_stop_charon(): can't stop charon !!!");
101 return -1;
102 }
103 else
104 {
105 plog("stater_stop_charon(): charon was not started...");
106 }
107 return -1;
108 }
109
110
111 int
112 starter_start_charon (starter_config_t *cfg, bool no_fork)
113 {
114 struct stat stb;
115 int pid, i;
116 char buffer[BUF_LEN];
117 int argc = 1;
118 char *arg[] = {
119 CHARON_CMD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
120 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
121 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
122 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
123 };
124
125 if (!no_fork)
126 {
127 arg[argc++] = "--use-syslog";
128 }
129
130 /* parse debug string */
131 {
132 int level;
133 char *pos, *buf_pos, type[4];
134
135 pos = cfg->setup.charondebug;
136 buf_pos = buffer;
137
138 while (pos && sscanf(pos, "%4s %d,", type, &level) == 2)
139 {
140 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type);
141 arg[argc++] = buf_pos;
142 buf_pos += strlen(buf_pos) + 1;
143 if (buf_pos >= buffer + sizeof(buffer))
144 {
145 break;
146 }
147 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level);
148 arg[argc++] = buf_pos;
149 buf_pos += strlen(buf_pos) + 1;
150 if (buf_pos >= buffer + sizeof(buffer))
151 {
152 break;
153 }
154
155 /* get next */
156 pos = strchr(pos, ',');
157 if (pos)
158 {
159 pos++;
160 }
161 }
162 }
163
164 if (_charon_pid)
165 {
166 plog("starter_start_charon(): charon already started...");
167 return -1;
168 }
169 else
170 {
171 unlink(CHARON_CTL_FILE);
172 _stop_requested = 0;
173
174 pid = fork();
175 switch (pid)
176 {
177 case -1:
178 plog("can't fork(): %s", strerror(errno));
179 return -1;
180 case 0:
181 /* child */
182 setsid();
183 sigprocmask(SIG_SETMASK, 0, NULL);
184 /* disable glibc's malloc checker, conflicts with leak detective */
185 setenv("MALLOC_CHECK_", "0", 1);
186 execv(arg[0], arg);
187 plog("can't execv(%s,...): %s", arg[0], strerror(errno));
188 exit(1);
189 default:
190 /* father */
191 _charon_pid = pid;
192 for (i = 0; i < 500 && _charon_pid; i++)
193 {
194 /* wait for charon for a maximum of 500 x 20 ms = 10 s */
195 usleep(20000);
196 if (stat(CHARON_PID_FILE, &stb) == 0)
197 {
198 plog("charon (%d) started after %d ms", _charon_pid, 20*(i+1));
199 return 0;
200 }
201 }
202 if (_charon_pid)
203 {
204 /* If charon is started but with no ctl file, stop it */
205 plog("charon too long to start... - kill kill");
206 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
207 {
208 if (i == 0)
209 {
210 kill(pid, SIGINT);
211 }
212 else if (i < 10)
213 {
214 kill(pid, SIGTERM);
215 }
216 else
217 {
218 kill(pid, SIGKILL);
219 }
220 usleep(20000);
221 }
222 }
223 else
224 {
225 plog("charon refused to be started");
226 }
227 return -1;
228 }
229 }
230 return -1;
231 }