diff options
| -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; |
