summaryrefslogtreecommitdiffstats
path: root/libusbmuxd
diff options
context:
space:
mode:
authorGravatar Hector Martin2009-08-20 03:42:52 +0200
committerGravatar Hector Martin2009-08-20 06:51:10 +0200
commit1a0c58e4062da7db73b4c08963f741cf016f6aa5 (patch)
treeb250f094e978d48622ecf652e28e9f3b68873893 /libusbmuxd
parentf4854f3fd725b5ba49cd5157d941783cffa08c04 (diff)
parent79ca4d9a3c3a82bb5a3f9be1ac7a2533c7a89b05 (diff)
downloadusbmuxd-1a0c58e4062da7db73b4c08963f741cf016f6aa5.tar.gz
usbmuxd-1a0c58e4062da7db73b4c08963f741cf016f6aa5.tar.bz2
Merge the two development histories
Diffstat (limited to 'libusbmuxd')
-rw-r--r--libusbmuxd/CMakeLists.txt12
-rw-r--r--libusbmuxd/libusbmuxd.c248
-rw-r--r--libusbmuxd/sock_stuff.c301
-rw-r--r--libusbmuxd/sock_stuff.h28
-rw-r--r--libusbmuxd/usbmuxd-proto.h52
-rw-r--r--libusbmuxd/usbmuxd.h91
6 files changed, 732 insertions, 0 deletions
diff --git a/libusbmuxd/CMakeLists.txt b/libusbmuxd/CMakeLists.txt
new file mode 100644
index 0000000..61de1a8
--- /dev/null
+++ b/libusbmuxd/CMakeLists.txt
@@ -0,0 +1,12 @@
1add_library (libusbmuxd libusbmuxd.c sock_stuff.c)
2
3# 'lib' is a UNIXism, the proper CMake target is usbmuxd
4# But we can't use that due to the conflict with the usbmuxd daemon,
5# so instead change the library output base name to usbmuxd here
6set_target_properties(libusbmuxd PROPERTIES OUTPUT_NAME usbmuxd)
7
8install(TARGETS libusbmuxd
9 ARCHIVE DESTINATION lib
10 LIBRARY DESTINATION lib
11)
12install(FILES usbmuxd.h usbmuxd-proto.h DESTINATION include)
diff --git a/libusbmuxd/libusbmuxd.c b/libusbmuxd/libusbmuxd.c
new file mode 100644
index 0000000..090695f
--- /dev/null
+++ b/libusbmuxd/libusbmuxd.c
@@ -0,0 +1,248 @@
1#include <stdint.h>
2#include <stdlib.h>
3#include <errno.h>
4#include <stdio.h>
5#include <string.h>
6#include <sys/socket.h>
7#include <arpa/inet.h>
8#include <unistd.h>
9
10// usbmuxd public interface
11#include "usbmuxd.h"
12// usbmuxd protocol
13#include "usbmuxd-proto.h"
14// socket utility functions
15#include "sock_stuff.h"
16
17static int usbmuxd_get_result(int sfd, uint32_t tag, uint32_t * result)
18{
19 struct usbmuxd_result res;
20 int recv_len;
21
22 if (!result) {
23 return -EINVAL;
24 }
25
26 if ((recv_len = recv_buf(sfd, &res, sizeof(res))) <= 0) {
27 perror("recv");
28 return -errno;
29 } else {
30 if ((recv_len == sizeof(res))
31 && (res.header.length == (uint32_t) recv_len)
32 && (res.header.reserved == 0)
33 && (res.header.type == USBMUXD_RESULT)
34 ) {
35 *result = res.result;
36 if (res.header.tag == tag) {
37 return 1;
38 } else {
39 return 0;
40 }
41 }
42 }
43
44 return -1;
45}
46
47int usbmuxd_scan(usbmuxd_scan_result ** available_devices)
48{
49 struct usbmuxd_scan_request s_req;
50 int sfd;
51 int scan_success = 0;
52 uint32_t res;
53 uint32_t pktlen;
54 int recv_len;
55 usbmuxd_scan_result *newlist = NULL;
56 struct usbmuxd_device_info_record dev_info_pkt;
57 int dev_cnt = 0;
58
59 sfd = connect_unix_socket(USBMUXD_SOCKET_FILE);
60 if (sfd < 0) {
61 fprintf(stderr, "%s: error opening socket!\n", __func__);
62 return sfd;
63 }
64
65 s_req.header.length = sizeof(struct usbmuxd_scan_request);
66 s_req.header.reserved = 0;
67 s_req.header.type = USBMUXD_SCAN;
68 s_req.header.tag = 2;
69
70 // send scan request packet
71 if (send_buf(sfd, &s_req, s_req.header.length) ==
72 (int) s_req.header.length) {
73 res = -1;
74 // get response
75 if (usbmuxd_get_result(sfd, s_req.header.tag, &res) && (res == 0)) {
76 scan_success = 1;
77 } else {
78 fprintf(stderr,
79 "%s: Did not get response to scan request (with result=0)...\n",
80 __func__);
81 close(sfd);
82 return res;
83 }
84 }
85
86 if (!scan_success) {
87 fprintf(stderr, "%s: Could not send scan request!\n", __func__);
88 return -1;
89 }
90
91 *available_devices = NULL;
92 // receive device list
93 while (1) {
94 if (recv_buf_timeout(sfd, &pktlen, 4, MSG_PEEK, 1000) == 4) {
95 if (pktlen != sizeof(dev_info_pkt)) {
96 // invalid packet size received!
97 fprintf(stderr,
98 "%s: Invalid packet size (%d) received when expecting a device info record.\n",
99 __func__, pktlen);
100 break;
101 }
102
103 recv_len = recv_buf(sfd, &dev_info_pkt, pktlen);
104 if (recv_len <= 0) {
105 fprintf(stderr,
106 "%s: Error when receiving device info record\n",
107 __func__);
108 break;
109 } else if ((uint32_t) recv_len < pktlen) {
110 fprintf(stderr,
111 "%s: received less data than specified in header!\n",
112 __func__);
113 } else {
114 //fprintf(stderr, "%s: got device record with id %d, UUID=%s\n", __func__, dev_info_pkt.device_info.device_id, dev_info_pkt.device_info.serial_number);
115 newlist =
116 (usbmuxd_scan_result *) realloc(*available_devices,
117 sizeof
118 (usbmuxd_scan_result) *
119 (dev_cnt + 1));
120 if (newlist) {
121 newlist[dev_cnt].handle =
122 (int) dev_info_pkt.device.device_id;
123 newlist[dev_cnt].product_id =
124 dev_info_pkt.device.product_id;
125 memset(newlist[dev_cnt].serial_number, '\0',
126 sizeof(newlist[dev_cnt].serial_number));
127 memcpy(newlist[dev_cnt].serial_number,
128 dev_info_pkt.device.serial_number,
129 sizeof(dev_info_pkt.device.serial_number));
130 *available_devices = newlist;
131 dev_cnt++;
132 } else {
133 fprintf(stderr,
134 "%s: ERROR: out of memory when trying to realloc!\n",
135 __func__);
136 break;
137 }
138 }
139 } else {
140 // we _should_ have all of them now.
141 // or perhaps an error occured.
142 break;
143 }
144 }
145
146 // terminating zero record
147 newlist =
148 (usbmuxd_scan_result *) realloc(*available_devices,
149 sizeof(usbmuxd_scan_result) *
150 (dev_cnt + 1));
151 memset(newlist + dev_cnt, 0, sizeof(usbmuxd_scan_result));
152 *available_devices = newlist;
153
154 return dev_cnt;
155}
156
157int usbmuxd_connect(const int handle, const unsigned short tcp_port)
158{
159 int sfd;
160 struct usbmuxd_connect_request c_req;
161 int connected = 0;
162 uint32_t res = -1;
163
164 sfd = connect_unix_socket(USBMUXD_SOCKET_FILE);
165 if (sfd < 0) {
166 fprintf(stderr, "%s: Error: Connection to usbmuxd failed: %s\n",
167 __func__, strerror(errno));
168 return sfd;
169 }
170
171 c_req.header.length = sizeof(c_req);
172 c_req.header.reserved = 0;
173 c_req.header.type = USBMUXD_CONNECT;
174 c_req.header.tag = 3;
175 c_req.device_id = (uint32_t) handle;
176 c_req.tcp_dport = htons(tcp_port);
177 c_req.reserved = 0;
178
179 if (send_buf(sfd, &c_req, sizeof(c_req)) < 0) {
180 perror("send");
181 } else {
182 // read ACK
183 //fprintf(stderr, "%s: Reading connect result...\n", __func__);
184 if (usbmuxd_get_result(sfd, c_req.header.tag, &res)) {
185 if (res == 0) {
186 //fprintf(stderr, "%s: Connect success!\n", __func__);
187 connected = 1;
188 } else {
189 fprintf(stderr, "%s: Connect failed, Error code=%d\n",
190 __func__, res);
191 }
192 }
193 }
194
195 if (connected) {
196 return sfd;
197 }
198
199 close(sfd);
200
201 return -1;
202}
203
204int usbmuxd_disconnect(int sfd)
205{
206 return close(sfd);
207}
208
209int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes)
210{
211 int num_sent;
212
213 if (sfd < 0) {
214 return -EINVAL;
215 }
216
217 num_sent = send(sfd, (void*)data, len, 0);
218 if (num_sent < 0) {
219 *sent_bytes = 0;
220 fprintf(stderr, "%s: Error %d when sending: %s\n", __func__, num_sent, strerror(errno));
221 return num_sent;
222 } else if ((uint32_t)num_sent < len) {
223 fprintf(stderr, "%s: Warning: Did not send enough (only %d of %d)\n", __func__, num_sent, len);
224 }
225
226 *sent_bytes = num_sent;
227
228 return 0;
229}
230
231int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout)
232{
233 int num_recv = recv_buf_timeout(sfd, (void*)data, len, 0, timeout);
234 if (num_recv < 0) {
235 *recv_bytes = 0;
236 return num_recv;
237 }
238
239 *recv_bytes = num_recv;
240
241 return 0;
242}
243
244int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes)
245{
246 return usbmuxd_recv_timeout(sfd, data, len, recv_bytes, 5000);
247}
248
diff --git a/libusbmuxd/sock_stuff.c b/libusbmuxd/sock_stuff.c
new file mode 100644
index 0000000..137375d
--- /dev/null
+++ b/libusbmuxd/sock_stuff.c
@@ -0,0 +1,301 @@
1#include <stdio.h>
2#include <stddef.h>
3#include <unistd.h>
4#include <errno.h>
5#include <sys/time.h>
6#include <sys/stat.h>
7#include <sys/socket.h>
8#include <sys/un.h>
9#include <netinet/in.h>
10#include <netdb.h>
11#include <arpa/inet.h>
12#include "sock_stuff.h"
13
14#define RECV_TIMEOUT 20000
15
16static int verbose = 0;
17
18void sock_stuff_set_verbose(int level)
19{
20 verbose = level;
21}
22
23int create_unix_socket(const char *filename)
24{
25 struct sockaddr_un name;
26 int sock;
27 size_t size;
28
29 // remove if still present
30 unlink(filename);
31
32 /* Create the socket. */
33 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
34 if (sock < 0) {
35 perror("socket");
36 return -1;
37 }
38
39 /* Bind a name to the socket. */
40 name.sun_family = AF_LOCAL;
41 strncpy(name.sun_path, filename, sizeof(name.sun_path));
42 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
43
44 /* The size of the address is
45 the offset of the start of the filename,
46 plus its length,
47 plus one for the terminating null byte.
48 Alternatively you can just do:
49 size = SUN_LEN (&name);
50 */
51 size = (offsetof(struct sockaddr_un, sun_path)
52 + strlen(name.sun_path) + 1);
53
54 if (bind(sock, (struct sockaddr *) &name, size) < 0) {
55 perror("bind");
56 close(sock);
57 return -1;
58 }
59
60 if (listen(sock, 10) < 0) {
61 perror("listen");
62 close(sock);
63 return -1;
64 }
65
66 return sock;
67}
68
69int connect_unix_socket(const char *filename)
70{
71 struct sockaddr_un name;
72 int sfd = -1;
73 size_t size;
74 struct stat fst;
75
76 // check if socket file exists...
77 if (stat(filename, &fst) != 0) {
78 if (verbose >= 2)
79 fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
80 strerror(errno));
81 return -1;
82 }
83 // ... and if it is a unix domain socket
84 if (!S_ISSOCK(fst.st_mode)) {
85 if (verbose >= 2)
86 fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
87 filename);
88 return -1;
89 }
90 // make a new socket
91 if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
92 if (verbose >= 2)
93 fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
94 return -1;
95 }
96 // and connect to 'filename'
97 name.sun_family = AF_LOCAL;
98 strncpy(name.sun_path, filename, sizeof(name.sun_path));
99 name.sun_path[sizeof(name.sun_path) - 1] = 0;
100
101 size = (offsetof(struct sockaddr_un, sun_path)
102 + strlen(name.sun_path) + 1);
103
104 if (connect(sfd, (struct sockaddr *) &name, size) < 0) {
105 close(sfd);
106 if (verbose >= 2)
107 fprintf(stderr, "%s: connect: %s\n", __func__,
108 strerror(errno));
109 return -1;
110 }
111
112 return sfd;
113}
114
115int create_socket(uint16_t port)
116{
117 int sfd = -1;
118 int yes = 1;
119 struct sockaddr_in saddr;
120
121 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
122 perror("socket()");
123 return -1;
124 }
125
126 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
127 perror("setsockopt()");
128 close(sfd);
129 return -1;
130 }
131
132 memset((void *) &saddr, 0, sizeof(saddr));
133 saddr.sin_family = AF_INET;
134 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
135 saddr.sin_port = htons(port);
136
137 if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) {
138 perror("bind()");
139 close(sfd);
140 return -1;
141 }
142
143 if (listen(sfd, 1) == -1) {
144 perror("listen()");
145 close(sfd);
146 return -1;
147 }
148
149 return sfd;
150}
151
152int connect_socket(const char *addr, uint16_t port)
153{
154 int sfd = -1;
155 int yes = 1;
156 struct hostent *hp;
157 struct sockaddr_in saddr;
158
159 if (!addr) {
160 errno = EINVAL;
161 return -1;
162 }
163
164 if ((hp = gethostbyname(addr)) == NULL) {
165 if (verbose >= 2)
166 fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr);
167 return -1;
168 }
169
170 if (!hp->h_addr) {
171 if (verbose >= 2)
172 fprintf(stderr, "%s: gethostbyname returned NULL address!\n",
173 __func__);
174 return -1;
175 }
176
177 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
178 perror("socket()");
179 return -1;
180 }
181
182 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
183 perror("setsockopt()");
184 close(sfd);
185 return -1;
186 }
187
188 memset((void *) &saddr, 0, sizeof(saddr));
189 saddr.sin_family = AF_INET;
190 saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr;
191 saddr.sin_port = htons(port);
192
193 if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
194 perror("connect");
195 close(sfd);
196 return -2;
197 }
198
199 return sfd;
200}
201
202int check_fd(int fd, fd_mode fdm, unsigned int timeout)
203{
204 fd_set fds;
205 int sret;
206 int eagain;
207 struct timeval to;
208
209 if (fd <= 0) {
210 if (verbose >= 2)
211 fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
212 return -1;
213 }
214
215 FD_ZERO(&fds);
216 FD_SET(fd, &fds);
217
218 to.tv_sec = (time_t) (timeout / 1000);
219 to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
220
221 sret = -1;
222
223 do {
224 eagain = 0;
225 switch (fdm) {
226 case FD_READ:
227 sret = select(fd + 1, &fds, NULL, NULL, &to);
228 break;
229 case FD_WRITE:
230 sret = select(fd + 1, NULL, &fds, NULL, &to);
231 break;
232 case FD_EXCEPT:
233 sret = select(fd + 1, NULL, NULL, &fds, &to);
234 break;
235 default:
236 return -1;
237 }
238
239 if (sret < 0) {
240 switch (errno) {
241 case EINTR:
242 // interrupt signal in select
243 if (verbose >= 2)
244 fprintf(stderr, "%s: EINTR\n", __func__);
245 eagain = 1;
246 break;
247 case EAGAIN:
248 if (verbose >= 2)
249 fprintf(stderr, "%s: EAGAIN\n", __func__);
250 break;
251 default:
252 if (verbose >= 2)
253 fprintf(stderr, "%s: select failed: %s\n", __func__,
254 strerror(errno));
255 return -1;
256 }
257 }
258 } while (eagain);
259
260 return sret;
261}
262
263int recv_buf(int fd, void *data, size_t length)
264{
265 return recv_buf_timeout(fd, data, length, 0, RECV_TIMEOUT);
266}
267
268int peek_buf(int fd, void *data, size_t length)
269{
270 return recv_buf_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
271}
272
273int recv_buf_timeout(int fd, void *data, size_t length, int flags,
274 unsigned int timeout)
275{
276 int res;
277 int result;
278
279 // check if data is available
280 res = check_fd(fd, FD_READ, timeout);
281 if (res <= 0) {
282 return res;
283 }
284 // if we get here, there _is_ data available
285 result = recv(fd, data, length, flags);
286 if (res > 0 && result == 0) {
287 // but this is an error condition
288 if (verbose >= 3)
289 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
290 return -EAGAIN;
291 }
292 if (result < 0) {
293 return -errno;
294 }
295 return result;
296}
297
298int send_buf(int fd, void *data, size_t length)
299{
300 return send(fd, data, length, 0);
301}
diff --git a/libusbmuxd/sock_stuff.h b/libusbmuxd/sock_stuff.h
new file mode 100644
index 0000000..190f7e1
--- /dev/null
+++ b/libusbmuxd/sock_stuff.h
@@ -0,0 +1,28 @@
1#ifndef __SOCK_STUFF_H
2#define __SOCK_STUFF_H
3
4#include <stdint.h>
5
6enum fd_mode {
7 FD_READ,
8 FD_WRITE,
9 FD_EXCEPT
10};
11typedef enum fd_mode fd_mode;
12
13int create_unix_socket(const char *filename);
14int connect_unix_socket(const char *filename);
15int create_socket(uint16_t port);
16int connect_socket(const char *addr, uint16_t port);
17int check_fd(int fd, fd_mode fdm, unsigned int timeout);
18
19int recv_buf(int fd, void *data, size_t size);
20int peek_buf(int fd, void *data, size_t size);
21int recv_buf_timeout(int fd, void *data, size_t size, int flags,
22 unsigned int timeout);
23
24int send_buf(int fd, void *data, size_t size);
25
26void sock_stuff_set_verbose(int level);
27
28#endif /* __SOCK_STUFF_H */
diff --git a/libusbmuxd/usbmuxd-proto.h b/libusbmuxd/usbmuxd-proto.h
new file mode 100644
index 0000000..7f8c2d6
--- /dev/null
+++ b/libusbmuxd/usbmuxd-proto.h
@@ -0,0 +1,52 @@
1/* Protocol defintion for usbmuxd proxy protocol */
2
3#ifndef __USBMUXD_PROTO_H
4#define __USBMUXD_PROTO_H
5
6#include <stdint.h>
7
8#define USBMUXD_SOCKET_FILE "/var/run/usbmuxd"
9
10struct usbmuxd_header {
11 uint32_t length; // length of message, including header
12 uint32_t reserved; // always zero
13 uint32_t type; // message type
14 uint32_t tag; // responses to this query will echo back this tag
15} __attribute__((__packed__));
16
17struct usbmuxd_result {
18 struct usbmuxd_header header;
19 uint32_t result;
20} __attribute__((__packed__));
21
22struct usbmuxd_connect_request {
23 struct usbmuxd_header header;
24 uint32_t device_id;
25 uint16_t tcp_dport; // TCP port number
26 uint16_t reserved; // set to zero
27} __attribute__((__packed__));
28
29struct usbmuxd_device {
30 uint32_t device_id;
31 uint16_t product_id;
32 char serial_number[40];
33} __attribute__((__packed__));
34
35struct usbmuxd_device_info_record {
36 struct usbmuxd_header header;
37 struct usbmuxd_device device;
38 char padding[222];
39} __attribute__((__packed__));
40
41struct usbmuxd_scan_request {
42 struct usbmuxd_header header;
43} __attribute__((__packed__));
44
45enum {
46 USBMUXD_RESULT = 1,
47 USBMUXD_CONNECT = 2,
48 USBMUXD_SCAN = 3,
49 USBMUXD_DEVICE_INFO = 4,
50};
51
52#endif /* __USBMUXD_PROTO_H */
diff --git a/libusbmuxd/usbmuxd.h b/libusbmuxd/usbmuxd.h
new file mode 100644
index 0000000..ba45ec3
--- /dev/null
+++ b/libusbmuxd/usbmuxd.h
@@ -0,0 +1,91 @@
1#ifndef __USBMUXD_H
2#define __USBMUXD_H
3
4/**
5 * Array entry returned by 'usbmuxd_scan()' scanning.
6 *
7 * If more than one device is available, 'product_id' and
8 * 'serial_number' and be analysed to help make a selection.
9 * The relevant 'handle' should be passed to 'usbmuxd_connect()', to
10 * start a proxy connection. The value 'handle' should be considered
11 * opaque and no presumption made about the meaning of its value.
12 */
13typedef struct {
14 int handle;
15 int product_id;
16 char serial_number[41];
17} usbmuxd_scan_result;
18
19/**
20 * Contacts usbmuxd and performs a scan for connected devices.
21 *
22 * @param available_devices pointer to array of usbmuxd_scan_result.
23 * Array of available devices. The required 'handle'
24 * should be passed to 'usbmuxd_connect()'. The returned array
25 * is zero-terminated for convenience; the final (unused)
26 * entry containing handle == 0. The returned array pointer
27 * should be freed by passing to 'free()' after use.
28 *
29 * @return number of available devices, zero on no devices, or negative on error
30 */
31int usbmuxd_scan(usbmuxd_scan_result **available_devices);
32
33/**
34 * Request proxy connect to
35 *
36 * @param handle returned by 'usbmuxd_scan()'
37 *
38 * @param tcp_port TCP port number on device, in range 0-65535.
39 * common values are 62078 for lockdown, and 22 for SSH.
40 *
41 * @return file descriptor socket of the connection, or -1 on error
42 */
43int usbmuxd_connect(const int handle, const unsigned short tcp_port);
44
45/**
46 * Disconnect. For now, this just closes the socket file descriptor.
47 *
48 * @param sfd socker file descriptor returned by usbmuxd_connect()
49 *
50 * @return 0 on success, -1 on error.
51 */
52int usbmuxd_disconnect(int sfd);
53
54/**
55 * Send data to the specified socket.
56 *
57 * @param sfd socket file descriptor returned by usbmuxd_connect()
58 * @param data buffer to send
59 * @param len size of buffer to send
60 * @param sent_bytes how many bytes sent
61 *
62 * @return 0 on success, a negative errno value otherwise.
63 */
64int usbmuxd_send(int sfd, const char *data, uint32_t len, uint32_t *sent_bytes);
65
66/**
67 * Receive data from the specified socket.
68 *
69 * @param sfd socket file descriptor returned by usbmuxd_connect()
70 * @param data buffer to put the data to
71 * @param len number of bytes to receive
72 * @param recv_bytes number of bytes received
73 * @param timeout how many milliseconds to wait for data
74 *
75 * @return 0 on success, a negative errno value otherwise.
76 */
77int usbmuxd_recv_timeout(int sfd, char *data, uint32_t len, uint32_t *recv_bytes, unsigned int timeout);
78
79/**
80 * Receive data from the specified socket with a default timeout.
81 *
82 * @param sfd socket file descriptor returned by usbmuxd_connect()
83 * @param data buffer to put the data to
84 * @param len number of bytes to receive
85 * @param recv_bytes number of bytes received
86 *
87 * @return 0 on success, a negative errno value otherwise.
88 */
89int usbmuxd_recv(int sfd, char *data, uint32_t len, uint32_t *recv_bytes);
90
91#endif /* __USBMUXD_H */