summaryrefslogtreecommitdiffstats
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/socket.c215
-rw-r--r--common/socket.h10
2 files changed, 165 insertions, 60 deletions
diff --git a/common/socket.c b/common/socket.c
index e2968a6..aa97848 100644
--- a/common/socket.c
+++ b/common/socket.c
@@ -1,8 +1,8 @@
1/* 1/*
2 * socket.c 2 * socket.c
3 * 3 *
4 * Copyright (c) 2012 Martin Szulecki All Rights Reserved. 4 * Copyright (C) 2012-2018 Nikias Bassen <nikias@gmx.li>
5 * Copyright (c) 2012 Nikias Bassen All Rights Reserved. 5 * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
@@ -19,6 +19,9 @@
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22#ifdef HAVE_CONFIG_H
23#include <config.h>
24#endif
22#include <stdio.h> 25#include <stdio.h>
23#include <stddef.h> 26#include <stddef.h>
24#include <stdlib.h> 27#include <stdlib.h>
@@ -29,18 +32,26 @@
29#include <sys/stat.h> 32#include <sys/stat.h>
30#ifdef WIN32 33#ifdef WIN32
31#include <winsock2.h> 34#include <winsock2.h>
35#include <ws2tcpip.h>
32#include <windows.h> 36#include <windows.h>
33static int wsa_init = 0; 37static int wsa_init = 0;
34#else 38#else
35#include <sys/socket.h> 39#include <sys/socket.h>
36#include <sys/un.h> 40#include <sys/un.h>
37#include <netinet/in.h> 41#include <netinet/in.h>
42#include <netinet/tcp.h>
38#include <netdb.h> 43#include <netdb.h>
39#include <arpa/inet.h> 44#include <arpa/inet.h>
45#include <fcntl.h>
40#endif 46#endif
41#include "socket.h" 47#include "socket.h"
42 48
43#define RECV_TIMEOUT 20000 49#define RECV_TIMEOUT 20000
50#define CONNECT_TIMEOUT 5000
51
52#ifndef ECONNRESET
53#define ECONNRESET 108
54#endif
44 55
45static int verbose = 0; 56static int verbose = 0;
46 57
@@ -54,34 +65,34 @@ int socket_create_unix(const char *filename)
54{ 65{
55 struct sockaddr_un name; 66 struct sockaddr_un name;
56 int sock; 67 int sock;
57 size_t size; 68#ifdef SO_NOSIGPIPE
69 int yes = 1;
70#endif
58 71
59 // remove if still present 72 // remove if still present
60 unlink(filename); 73 unlink(filename);
61 74
62 /* Create the socket. */ 75 /* Create the socket. */
63 sock = socket(PF_LOCAL, SOCK_STREAM, 0); 76 sock = socket(PF_UNIX, SOCK_STREAM, 0);
64 if (sock < 0) { 77 if (sock < 0) {
65 perror("socket"); 78 perror("socket");
66 return -1; 79 return -1;
67 } 80 }
68 81
82#ifdef SO_NOSIGPIPE
83 if (setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
84 perror("setsockopt()");
85 socket_close(sock);
86 return -1;
87 }
88#endif
89
69 /* Bind a name to the socket. */ 90 /* Bind a name to the socket. */
70 name.sun_family = AF_LOCAL; 91 name.sun_family = AF_UNIX;
71 strncpy(name.sun_path, filename, sizeof(name.sun_path)); 92 strncpy(name.sun_path, filename, sizeof(name.sun_path));
72 name.sun_path[sizeof(name.sun_path) - 1] = '\0'; 93 name.sun_path[sizeof(name.sun_path) - 1] = '\0';
73 94
74 /* The size of the address is 95 if (bind(sock, (struct sockaddr*)&name, sizeof(name)) < 0) {
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"); 96 perror("bind");
86 socket_close(sock); 97 socket_close(sock);
87 return -1; 98 return -1;
@@ -100,8 +111,11 @@ int socket_connect_unix(const char *filename)
100{ 111{
101 struct sockaddr_un name; 112 struct sockaddr_un name;
102 int sfd = -1; 113 int sfd = -1;
103 size_t size;
104 struct stat fst; 114 struct stat fst;
115#ifdef SO_NOSIGPIPE
116 int yes = 1;
117#endif
118 int bufsize = 0x20000;
105 119
106 // check if socket file exists... 120 // check if socket file exists...
107 if (stat(filename, &fst) != 0) { 121 if (stat(filename, &fst) != 0) {
@@ -118,20 +132,33 @@ int socket_connect_unix(const char *filename)
118 return -1; 132 return -1;
119 } 133 }
120 // make a new socket 134 // make a new socket
121 if ((sfd = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { 135 if ((sfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
122 if (verbose >= 2) 136 if (verbose >= 2)
123 fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno)); 137 fprintf(stderr, "%s: socket: %s\n", __func__, strerror(errno));
124 return -1; 138 return -1;
125 } 139 }
140
141 if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) {
142 perror("Could not set send buffer for socket");
143 }
144
145 if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) {
146 perror("Could not set receive buffer for socket");
147 }
148
149#ifdef SO_NOSIGPIPE
150 if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
151 perror("setsockopt()");
152 socket_close(sfd);
153 return -1;
154 }
155#endif
126 // and connect to 'filename' 156 // and connect to 'filename'
127 name.sun_family = AF_LOCAL; 157 name.sun_family = AF_UNIX;
128 strncpy(name.sun_path, filename, sizeof(name.sun_path)); 158 strncpy(name.sun_path, filename, sizeof(name.sun_path));
129 name.sun_path[sizeof(name.sun_path) - 1] = 0; 159 name.sun_path[sizeof(name.sun_path) - 1] = 0;
130 160
131 size = (offsetof(struct sockaddr_un, sun_path) 161 if (connect(sfd, (struct sockaddr*)&name, sizeof(name)) < 0) {
132 + strlen(name.sun_path) + 1);
133
134 if (connect(sfd, (struct sockaddr *) &name, size) < 0) {
135 socket_close(sfd); 162 socket_close(sfd);
136 if (verbose >= 2) 163 if (verbose >= 2)
137 fprintf(stderr, "%s: connect: %s\n", __func__, 164 fprintf(stderr, "%s: connect: %s\n", __func__,
@@ -170,6 +197,14 @@ int socket_create(uint16_t port)
170 return -1; 197 return -1;
171 } 198 }
172 199
200#ifdef SO_NOSIGPIPE
201 if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
202 perror("setsockopt()");
203 socket_close(sfd);
204 return -1;
205 }
206#endif
207
173 memset((void *) &saddr, 0, sizeof(saddr)); 208 memset((void *) &saddr, 0, sizeof(saddr));
174 saddr.sin_family = AF_INET; 209 saddr.sin_family = AF_INET;
175 saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 210 saddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
@@ -194,9 +229,14 @@ int socket_connect(const char *addr, uint16_t port)
194{ 229{
195 int sfd = -1; 230 int sfd = -1;
196 int yes = 1; 231 int yes = 1;
197 struct hostent *hp; 232 int bufsize = 0x20000;
198 struct sockaddr_in saddr; 233 struct addrinfo hints;
234 struct addrinfo *result, *rp;
235 char portstr[8];
236 int res;
199#ifdef WIN32 237#ifdef WIN32
238 u_long l_yes = 1;
239 u_long l_no = 0;
200 WSADATA wsa_data; 240 WSADATA wsa_data;
201 if (!wsa_init) { 241 if (!wsa_init) {
202 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { 242 if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) {
@@ -205,6 +245,8 @@ int socket_connect(const char *addr, uint16_t port)
205 } 245 }
206 wsa_init = 1; 246 wsa_init = 1;
207 } 247 }
248#else
249 int flags = 0;
208#endif 250#endif
209 251
210 if (!addr) { 252 if (!addr) {
@@ -212,39 +254,99 @@ int socket_connect(const char *addr, uint16_t port)
212 return -1; 254 return -1;
213 } 255 }
214 256
215 if ((hp = gethostbyname(addr)) == NULL) { 257 memset(&hints, '\0', sizeof(struct addrinfo));
216 if (verbose >= 2) 258 hints.ai_family = AF_UNSPEC;
217 fprintf(stderr, "%s: unknown host '%s'\n", __func__, addr); 259 hints.ai_socktype = SOCK_STREAM;
260 hints.ai_flags = 0;
261 hints.ai_protocol = IPPROTO_TCP;
262
263 sprintf(portstr, "%d", port);
264
265 res = getaddrinfo(addr, portstr, &hints, &result);
266 if (res != 0) {
267 fprintf(stderr, "%s: getaddrinfo: %s\n", __func__, gai_strerror(res));
218 return -1; 268 return -1;
219 } 269 }
220 270
221 if (!hp->h_addr) { 271 for (rp = result; rp != NULL; rp = rp->ai_next) {
222 if (verbose >= 2) 272 sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
223 fprintf(stderr, "%s: gethostbyname returned NULL address!\n", 273 if (sfd == -1) {
224 __func__); 274 continue;
225 return -1; 275 }
276
277 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) {
278 perror("setsockopt()");
279 socket_close(sfd);
280 continue;
281 }
282
283#ifdef WIN32
284 ioctlsocket(sfd, FIONBIO, &l_yes);
285#else
286 fcntl(sfd, F_SETFL, O_NONBLOCK);
287#endif
288
289 if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) {
290 break;
291 }
292#ifdef WIN32
293 if (WSAGetLastError() == WSAEWOULDBLOCK)
294#else
295 if (errno == EINPROGRESS)
296#endif
297 {
298 fd_set fds;
299 FD_ZERO(&fds);
300 FD_SET(sfd, &fds);
301
302 struct timeval timeout;
303 timeout.tv_sec = CONNECT_TIMEOUT / 1000;
304 timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000;
305 if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) {
306 int so_error;
307 socklen_t len = sizeof(so_error);
308 getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len);
309 if (so_error == 0) {
310 break;
311 }
312 }
313 }
314 socket_close(sfd);
226 } 315 }
227 316
228 if (0 > (sfd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP))) { 317 freeaddrinfo(result);
229 perror("socket()"); 318
319 if (rp == NULL) {
320 if (verbose >= 2)
321 fprintf(stderr, "%s: Could not connect to %s:%d\n", __func__, addr, port);
230 return -1; 322 return -1;
231 } 323 }
232 324
233 if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { 325#ifdef WIN32
326 ioctlsocket(sfd, FIONBIO, &l_no);
327#else
328 flags = fcntl(sfd, F_GETFL, 0);
329 fcntl(sfd, F_SETFL, flags & (~O_NONBLOCK));
330#endif
331
332#ifdef SO_NOSIGPIPE
333 if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) {
234 perror("setsockopt()"); 334 perror("setsockopt()");
235 socket_close(sfd); 335 socket_close(sfd);
236 return -1; 336 return -1;
237 } 337 }
338#endif
238 339
239 memset((void *) &saddr, 0, sizeof(saddr)); 340 if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) {
240 saddr.sin_family = AF_INET; 341 perror("Could not set TCP_NODELAY on socket");
241 saddr.sin_addr.s_addr = *(uint32_t *) hp->h_addr; 342 }
242 saddr.sin_port = htons(port);
243 343
244 if (connect(sfd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) { 344 if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) {
245 perror("connect"); 345 perror("Could not set send buffer for socket");
246 socket_close(sfd); 346 }
247 return -2; 347
348 if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) {
349 perror("Could not set receive buffer for socket");
248 } 350 }
249 351
250 return sfd; 352 return sfd;
@@ -258,7 +360,7 @@ int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
258 struct timeval to; 360 struct timeval to;
259 struct timeval *pto; 361 struct timeval *pto;
260 362
261 if (fd <= 0) { 363 if (fd < 0) {
262 if (verbose >= 2) 364 if (verbose >= 2)
263 fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd); 365 fprintf(stderr, "ERROR: invalid fd in check_fd %d\n", fd);
264 return -1; 366 return -1;
@@ -267,17 +369,16 @@ int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout)
267 FD_ZERO(&fds); 369 FD_ZERO(&fds);
268 FD_SET(fd, &fds); 370 FD_SET(fd, &fds);
269 371
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; 372 sret = -1;
279 373
280 do { 374 do {
375 if (timeout > 0) {
376 to.tv_sec = (time_t) (timeout / 1000);
377 to.tv_usec = (time_t) ((timeout - (to.tv_sec * 1000)) * 1000);
378 pto = &to;
379 } else {
380 pto = NULL;
381 }
281 eagain = 0; 382 eagain = 0;
282 switch (fdm) { 383 switch (fdm) {
283 case FDM_READ: 384 case FDM_READ:
@@ -378,7 +479,7 @@ int socket_receive_timeout(int fd, void *data, size_t length, int flags,
378 // but this is an error condition 479 // but this is an error condition
379 if (verbose >= 3) 480 if (verbose >= 3)
380 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd); 481 fprintf(stderr, "%s: fd=%d recv returned 0\n", __func__, fd);
381 return -EAGAIN; 482 return -ECONNRESET;
382 } 483 }
383 if (result < 0) { 484 if (result < 0) {
384 return -errno; 485 return -errno;
@@ -388,5 +489,9 @@ int socket_receive_timeout(int fd, void *data, size_t length, int flags,
388 489
389int socket_send(int fd, void *data, size_t length) 490int socket_send(int fd, void *data, size_t length)
390{ 491{
391 return send(fd, data, length, 0); 492 int flags = 0;
493#ifdef MSG_NOSIGNAL
494 flags |= MSG_NOSIGNAL;
495#endif
496 return send(fd, data, length, flags);
392} 497}
diff --git a/common/socket.h b/common/socket.h
index 81ee083..e31de6b 100644
--- a/common/socket.h
+++ b/common/socket.h
@@ -1,8 +1,8 @@
1/* 1/*
2 * socket.h 2 * socket.h
3 * 3 *
4 * Copyright (c) 2012 Martin Szulecki All Rights Reserved. 4 * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org>
5 * Copyright (c) 2012 Nikias Bassen All Rights Reserved. 5 * Copyright (C) 2012 Nikias Bassen <nikias@gmx.li>
6 * 6 *
7 * This library is free software; you can redistribute it and/or 7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public 8 * modify it under the terms of the GNU Lesser General Public
@@ -19,8 +19,8 @@
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */ 20 */
21 21
22#ifndef __SOCKET_SOCKET_H 22#ifndef SOCKET_SOCKET_H
23#define __SOCKET_SOCKET_H 23#define SOCKET_SOCKET_H
24 24
25#include <stdlib.h> 25#include <stdlib.h>
26#include <stdint.h> 26#include <stdint.h>
@@ -62,4 +62,4 @@ int socket_send(int fd, void *data, size_t size);
62 62
63void socket_set_verbose(int level); 63void socket_set_verbose(int level);
64 64
65#endif /* __SOCKET_SOCKET_H */ 65#endif /* SOCKET_SOCKET_H */