blob: 0be22f0835374b537aeee97815c30c313738e2a5 [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{
60 int timeout = 0;
61 int i;
62
63 for (i = 2; i < argc; ++i) {
64 if (!argv[i][0]) {
65 pppd_argc = argc - i - 1;
66 pppd_argv = &argv[i + 1];
67 argc = i;
68 break;
69 }
70 }
71
72 if (argc >= 2) {
73 for (i = 0; protocols[i]; ++i) {
74 if (!strcmp(argv[1], protocols[i]->name)) {
75 log_print(INFO, "Using protocol %s", protocols[i]->name);
76 the_protocol = protocols[i];
77 timeout = the_protocol->connect(argc - 2, &argv[2]);
78 break;
79 }
80 }
81 }
82
83 if (!the_protocol || timeout == -USAGE_ERROR) {
84 printf("Usage: %s <protocol-args> '' <pppd-args>, "
85 "where protocol-args are one of:\n", argv[0]);
86 for (i = 0; protocols[i]; ++i) {
87 printf(" %s %s\n", protocols[i]->name, protocols[i]->usage);
88 }
89 exit(USAGE_ERROR);
90 }
91 return timeout;
92}
93
94static void stop_pppd()
95{
96 if (pppd_pid) {
97 log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid);
98 kill(pppd_pid, SIGTERM);
99 sleep(5);
100 pppd_pid = 0;
101 }
102}
103
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800104#ifdef ANDROID_CHANGES
105
106static int get_control_and_arguments(int *argc, char ***argv)
107{
108 static char *args[256];
109 int control;
110 int i;
111
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800112 if ((i = android_get_control_socket("mtpd")) == -1) {
113 return -1;
114 }
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800115 log_print(DEBUG, "Waiting for control socket");
Chia-chi Yeh063bb922009-06-15 14:43:38 +0800116 if (listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800117 log_print(FATAL, "Cannot get control socket");
118 exit(SYSTEM_ERROR);
119 }
120 close(i);
121 fcntl(control, F_SETFD, FD_CLOEXEC);
122
123 args[0] = (*argv)[0];
124 for (i = 1; i < 256; ++i) {
125 unsigned char length;
126 if (recv(control, &length, 1, 0) != 1) {
127 log_print(FATAL, "Cannot get argument length");
128 exit(SYSTEM_ERROR);
129 }
130 if (length == 0xFF) {
131 break;
132 } else {
133 int offset = 0;
134 args[i] = malloc(length + 1);
135 while (offset < length) {
136 int n = recv(control, &args[i][offset], length - offset, 0);
137 if (n > 0) {
138 offset += n;
139 } else {
140 log_print(FATAL, "Cannot get argument value");
141 exit(SYSTEM_ERROR);
142 }
143 }
144 args[i][length] = 0;
145 }
146 }
147 log_print(DEBUG, "Received %d arguments", i - 1);
148
149 *argc = i;
150 *argv = args;
151 return control;
152}
153
154#endif
155
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800156int main(int argc, char **argv)
157{
158 struct pollfd pollfds[2];
159 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800160 int status;
161#ifdef ANDROID_CHANGES
162 unsigned char code;
163 int control = get_control_and_arguments(&argc, &argv);
164 code = argc - 1;
165 send(control, &code, 1, 0);
166#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800167
168 srandom(time(NULL));
169
170 if (pipe(signals) == -1) {
171 log_print(FATAL, "Pipe() %s", strerror(errno));
172 exit(SYSTEM_ERROR);
173 }
Chia-chi Yeh2d247652009-06-23 09:13:45 +0800174 fcntl(signals[0], F_SETFD, FD_CLOEXEC);
175 fcntl(signals[1], F_SETFD, FD_CLOEXEC);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800176
Chia-chi Yeha7776542009-06-19 16:36:32 +0800177 timeout = initialize(argc, argv);
178
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800179 signal(SIGHUP, interrupt);
180 signal(SIGINT, interrupt);
181 signal(SIGTERM, interrupt);
182 signal(SIGCHLD, interrupt);
183 signal(SIGPIPE, SIG_IGN);
184 atexit(stop_pppd);
185
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800186 pollfds[0].fd = signals[0];
187 pollfds[0].events = POLLIN;
188 pollfds[1].fd = the_socket;
189 pollfds[1].events = POLLIN;
190
191 while (timeout >= 0) {
192 if (poll(pollfds, 2, timeout ? timeout : -1) == -1 && errno != EINTR) {
193 log_print(FATAL, "Poll() %s", strerror(errno));
194 exit(SYSTEM_ERROR);
195 }
196 if (pollfds[0].revents) {
197 break;
198 }
199 timeout = pollfds[1].revents ?
200 the_protocol->process() : the_protocol->timeout();
201 }
202
203 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800204 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800205 } else {
206 int signal;
207 read(signals[0], &signal, sizeof(int));
208 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800209 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
210 && WIFEXITED(status)) {
211 status = WEXITSTATUS(status);
212 log_print(INFO, "Pppd is terminated (status = %d)", status);
213 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800214 pppd_pid = 0;
215 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800216 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800217 }
218 }
219
220 stop_pppd();
221 the_protocol->shutdown();
222
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800223#ifdef ANDROID_CHANGES
224 code = status;
225 send(control, &code, 1, 0);
226#endif
227 log_print(INFO, "Mtpd is terminated (status = %d)", status);
228 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800229}
230
231void log_print(int level, char *format, ...)
232{
233 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800234#ifdef ANDROID_CHANGES
235 static int levels[5] = {
236 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
237 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
238 };
239 va_list ap;
240 va_start(ap, format);
241 __android_log_vprint(levels[level], "mtpd", format, ap);
242 va_end(ap);
243#else
244 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800245 va_list ap;
246 fprintf(stderr, "%c: ", levels[level]);
247 va_start(ap, format);
248 vfprintf(stderr, format, ap);
249 va_end(ap);
250 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800251#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800252 }
253}
254
255void create_socket(int family, int type, char *server, char *port)
256{
257 struct addrinfo hints = {
258 .ai_flags = AI_NUMERICSERV,
259 .ai_family = family,
260 .ai_socktype = type,
261 };
262 struct addrinfo *records;
263 struct addrinfo *r;
264 int error;
265
266 log_print(INFO, "Connecting to %s port %s", server, port);
267
268 error = getaddrinfo(server, port, &hints, &records);
269 if (error) {
270 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
271 strerror(errno) : gai_strerror(error));
272 exit(NETWORK_ERROR);
273 }
274
275 for (r = records; r; r = r->ai_next) {
276 the_socket = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
Chia-chi Yeha7776542009-06-19 16:36:32 +0800277 if (the_socket != -1) {
278 if (connect(the_socket, r->ai_addr, r->ai_addrlen) == 0) {
279 break;
280 }
281 close(the_socket);
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800282 }
283 }
284
285 freeaddrinfo(records);
286
287 if (the_socket == -1) {
288 log_print(FATAL, "Connect() %s", strerror(errno));
289 exit(NETWORK_ERROR);
290 }
291
292 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
293 log_print(INFO, "Connection established (socket = %d)", the_socket);
294}
295
296void start_pppd(int pppox)
297{
298 if (pppd_pid) {
299 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
300 close(pppox);
301 return;
302 }
303
304 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
305
306 pppd_pid = fork();
307 if (pppd_pid < 0) {
308 log_print(FATAL, "Fork() %s", strerror(errno));
309 exit(SYSTEM_ERROR);
310 }
311
312 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800313 char *args[pppd_argc + 5];
314 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800315
316 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800317 args[0] = "pppd";
318 args[1] = "nodetach";
319 args[2] = "pppox";
320 args[3] = number;
321 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
322 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800323
324 execvp("pppd", args);
325 log_print(FATAL, "Exec() %s", strerror(errno));
326 exit(1); /* Pretending a fatal error in pppd. */
327 }
328
329 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
330 close(pppox);
331}