diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/main.c | 187 |
1 files changed, 167 insertions, 20 deletions
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * main.c | 2 | * main.c |
3 | * | 3 | * |
4 | * Copyright (C) 2009-2019 Nikias Bassen <nikias@gmx.li> | 4 | * Copyright (C) 2009-2021 Nikias Bassen <nikias@gmx.li> |
5 | * Copyright (C) 2013-2014 Martin Szulecki <m.szulecki@libimobiledevice.org> | 5 | * Copyright (C) 2013-2014 Martin Szulecki <m.szulecki@libimobiledevice.org> |
6 | * Copyright (C) 2009 Hector Martin <hector@marcansoft.com> | 6 | * Copyright (C) 2009 Hector Martin <hector@marcansoft.com> |
7 | * Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org> | 7 | * Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org> |
@@ -36,6 +36,9 @@ | |||
36 | #include <unistd.h> | 36 | #include <unistd.h> |
37 | #include <sys/socket.h> | 37 | #include <sys/socket.h> |
38 | #include <sys/un.h> | 38 | #include <sys/un.h> |
39 | #include <netinet/in.h> | ||
40 | #include <netdb.h> | ||
41 | #include <arpa/inet.h> | ||
39 | #include <sys/stat.h> | 42 | #include <sys/stat.h> |
40 | #include <sys/types.h> | 43 | #include <sys/types.h> |
41 | #include <sys/resource.h> | 44 | #include <sys/resource.h> |
@@ -69,22 +72,162 @@ static int opt_enable_exit = 0; | |||
69 | static int opt_exit = 0; | 72 | static int opt_exit = 0; |
70 | static int exit_signal = 0; | 73 | static int exit_signal = 0; |
71 | static int daemon_pipe; | 74 | static int daemon_pipe; |
75 | static const char *listen_addr = NULL; | ||
72 | 76 | ||
73 | static int report_to_parent = 0; | 77 | static int report_to_parent = 0; |
74 | 78 | ||
75 | static int create_socket(void) { | 79 | static int create_socket(void) |
76 | struct sockaddr_un bind_addr; | 80 | { |
77 | int listenfd; | 81 | int listenfd; |
82 | const char* socket_addr = socket_path; | ||
83 | const char* tcp_port; | ||
84 | char listen_addr_str[256]; | ||
85 | |||
86 | if (listen_addr) { | ||
87 | socket_addr = listen_addr; | ||
88 | } | ||
89 | tcp_port = strrchr(socket_addr, ':'); | ||
90 | if (tcp_port) { | ||
91 | tcp_port++; | ||
92 | size_t nlen = tcp_port - socket_addr; | ||
93 | char* hostname = malloc(nlen); | ||
94 | struct addrinfo hints; | ||
95 | struct addrinfo *result, *rp; | ||
96 | int yes = 1; | ||
97 | int res; | ||
98 | |||
99 | strncpy(hostname, socket_addr, nlen-1); | ||
100 | hostname[nlen-1] = '\0'; | ||
101 | |||
102 | memset(&hints, '\0', sizeof(struct addrinfo)); | ||
103 | hints.ai_family = AF_UNSPEC; | ||
104 | hints.ai_socktype = SOCK_STREAM; | ||
105 | hints.ai_flags = AI_PASSIVE | AI_NUMERICSERV; | ||
106 | hints.ai_protocol = IPPROTO_TCP; | ||
107 | |||
108 | res = getaddrinfo(hostname, tcp_port, &hints, &result); | ||
109 | free(hostname); | ||
110 | if (res != 0) { | ||
111 | usbmuxd_log(LL_FATAL, "%s: getaddrinfo() failed: %s\n", __func__, gai_strerror(res)); | ||
112 | return -1; | ||
113 | } | ||
78 | 114 | ||
79 | if(unlink(socket_path) == -1 && errno != ENOENT) { | 115 | for (rp = result; rp != NULL; rp = rp->ai_next) { |
80 | usbmuxd_log(LL_FATAL, "unlink(%s) failed: %s", socket_path, strerror(errno)); | 116 | listenfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); |
81 | return -1; | 117 | if (listenfd == -1) { |
82 | } | 118 | listenfd = -1; |
119 | continue; | ||
120 | } | ||
83 | 121 | ||
84 | listenfd = socket(AF_UNIX, SOCK_STREAM, 0); | 122 | if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { |
85 | if (listenfd == -1) { | 123 | usbmuxd_log(LL_ERROR, "%s: setsockopt(): %s", __func__, strerror(errno)); |
86 | usbmuxd_log(LL_FATAL, "socket() failed: %s", strerror(errno)); | 124 | close(listenfd); |
87 | return -1; | 125 | listenfd = -1; |
126 | continue; | ||
127 | } | ||
128 | |||
129 | #ifdef SO_NOSIGPIPE | ||
130 | if (setsockopt(listenfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
131 | usbmuxd_log(LL_ERROR, "%s: setsockopt(): %s", __func__, strerror(errno)); | ||
132 | close(listenfd); | ||
133 | listenfd = -1; | ||
134 | continue; | ||
135 | } | ||
136 | #endif | ||
137 | |||
138 | #if defined(AF_INET6) && defined(IPV6_V6ONLY) | ||
139 | if (rp->ai_family == AF_INET6) { | ||
140 | if (setsockopt(listenfd, IPPROTO_IPV6, IPV6_V6ONLY, (void*)&yes, sizeof(int)) == -1) { | ||
141 | usbmuxd_log(LL_ERROR, "%s: setsockopt() IPV6_V6ONLY: %s", __func__, strerror(errno)); | ||
142 | } | ||
143 | } | ||
144 | #endif | ||
145 | |||
146 | if (bind(listenfd, rp->ai_addr, rp->ai_addrlen) < 0) { | ||
147 | usbmuxd_log(LL_FATAL, "%s: bind() failed: %s", __func__, strerror(errno)); | ||
148 | close(listenfd); | ||
149 | listenfd = -1; | ||
150 | continue; | ||
151 | } | ||
152 | |||
153 | const void *addrdata = NULL; | ||
154 | if (rp->ai_family == AF_INET) { | ||
155 | addrdata = &((struct sockaddr_in*)rp->ai_addr)->sin_addr; | ||
156 | } | ||
157 | #ifdef AF_INET6 | ||
158 | else if (rp->ai_family == AF_INET6) { | ||
159 | addrdata = &((struct sockaddr_in6*)rp->ai_addr)->sin6_addr; | ||
160 | } | ||
161 | #endif | ||
162 | if (addrdata) { | ||
163 | char* endp = NULL; | ||
164 | uint16_t listen_port = 0; | ||
165 | if (rp->ai_family == AF_INET) { | ||
166 | listen_port = ntohs(((struct sockaddr_in*)rp->ai_addr)->sin_port); | ||
167 | if (inet_ntop(AF_INET, addrdata, listen_addr_str, sizeof(listen_addr_str)-6)) { | ||
168 | endp = &listen_addr_str[0] + strlen(listen_addr_str); | ||
169 | } | ||
170 | } | ||
171 | #ifdef AF_INET6 | ||
172 | else if (rp->ai_family == AF_INET6) { | ||
173 | listen_port = ntohs(((struct sockaddr_in6*)rp->ai_addr)->sin6_port); | ||
174 | listen_addr_str[0] = '['; | ||
175 | if (inet_ntop(AF_INET6, addrdata, listen_addr_str+1, sizeof(listen_addr_str)-8)) { | ||
176 | endp = &listen_addr_str[0] + strlen(listen_addr_str); | ||
177 | } | ||
178 | if (endp) { | ||
179 | *endp = ']'; | ||
180 | endp++; | ||
181 | } | ||
182 | } | ||
183 | #endif | ||
184 | if (endp) { | ||
185 | sprintf(endp, ":%u", listen_port); | ||
186 | } | ||
187 | } | ||
188 | break; | ||
189 | } | ||
190 | freeaddrinfo(result); | ||
191 | if (listenfd == -1) { | ||
192 | usbmuxd_log(LL_FATAL, "%s: Failed to create listening socket", __func__); | ||
193 | return -1; | ||
194 | } | ||
195 | } else { | ||
196 | struct sockaddr_un bind_addr; | ||
197 | |||
198 | if (strcmp(socket_addr, socket_path) != 0) { | ||
199 | struct stat fst; | ||
200 | if (stat(socket_addr, &fst) == 0) { | ||
201 | if (!S_ISSOCK(fst.st_mode)) { | ||
202 | usbmuxd_log(LL_FATAL, "FATAL: File '%s' already exists and is not a socket file. Refusing to continue.", socket_addr); | ||
203 | return -1; | ||
204 | } | ||
205 | } | ||
206 | } | ||
207 | |||
208 | if (unlink(socket_addr) == -1 && errno != ENOENT) { | ||
209 | usbmuxd_log(LL_FATAL, "%s: unlink(%s) failed: %s", __func__, socket_addr, strerror(errno)); | ||
210 | return -1; | ||
211 | } | ||
212 | |||
213 | listenfd = socket(AF_UNIX, SOCK_STREAM, 0); | ||
214 | if (listenfd == -1) { | ||
215 | usbmuxd_log(LL_FATAL, "socket() failed: %s", strerror(errno)); | ||
216 | return -1; | ||
217 | } | ||
218 | |||
219 | bzero(&bind_addr, sizeof(bind_addr)); | ||
220 | bind_addr.sun_family = AF_UNIX; | ||
221 | strncpy(bind_addr.sun_path, socket_addr, sizeof(bind_addr.sun_path)); | ||
222 | bind_addr.sun_path[sizeof(bind_addr.sun_path) - 1] = '\0'; | ||
223 | |||
224 | if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) { | ||
225 | usbmuxd_log(LL_FATAL, "bind() failed: %s", strerror(errno)); | ||
226 | return -1; | ||
227 | } | ||
228 | chmod(socket_addr, 0666); | ||
229 | |||
230 | snprintf(listen_addr_str, sizeof(listen_addr_str), "%s", socket_addr); | ||
88 | } | 231 | } |
89 | 232 | ||
90 | int flags = fcntl(listenfd, F_GETFL, 0); | 233 | int flags = fcntl(listenfd, F_GETFL, 0); |
@@ -96,21 +239,13 @@ static int create_socket(void) { | |||
96 | } | 239 | } |
97 | } | 240 | } |
98 | 241 | ||
99 | bzero(&bind_addr, sizeof(bind_addr)); | ||
100 | bind_addr.sun_family = AF_UNIX; | ||
101 | strcpy(bind_addr.sun_path, socket_path); | ||
102 | if (bind(listenfd, (struct sockaddr*)&bind_addr, sizeof(bind_addr)) != 0) { | ||
103 | usbmuxd_log(LL_FATAL, "bind() failed: %s", strerror(errno)); | ||
104 | return -1; | ||
105 | } | ||
106 | |||
107 | // Start listening | 242 | // Start listening |
108 | if (listen(listenfd, 256) != 0) { | 243 | if (listen(listenfd, 256) != 0) { |
109 | usbmuxd_log(LL_FATAL, "listen() failed: %s", strerror(errno)); | 244 | usbmuxd_log(LL_FATAL, "listen() failed: %s", strerror(errno)); |
110 | return -1; | 245 | return -1; |
111 | } | 246 | } |
112 | 247 | ||
113 | chmod(socket_path, 0666); | 248 | usbmuxd_log(LL_INFO, "Listening on %s", listen_addr_str); |
114 | 249 | ||
115 | return listenfd; | 250 | return listenfd; |
116 | } | 251 | } |
@@ -381,6 +516,9 @@ static void usage() | |||
381 | #ifdef HAVE_SYSTEMD | 516 | #ifdef HAVE_SYSTEMD |
382 | printf(" -s, --systemd\t\tRun in systemd operation mode (implies -z and -f).\n"); | 517 | printf(" -s, --systemd\t\tRun in systemd operation mode (implies -z and -f).\n"); |
383 | #endif | 518 | #endif |
519 | printf(" -S, --socket ADDR:PORT | PATH Specify source ADDR and PORT or a UNIX\n"); | ||
520 | printf(" \t\tsocket PATH to use for the listening socket.\n"); | ||
521 | printf(" \t\tDefault: %s\n", socket_path); | ||
384 | printf(" -x, --exit\t\tNotify a running instance to exit if there are no devices\n"); | 522 | printf(" -x, --exit\t\tNotify a running instance to exit if there are no devices\n"); |
385 | printf(" \t\tconnected (sends SIGUSR1 to running instance) and exit.\n"); | 523 | printf(" \t\tconnected (sends SIGUSR1 to running instance) and exit.\n"); |
386 | printf(" -X, --force-exit\tNotify a running instance to exit even if there are still\n"); | 524 | printf(" -X, --force-exit\tNotify a running instance to exit even if there are still\n"); |
@@ -408,6 +546,7 @@ static void parse_opts(int argc, char **argv) | |||
408 | #ifdef HAVE_SYSTEMD | 546 | #ifdef HAVE_SYSTEMD |
409 | {"systemd", no_argument, NULL, 's'}, | 547 | {"systemd", no_argument, NULL, 's'}, |
410 | #endif | 548 | #endif |
549 | {"socket", required_argument, NULL, 'S'}, | ||
411 | {"exit", no_argument, NULL, 'x'}, | 550 | {"exit", no_argument, NULL, 'x'}, |
412 | {"force-exit", no_argument, NULL, 'X'}, | 551 | {"force-exit", no_argument, NULL, 'X'}, |
413 | {"logfile", required_argument, NULL, 'l'}, | 552 | {"logfile", required_argument, NULL, 'l'}, |
@@ -468,6 +607,14 @@ static void parse_opts(int argc, char **argv) | |||
468 | case 'z': | 607 | case 'z': |
469 | opt_enable_exit = 1; | 608 | opt_enable_exit = 1; |
470 | break; | 609 | break; |
610 | case 'S': | ||
611 | if (!*optarg || *optarg == '-') { | ||
612 | usbmuxd_log(LL_FATAL, "ERROR: --socket requires an argument"); | ||
613 | usage(); | ||
614 | exit(2); | ||
615 | } | ||
616 | listen_addr = optarg; | ||
617 | break; | ||
471 | case 'x': | 618 | case 'x': |
472 | opt_exit = 1; | 619 | opt_exit = 1; |
473 | exit_signal = SIGUSR1; | 620 | exit_signal = SIGUSR1; |