blob: 1198d9d87fab6a7513097aa71c80bd37b8937f9b [file] [log] [blame]
Chia-chi Yeh79e62322009-06-02 08:49:55 +08001/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <stdarg.h>
20#include <string.h>
21#include <errno.h>
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <sys/poll.h>
25#include <sys/wait.h>
26#include <netdb.h>
27#include <signal.h>
28#include <unistd.h>
29#include <fcntl.h>
30#include <time.h>
31
Chia-chi Yeh84e31952009-06-08 14:11:34 +080032#ifdef ANDROID_CHANGES
33#include <android/log.h>
34#include <cutils/sockets.h>
35#endif
36
Chia-chi Yeh79e62322009-06-02 08:49:55 +080037#include "mtpd.h"
38
39int the_socket = -1;
40
41extern struct protocol l2tp;
Chia-chi Yeh063bb922009-06-15 14:43:38 +080042extern struct protocol pptp;
43static struct protocol *protocols[] = {&l2tp, &pptp, NULL};
Chia-chi Yeh79e62322009-06-02 08:49:55 +080044static struct protocol *the_protocol;
45
46static int pppd_argc;
47static char **pppd_argv;
48static pid_t pppd_pid;
49
50/* We redirect signals to a pipe in order to prevent race conditions. */
51static int signals[2];
52
53static void interrupt(int signal)
54{
55 write(signals[1], &signal, sizeof(int));
56}
57
58static int initialize(int argc, char **argv)
59{
Chia-chi Yeh79e62322009-06-02 08:49:55 +080060 int i;
61
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070062 for (i = 0; protocols[i]; ++i) {
63 struct protocol *p = protocols[i];
64 if (argc - 2 >= p->arguments && !strcmp(argv[1], p->name)) {
65 log_print(INFO, "Using protocol %s", p->name);
66 the_protocol = p;
Chia-chi Yeh79e62322009-06-02 08:49:55 +080067 break;
68 }
69 }
70
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070071 if (!the_protocol) {
72 printf("Usages:\n");
Chia-chi Yeh79e62322009-06-02 08:49:55 +080073 for (i = 0; protocols[i]; ++i) {
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070074 struct protocol *p = protocols[i];
75 printf(" %s %s %s pppd-arguments\n", argv[0], p->name, p->usage);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080076 }
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070077 exit(0);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080078 }
79
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070080 pppd_argc = argc - 2 - the_protocol->arguments;
81 pppd_argv = &argv[2 + the_protocol->arguments];
82 return the_protocol->connect(&argv[2]);
Chia-chi Yeh79e62322009-06-02 08:49:55 +080083}
84
85static void stop_pppd()
86{
87 if (pppd_pid) {
88 log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid);
89 kill(pppd_pid, SIGTERM);
90 sleep(5);
91 pppd_pid = 0;
92 }
93}
94
Chia-chi Yeh84e31952009-06-08 14:11:34 +080095#ifdef ANDROID_CHANGES
96
97static int get_control_and_arguments(int *argc, char ***argv)
98{
Chia-chi Yeh7b66d202011-06-28 16:39:23 -070099 static char *args[32];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800100 int control;
101 int i;
102
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800103 if ((i = android_get_control_socket("mtpd")) == -1) {
104 return -1;
105 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800106 log_print(DEBUG, "Waiting for control socket");
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800107 if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800108 log_print(FATAL, "Cannot get control socket");
109 exit(SYSTEM_ERROR);
110 }
111 close(i);
112 fcntl(control, F_SETFD, FD_CLOEXEC);
113
114 args[0] = (*argv)[0];
Chia-chi Yeh7b66d202011-06-28 16:39:23 -0700115 for (i = 1; i < 32; ++i) {
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700116 unsigned char bytes[2];
117 if (recv(control, &bytes[0], 1, 0) != 1
118 || recv(control, &bytes[1], 1, 0) != 1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800119 log_print(FATAL, "Cannot get argument length");
120 exit(SYSTEM_ERROR);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800121 } else {
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700122 int length = bytes[0] << 8 | bytes[1];
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800123 int offset = 0;
Chia-chi Yeh41ab6202011-06-28 16:52:02 -0700124
125 if (length == 0xFFFF) {
126 break;
127 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800128 args[i] = malloc(length + 1);
129 while (offset < length) {
130 int n = recv(control, &args[i][offset], length - offset, 0);
131 if (n > 0) {
132 offset += n;
133 } else {
134 log_print(FATAL, "Cannot get argument value");
135 exit(SYSTEM_ERROR);
136 }
137 }
138 args[i][length] = 0;
139 }
140 }
141 log_print(DEBUG, "Received %d arguments", i - 1);
142
143 *argc = i;
144 *argv = args;
145 return control;
146}
147
148#endif
149
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800150int main(int argc, char **argv)
151{
152 struct pollfd pollfds[2];
153 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800154 int status;
155#ifdef ANDROID_CHANGES
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800156 int control = get_control_and_arguments(&argc, &argv);
Chia-chi Yehfa04c312009-07-11 01:01:33 +0800157 unsigned char code = argc - 1;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800158 send(control, &code, 1, 0);
159#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800160
161 srandom(time(NULL));
162
163 if (pipe(signals) == -1) {
164 log_print(FATAL, "Pipe() %s", strerror(errno));
165 exit(SYSTEM_ERROR);
166 }
Chia-chi Yeh2d247652009-06-23 09:13:45 +0800167 fcntl(signals[0], F_SETFD, FD_CLOEXEC);
168 fcntl(signals[1], F_SETFD, FD_CLOEXEC);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800169
Chia-chi Yeha7776542009-06-19 16:36:32 +0800170 timeout = initialize(argc, argv);
171
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800172 signal(SIGHUP, interrupt);
173 signal(SIGINT, interrupt);
174 signal(SIGTERM, interrupt);
175 signal(SIGCHLD, interrupt);
176 signal(SIGPIPE, SIG_IGN);
177 atexit(stop_pppd);
178
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800179 pollfds[0].fd = signals[0];
180 pollfds[0].events = POLLIN;
181 pollfds[1].fd = the_socket;
182 pollfds[1].events = POLLIN;
183
184 while (timeout >= 0) {
185 if (poll(pollfds, 2, timeout ? timeout : -1) == -1 && errno != EINTR) {
186 log_print(FATAL, "Poll() %s", strerror(errno));
187 exit(SYSTEM_ERROR);
188 }
189 if (pollfds[0].revents) {
190 break;
191 }
192 timeout = pollfds[1].revents ?
193 the_protocol->process() : the_protocol->timeout();
194 }
195
196 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800197 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800198 } else {
199 int signal;
200 read(signals[0], &signal, sizeof(int));
201 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800202 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
203 && WIFEXITED(status)) {
204 status = WEXITSTATUS(status);
205 log_print(INFO, "Pppd is terminated (status = %d)", status);
206 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800207 pppd_pid = 0;
208 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800209 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800210 }
211 }
212
213 stop_pppd();
214 the_protocol->shutdown();
215
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800216#ifdef ANDROID_CHANGES
217 code = status;
218 send(control, &code, 1, 0);
219#endif
220 log_print(INFO, "Mtpd is terminated (status = %d)", status);
221 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800222}
223
224void log_print(int level, char *format, ...)
225{
226 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800227#ifdef ANDROID_CHANGES
228 static int levels[5] = {
229 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
230 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
231 };
232 va_list ap;
233 va_start(ap, format);
234 __android_log_vprint(levels[level], "mtpd", format, ap);
235 va_end(ap);
236#else
237 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800238 va_list ap;
239 fprintf(stderr, "%c: ", levels[level]);
240 va_start(ap, format);
241 vfprintf(stderr, format, ap);
242 va_end(ap);
243 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800244#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800245 }
246}
247
248void create_socket(int family, int type, char *server, char *port)
249{
250 struct addrinfo hints = {
251 .ai_flags = AI_NUMERICSERV,
252 .ai_family = family,
253 .ai_socktype = type,
254 };
255 struct addrinfo *records;
256 struct addrinfo *r;
257 int error;
258
259 log_print(INFO, "Connecting to %s port %s", server, port);
260
261 error = getaddrinfo(server, port, &hints, &records);
262 if (error) {
263 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
264 strerror(errno) : gai_strerror(error));
265 exit(NETWORK_ERROR);
266 }
267
268 for (r = records; r; r = r->ai_next) {
269 the_socket = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
Chia-chi Yeha7776542009-06-19 16:36:32 +0800270 if (the_socket != -1) {
271 if (connect(the_socket, r->ai_addr, r->ai_addrlen) == 0) {
272 break;
273 }
274 close(the_socket);
Chia-chi Yehfa04c312009-07-11 01:01:33 +0800275 the_socket = -1;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800276 }
277 }
278
279 freeaddrinfo(records);
280
281 if (the_socket == -1) {
282 log_print(FATAL, "Connect() %s", strerror(errno));
283 exit(NETWORK_ERROR);
284 }
285
286 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
287 log_print(INFO, "Connection established (socket = %d)", the_socket);
288}
289
290void start_pppd(int pppox)
291{
292 if (pppd_pid) {
293 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
294 close(pppox);
295 return;
296 }
297
298 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
299
300 pppd_pid = fork();
301 if (pppd_pid < 0) {
302 log_print(FATAL, "Fork() %s", strerror(errno));
303 exit(SYSTEM_ERROR);
304 }
305
306 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800307 char *args[pppd_argc + 5];
308 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800309
310 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800311 args[0] = "pppd";
312 args[1] = "nodetach";
313 args[2] = "pppox";
314 args[3] = number;
315 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
316 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800317
Chia-chi Yeh4a721df2009-12-15 03:53:47 +0800318#ifdef ANDROID_CHANGES
319 {
320 char envargs[65536];
321 char *tail = envargs;
322 int i;
323 /* Hex encode the arguments using [A-P] instead of [0-9A-F]. */
324 for (i = 0; args[i]; ++i) {
325 char *p = args[i];
326 do {
327 *tail++ = 'A' + ((*p >> 4) & 0x0F);
328 *tail++ = 'A' + (*p & 0x0F);
329 } while (*p++);
330 }
331 *tail = 0;
332 setenv("envargs", envargs, 1);
333 args[1] = NULL;
334 }
335#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800336 execvp("pppd", args);
337 log_print(FATAL, "Exec() %s", strerror(errno));
338 exit(1); /* Pretending a fatal error in pppd. */
339 }
340
341 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
342 close(pppox);
343}