blob: 5a2492bdc46d277749e07598c1ef67d145c91b1e [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;
42static struct protocol *protocols[] = {&l2tp, NULL};
43static struct protocol *the_protocol;
44
45static int pppd_argc;
46static char **pppd_argv;
47static pid_t pppd_pid;
48
49/* We redirect signals to a pipe in order to prevent race conditions. */
50static int signals[2];
51
52static void interrupt(int signal)
53{
54 write(signals[1], &signal, sizeof(int));
55}
56
57static int initialize(int argc, char **argv)
58{
59 int timeout = 0;
60 int i;
61
62 for (i = 2; i < argc; ++i) {
63 if (!argv[i][0]) {
64 pppd_argc = argc - i - 1;
65 pppd_argv = &argv[i + 1];
66 argc = i;
67 break;
68 }
69 }
70
71 if (argc >= 2) {
72 for (i = 0; protocols[i]; ++i) {
73 if (!strcmp(argv[1], protocols[i]->name)) {
74 log_print(INFO, "Using protocol %s", protocols[i]->name);
75 the_protocol = protocols[i];
76 timeout = the_protocol->connect(argc - 2, &argv[2]);
77 break;
78 }
79 }
80 }
81
82 if (!the_protocol || timeout == -USAGE_ERROR) {
83 printf("Usage: %s <protocol-args> '' <pppd-args>, "
84 "where protocol-args are one of:\n", argv[0]);
85 for (i = 0; protocols[i]; ++i) {
86 printf(" %s %s\n", protocols[i]->name, protocols[i]->usage);
87 }
88 exit(USAGE_ERROR);
89 }
90 return timeout;
91}
92
93static void stop_pppd()
94{
95 if (pppd_pid) {
96 log_print(INFO, "Sending signal to pppd (pid = %d)", pppd_pid);
97 kill(pppd_pid, SIGTERM);
98 sleep(5);
99 pppd_pid = 0;
100 }
101}
102
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800103#ifdef ANDROID_CHANGES
104
105static int get_control_and_arguments(int *argc, char ***argv)
106{
107 static char *args[256];
108 int control;
109 int i;
110
111 log_print(DEBUG, "Waiting for control socket");
112 i = android_get_control_socket("mtpd");
113 if (i == -1 || listen(i, 1) == -1 || (control = accept(i, NULL, 0)) == -1) {
114 log_print(FATAL, "Cannot get control socket");
115 exit(SYSTEM_ERROR);
116 }
117 close(i);
118 fcntl(control, F_SETFD, FD_CLOEXEC);
119
120 args[0] = (*argv)[0];
121 for (i = 1; i < 256; ++i) {
122 unsigned char length;
123 if (recv(control, &length, 1, 0) != 1) {
124 log_print(FATAL, "Cannot get argument length");
125 exit(SYSTEM_ERROR);
126 }
127 if (length == 0xFF) {
128 break;
129 } else {
130 int offset = 0;
131 args[i] = malloc(length + 1);
132 while (offset < length) {
133 int n = recv(control, &args[i][offset], length - offset, 0);
134 if (n > 0) {
135 offset += n;
136 } else {
137 log_print(FATAL, "Cannot get argument value");
138 exit(SYSTEM_ERROR);
139 }
140 }
141 args[i][length] = 0;
142 }
143 }
144 log_print(DEBUG, "Received %d arguments", i - 1);
145
146 *argc = i;
147 *argv = args;
148 return control;
149}
150
151#endif
152
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800153int main(int argc, char **argv)
154{
155 struct pollfd pollfds[2];
156 int timeout;
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800157 int status;
158#ifdef ANDROID_CHANGES
159 unsigned char code;
160 int control = get_control_and_arguments(&argc, &argv);
161 code = argc - 1;
162 send(control, &code, 1, 0);
163#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800164
165 srandom(time(NULL));
166
167 if (pipe(signals) == -1) {
168 log_print(FATAL, "Pipe() %s", strerror(errno));
169 exit(SYSTEM_ERROR);
170 }
171
172 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
179 timeout = initialize(argc, argv);
180 pollfds[0].fd = signals[0];
181 pollfds[0].events = POLLIN;
182 pollfds[1].fd = the_socket;
183 pollfds[1].events = POLLIN;
184
185 while (timeout >= 0) {
186 if (poll(pollfds, 2, timeout ? timeout : -1) == -1 && errno != EINTR) {
187 log_print(FATAL, "Poll() %s", strerror(errno));
188 exit(SYSTEM_ERROR);
189 }
190 if (pollfds[0].revents) {
191 break;
192 }
193 timeout = pollfds[1].revents ?
194 the_protocol->process() : the_protocol->timeout();
195 }
196
197 if (timeout < 0) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800198 status = -timeout;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800199 } else {
200 int signal;
201 read(signals[0], &signal, sizeof(int));
202 log_print(INFO, "Received signal %d", signal);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800203 if (signal == SIGCHLD && waitpid(pppd_pid, &status, WNOHANG) == pppd_pid
204 && WIFEXITED(status)) {
205 status = WEXITSTATUS(status);
206 log_print(INFO, "Pppd is terminated (status = %d)", status);
207 status += PPPD_EXITED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800208 pppd_pid = 0;
209 } else {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800210 status = USER_REQUESTED;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800211 }
212 }
213
214 stop_pppd();
215 the_protocol->shutdown();
216
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800217#ifdef ANDROID_CHANGES
218 code = status;
219 send(control, &code, 1, 0);
220#endif
221 log_print(INFO, "Mtpd is terminated (status = %d)", status);
222 return status;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800223}
224
225void log_print(int level, char *format, ...)
226{
227 if (level >= 0 && level <= LOG_MAX) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800228#ifdef ANDROID_CHANGES
229 static int levels[5] = {
230 ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
231 ANDROID_LOG_ERROR, ANDROID_LOG_FATAL
232 };
233 va_list ap;
234 va_start(ap, format);
235 __android_log_vprint(levels[level], "mtpd", format, ap);
236 va_end(ap);
237#else
238 static char *levels = "DIWEF";
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800239 va_list ap;
240 fprintf(stderr, "%c: ", levels[level]);
241 va_start(ap, format);
242 vfprintf(stderr, format, ap);
243 va_end(ap);
244 fputc('\n', stderr);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800245#endif
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800246 }
247}
248
249void create_socket(int family, int type, char *server, char *port)
250{
251 struct addrinfo hints = {
252 .ai_flags = AI_NUMERICSERV,
253 .ai_family = family,
254 .ai_socktype = type,
255 };
256 struct addrinfo *records;
257 struct addrinfo *r;
258 int error;
259
260 log_print(INFO, "Connecting to %s port %s", server, port);
261
262 error = getaddrinfo(server, port, &hints, &records);
263 if (error) {
264 log_print(FATAL, "Getaddrinfo() %s", (error == EAI_SYSTEM) ?
265 strerror(errno) : gai_strerror(error));
266 exit(NETWORK_ERROR);
267 }
268
269 for (r = records; r; r = r->ai_next) {
270 the_socket = socket(r->ai_family, r->ai_socktype, r->ai_protocol);
271 if (the_socket != -1
272 && connect(the_socket, r->ai_addr, r->ai_addrlen) == 0) {
273 break;
274 }
275 }
276
277 freeaddrinfo(records);
278
279 if (the_socket == -1) {
280 log_print(FATAL, "Connect() %s", strerror(errno));
281 exit(NETWORK_ERROR);
282 }
283
284 fcntl(the_socket, F_SETFD, FD_CLOEXEC);
285 log_print(INFO, "Connection established (socket = %d)", the_socket);
286}
287
288void start_pppd(int pppox)
289{
290 if (pppd_pid) {
291 log_print(WARNING, "Pppd is already started (pid = %d)", pppd_pid);
292 close(pppox);
293 return;
294 }
295
296 log_print(INFO, "Starting pppd (pppox = %d)", pppox);
297
298 pppd_pid = fork();
299 if (pppd_pid < 0) {
300 log_print(FATAL, "Fork() %s", strerror(errno));
301 exit(SYSTEM_ERROR);
302 }
303
304 if (!pppd_pid) {
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800305 char *args[pppd_argc + 5];
306 char number[12];
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800307
308 sprintf(number, "%d", pppox);
Chia-chi Yeh84e31952009-06-08 14:11:34 +0800309 args[0] = "pppd";
310 args[1] = "nodetach";
311 args[2] = "pppox";
312 args[3] = number;
313 memcpy(&args[4], pppd_argv, sizeof(char *) * pppd_argc);
314 args[4 + pppd_argc] = NULL;
Chia-chi Yeh79e62322009-06-02 08:49:55 +0800315
316 execvp("pppd", args);
317 log_print(FATAL, "Exec() %s", strerror(errno));
318 exit(1); /* Pretending a fatal error in pppd. */
319 }
320
321 log_print(INFO, "Pppd started (pid = %d)", pppd_pid);
322 close(pppox);
323}