blob: 4a06f3be81864a461b7e0c78308f9dd24837e78d [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 }
174
175 signal(SIGHUP, interrupt);
176 signal(SIGINT, interrupt);
177 signal(SIGTERM, interrupt);
178 signal(SIGCHLD, interrupt);
179 signal(SIGPIPE, SIG_IGN);
180 atexit(stop_pppd);
181
182 timeout = initialize(argc, argv);
183 pollfds[0].fd = signals[0];
184 pollfds[0].events = POLLIN;
185 pollfds[1].fd = the_socket;
186 pollfds[1].events = POLLIN;
187
188 while (timeout >= 0) {
189 if (poll(pollfds, 2, timeout ? timeout : -1) == -1 && errno != EINTR) {
190 log_print(FATAL, "Poll() %s", strerror(errno));
191 exit(SYSTEM_ERROR);
192 }
193 if (pollfds[0].revents) {
194 break;
195 }
196 timeout = pollfds[1].revents ?
197 the_protocol->process() : the_protocol->timeout();
198 }
199
200 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800201 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800202 } else {
203 int signal;
204 read(signals[0], &signal, sizeof(int));
205 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800206 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
207 && WIFEXITED(status)) {
208 status = WEXITSTATUS(status);
209 log_print(INFO, "Pppd is terminated (status = %d)", status);
210 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800211 pppd_pid = 0;
212 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800213 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800214 }
215 }
216
217 stop_pppd();
218 the_protocol->shutdown();
219
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800220#ifdef ANDROID_CHANGES
221 code = status;
222 send(control, &code, 1, 0);
223#endif
224 log_print(INFO, "Mtpd is terminated (status = %d)", status);
225 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800226}
227
228void log_print(int level, char *format, ...)
229{
230 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800231#ifdef ANDROID_CHANGES
232 static int levels[5] = {
233 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
234 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
235 };
236 va_list ap;
237 va_start(ap, format);
238 __android_log_vprint(levels[level], "mtpd", format, ap);
239 va_end(ap);
240#else
241 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800242 va_list ap;
243 fprintf(stderr, "%c: ", levels[level]);
244 va_start(ap, format);
245 vfprintf(stderr, format, ap);
246 va_end(ap);
247 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800248#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800249 }
250}
251
252void create_socket(int family, int type, char *server, char *port)
253{
254 struct addrinfo hints = {
255 .ai_flags = AI_NUMERICSERV,
256 .ai_family = family,
257 .ai_socktype = type,
258 };
259 struct addrinfo *records;
260 struct addrinfo *r;
261 int error;
262
263 log_print(INFO, "Connecting to %s port %s", server, port);
264
265 error = getaddrinfo(server, port, &hints, &records);
266 if (error) {
267 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
268 strerror(errno) : gai_strerror(error));
269 exit(NETWORK_ERROR);
270 }
271
272 for (r = records; r; r = r->ai_next) {
273 the_socket = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
274 if (the_socket != -1
275 && connect(the_socket, r->ai_addr, r->ai_addrlen) == 0) {
276 break;
277 }
278 }
279
280 freeaddrinfo(records);
281
282 if (the_socket == -1) {
283 log_print(FATAL, "Connect() %s", strerror(errno));
284 exit(NETWORK_ERROR);
285 }
286
287 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
288 log_print(INFO, "Connection established (socket = %d)", the_socket);
289}
290
291void start_pppd(int pppox)
292{
293 if (pppd_pid) {
294 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
295 close(pppox);
296 return;
297 }
298
299 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
300
301 pppd_pid = fork();
302 if (pppd_pid < 0) {
303 log_print(FATAL, "Fork() %s", strerror(errno));
304 exit(SYSTEM_ERROR);
305 }
306
307 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800308 char *args[pppd_argc + 5];
309 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800310
311 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800312 args[0] = "pppd";
313 args[1] = "nodetach";
314 args[2] = "pppox";
315 args[3] = number;
316 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
317 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800318
319 execvp("pppd", args);
320 log_print(FATAL, "Exec() %s", strerror(errno));
321 exit(1); /* Pretending a fatal error in pppd. */
322 }
323
324 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
325 close(pppox);
326}