summaryrefslogtreecommitdiffstats
path: root/src/usbmux.c
diff options
context:
space:
mode:
authorGravatar Matt Colyer2008-08-04 23:41:56 -0700
committerGravatar Matt Colyer2008-08-04 23:41:56 -0700
commit62bcedced863a9c4ecc3601638635dfe172a9130 (patch)
tree9937b4f6fbb848c1854e0add40f7ee86bba10d88 /src/usbmux.c
parent294f6080e7c26cb390093eead11c8e0757e00fe2 (diff)
downloadlibimobiledevice-62bcedced863a9c4ecc3601638635dfe172a9130.tar.gz
libimobiledevice-62bcedced863a9c4ecc3601638635dfe172a9130.tar.bz2
Zack's C. rewrite of usbmux (with a few additions by Matt Colyer).
Diffstat (limited to 'src/usbmux.c')
-rw-r--r--src/usbmux.c251
1 files changed, 186 insertions, 65 deletions
diff --git a/src/usbmux.c b/src/usbmux.c
index bdeea09..043f8af 100644
--- a/src/usbmux.c
+++ b/src/usbmux.c
@@ -29,6 +29,9 @@
29 29
30extern int debug; 30extern int debug;
31 31
32static usbmux_connection **connlist = NULL;
33static int connections = 0;
34
32usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) { 35usbmux_tcp_header *new_mux_packet(uint16 s_port, uint16 d_port) {
33 usbmux_tcp_header *conn = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); 36 usbmux_tcp_header *conn = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header));
34 conn->type = htonl(6); 37 conn->type = htonl(6);
@@ -54,6 +57,47 @@ usbmux_version_header *version_header() {
54 return version; 57 return version;
55} 58}
56 59
60
61// Maintenance functions.
62
63/* delete_connection(connection)
64 * connection: the connection to delete from the tracking list.
65 * Removes a connection from the list of connections made.
66 * The list of connections is necessary for buffering.
67 */
68
69void delete_connection(usbmux_connection *connection) {
70 usbmux_connection **newlist = (usbmux_connection**)malloc(sizeof(usbmux_connection*) * (connections - 1));
71 int i = 0, j = 0;
72 for (i = 0; i < connections; i++) {
73 if (connlist[i] == connection) continue;
74 else {
75 newlist[j] = connlist[i];
76 j++;
77 }
78 }
79 free(connlist);
80 connlist = newlist;
81 connections--;
82 if (connection->recv_buffer) free(connection->recv_buffer);
83 if (connection->header) free(connection->header);
84 connection->r_len = 0;
85 free(connection);
86}
87
88/* add_connection(connection)
89 * connection: the connection to add to the global list of connections.
90 * Adds a connection to the list of connections made.
91 * The connection list is necessary for buffering.
92 */
93
94void add_connection(usbmux_connection *connection) {
95 usbmux_connection **newlist = (usbmux_connection**)realloc(connlist, sizeof(usbmux_connection*) * (connections+1));
96 newlist[connections] = connection;
97 connlist = newlist;
98 connections++;
99}
100
57/* mux_connect(phone, s_port, d_port) 101/* mux_connect(phone, s_port, d_port)
58 * This is a higher-level USBMuxTCP-type function. 102 * This is a higher-level USBMuxTCP-type function.
59 * phone: the iPhone to initialize a connection on. 103 * phone: the iPhone to initialize a connection on.
@@ -64,27 +108,33 @@ usbmux_version_header *version_header() {
64 * Returns a mux TCP header for the connection which is used for tracking and data transfer. 108 * Returns a mux TCP header for the connection which is used for tracking and data transfer.
65 */ 109 */
66 110
67usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port) { 111usbmux_connection *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port) {
68 if (!phone || !s_port || !d_port) return NULL; 112 if (!phone || !s_port || !d_port) return NULL;
69 int bytes = 0; 113 int bytes = 0;
70 // Initialize connection stuff 114 // Initialize connection stuff
71 usbmux_tcp_header *new_connection; 115 usbmux_connection *new_connection = (usbmux_connection*)malloc(sizeof(usbmux_connection));
72 new_connection = new_mux_packet(s_port, d_port); 116 new_connection->header = new_mux_packet(s_port, d_port);
73 usbmux_tcp_header *response; 117 usbmux_tcp_header *response;
74 response = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header)); 118 response = (usbmux_tcp_header*)malloc(sizeof(usbmux_tcp_header));
75 // blargg 119 // blargg
76 if (new_connection) { 120 if (new_connection && new_connection->header) {
77 new_connection->tcp_flags = 0x02; 121 new_connection->header->tcp_flags = 0x02;
78 new_connection->length = htonl(new_connection->length); 122 new_connection->header->length = htonl(new_connection->header->length);
79 new_connection->length16 = htons(new_connection->length16); 123 new_connection->header->length16 = htons(new_connection->header->length16);
80 124
81 if (send_to_phone(phone, (char*)new_connection, sizeof(*new_connection)) >= 0) { 125 if (send_to_phone(phone, (char*)new_connection->header, sizeof(usbmux_tcp_header)) >= 0) {
82 bytes = recv_from_phone(phone, (char*)response, sizeof(*response)); 126 bytes = recv_from_phone(phone, (char*)response, sizeof(*response));
83 if (response->tcp_flags != 0x12) return NULL; 127 if (response->tcp_flags != 0x12) return NULL;
84 else { 128 else {
85 new_connection->tcp_flags = 0x10; 129 if (debug) printf("mux_connect: connection success\n");
86 new_connection->scnt = 1; 130 new_connection->header->tcp_flags = 0x10;
87 new_connection->ocnt = 1; 131 new_connection->header->scnt = 1;
132 new_connection->header->ocnt = 1;
133 add_connection(new_connection);
134 new_connection->phone = phone;
135 new_connection->recv_buffer = NULL;
136 new_connection->r_len = 0;
137 add_connection(new_connection);
88 return new_connection; 138 return new_connection;
89 } 139 }
90 } else { 140 } else {
@@ -103,23 +153,24 @@ usbmux_tcp_header *mux_connect(iPhone *phone, uint16 s_port, uint16 d_port) {
103 * 153 *
104 * Doesn't return anything; WILL FREE THE CONNECTION'S MEMORY!!! 154 * Doesn't return anything; WILL FREE THE CONNECTION'S MEMORY!!!
105 */ 155 */
106void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection) { 156
107 if (!phone || !connection) return; 157void mux_close_connection(usbmux_connection *connection) {
158 if (!connection || !connection->phone) return;
108 159
109 connection->tcp_flags = 0x04; 160 connection->header->tcp_flags = 0x04;
110 connection->scnt = htonl(connection->scnt); 161 connection->header->scnt = htonl(connection->header->scnt);
111 connection->ocnt = htonl(connection->ocnt); 162 connection->header->ocnt = htonl(connection->header->ocnt);
112 int bytes = 0; 163 int bytes = 0;
113 164
114 bytes = usb_bulk_write(phone->device, BULKOUT, (char*)connection, sizeof(*connection), 800); 165 bytes = usb_bulk_write(connection->phone->device, BULKOUT, (char*)connection->header, sizeof(usbmux_tcp_header), 800);
115 if(debug && bytes < 0) 166 if(debug && bytes < 0)
116 printf("mux_close_connection(): when writing, libusb gave me the error: %s\n", usb_strerror()); 167 printf("mux_close_connection(): when writing, libusb gave me the error: %s\n", usb_strerror());
117 168
118 bytes = usb_bulk_read(phone->device, BULKIN, (char*)connection, sizeof(*connection), 800); 169 bytes = usb_bulk_read(connection->phone->device, BULKIN, (char*)connection->header, sizeof(usbmux_tcp_header), 800);
119 if(debug && bytes < 0) 170 if(debug && bytes < 0)
120 printf("get_iPhone(): when reading, libusb gave me the error: %s\n", usb_strerror()); 171 printf("get_iPhone(): when reading, libusb gave me the error: %s\n", usb_strerror());
121 172
122 free(connection); 173 delete_connection(connection);
123} 174}
124 175
125/* mux_send(phone, connection, data, datalen) 176/* mux_send(phone, connection, data, datalen)
@@ -131,40 +182,46 @@ void mux_close_connection(iPhone *phone, usbmux_tcp_header *connection) {
131 * 182 *
132 * Returns number of bytes sent, minus the header (28), or -1 on error. 183 * Returns number of bytes sent, minus the header (28), or -1 on error.
133 */ 184 */
134int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { 185int mux_send(usbmux_connection *connection, const char *data, uint32 datalen) {
135 if (!phone || !connection || !data || datalen == 0) return -1; 186 if (!connection->phone || !connection || !data || datalen == 0) return -1;
136 // connection->scnt and connection->ocnt should already be in host notation... 187 // connection->scnt and connection->ocnt should already be in host notation...
137 // we don't need to change them juuuust yet. 188 // we don't need to change them juuuust yet.
138 int bytes = 0; 189 int bytes = 0;
139 if (debug) printf("mux_send(): client wants to send %i bytes\n", datalen); 190 if (debug) printf("mux_send(): client wants to send %i bytes\n", datalen);
140 char *buffer = (char*)malloc(sizeof(*connection) + datalen + 2); // allow 2 bytes of safety padding 191 char *buffer = (char*)malloc(sizeof(usbmux_tcp_header) + datalen + 2); // allow 2 bytes of safety padding
141 // Set the length and pre-emptively htonl/htons it 192 // Set the length and pre-emptively htonl/htons it
142 connection->length = htonl(sizeof(*connection) + datalen); 193 connection->header->length = htonl(sizeof(usbmux_tcp_header) + datalen);
143 connection->length16 = htons(sizeof(*connection) + datalen); 194 connection->header->length16 = htons(sizeof(usbmux_tcp_header) + datalen);
144 195
145 // Put scnt and ocnt into big-endian notation 196 // Put scnt and ocnt into big-endian notation
146 connection->scnt = htonl(connection->scnt); 197 connection->header->scnt = htonl(connection->header->scnt);
147 connection->ocnt = htonl(connection->ocnt); 198 connection->header->ocnt = htonl(connection->header->ocnt);
148 // Concatenation of stuff in the buffer. 199 // Concatenation of stuff in the buffer.
149 memcpy(buffer, connection, sizeof(*connection)); 200 memcpy(buffer, connection->header, sizeof(usbmux_tcp_header));
150 memcpy(buffer+sizeof(*connection)/*+sizeof(datalen)*/, data, datalen); 201 memcpy(buffer+sizeof(usbmux_tcp_header), data, datalen);
151 202
152 // We have a buffer full of data, we should now send it to the phone. 203 // We have a buffer full of data, we should now send it to the phone.
153 if (debug) printf("actually sending %i bytes of data at %x\n", sizeof(*connection)+datalen, buffer); 204 if (debug) printf("actually sending %i bytes of data at %x\n", sizeof(usbmux_tcp_header)+datalen, buffer);
154 205
155 206
156 bytes = send_to_phone(phone, buffer, sizeof(*connection)+datalen); 207 bytes = send_to_phone(connection->phone, buffer, sizeof(usbmux_tcp_header)+datalen);
157 208 if (debug) printf("mux_send: sent %i bytes!\n", bytes);
158 // Now that we've sent it off, we can clean up after our sloppy selves. 209 // Now that we've sent it off, we can clean up after our sloppy selves.
159 free(buffer); 210 if (debug) {
211 FILE *packet = fopen("packet", "a+");
212 fwrite(buffer, 1, bytes, packet);
213 fclose(packet);
214 printf("\n");
215 }
160 216
217 if (buffer) free(buffer);
161 // Re-calculate scnt and ocnt 218 // Re-calculate scnt and ocnt
162 connection->scnt = ntohl(connection->scnt) + datalen; 219 connection->header->scnt = ntohl(connection->header->scnt) + datalen;
163 connection->ocnt = ntohl(connection->ocnt); 220 connection->header->ocnt = ntohl(connection->header->ocnt);
164 221
165 // Revert lengths 222 // Revert lengths
166 connection->length = ntohl(connection->length); 223 connection->header->length = ntohl(connection->header->length);
167 connection->length16 = ntohs(connection->length16); 224 connection->header->length16 = ntohs(connection->header->length16);
168 225
169 // Now return the bytes. 226 // Now return the bytes.
170 if (bytes < sizeof(*connection)+datalen) { 227 if (bytes < sizeof(*connection)+datalen) {
@@ -186,39 +243,103 @@ int mux_send(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 da
186 * Returns: how many bytes were read, or -1 if something bad happens. 243 * Returns: how many bytes were read, or -1 if something bad happens.
187 */ 244 */
188 245
189int mux_recv(iPhone *phone, usbmux_tcp_header *connection, char *data, uint32 datalen) { 246int mux_recv(usbmux_connection *connection, char *data, uint32 datalen) {
190 char *buffer = (char*)malloc(sizeof(*connection) + sizeof(datalen) + datalen); 247 /*
191 int bytes = 0, my_datalen = 0; 248 * Order of operation:
249 * 1.) Check if the connection has a pre-received buffer.
250 * 2.) If so, fill data with the buffer, as much as needed.
251 * a.) Return quickly if the buffer has enough
252 * b.) If the buffer is only part of the datalen, get the rest of datalen (and if we can't, just return)
253 * 3.) If not, receive directly from the phone.
254 * a.) Check incoming packet's ports. If proper, follow proper buffering and receiving operation.
255 * b.) If not, find the connection the ports belong to and fill that connection's buffer, then return mux_recv with the same args to try again.
256 */
192 if (debug) printf("mux_recv: datalen == %i\n", datalen); 257 if (debug) printf("mux_recv: datalen == %i\n", datalen);
193 bytes = recv_from_phone(phone, buffer, sizeof(*connection) + datalen); 258 int bytes = 0, i = 0, complex = 0, offset = 0;
194 if (debug) printf("mux_recv: bytes == %i\n", bytes); 259 char *buffer = NULL;
195 if (bytes < datalen) { 260 usbmux_tcp_header *header = NULL;
196 if (bytes < 28) { 261
197 // if they didn't do that annoying thing, something else mighta happened. 262 if (connection->recv_buffer) {
198 if (debug) printf("mux_recv: bytes too low anyway!\n"); 263 if (connection->r_len >= datalen) {
199 free(buffer); 264 memcpy(data, connection->recv_buffer, datalen);
200 return -1; 265 if (connection->r_len == datalen) {
201 } else if (bytes == 28) { // no data... 266 // reset everything
202 free(buffer); 267 free(connection->recv_buffer);
203 return 0; 268 connection->r_len = 0;
204 } else { // bytes > 28 269 connection->recv_buffer = NULL;
205 my_datalen = ntohl(buffer[4]) - 28; 270 } else {
206 connection->ocnt += my_datalen; 271 buffer = (char*)malloc(sizeof(char) * (connection->r_len - datalen));
207 memcpy(data, buffer+28, bytes - 28); 272 memcpy(buffer, connection->recv_buffer+datalen, (connection->r_len - datalen));
208 free(buffer); 273 connection->r_len -= datalen;
209 if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); 274 free(connection->recv_buffer);
210 return bytes - 28; 275 connection->recv_buffer = buffer;
276 }
277
278 // Since we were able to fill the data straight from our buffer, we can just return datalen. See 2a above.
279 return datalen;
280 } else {
281 memcpy(data, connection->recv_buffer, connection->r_len);
282 free(connection->recv_buffer); // don't need to deal with anymore, but...
283 offset = connection->r_len; // see #2b, above
284 connection->r_len = 0;
211 } 285 }
212 } else {// all's good, they didn't do anything bonky. 286 } // End of what to do if we have a pre-buffer. See #1 and #2 above.
213 my_datalen = ntohl(buffer[4]) - 28; 287
214 connection->ocnt += my_datalen; 288 buffer = (char*)malloc(sizeof(char) * 131072); // make sure we get enough ;)
215 if (bytes == (datalen+28)) memcpy(data, buffer+28, datalen); 289
216 else if (bytes == datalen) memcpy(data, buffer+28, datalen-28); 290 // See #3.
291 bytes = recv_from_phone(connection->phone, buffer, 131072);
292 if (bytes < 28) {
293 free(buffer);
294 if (debug) printf("mux_recv: Did not even get the header.\n");
295 return -1;
296 }
297
298 header = (usbmux_tcp_header*)buffer;
299 if (header->sport != connection->header->dport || header->dport != connection->header->sport) {
300 // Ooooops -- we got someone else's packet.
301 // We gotta stick it in their buffer. (Take that any old way you want ;) )
302 for (i = 0; i < connections; i++) {
303 if (connlist[i]->header->sport == header->dport && connlist[i]->header->dport == header->sport) {
304 // we have a winner.
305 connlist[i]->r_len += bytes - 28;
306 connlist[i]->recv_buffer = (char*)realloc(connlist[i]->recv_buffer, sizeof(char) * connection->r_len); // grow their buffer
307 complex = connlist[i]->r_len - (bytes - 28);
308 memcpy(connlist[i]->recv_buffer+complex, buffer+28, bytes-28); // paste into their buffer
309 connlist[i]->header->ocnt += bytes-28;
310 }
311 }
312 // If it wasn't ours, it's been handled by this point... or forgotten.
313 // Free our buffer and continue.
314 free(buffer);
315 buffer = NULL;
316 return mux_recv(connection, data, datalen); // recurse back in to try again
317 }
318
319 // The packet was absolutely meant for us if it hits this point.
320 // The pre-buffer has been taken care of, so, again, if we're at this point we have to read from the phone.
321
322 if ((bytes-28) > datalen) {
323 // Copy what we need into the data, buffer the rest because we can.
324 memcpy(data+offset, buffer+28, datalen); // data+offset: see #2b, above
325 complex = connection->r_len + (bytes-28) - datalen;
326 connection->recv_buffer = (char*)realloc(connection->recv_buffer, (sizeof(char) * complex));
327 connection->r_len = complex;
328 complex = connection->r_len - (bytes-28) - datalen;
329 memcpy(connection->recv_buffer+complex, buffer+28+datalen, (bytes-28) - datalen);
330 free(buffer);
331 connection->header->ocnt += bytes-28;
332 return datalen;
333 } else {
334 // Fill the data with what we have, and just return.
335 memcpy(data+offset, buffer+28, bytes-28); // data+offset: see #2b, above
336 connection->header->ocnt += bytes-28;
217 free(buffer); 337 free(buffer);
218 if (debug) printf("mux_recv: bytes received: %i\n", bytes - 28); 338 return (bytes-28);
219 return bytes - 28;
220 } 339 }
221 340
222 return bytes; 341 // If we get to this point, 'tis probably bad.
342 if (debug) printf("mux_recv: Heisenbug: bytes and datalen not matching up\n");
343 return -1;
223} 344}
224 345