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 @@
+/*
+ * iproxy -- proxy that enables tcp service access to iPhone/iPod
+ * via USB cable
+ * TODO: improve code...
+ *
+ * Copyright (c) 2009 Nikias Bassen. All Rights Reserved.
+ * Based upon iTunnel source code, Copyright (c) 2008 Jing Su.
+ * http://www.cs.toronto.edu/~jingsu/itunnel/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <errno.h>
+#include <arpa/inet.h>
+#include <pthread.h>
+#include "usbmuxd.h"
+#include "sock_stuff.h"
+
+#define SOCKET_FILE "/var/run/usbmuxd"
+
+volatile int stop_ctos = 0;
+volatile int stop_stoc = 0;
+
+static uint16_t listen_port = 0;
+static uint16_t device_port = 0;
+
+pthread_mutex_t smutex = PTHREAD_MUTEX_INITIALIZER;
+
+struct client_data {
+ int fd;
+ int sfd;
+};
+
+int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t *result)
+{
+ struct usbmux_result res;
+ int recv_len;
+ int i;
+ uint32_t rrr[5];
+
+ if (!result) {
+ return -EINVAL;
+ }
+
+ if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) {
+ perror("recv");
+ return -errno;
+ } else {
+ memcpy(&rrr, &res, recv_len);
+ for (i = 0; i < recv_len/4; i++) {
+ fprintf(stderr, "%08x ", rrr[i]);
+ }
+ fprintf(stderr, "\n");
+ if ((recv_len == sizeof(res))
+ && (res.header.length == recv_len)
+ && (res.header.reserved == 0)
+ && (res.header.type == usbmux_result)
+ ) {
+ *result = res.result;
+ if (res.header.tag == tag) {
+ return 1;
+ } else {
+ return 0;
+ }
+ }
+ }
+
+ return -1;
+}
+
+void *run_stoc_loop(void *arg)
+{
+ struct client_data *cdata = (struct client_data*)arg;
+ int recv_len;
+ int sent;
+ char buffer[131072];
+
+ printf("%s: fd = %d\n", __func__, cdata->fd);
+
+ while (!stop_stoc && cdata->fd>0 && cdata->sfd>0) {
+ recv_len = recv_buf_timeout(cdata->sfd, buffer, sizeof(buffer), 0, 5000);
+ if (recv_len <= 0) {
+ if (recv_len == 0) {
+ // try again
+ continue;
+ } else {
+ fprintf(stderr, "recv failed: %s\n", strerror(errno));
+ break;
+ }
+ } else {
+ printf("received %d bytes from server\n", recv_len);
+ // send to socket
+ sent = send_buf(cdata->fd, buffer, recv_len);
+ if (sent < recv_len) {
+ if (sent <= 0) {
+ fprintf(stderr, "send failed: %s\n", strerror(errno));
+ break;
+ } else {
+ fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
+ }
+ } else {
+ // sending succeeded, receive from device
+ printf("pushed %d bytes to client\n", sent);
+ }
+ }
+ }
+ close(cdata->fd);
+ cdata->fd = -1;
+ stop_ctos = 1;
+
+ return NULL;
+}
+
+void *run_ctos_loop(void *arg)
+{
+ struct client_data *cdata = (struct client_data*)arg;
+ int recv_len;
+ int sent;
+ char buffer[131072];
+ pthread_t stoc = 0;
+
+ printf("%s: fd = %d\n", __func__, cdata->fd);
+
+ stop_stoc = 0;
+ pthread_create(&stoc, NULL, run_stoc_loop, cdata);
+
+ while (!stop_ctos && cdata->fd>0 && cdata->sfd>0) {
+ recv_len = recv_buf_timeout(cdata->fd, buffer, sizeof(buffer), 0, 5000);
+ if (recv_len <= 0) {
+ if (recv_len == 0) {
+ // try again
+ continue;
+ } else {
+ fprintf(stderr, "recv failed: %s\n", strerror(errno));
+ break;
+ }
+ } else {
+ printf("pulled %d bytes from client\n", recv_len);
+ // send to local socket
+ sent = send_buf(cdata->sfd, buffer, recv_len);
+ if (sent < recv_len) {
+ if (sent <= 0) {
+ fprintf(stderr, "send failed: %s\n", strerror(errno));
+ break;
+ } else {
+ fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
+ }
+ } else {
+ // sending succeeded, receive from device
+ printf("sent %d bytes to server\n", sent);
+ }
+ }
+ }
+ close(cdata->fd);
+ cdata->fd = -1;
+ stop_stoc = 1;
+
+ pthread_join(stoc, NULL);
+
+ return NULL;
+}
+
+int main(int argc, char **argv)
+{
+ int recv_len = 0;
+ int hello_done;
+ int connected;
+ uint32_t pktlen;
+ unsigned char *buf;
+ struct usbmux_header hello;
+ struct usbmux_dev_info device_info;
+ int sfd = -1;
+
+ if (argc != 3) {
+ printf("usage: %s LOCAL_PORT DEVICE_PORT\n", argv[0]);
+ return 0;
+ }
+
+ listen_port = atoi(argv[1]);
+ device_port = atoi(argv[2]);
+
+ if (!listen_port) {
+ fprintf(stderr, "Invalid listen_port specified!\n");
+ return -EINVAL;
+ }
+
+ if (!device_port) {
+ fprintf(stderr, "Invalid device_port specified!\n");
+ return -EINVAL;
+ }
+
+ sfd = connect_unix_socket(SOCKET_FILE);
+ if (sfd < 0) {
+ printf("error opening socket, terminating.\n");
+ return -1;
+ }
+
+ // send hello
+ hello.length = sizeof(struct usbmux_header);
+ hello.reserved = 0;
+ hello.type = usbmux_hello;
+ hello.tag = 2;
+
+ hello_done = 0;
+ connected = 0;
+
+ fprintf(stdout, "sending Hello packet\n");
+ if (send(sfd, &hello, hello.length, 0) == hello.length) {
+ uint32_t res = -1;
+ // get response
+ if (usbmuxd_get_result(sfd, hello.tag, &res) && (res==0)) {
+ fprintf(stdout, "Got Hello Response!\n");
+ hello_done = 1;
+ } else {
+ fprintf(stderr, "Did not get Hello response (with result=0)...\n");
+ close(sfd);
+ return -1;
+ }
+
+ device_info.device_id = 0;
+
+ if (hello_done) {
+ // get all devices
+ while (1) {
+ if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) {
+ buf = (unsigned char*)malloc(pktlen);
+ if (!buf) {
+ exit(-ENOMEM);
+ }
+ recv_len = recv_buf(sfd, buf, pktlen);
+ if (recv_len < pktlen) {
+ fprintf(stdout, "received less data than specified in header!\n");
+ }
+ fprintf(stdout, "Received device data\n");
+ //log_debug_buffer(stdout, (char*)buf, pktlen);
+ memcpy(&device_info, buf + sizeof(struct usbmux_header), sizeof(device_info));
+ free(buf);
+ } else {
+ // we _should_ have all of them now.
+ // or perhaps an error occured.
+ break;
+ }
+ }
+ }
+
+ if (device_info.device_id > 0) {
+ struct usbmux_connect_request c_req;
+
+ fprintf(stdout, "Requesting connecion to device %d port %d\n", device_info.device_id, device_port);
+
+ // try to connect to last device found
+ c_req.header.length = sizeof(c_req);
+ c_req.header.reserved = 0;
+ c_req.header.type = usbmux_connect;
+ c_req.header.tag = 3;
+ c_req.device_id = device_info.device_id;
+ c_req.port = htons(device_port);
+ c_req.reserved = 0;
+
+ if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) {
+ perror("send");
+ } else {
+ // read ACK
+ res = -1;
+ fprintf(stdout, "Reading connect result...\n");
+ if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) {
+ if (res == 0) {
+ fprintf(stdout, "Connect success!\n");
+ connected = 1;
+ } else {
+ fprintf(stderr, "Connect failed, Error code=%d\n", res);
+ }
+ }
+ }
+ }
+
+ if (connected) {
+ int mysock = create_socket(listen_port);
+ if (mysock < 0) {
+ fprintf(stderr, "Error creating socket: %s\n", strerror(errno));
+ } else {
+ pthread_t ctos;
+ struct sockaddr_in c_addr;
+ socklen_t len = sizeof(struct sockaddr_in);
+ struct client_data cdata;
+ int c_sock;
+ while (1) {
+ printf("waiting for connection\n");
+ c_sock = accept(mysock, (struct sockaddr*)&c_addr, &len);
+ if (c_sock) {
+ printf("accepted connection, fd = %d\n", c_sock);
+ cdata.fd = c_sock;
+ cdata.sfd = sfd;
+ stop_ctos = 0;
+ pthread_create(&ctos, NULL, run_ctos_loop, &cdata);
+ pthread_join(ctos, NULL);
+ } else {
+ break;
+ }
+ }
+ close(c_sock);
+ close(mysock);
+ }
+ } else {
+ fprintf(stderr, "No attached device found?!\n");
+ }
+ }
+ close(sfd);
+
+ return 0;
+}