iproxy.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. /*
  2. * iproxy.c -- proxy that enables tcp service access to iOS devices
  3. *
  4. * Copyright (C) 2014 Martin Szulecki <m.szulecki@libimobiledevice.org>
  5. * Copyright (C) 2009 Nikias Bassen <nikias@gmx.li>
  6. * Copyright (C) 2009 Paul Sladen <libiphone@paul.sladen.org>
  7. *
  8. * Based upon iTunnel source code, Copyright (c) 2008 Jing Su.
  9. * http://www.cs.toronto.edu/~jingsu/itunnel/
  10. *
  11. * This program is free software; you can redistribute it and/or modify
  12. * it under the terms of the GNU General Public License as published by
  13. * the Free Software Foundation; either version 2 of the License, or
  14. * (at your option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. * GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License
  22. * along with this program; if not, write to the Free Software
  23. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  24. */
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <fcntl.h>
  29. #include <stddef.h>
  30. #include <unistd.h>
  31. #include <errno.h>
  32. #ifdef WIN32
  33. #include <windows.h>
  34. #include <winsock2.h>
  35. typedef unsigned int socklen_t;
  36. #else
  37. #include <sys/socket.h>
  38. #include <sys/un.h>
  39. #include <arpa/inet.h>
  40. #include <pthread.h>
  41. #include <netinet/in.h>
  42. #endif
  43. #include "socket.h"
  44. #include "usbmuxd.h"
  45. static uint16_t listen_port = 0;
  46. static uint16_t device_port = 0;
  47. static char* device_udid = NULL;
  48. struct client_data {
  49. int fd;
  50. int sfd;
  51. volatile int stop_ctos;
  52. volatile int stop_stoc;
  53. };
  54. static void *run_stoc_loop(void *arg)
  55. {
  56. struct client_data *cdata = (struct client_data*)arg;
  57. int recv_len;
  58. int sent;
  59. char buffer[131072];
  60. printf("%s: fd = %d\n", __func__, cdata->fd);
  61. while (!cdata->stop_stoc && cdata->fd > 0 && cdata->sfd > 0) {
  62. recv_len = socket_receive_timeout(cdata->sfd, buffer, sizeof(buffer), 0, 5000);
  63. if (recv_len <= 0) {
  64. if (recv_len == 0) {
  65. // try again
  66. continue;
  67. } else {
  68. fprintf(stderr, "recv failed: %s\n", strerror(-recv_len));
  69. break;
  70. }
  71. } else {
  72. // send to socket
  73. sent = socket_send(cdata->fd, buffer, recv_len);
  74. if (sent < recv_len) {
  75. if (sent <= 0) {
  76. fprintf(stderr, "send failed: %s\n", strerror(errno));
  77. break;
  78. } else {
  79. fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
  80. }
  81. }
  82. }
  83. }
  84. socket_close(cdata->fd);
  85. cdata->fd = -1;
  86. cdata->stop_ctos = 1;
  87. return NULL;
  88. }
  89. static void *run_ctos_loop(void *arg)
  90. {
  91. struct client_data *cdata = (struct client_data*)arg;
  92. int recv_len;
  93. int sent;
  94. char buffer[131072];
  95. #ifdef WIN32
  96. HANDLE stoc = NULL;
  97. #else
  98. pthread_t stoc;
  99. #endif
  100. printf("%s: fd = %d\n", __func__, cdata->fd);
  101. cdata->stop_stoc = 0;
  102. #ifdef WIN32
  103. stoc = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)run_stoc_loop, cdata, 0, NULL);
  104. #else
  105. pthread_create(&stoc, NULL, run_stoc_loop, cdata);
  106. #endif
  107. while (!cdata->stop_ctos && cdata->fd>0 && cdata->sfd>0) {
  108. recv_len = socket_receive_timeout(cdata->fd, buffer, sizeof(buffer), 0, 5000);
  109. if (recv_len <= 0) {
  110. if (recv_len == 0) {
  111. // try again
  112. continue;
  113. } else {
  114. fprintf(stderr, "recv failed: %s\n", strerror(-recv_len));
  115. break;
  116. }
  117. } else {
  118. // send to local socket
  119. sent = socket_send(cdata->sfd, buffer, recv_len);
  120. if (sent < recv_len) {
  121. if (sent <= 0) {
  122. fprintf(stderr, "send failed: %s\n", strerror(errno));
  123. break;
  124. } else {
  125. fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
  126. }
  127. }
  128. }
  129. }
  130. socket_close(cdata->fd);
  131. cdata->fd = -1;
  132. cdata->stop_stoc = 1;
  133. #ifdef WIN32
  134. WaitForSingleObject(stoc, INFINITE);
  135. #else
  136. pthread_join(stoc, NULL);
  137. #endif
  138. return NULL;
  139. }
  140. static void *acceptor_thread(void *arg)
  141. {
  142. struct client_data *cdata;
  143. usbmuxd_device_info_t *dev_list = NULL;
  144. #ifdef WIN32
  145. HANDLE ctos = NULL;
  146. #else
  147. pthread_t ctos;
  148. #endif
  149. int count;
  150. if (!arg) {
  151. fprintf(stderr, "invalid client_data provided!\n");
  152. return NULL;
  153. }
  154. cdata = (struct client_data*)arg;
  155. if ((count = usbmuxd_get_device_list(&dev_list)) < 0) {
  156. printf("Connecting to usbmuxd failed, terminating.\n");
  157. free(dev_list);
  158. if (cdata->fd > 0) {
  159. socket_close(cdata->fd);
  160. }
  161. free(cdata);
  162. return NULL;
  163. }
  164. fprintf(stdout, "Number of available devices == %d\n", count);
  165. if (dev_list == NULL || dev_list[0].handle == 0) {
  166. printf("No connected device found, terminating.\n");
  167. free(dev_list);
  168. if (cdata->fd > 0) {
  169. socket_close(cdata->fd);
  170. }
  171. free(cdata);
  172. return NULL;
  173. }
  174. usbmuxd_device_info_t *dev = NULL;
  175. if (device_udid) {
  176. int i;
  177. for (i = 0; i < count; i++) {
  178. if (strncmp(dev_list[i].udid, device_udid, sizeof(dev_list[0].udid)) == 0) {
  179. dev = &(dev_list[i]);
  180. break;
  181. }
  182. }
  183. } else {
  184. dev = &(dev_list[0]);
  185. }
  186. if (dev == NULL || dev->handle == 0) {
  187. printf("No connected/matching device found, disconnecting client.\n");
  188. free(dev_list);
  189. if (cdata->fd > 0) {
  190. socket_close(cdata->fd);
  191. }
  192. free(cdata);
  193. return NULL;
  194. }
  195. fprintf(stdout, "Requesting connecion to device handle == %d (serial: %s), port %d\n", dev->handle, dev->udid, device_port);
  196. cdata->sfd = usbmuxd_connect(dev->handle, device_port);
  197. free(dev_list);
  198. if (cdata->sfd < 0) {
  199. fprintf(stderr, "Error connecting to device!\n");
  200. } else {
  201. cdata->stop_ctos = 0;
  202. #ifdef WIN32
  203. ctos = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)run_ctos_loop, cdata, 0, NULL);
  204. WaitForSingleObject(ctos, INFINITE);
  205. #else
  206. pthread_create(&ctos, NULL, run_ctos_loop, cdata);
  207. pthread_join(ctos, NULL);
  208. #endif
  209. }
  210. if (cdata->fd > 0) {
  211. socket_close(cdata->fd);
  212. }
  213. if (cdata->sfd > 0) {
  214. socket_close(cdata->sfd);
  215. }
  216. free(cdata);
  217. return NULL;
  218. }
  219. int main(int argc, char **argv)
  220. {
  221. int mysock = -1;
  222. if (argc < 3) {
  223. printf("usage: %s LOCAL_TCP_PORT DEVICE_TCP_PORT [UDID]\n", argv[0]);
  224. return 0;
  225. }
  226. listen_port = atoi(argv[1]);
  227. device_port = atoi(argv[2]);
  228. if (argc > 3) {
  229. device_udid = argv[3];
  230. }
  231. if (!listen_port) {
  232. fprintf(stderr, "Invalid listen_port specified!\n");
  233. return -EINVAL;
  234. }
  235. if (!device_port) {
  236. fprintf(stderr, "Invalid device_port specified!\n");
  237. return -EINVAL;
  238. }
  239. // first create the listening socket endpoint waiting for connections.
  240. mysock = socket_create(listen_port);
  241. if (mysock < 0) {
  242. fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
  243. return -errno;
  244. } else {
  245. #ifdef WIN32
  246. HANDLE acceptor = NULL;
  247. #else
  248. pthread_t acceptor;
  249. #endif
  250. struct client_data *cdata;
  251. int c_sock;
  252. while (1) {
  253. printf("waiting for connection\n");
  254. c_sock = socket_accept(mysock, listen_port);
  255. if (c_sock) {
  256. printf("accepted connection, fd = %d\n", c_sock);
  257. cdata = (struct client_data*)malloc(sizeof(struct client_data));
  258. if (!cdata) {
  259. socket_close(c_sock);
  260. fprintf(stderr, "ERROR: Out of memory\n");
  261. return -1;
  262. }
  263. cdata->fd = c_sock;
  264. #ifdef WIN32
  265. acceptor = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)acceptor_thread, cdata, 0, NULL);
  266. CloseHandle(acceptor);
  267. #else
  268. pthread_create(&acceptor, NULL, acceptor_thread, cdata);
  269. pthread_detach(acceptor);
  270. #endif
  271. } else {
  272. break;
  273. }
  274. }
  275. socket_close(c_sock);
  276. socket_close(mysock);
  277. }
  278. return 0;
  279. }