summaryrefslogtreecommitdiffstats
path: root/iproxy.c
diff options
context:
space:
mode:
Diffstat (limited to 'iproxy.c')
-rw-r--r--iproxy.c329
1 files changed, 329 insertions, 0 deletions
diff --git a/iproxy.c b/iproxy.c
new file mode 100644
index 0000000..df3d689
--- /dev/null
+++ b/iproxy.c
@@ -0,0 +1,329 @@
1/*
2 * iproxy -- proxy that enables tcp service access to iPhone/iPod
3 * via USB cable
4 * TODO: improve code...
5 *
6 * Copyright (c) 2009 Nikias Bassen. All Rights Reserved.
7 * Based upon iTunnel source code, Copyright (c) 2008 Jing Su.
8 * http://www.cs.toronto.edu/~jingsu/itunnel/
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 */
24#include <stdio.h>
25#include <stdlib.h>
26#include <fcntl.h>
27#include <stddef.h>
28#include <sys/socket.h>
29#include <sys/un.h>
30#include <unistd.h>
31#include <errno.h>
32#include <arpa/inet.h>
33#include <pthread.h>
34#include "usbmuxd.h"
35#include "sock_stuff.h"
36
37#define SOCKET_FILE "/var/run/usbmuxd"
38
39volatile int stop_ctos = 0;
40volatile int stop_stoc = 0;
41
42static uint16_t listen_port = 0;
43static uint16_t device_port = 0;
44
45pthread_mutex_t smutex = PTHREAD_MUTEX_INITIALIZER;
46
47struct client_data {
48 int fd;
49 int sfd;
50};
51
52int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result)
53{
54 struct usbmux_result res;
55 int recv_len;
56 int i;
57 uint32_t rrr[5];
58
59 if (!result) {
60 return -EINVAL;
61 }
62
63 if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) {
64 perror("recv");
65 return -errno;
66 } else {
67 memcpy(&rrr, &res, recv_len);
68 for (i = 0; i < recv_len/4; i++) {
69 fprintf(stderr, "%08x ", rrr[i]);
70 }
71 fprintf(stderr, "\n");
72 if ((recv_len == sizeof(res))
73 && (res.header.length == recv_len)
74 && (res.header.reserved == 0)
75 && (res.header.type == usbmux_result)
76 ) {
77 *result = res.result;
78 if (res.header.tag == tag) {
79 return 1;
80 } else {
81 return 0;
82 }
83 }
84 }
85
86 return -1;
87}
88
89void *run_stoc_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
96 printf("%s: fd = %d\n", __func__, cdata->fd);
97
98 while (!stop_stoc && cdata->fd>0 && cdata->sfd>0) {
99 recv_len = recv_buf_timeout(cdata->sfd, buffer, sizeof(buffer), 0, 5000);
100 if (recv_len <= 0) {
101 if (recv_len == 0) {
102 // try again
103 continue;
104 } else {
105 fprintf(stderr, "recv failed: %s\n", strerror(errno));
106 break;
107 }
108 } else {
109 printf("received %d bytes from server\n", recv_len);
110 // send to socket
111 sent = send_buf(cdata->fd, buffer, recv_len);
112 if (sent < recv_len) {
113 if (sent <= 0) {
114 fprintf(stderr, "send failed: %s\n", strerror(errno));
115 break;
116 } else {
117 fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
118 }
119 } else {
120 // sending succeeded, receive from device
121 printf("pushed %d bytes to client\n", sent);
122 }
123 }
124 }
125 close(cdata->fd);
126 cdata->fd = -1;
127 stop_ctos = 1;
128
129 return NULL;
130}
131
132void *run_ctos_loop(void *arg)
133{
134 struct client_data *cdata = (struct client_data*)arg;
135 int recv_len;
136 int sent;
137 char buffer[131072];
138 pthread_t stoc = 0;
139
140 printf("%s: fd = %d\n", __func__, cdata->fd);
141
142 stop_stoc = 0;
143 pthread_create(&stoc, NULL, run_stoc_loop, cdata);
144
145 while (!stop_ctos && cdata->fd>0 && cdata->sfd>0) {
146 recv_len = recv_buf_timeout(cdata->fd, buffer, sizeof(buffer), 0, 5000);
147 if (recv_len <= 0) {
148 if (recv_len == 0) {
149 // try again
150 continue;
151 } else {
152 fprintf(stderr, "recv failed: %s\n", strerror(errno));
153 break;
154 }
155 } else {
156 printf("pulled %d bytes from client\n", recv_len);
157 // send to local socket
158 sent = send_buf(cdata->sfd, buffer, recv_len);
159 if (sent < recv_len) {
160 if (sent <= 0) {
161 fprintf(stderr, "send failed: %s\n", strerror(errno));
162 break;
163 } else {
164 fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
165 }
166 } else {
167 // sending succeeded, receive from device
168 printf("sent %d bytes to server\n", sent);
169 }
170 }
171 }
172 close(cdata->fd);
173 cdata->fd = -1;
174 stop_stoc = 1;
175
176 pthread_join(stoc, NULL);
177
178 return NULL;
179}
180
181int main(int argc, char **argv)
182{
183 int recv_len = 0;
184 int hello_done;
185 int connected;
186 uint32_t pktlen;
187 unsigned char *buf;
188 struct usbmux_header hello;
189 struct usbmux_dev_info device_info;
190 int sfd = -1;
191
192 if (argc != 3) {
193 printf("usage: %s LOCAL_PORT DEVICE_PORT\n", argv[0]);
194 return 0;
195 }
196
197 listen_port = atoi(argv[1]);
198 device_port = atoi(argv[2]);
199
200 if (!listen_port) {
201 fprintf(stderr, "Invalid listen_port specified!\n");
202 return -EINVAL;
203 }
204
205 if (!device_port) {
206 fprintf(stderr, "Invalid device_port specified!\n");
207 return -EINVAL;
208 }
209
210 sfd = connect_unix_socket(SOCKET_FILE);
211 if (sfd < 0) {
212 printf("error opening socket, terminating.\n");
213 return -1;
214 }
215
216 // send hello
217 hello.length = sizeof(struct usbmux_header);
218 hello.reserved = 0;
219 hello.type = usbmux_hello;
220 hello.tag = 2;
221
222 hello_done = 0;
223 connected = 0;
224
225 fprintf(stdout, "sending Hello packet\n");
226 if (send(sfd, &hello, hello.length, 0) == hello.length) {
227 uint32_t res = -1;
228 // get response
229 if (usbmuxd_get_result(sfd, hello.tag, &res) && (res==0)) {
230 fprintf(stdout, "Got Hello Response!\n");
231 hello_done = 1;
232 } else {
233 fprintf(stderr, "Did not get Hello response (with result=0)...\n");
234 close(sfd);
235 return -1;
236 }
237
238 device_info.device_id = 0;
239
240 if (hello_done) {
241 // get all devices
242 while (1) {
243 if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) {
244 buf = (unsigned char*)malloc(pktlen);
245 if (!buf) {
246 exit(-ENOMEM);
247 }
248 recv_len = recv_buf(sfd, buf, pktlen);
249 if (recv_len < pktlen) {
250 fprintf(stdout, "received less data than specified in header!\n");
251 }
252 fprintf(stdout, "Received device data\n");
253 //log_debug_buffer(stdout, (char*)buf, pktlen);
254 memcpy(&device_info, buf + sizeof(struct usbmux_header), sizeof(device_info));
255 free(buf);
256 } else {
257 // we _should_ have all of them now.
258 // or perhaps an error occured.
259 break;
260 }
261 }
262 }
263
264 if (device_info.device_id > 0) {
265 struct usbmux_connect_request c_req;
266
267 fprintf(stdout, "Requesting connecion to device %d port %d\n", device_info.device_id, device_port);
268
269 // try to connect to last device found
270 c_req.header.length = sizeof(c_req);
271 c_req.header.reserved = 0;
272 c_req.header.type = usbmux_connect;
273 c_req.header.tag = 3;
274 c_req.device_id = device_info.device_id;
275 c_req.port = htons(device_port);
276 c_req.reserved = 0;
277
278 if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) {
279 perror("send");
280 } else {
281 // read ACK
282 res = -1;
283 fprintf(stdout, "Reading connect result...\n");
284 if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) {
285 if (res == 0) {
286 fprintf(stdout, "Connect success!\n");
287 connected = 1;
288 } else {
289 fprintf(stderr, "Connect failed, Error code=%d\n", res);
290 }
291 }
292 }
293 }
294
295 if (connected) {
296 int mysock = create_socket(listen_port);
297 if (mysock < 0) {
298 fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
299 } else {
300 pthread_t ctos;
301 struct sockaddr_in c_addr;
302 socklen_t len = sizeof(struct sockaddr_in);
303 struct client_data cdata;
304 int c_sock;
305 while (1) {
306 printf("waiting for connection\n");
307 c_sock = accept(mysock, (struct sockaddr*)&c_addr, &len);
308 if (c_sock) {
309 printf("accepted connection, fd = %d\n", c_sock);
310 cdata.fd = c_sock;
311 cdata.sfd = sfd;
312 stop_ctos = 0;
313 pthread_create(&ctos, NULL, run_ctos_loop, &cdata);
314 pthread_join(ctos, NULL);
315 } else {
316 break;
317 }
318 }
319 close(c_sock);
320 close(mysock);
321 }
322 } else {
323 fprintf(stderr, "No attached device found?!\n");
324 }
325 }
326 close(sfd);
327
328 return 0;
329}