summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Martin Szulecki2012-09-04 00:36:40 +0200
committerGravatar Martin Szulecki2012-10-21 14:19:50 +0200
commitd09e25b69d2744ba7a6a88cc58d9cc8fc4810d2a (patch)
treee9caed03fb33d4eb3eadda59fdaa89cb0041471e
parentb3a679c7c6a2ab30aaac27abd79428b557511bf2 (diff)
downloadlibimobiledevice-d09e25b69d2744ba7a6a88cc58d9cc8fc4810d2a.tar.gz
libimobiledevice-d09e25b69d2744ba7a6a88cc58d9cc8fc4810d2a.tar.bz2
Add new idevicedebugserverproxy tool
-rw-r--r--tools/Makefile.am7
-rw-r--r--tools/idevicedebugserverproxy.c374
-rw-r--r--tools/socket.c392
-rw-r--r--tools/socket.h65
-rw-r--r--tools/thread.c47
-rw-r--r--tools/thread.h38
6 files changed, 922 insertions, 1 deletions
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 6a4822b..904159b 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = -I$(top_srcdir)/include
3AM_CFLAGS = $(GLOBAL_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(openssl_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS) 3AM_CFLAGS = $(GLOBAL_CFLAGS) $(libgnutls_CFLAGS) $(libtasn1_CFLAGS) $(openssl_CFLAGS) $(libplist_CFLAGS) $(LFS_CFLAGS)
4AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(openssl_LIBS) $(libplist_LIBS) 4AM_LDFLAGS = $(libgnutls_LIBS) $(libtasn1_LIBS) $(openssl_LIBS) $(libplist_LIBS)
5 5
6bin_PROGRAMS = idevice_id ideviceinfo idevicepair idevicesyslog ideviceimagemounter idevicescreenshot ideviceenterrecovery idevicedate idevicebackup idevicebackup2 ideviceprovision 6bin_PROGRAMS = idevice_id ideviceinfo idevicepair idevicesyslog ideviceimagemounter idevicescreenshot ideviceenterrecovery idevicedate idevicebackup idevicebackup2 ideviceprovision idevicedebugserverproxy
7 7
8ideviceinfo_SOURCES = ideviceinfo.c 8ideviceinfo_SOURCES = ideviceinfo.c
9ideviceinfo_CFLAGS = $(AM_CFLAGS) 9ideviceinfo_CFLAGS = $(AM_CFLAGS)
@@ -59,3 +59,8 @@ ideviceprovision_SOURCES = ideviceprovision.c
59ideviceprovision_CFLAGS = $(AM_CFLAGS) 59ideviceprovision_CFLAGS = $(AM_CFLAGS)
60ideviceprovision_LDFLAGS = $(AM_LDFLAGS) 60ideviceprovision_LDFLAGS = $(AM_LDFLAGS)
61ideviceprovision_LDADD = ../src/libimobiledevice.la 61ideviceprovision_LDADD = ../src/libimobiledevice.la
62
63idevicedebugserverproxy_SOURCES = idevicedebugserverproxy.c socket.c thread.c
64idevicedebugserverproxy_CFLAGS = $(AM_CFLAGS)
65idevicedebugserverproxy_LDFLAGS = $(AM_LDFLAGS)
66idevicedebugserverproxy_LDADD = ../src/libimobiledevice.la
diff --git a/tools/idevicedebugserverproxy.c b/tools/idevicedebugserverproxy.c
new file mode 100644
index 0000000..4487647
--- /dev/null
+++ b/tools/idevicedebugserverproxy.c
@@ -0,0 +1,374 @@
1/*
2 * idevicedebugserverproxy.c
3 * Proxy a debugserver connection from device for remote debugging
4 *
5 * Copyright (c) 2012 Martin Szulecki All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <errno.h>
26#include <signal.h>
27
28#include <libimobiledevice/libimobiledevice.h>
29#include <libimobiledevice/lockdown.h>
30
31#include "socket.h"
32#include "thread.h"
33
34#define info(...) fprintf(stdout, __VA_ARGS__); fflush(stdout)
35#define debug(...) if(debug_mode) fprintf(stdout, __VA_ARGS__)
36
37static int debug_mode = 0;
38static int quit_flag = 0;
39
40typedef struct {
41 int server_fd;
42 int client_fd;
43 uint16_t local_port;
44 uint16_t remote_port;
45 idevice_connection_t device_connection;
46 volatile int stop_ctod;
47 volatile int stop_dtoc;
48} socket_info_t;
49
50static void clean_exit(int sig)
51{
52 fprintf(stderr, "Exiting...\n");
53 quit_flag++;
54}
55
56static void print_usage(int argc, char **argv)
57{
58 char *name = NULL;
59
60 name = strrchr(argv[0], '/');
61 printf("Usage: %s [OPTIONS] <PORT>\n", (name ? name + 1: argv[0]));
62 printf("Proxy debugserver connection from device to a local socket at PORT.\n\n");
63 printf(" -d, --debug\t\tenable communication debugging\n");
64 printf(" -u, --udid UDID\ttarget specific device by its 40-digit device UDID\n");
65 printf(" -h, --help\t\tprints usage information\n");
66 printf("\n");
67}
68
69static void *thread_device_to_client(void *data)
70{
71 socket_info_t* socket_info = (socket_info_t*)data;
72 idevice_error_t res = IDEVICE_E_UNKNOWN_ERROR;
73
74 int recv_len;
75 int sent;
76 char buffer[131072];
77
78 debug("%s: started thread...\n", __func__);
79
80 debug("%s: client_fd = %d\n", __func__, socket_info->client_fd);
81 debug("%s: server fd = %d\n", __func__, socket_info->server_fd);
82
83 while (!quit_flag && !socket_info->stop_dtoc && socket_info->client_fd > 0 && socket_info->server_fd > 0) {
84 debug("%s: receiving data from device...\n", __func__);
85
86 res = idevice_connection_receive_timeout(socket_info->device_connection, buffer, sizeof(buffer), (uint32_t*)&recv_len, 5000);
87
88 if (recv_len <= 0) {
89 if (recv_len == 0 && res == IDEVICE_E_SUCCESS) {
90 // try again
91 continue;
92 } else {
93 fprintf(stderr, "recv failed: %s\n", strerror(errno));
94 break;
95 }
96 } else {
97 /* send to device */
98 debug("%s: sending data to device...\n", __func__);
99 sent = socket_send(socket_info->client_fd, buffer, recv_len);
100 if (sent < recv_len) {
101 if (sent <= 0) {
102 fprintf(stderr, "send failed: %s\n", strerror(errno));
103 break;
104 } else {
105 fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
106 }
107 } else {
108 // sending succeeded, receive from device
109 debug("%s: pushed %d bytes to client\n", __func__, sent);
110 }
111 }
112 }
113
114 debug("%s: shutting down...\n", __func__);
115
116 socket_shutdown(socket_info->client_fd, SHUT_RDWR);
117 socket_close(socket_info->client_fd);
118
119 socket_info->client_fd = -1;
120 socket_info->stop_ctod = 1;
121
122 return NULL;
123}
124
125static void *thread_client_to_device(void *data)
126{
127 socket_info_t* socket_info = (socket_info_t*)data;
128 idevice_error_t res = IDEVICE_E_UNKNOWN_ERROR;
129
130 int recv_len;
131 int sent;
132 char buffer[131072];
133 thread_t dtoc;
134
135 debug("%s: started thread...\n", __func__);
136
137 debug("%s: client_fd = %d\n", __func__, socket_info->client_fd);
138 debug("%s: server_fd = %d\n", __func__, socket_info->server_fd);
139
140 /* spawn server to client thread */
141 socket_info->stop_dtoc = 0;
142 if (thread_create(&dtoc, thread_device_to_client, data) != 0) {
143 fprintf(stderr, "Failed to start device to client thread...\n");
144 }
145
146 while (!quit_flag && !socket_info->stop_ctod && socket_info->client_fd > 0 && socket_info->server_fd > 0) {
147 debug("%s: receiving data from client...\n", __func__);
148
149 /* attempt to read incoming data from client */
150 recv_len = socket_receive_timeout(socket_info->client_fd, buffer, sizeof(buffer), 0, 5000);
151
152 /* any data received? */
153 if (recv_len <= 0) {
154 if (recv_len == 0) {
155 /* try again */
156 continue;
157 } else {
158 fprintf(stderr, "Receive failed: %s\n", strerror(errno));
159 break;
160 }
161 } else {
162 /* forward data to device */
163 debug("%s: sending data to device...\n", __func__);
164 res = idevice_connection_send(socket_info->device_connection, buffer, recv_len, (uint32_t*)&sent);
165
166 if (sent < recv_len || res != IDEVICE_E_SUCCESS) {
167 if (sent <= 0) {
168 fprintf(stderr, "send failed: %s\n", strerror(errno));
169 break;
170 } else {
171 fprintf(stderr, "only sent %d from %d bytes\n", sent, recv_len);
172 }
173 } else {
174 // sending succeeded, receive from device
175 debug("%s: sent %d bytes to device\n", __func__, sent);
176 }
177 }
178 }
179
180 debug("%s: shutting down...\n", __func__);
181
182 socket_shutdown(socket_info->client_fd, SHUT_RDWR);
183 socket_close(socket_info->client_fd);
184
185 socket_info->client_fd = -1;
186 socket_info->stop_dtoc = 1;
187
188 /* join other thread to allow it to stop */
189 thread_join(dtoc);
190
191 return NULL;
192}
193
194static void* connection_handler(void* data)
195{
196 socket_info_t* socket_info = (socket_info_t*)data;
197 thread_t ctod;
198
199 debug("%s: client_fd = %d\n", __func__, socket_info->client_fd);
200
201 /* spawn client to device thread */
202 socket_info->stop_ctod = 0;
203 if (thread_create(&ctod, thread_client_to_device, data) != 0) {
204 fprintf(stderr, "Failed to start client to device thread...\n");
205 }
206
207 /* join the fun */
208 thread_join(ctod);
209
210 /* shutdown client socket */
211 socket_shutdown(socket_info->client_fd, SHUT_RDWR);
212 socket_close(socket_info->client_fd);
213
214 /* shutdown server socket if we have to terminate to unblock the server loop */
215 if (quit_flag) {
216 socket_shutdown(socket_info->server_fd, SHUT_RDWR);
217 socket_close(socket_info->server_fd);
218 }
219
220 return NULL;
221}
222
223int main(int argc, char *argv[])
224{
225 lockdownd_client_t lockdown = NULL;
226 idevice_t device = NULL;
227 idevice_connection_t connection = NULL;
228 idevice_error_t ret = IDEVICE_E_UNKNOWN_ERROR;
229 thread_t th;
230 char udid[41];
231 udid[0] = 0;
232 uint16_t port = 0;
233 uint16_t local_port = 0;
234 int result = EXIT_SUCCESS;
235 int i;
236
237 /* bind signals */
238 signal(SIGINT, clean_exit);
239 signal(SIGTERM, clean_exit);
240#ifndef WIN32
241 signal(SIGQUIT, clean_exit);
242 signal(SIGPIPE, SIG_IGN);
243#endif
244
245 /* parse cmdline arguments */
246 for (i = 1; i < argc; i++) {
247 if (!strcmp(argv[i], "-d") || !strcmp(argv[i], "--debug")) {
248 debug_mode = 1;
249 idevice_set_debug_level(1);
250 socket_set_verbose(3);
251 continue;
252 }
253 else if (!strcmp(argv[i], "-u") || !strcmp(argv[i], "--udid")) {
254 i++;
255 if (!argv[i] || (strlen(argv[i]) != 40)) {
256 print_usage(argc, argv);
257 return 0;
258 }
259 strcpy(udid, argv[i]);
260 continue;
261 }
262 else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
263 print_usage(argc, argv);
264 return EXIT_SUCCESS;
265 }
266 else if (atoi(argv[i]) > 0) {
267 local_port = atoi(argv[i]);
268 continue;
269 }
270 else {
271 print_usage(argc, argv);
272 return EXIT_SUCCESS;
273 }
274 }
275
276 /* a PORT is mandatory */
277 if (!local_port) {
278 fprintf(stderr, "Please specify a PORT.\n");
279 print_usage(argc, argv);
280 goto leave_cleanup;
281 }
282
283 /* start services and connect to device */
284 if (udid[0] != 0) {
285 ret = idevice_new(&device, udid);
286 if (ret != IDEVICE_E_SUCCESS) {
287 fprintf(stderr, "No device found with udid %s, is it plugged in?\n", udid);
288 result = EXIT_FAILURE;
289 goto leave_cleanup;
290 }
291 }
292 else
293 {
294 ret = idevice_new(&device, NULL);
295 if (ret != IDEVICE_E_SUCCESS) {
296 fprintf(stderr, "No device found, is it plugged in?\n");
297 result = EXIT_FAILURE;
298 goto leave_cleanup;
299 }
300 }
301
302 if (LOCKDOWN_E_SUCCESS != lockdownd_client_new_with_handshake(device, &lockdown, "idevicedebugserverproxy")) {
303 fprintf(stderr, "Could not connect to lockdownd. Exiting.\n");
304 result = EXIT_FAILURE;
305 goto leave_cleanup;
306 }
307
308 if ((lockdownd_start_service(lockdown, "com.apple.debugserver", &port) != LOCKDOWN_E_SUCCESS) || !port) {
309 fprintf(stderr, "Could not start com.apple.debugserver!\nPlease make sure to mount the developer disk image first.\n");
310 result = EXIT_FAILURE;
311 goto leave_cleanup;
312 }
313
314 if (idevice_connect(device, port, &connection) != IDEVICE_E_SUCCESS) {
315 fprintf(stderr, "Connection to debugserver port %d failed!\n", (int)&port);
316 result = EXIT_FAILURE;
317 goto leave_cleanup;
318 }
319
320 /* free lockdown connection if running as it is not needed anymore */
321 if (lockdown) {
322 lockdownd_client_free(lockdown);
323 lockdown = NULL;
324 }
325
326 /* setup and create socket endpoint */
327 socket_info_t socket_info;
328
329 socket_info.device_connection = connection;
330 socket_info.local_port = local_port;
331 socket_info.remote_port = port;
332
333 /* create local socket */
334 socket_info.server_fd = socket_create(socket_info.local_port);
335 if (socket_info.server_fd < 0) {
336 fprintf(stderr, "Could not create socket\n");
337 result = EXIT_FAILURE;
338 goto leave_cleanup;
339 }
340
341 while (!quit_flag) {
342 debug("%s: Waiting for connection on local port %d\n", __func__, socket_info.local_port);
343
344 /* wait for client */
345 socket_info.client_fd = socket_accept(socket_info.server_fd, socket_info.local_port);
346 if (socket_info.client_fd < 0) {
347 debug("%s: Continuing...\n", __func__);
348 continue;
349 }
350
351 debug("%s: Handling new client connection...\n", __func__);
352
353 if (thread_create(&th, connection_handler, (void*)&socket_info) != 0) {
354 fprintf(stderr, "Could not start connection handler.\n");
355 socket_shutdown(socket_info.server_fd, SHUT_RDWR);
356 socket_close(socket_info.server_fd);
357 }
358 }
359
360 debug("%s: Shutting down debugserver proxy...\n", __func__);
361
362leave_cleanup:
363 if (connection) {
364 idevice_disconnect(connection);
365 }
366 if (lockdown) {
367 lockdownd_client_free(lockdown);
368 }
369 if (device) {
370 idevice_free(device);
371 }
372
373 return result;
374}
diff --git a/tools/socket.c b/tools/socket.c
new file mode 100644
index 0000000..c35de33
--- /dev/null
+++ b/tools/socket.c
@@ -0,0 +1,392 @@
1/*
2 * socket.c
3 *
4 * Copyright (c) 2012 Martin Szulecki All Rights Reserved.
5 * Copyright (c) 2012 Nikias Bassen All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include <stdio.h>
23#include <stddef.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27#include <errno.h>
28#include <sys/time.h>
29#include <sys/stat.h>
30#ifdef WIN32
31#include <winsock2.h>
32#include <windows.h>
33static int wsa_init = 0;
34#else
35#include <sys/socket.h>
36#include <sys/un.h>
37#include <netinet/in.h>
38#include <netdb.h>
39#include <arpa/inet.h>
40#endif
41#include "socket.h"
42
43#define RECV_TIMEOUT 20000
44
45static int verbose = 0;
46
47void socket_set_verbose(int level)
48{
49 verbose = level;
50}
51
52#ifndef WIN32
53int socket_create_unix(const char *filename)
54{
55 struct sockaddr_un name;
56 int sock;
57 size_t size;
58
59 // remove if still present
60 unlink(filename);
61
62 /* Create the socket. */
63 sock = socket(PF_LOCAL, SOCK_STREAM, 0);
64 if (sock < 0) {
65 perror("socket");
66 return -1;
67 }
68
69 /* Bind a name to the socket. */
70 name.sun_family = AF_LOCAL;
71 strncpy(name.sun_path, filename, sizeof(name.sun_path));
72 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
73
74 /* The size of the address is
75 the offset of the start of the filename,
76 plus its length,
77 plus one for the terminating null byte.
78 Alternatively you can just do:
79 size = SUN_LEN (&name);
80 */
81 size = (offsetof(struct sockaddr_un, sun_path)
82 + strlen(name.sun_path) + 1);
83
84 if (bind(sock, (struct sockaddr *) &name, size) < 0) {
85 perror("bind");
86 socket_close(sock);
87 return -1;
88 }
89
90 if (listen(sock, 10) < 0) {
91 perror("listen");
92 socket_close(sock);
93 return -1;
94 }
95
96 return sock;
97}
98
99int socket_connect_unix(const char *filename)
100{
101 struct sockaddr_un name;
102 int sfd = -1;
103 size_t size;
104 struct stat fst;
105
106 // check if socket file exists...
107 if (stat(filename, &fst) != 0) {
108 if (verbose >= 2)
109 fprintf(stderr, "%s: stat '%s': %s\n", __func__, filename,
110 strerror(errno));
111 return -1;
112 }
113 // ... and if it is a unix domain socket
114 if (!S_ISSOCK(fst.st_mode)) {
115 if (verbose >= 2)
116 fprintf(stderr, "%s: File '%s' is not a socket!\n", __func__,
117 filename);
118 return -1;
119 }
120 // make a new socket
121 if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) {
122 if (verbose >= 2)
123 fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
124 return -1;
125 }
126 // and connect to 'filename'
127 name.sun_family = AF_LOCAL;
128 strncpy(name.sun_path, filename, sizeof(name.sun_path));
129 name.sun_path[sizeof(name.sun_path) - 1] = 0;
130
131 size = (offsetof(struct sockaddr_un, sun_path)
132 + strlen(name.sun_path) + 1);
133
134 if (connect(sfd, (struct sockaddr *) &name, size) < 0) {
135 socket_close(sfd);
136 if (verbose >= 2)
137 fprintf(stderr, "%s: connect: %s\n", __func__,
138 strerror(errno));
139 return -1;
140 }
141
142 return sfd;
143}
144#endif
145
146int socket_create(uint16_t port)
147{
148 int sfd = -1;
149 int yes = 1;
150#ifdef WIN32
151 WSADATA wsa_data;
152 if (!wsa_init) {
153 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
154 fprintf(stderr, "WSAStartup failed!\n");
155 ExitProcess(-1);
156 }
157 wsa_init = 1;
158 }
159#endif
160 struct sockaddr_in saddr;
161
162 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
163 perror("socket()");
164 return -1;
165 }
166
167 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
168 perror("setsockopt()");
169 socket_close(sfd);
170 return -1;
171 }
172
173 memset((void *) &saddr, 0, sizeof(saddr));
174 saddr.sin_family = AF_INET;
175 saddr.sin_addr.s_addr = htonl(INADDR_ANY);
176 saddr.sin_port = htons(port);
177
178 if (0 > bind(sfd, (struct sockaddr *) &saddr, sizeof(saddr))) {
179 perror("bind()");
180 socket_close(sfd);
181 return -1;
182 }
183
184 if (listen(sfd, 1) == -1) {
185 perror("listen()");
186 socket_close(sfd);
187 return -1;
188 }
189
190 return sfd;
191}
192
193int socket_connect(const char *addr, uint16_t port)
194{
195 int sfd = -1;
196 int yes = 1;
197 struct hostent *hp;
198 struct sockaddr_in saddr;
199#ifdef WIN32
200 WSADATA wsa_data;
201 if (!wsa_init) {
202 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
203 fprintf(stderr, "WSAStartup failed!\n");
204 ExitProcess(-1);
205 }
206 wsa_init = 1;
207 }
208#endif
209
210 if (!addr) {
211 errno = EINVAL;
212 return -1;
213 }
214
215 if ((hp = gethostbyname(addr)) == NULL) {
216 if (verbose >= 2)
217 fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr);
218 return -1;
219 }
220
221 if (!hp->h_addr) {
222 if (verbose >= 2)
223 fprintf(stderr, "%s: gethostbyname returned NULL address!\n",
224 __func__);
225 return -1;
226 }
227
228 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) {
229 perror("socket()");
230 return -1;
231 }
232
233 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
234 perror("setsockopt()");
235 socket_close(sfd);
236 return -1;
237 }
238
239 memset((void *) &saddr, 0, sizeof(saddr));
240 saddr.sin_family = AF_INET;
241 saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr;
242 saddr.sin_port = htons(port);
243
244 if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) {
245 perror("connect");
246 socket_close(sfd);
247 return -2;
248 }
249
250 return sfd;
251}
252
253int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
254{
255 fd_set fds;
256 int sret;
257 int eagain;
258 struct timeval to;
259 struct timeval *pto;
260
261 if (fd <= 0) {
262 if (verbose >= 2)
263 fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
264 return -1;
265 }
266
267 FD_ZERO(&fds);
268 FD_SET(fd, &fds);
269
270 if (timeout > 0) {
271 to.tv_sec = (time_t) (timeout / 1000);
272 to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
273 pto = &to;
274 } else {
275 pto = NULL;
276 }
277
278 sret = -1;
279
280 do {
281 eagain = 0;
282 switch (fdm) {
283 case FDM_READ:
284 sret = select(fd + 1, &fds, NULL, NULL, pto);
285 break;
286 case FDM_WRITE:
287 sret = select(fd + 1, NULL, &fds, NULL, pto);
288 break;
289 case FDM_EXCEPT:
290 sret = select(fd + 1, NULL, NULL, &fds, pto);
291 break;
292 default:
293 return -1;
294 }
295
296 if (sret < 0) {
297 switch (errno) {
298 case EINTR:
299 // interrupt signal in select
300 if (verbose >= 2)
301 fprintf(stderr, "%s: EINTR\n", __func__);
302 eagain = 1;
303 break;
304 case EAGAIN:
305 if (verbose >= 2)
306 fprintf(stderr, "%s: EAGAIN\n", __func__);
307 break;
308 default:
309 if (verbose >= 2)
310 fprintf(stderr, "%s: select failed: %s\n", __func__,
311 strerror(errno));
312 return -1;
313 }
314 }
315 } while (eagain);
316
317 return sret;
318}
319
320int socket_accept(int fd, uint16_t port)
321{
322#ifdef WIN32
323 int addr_len;
324#else
325 socklen_t addr_len;
326#endif
327 int result;
328 struct sockaddr_in addr;
329
330 memset(&addr, 0, sizeof(addr));
331 addr.sin_family = AF_INET;
332 addr.sin_addr.s_addr = htonl(INADDR_ANY);
333 addr.sin_port = htons(port);
334
335 addr_len = sizeof(addr);
336 result = accept(fd, (struct sockaddr*)&addr, &addr_len);
337
338 return result;
339}
340
341int socket_shutdown(int fd, int how)
342{
343 return shutdown(fd, how);
344}
345
346int socket_close(int fd) {
347#ifdef WIN32
348 return closesocket(fd);
349#else
350 return close(fd);
351#endif
352}
353
354int socket_receive(int fd, void *data, size_t length)
355{
356 return socket_receive_timeout(fd, data, length, 0, RECV_TIMEOUT);
357}
358
359int socket_peek(int fd, void *data, size_t length)
360{
361 return socket_receive_timeout(fd, data, length, MSG_PEEK, RECV_TIMEOUT);
362}
363
364int socket_receive_timeout(int fd, void *data, size_t length, int flags,
365 unsigned int timeout)
366{
367 int res;
368 int result;
369
370 // check if data is available
371 res = socket_check_fd(fd, FDM_READ, timeout);
372 if (res <= 0) {
373 return res;
374 }
375 // if we get here, there _is_ data available
376 result = recv(fd, data, length, flags);
377 if (res > 0 && result == 0) {
378 // but this is an error condition
379 if (verbose >= 3)
380 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
381 return -EAGAIN;
382 }
383 if (result < 0) {
384 return -errno;
385 }
386 return result;
387}
388
389int socket_send(int fd, void *data, size_t length)
390{
391 return send(fd, data, length, 0);
392}
diff --git a/tools/socket.h b/tools/socket.h
new file mode 100644
index 0000000..c2b2599
--- /dev/null
+++ b/tools/socket.h
@@ -0,0 +1,65 @@
1/*
2 * socket.h
3 *
4 * Copyright (c) 2012 Martin Szulecki All Rights Reserved.
5 * Copyright (c) 2012 Nikias Bassen All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef __SOCKET_SOCKET_H
23#define __SOCKET_SOCKET_H
24
25#include <stdlib.h>
26#include <stdint.h>
27
28enum fd_mode {
29 FDM_READ,
30 FDM_WRITE,
31 FDM_EXCEPT
32};
33typedef enum fd_mode fd_mode;
34
35#ifdef WIN32
36#include <winsock2.h>
37#define SHUT_RD SD_READ
38#define SHUT_WR SD_WRITE
39#define SHUT_RDWR SD_BOTH
40#else
41#include <sys/socket.h>
42#endif
43
44#ifndef WIN32
45int socket_create_unix(const char *filename);
46int socket_connect_unix(const char *filename);
47#endif
48int socket_create(uint16_t port);
49int socket_connect(const char *addr, uint16_t port);
50int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout);
51int socket_accept(int fd, uint16_t port);
52
53int socket_shutdown(int fd, int how);
54int socket_close(int fd);
55
56int socket_receive(int fd, void *data, size_t size);
57int socket_peek(int fd, void *data, size_t size);
58int socket_receive_timeout(int fd, void *data, size_t size, int flags,
59 unsigned int timeout);
60
61int socket_send(int fd, void *data, size_t size);
62
63void socket_set_verbose(int level);
64
65#endif /* __SOCKET_SOCKET_H */
diff --git a/tools/thread.c b/tools/thread.c
new file mode 100644
index 0000000..f077243
--- /dev/null
+++ b/tools/thread.c
@@ -0,0 +1,47 @@
1/*
2 * thread.c
3 *
4 * Copyright (c) 2012 Martin Szulecki All Rights Reserved.
5 * Copyright (c) 2012 Nikias Bassen All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#include "thread.h"
23
24int thread_create(thread_t *thread, thread_func_t thread_func, void* data)
25{
26#ifdef WIN32
27 HANDLE th = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)thread_func, data, 0, NULL);
28 if (th == NULL) {
29 return -1;
30 }
31 *thread = th;
32 return 0;
33#else
34 int res = pthread_create(thread, NULL, thread_func, data);
35 return res;
36#endif
37}
38
39void thread_join(thread_t thread)
40{
41 /* wait for thread to complete */
42#ifdef WIN32
43 WaitForSingleObject(thread, INFINITE);
44#else
45 pthread_join(thread, NULL);
46#endif
47}
diff --git a/tools/thread.h b/tools/thread.h
new file mode 100644
index 0000000..983eeb5
--- /dev/null
+++ b/tools/thread.h
@@ -0,0 +1,38 @@
1/*
2 * thread.h
3 *
4 * Copyright (c) 2012 Martin Szulecki All Rights Reserved.
5 * Copyright (c) 2012 Nikias Bassen All Rights Reserved.
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#ifndef __THREAD_H
23#define __THREAD_H
24
25#ifdef WIN32
26#include <windows.h>
27typedef HANDLE thread_t;
28#else
29#include <pthread.h>
30typedef pthread_t thread_t;
31#endif
32
33typedef void* (*thread_func_t)(void* data);
34
35int thread_create(thread_t* thread, thread_func_t thread_func, void* data);
36void thread_join(thread_t thread);
37
38#endif