hiding XFRM message names from netlink
[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 char *pos, *level, *buf_pos, type[4];
132 pos = cfg->setup.charondebug;
133 buf_pos = buffer;
134 while (pos && sscanf(pos, "%4s %d,", type, &level) == 2)
135 {
136 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "--debug-%s", type);
137 arg[argc++] = buf_pos;
138 buf_pos += strlen(buf_pos) + 1;
139 if (buf_pos >= buffer + sizeof(buffer))
140 {
141 break;
142 }
143 snprintf(buf_pos, buffer + sizeof(buffer) - buf_pos, "%d", level);
144 arg[argc++] = buf_pos;
145 buf_pos += strlen(buf_pos) + 1;
146 if (buf_pos >= buffer + sizeof(buffer))
147 {
148 break;
149 }
150
151 /* get next */
152 pos = strchr(pos, ',');
153 if (pos)
154 {
155 pos++;
156 }
157 }
158 }
159
160 if (_charon_pid)
161 {
162 plog("starter_start_charon(): charon already started...");
163 return -1;
164 }
165 else
166 {
167 unlink(CHARON_CTL_FILE);
168 _stop_requested = 0;
169
170 pid = fork();
171 switch (pid)
172 {
173 case -1:
174 plog("can't fork(): %s", strerror(errno));
175 return -1;
176 case 0:
177 /* child */
178 setsid();
179 sigprocmask(SIG_SETMASK, 0, NULL);
180 /* disable glibc's malloc checker, conflicts with leak detective */
181 setenv("MALLOC_CHECK_", "0", 1);
182 execv(arg[0], arg);
183 plog("can't execv(%s,...): %s", arg[0], strerror(errno));
184 exit(1);
185 default:
186 /* father */
187 _charon_pid = pid;
188 for (i = 0; i < 500 && _charon_pid; i++)
189 {
190 /* wait for charon for a maximum of 500 x 20 ms = 10 s */
191 usleep(20000);
192 if (stat(CHARON_PID_FILE, &stb) == 0)
193 {
194 plog("charon (%d) started after %d ms", _charon_pid, 20*(i+1));
195 return 0;
196 }
197 }
198 if (_charon_pid)
199 {
200 /* If charon is started but with no ctl file, stop it */
201 plog("charon too long to start... - kill kill");
202 for (i = 0; i < 20 && (pid = _charon_pid) != 0; i++)
203 {
204 if (i == 0)
205 {
206 kill(pid, SIGINT);
207 }
208 else if (i < 10)
209 {
210 kill(pid, SIGTERM);
211 }
212 else
213 {
214 kill(pid, SIGKILL);
215 }
216 usleep(20000);
217 }
218 }
219 else
220 {
221 plog("charon refused to be started");
222 }
223 return -1;
224 }
225 }
226 return -1;
227 }