diff options
| -rw-r--r-- | common/socket.c | 235 | ||||
| -rw-r--r-- | common/socket.h | 5 |
2 files changed, 218 insertions, 22 deletions
diff --git a/common/socket.c b/common/socket.c index 777b23e..cf6e9eb 100644 --- a/common/socket.c +++ b/common/socket.c | |||
| @@ -1,7 +1,7 @@ | |||
| 1 | /* | 1 | /* |
| 2 | * socket.c | 2 | * socket.c |
| 3 | * | 3 | * |
| 4 | * Copyright (C) 2012-2018 Nikias Bassen <nikias@gmx.li> | 4 | * Copyright (C) 2012-2020 Nikias Bassen <nikias@gmx.li> |
| 5 | * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org> | 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 |
| @@ -49,6 +49,9 @@ static int wsa_init = 0; | |||
| 49 | #define RECV_TIMEOUT 20000 | 49 | #define RECV_TIMEOUT 20000 |
| 50 | #define CONNECT_TIMEOUT 5000 | 50 | #define CONNECT_TIMEOUT 5000 |
| 51 | 51 | ||
| 52 | #ifndef EAFNOSUPPORT | ||
| 53 | #define EAFNOSUPPORT 102 | ||
| 54 | #endif | ||
| 52 | #ifndef ECONNRESET | 55 | #ifndef ECONNRESET |
| 53 | #define ECONNRESET 108 | 56 | #define ECONNRESET 108 |
| 54 | #endif | 57 | #endif |
| @@ -63,6 +66,59 @@ void socket_set_verbose(int level) | |||
| 63 | verbose = level; | 66 | verbose = level; |
| 64 | } | 67 | } |
| 65 | 68 | ||
| 69 | const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size) | ||
| 70 | { | ||
| 71 | #ifdef WIN32 | ||
| 72 | WSADATA wsa_data; | ||
| 73 | if (!wsa_init) { | ||
| 74 | if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { | ||
| 75 | fprintf(stderr, "WSAStartup failed!\n"); | ||
| 76 | ExitProcess(-1); | ||
| 77 | } | ||
| 78 | wsa_init = 1; | ||
| 79 | } | ||
| 80 | DWORD addr_out_len = addr_out_size; | ||
| 81 | DWORD addrlen = 0; | ||
| 82 | |||
| 83 | if (addr->sa_family == AF_INET) { | ||
| 84 | addrlen = sizeof(struct sockaddr_in); | ||
| 85 | } | ||
| 86 | #ifdef AF_INET6 | ||
| 87 | else if (addr->sa_family == AF_INET6) { | ||
| 88 | addrlen = sizeof(struct sockaddr_in6); | ||
| 89 | } | ||
| 90 | #endif | ||
| 91 | else { | ||
| 92 | errno = EAFNOSUPPORT; | ||
| 93 | return NULL; | ||
| 94 | } | ||
| 95 | |||
| 96 | if (WSAAddressToString(addr, addrlen, NULL, addr_out, &addr_out_len) == 0) { | ||
| 97 | return addr_out; | ||
| 98 | } | ||
| 99 | #else | ||
| 100 | const void *addrdata = NULL; | ||
| 101 | |||
| 102 | if (addr->sa_family == AF_INET) { | ||
| 103 | addrdata = &((struct sockaddr_in*)addr)->sin_addr; | ||
| 104 | } | ||
| 105 | #ifdef AF_INET6 | ||
| 106 | else if (addr->sa_family == AF_INET6) { | ||
| 107 | addrdata = &((struct sockaddr_in6*)addr)->sin6_addr; | ||
| 108 | } | ||
| 109 | #endif | ||
| 110 | else { | ||
| 111 | errno = EAFNOSUPPORT; | ||
| 112 | return NULL; | ||
| 113 | } | ||
| 114 | |||
| 115 | if (inet_ntop(addr->sa_family, addrdata, addr_out, addr_out_size)) { | ||
| 116 | return addr_out; | ||
| 117 | } | ||
| 118 | #endif | ||
| 119 | return NULL; | ||
| 120 | } | ||
| 121 | |||
| 66 | #ifndef WIN32 | 122 | #ifndef WIN32 |
| 67 | int socket_create_unix(const char *filename) | 123 | int socket_create_unix(const char *filename) |
| 68 | { | 124 | { |
| @@ -161,11 +217,37 @@ int socket_connect_unix(const char *filename) | |||
| 161 | strncpy(name.sun_path, filename, sizeof(name.sun_path)); | 217 | strncpy(name.sun_path, filename, sizeof(name.sun_path)); |
| 162 | name.sun_path[sizeof(name.sun_path) - 1] = 0; | 218 | name.sun_path[sizeof(name.sun_path) - 1] = 0; |
| 163 | 219 | ||
| 164 | if (connect(sfd, (struct sockaddr*)&name, sizeof(name)) < 0) { | 220 | int flags = fcntl(sfd, F_GETFL, 0); |
| 221 | fcntl(sfd, F_SETFL, flags | O_NONBLOCK); | ||
| 222 | |||
| 223 | do { | ||
| 224 | if (connect(sfd, (struct sockaddr*)&name, sizeof(name)) != -1) { | ||
| 225 | break; | ||
| 226 | } | ||
| 227 | if (errno == EINPROGRESS) { | ||
| 228 | fd_set fds; | ||
| 229 | FD_ZERO(&fds); | ||
| 230 | FD_SET(sfd, &fds); | ||
| 231 | |||
| 232 | struct timeval timeout; | ||
| 233 | timeout.tv_sec = CONNECT_TIMEOUT / 1000; | ||
| 234 | timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000; | ||
| 235 | if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) { | ||
| 236 | int so_error; | ||
| 237 | socklen_t len = sizeof(so_error); | ||
| 238 | getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len); | ||
| 239 | if (so_error == 0) { | ||
| 240 | break; | ||
| 241 | } | ||
| 242 | } | ||
| 243 | } | ||
| 165 | socket_close(sfd); | 244 | socket_close(sfd); |
| 245 | sfd = -1; | ||
| 246 | } while (0); | ||
| 247 | |||
| 248 | if (sfd < 0) { | ||
| 166 | if (verbose >= 2) | 249 | if (verbose >= 2) |
| 167 | fprintf(stderr, "%s: connect: %s\n", __func__, | 250 | fprintf(stderr, "%s: connect: %s\n", __func__, strerror(errno)); |
| 168 | strerror(errno)); | ||
| 169 | return -1; | 251 | return -1; |
| 170 | } | 252 | } |
| 171 | 253 | ||
| @@ -228,6 +310,124 @@ int socket_create(uint16_t port) | |||
| 228 | return sfd; | 310 | return sfd; |
| 229 | } | 311 | } |
| 230 | 312 | ||
| 313 | int socket_connect_addr(struct sockaddr* addr, uint16_t port) | ||
| 314 | { | ||
| 315 | int sfd = -1; | ||
| 316 | int yes = 1; | ||
| 317 | int bufsize = 0x20000; | ||
| 318 | int addrlen = 0; | ||
| 319 | #ifdef WIN32 | ||
| 320 | u_long l_yes = 1; | ||
| 321 | WSADATA wsa_data; | ||
| 322 | if (!wsa_init) { | ||
| 323 | if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { | ||
| 324 | fprintf(stderr, "WSAStartup failed!\n"); | ||
| 325 | ExitProcess(-1); | ||
| 326 | } | ||
| 327 | wsa_init = 1; | ||
| 328 | } | ||
| 329 | #endif | ||
| 330 | |||
| 331 | if (addr->sa_family == AF_INET) { | ||
| 332 | struct sockaddr_in* addr_in = (struct sockaddr_in*)addr; | ||
| 333 | addr_in->sin_port = htons(port); | ||
| 334 | addrlen = sizeof(struct sockaddr_in); | ||
| 335 | } | ||
| 336 | #ifdef AF_INET6 | ||
| 337 | else if (addr->sa_family == AF_INET6) { | ||
| 338 | struct sockaddr_in6* addr_in = (struct sockaddr_in6*)addr; | ||
| 339 | addr_in->sin6_port = htons(port); | ||
| 340 | addrlen = sizeof(struct sockaddr_in6); | ||
| 341 | } | ||
| 342 | #endif | ||
| 343 | else { | ||
| 344 | fprintf(stderr, "ERROR: Unsupported address family"); | ||
| 345 | return -1; | ||
| 346 | } | ||
| 347 | |||
| 348 | sfd = socket(addr->sa_family, SOCK_STREAM, IPPROTO_TCP); | ||
| 349 | if (sfd == -1) { | ||
| 350 | perror("socket()"); | ||
| 351 | return -1; | ||
| 352 | } | ||
| 353 | |||
| 354 | #ifdef SO_NOSIGPIPE | ||
| 355 | if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
| 356 | perror("setsockopt()"); | ||
| 357 | socket_close(sfd); | ||
| 358 | return -1; | ||
| 359 | } | ||
| 360 | #endif | ||
| 361 | |||
| 362 | if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { | ||
| 363 | perror("setsockopt()"); | ||
| 364 | socket_close(sfd); | ||
| 365 | return -1; | ||
| 366 | } | ||
| 367 | |||
| 368 | #ifdef WIN32 | ||
| 369 | ioctlsocket(sfd, FIONBIO, &l_yes); | ||
| 370 | #else | ||
| 371 | int flags = fcntl(sfd, F_GETFL, 0); | ||
| 372 | fcntl(sfd, F_SETFL, flags | O_NONBLOCK); | ||
| 373 | #endif | ||
| 374 | |||
| 375 | do { | ||
| 376 | if (connect(sfd, addr, addrlen) != -1) { | ||
| 377 | break; | ||
| 378 | } | ||
| 379 | #ifdef WIN32 | ||
| 380 | if (WSAGetLastError() == WSAEWOULDBLOCK) | ||
| 381 | #else | ||
| 382 | if (errno == EINPROGRESS) | ||
| 383 | #endif | ||
| 384 | { | ||
| 385 | fd_set fds; | ||
| 386 | FD_ZERO(&fds); | ||
| 387 | FD_SET(sfd, &fds); | ||
| 388 | |||
| 389 | struct timeval timeout; | ||
| 390 | timeout.tv_sec = CONNECT_TIMEOUT / 1000; | ||
| 391 | timeout.tv_usec = (CONNECT_TIMEOUT - (timeout.tv_sec * 1000)) * 1000; | ||
| 392 | if (select(sfd + 1, NULL, &fds, NULL, &timeout) == 1) { | ||
| 393 | int so_error; | ||
| 394 | socklen_t len = sizeof(so_error); | ||
| 395 | getsockopt(sfd, SOL_SOCKET, SO_ERROR, (void*)&so_error, &len); | ||
| 396 | if (so_error == 0) { | ||
| 397 | errno = 0; | ||
| 398 | break; | ||
| 399 | } | ||
| 400 | errno = so_error; | ||
| 401 | } | ||
| 402 | } | ||
| 403 | socket_close(sfd); | ||
| 404 | sfd = -1; | ||
| 405 | } while (0); | ||
| 406 | |||
| 407 | if (sfd < 0) { | ||
| 408 | if (verbose >= 2) { | ||
| 409 | char addrtxt[48]; | ||
| 410 | socket_addr_to_string(addr, addrtxt, sizeof(addrtxt)); | ||
| 411 | fprintf(stderr, "%s: Could not connect to %s port %d\n", __func__, addrtxt, port); | ||
| 412 | } | ||
| 413 | return -1; | ||
| 414 | } | ||
| 415 | |||
| 416 | if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) { | ||
| 417 | perror("Could not set TCP_NODELAY on socket"); | ||
| 418 | } | ||
| 419 | |||
| 420 | if (setsockopt(sfd, SOL_SOCKET, SO_SNDBUF, (void*)&bufsize, sizeof(int)) == -1) { | ||
| 421 | perror("Could not set send buffer for socket"); | ||
| 422 | } | ||
| 423 | |||
| 424 | if (setsockopt(sfd, SOL_SOCKET, SO_RCVBUF, (void*)&bufsize, sizeof(int)) == -1) { | ||
| 425 | perror("Could not set receive buffer for socket"); | ||
| 426 | } | ||
| 427 | |||
| 428 | return sfd; | ||
| 429 | } | ||
| 430 | |||
| 231 | int socket_connect(const char *addr, uint16_t port) | 431 | int socket_connect(const char *addr, uint16_t port) |
| 232 | { | 432 | { |
| 233 | int sfd = -1; | 433 | int sfd = -1; |
| @@ -239,7 +439,6 @@ int socket_connect(const char *addr, uint16_t port) | |||
| 239 | int res; | 439 | int res; |
| 240 | #ifdef WIN32 | 440 | #ifdef WIN32 |
| 241 | u_long l_yes = 1; | 441 | u_long l_yes = 1; |
| 242 | u_long l_no = 0; | ||
| 243 | WSADATA wsa_data; | 442 | WSADATA wsa_data; |
| 244 | if (!wsa_init) { | 443 | if (!wsa_init) { |
| 245 | if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { | 444 | if (WSAStartup(MAKEWORD(2,2), &wsa_data) != ERROR_SUCCESS) { |
| @@ -277,6 +476,14 @@ int socket_connect(const char *addr, uint16_t port) | |||
| 277 | continue; | 476 | continue; |
| 278 | } | 477 | } |
| 279 | 478 | ||
| 479 | #ifdef SO_NOSIGPIPE | ||
| 480 | if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
| 481 | perror("setsockopt()"); | ||
| 482 | socket_close(sfd); | ||
| 483 | return -1; | ||
| 484 | } | ||
| 485 | #endif | ||
| 486 | |||
| 280 | if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { | 487 | if (setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int)) == -1) { |
| 281 | perror("setsockopt()"); | 488 | perror("setsockopt()"); |
| 282 | socket_close(sfd); | 489 | socket_close(sfd); |
| @@ -286,7 +493,8 @@ int socket_connect(const char *addr, uint16_t port) | |||
| 286 | #ifdef WIN32 | 493 | #ifdef WIN32 |
| 287 | ioctlsocket(sfd, FIONBIO, &l_yes); | 494 | ioctlsocket(sfd, FIONBIO, &l_yes); |
| 288 | #else | 495 | #else |
| 289 | fcntl(sfd, F_SETFL, O_NONBLOCK); | 496 | flags = fcntl(sfd, F_GETFL, 0); |
| 497 | fcntl(sfd, F_SETFL, flags | O_NONBLOCK); | ||
| 290 | #endif | 498 | #endif |
| 291 | 499 | ||
| 292 | if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) { | 500 | if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) { |
| @@ -325,21 +533,6 @@ int socket_connect(const char *addr, uint16_t port) | |||
| 325 | return -1; | 533 | return -1; |
| 326 | } | 534 | } |
| 327 | 535 | ||
| 328 | #ifdef WIN32 | ||
| 329 | ioctlsocket(sfd, FIONBIO, &l_no); | ||
| 330 | #else | ||
| 331 | flags = fcntl(sfd, F_GETFL, 0); | ||
| 332 | fcntl(sfd, F_SETFL, flags & (~O_NONBLOCK)); | ||
| 333 | #endif | ||
| 334 | |||
| 335 | #ifdef SO_NOSIGPIPE | ||
| 336 | if (setsockopt(sfd, SOL_SOCKET, SO_NOSIGPIPE, (void*)&yes, sizeof(int)) == -1) { | ||
| 337 | perror("setsockopt()"); | ||
| 338 | socket_close(sfd); | ||
| 339 | return -1; | ||
| 340 | } | ||
| 341 | #endif | ||
| 342 | |||
| 343 | if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) { | 536 | if (setsockopt(sfd, IPPROTO_TCP, TCP_NODELAY, (void*)&yes, sizeof(int)) == -1) { |
| 344 | perror("Could not set TCP_NODELAY on socket"); | 537 | perror("Could not set TCP_NODELAY on socket"); |
| 345 | } | 538 | } |
diff --git a/common/socket.h b/common/socket.h index e31de6b..38eeddf 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-2020 Nikias Bassen <nikias@gmx.li> | ||
| 4 | * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org> | 5 | * Copyright (C) 2012 Martin Szulecki <m.szulecki@libimobiledevice.org> |
| 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 |
| @@ -46,6 +46,7 @@ int socket_create_unix(const char *filename); | |||
| 46 | int socket_connect_unix(const char *filename); | 46 | int socket_connect_unix(const char *filename); |
| 47 | #endif | 47 | #endif |
| 48 | int socket_create(uint16_t port); | 48 | int socket_create(uint16_t port); |
| 49 | int socket_connect_addr(struct sockaddr *addr, uint16_t port); | ||
| 49 | int socket_connect(const char *addr, uint16_t port); | 50 | int socket_connect(const char *addr, uint16_t port); |
| 50 | int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout); | 51 | int socket_check_fd(int fd, fd_mode fdm, unsigned int timeout); |
| 51 | int socket_accept(int fd, uint16_t port); | 52 | int socket_accept(int fd, uint16_t port); |
| @@ -62,4 +63,6 @@ int socket_send(int fd, void *data, size_t size); | |||
| 62 | 63 | ||
| 63 | void socket_set_verbose(int level); | 64 | void socket_set_verbose(int level); |
| 64 | 65 | ||
| 66 | const char *socket_addr_to_string(struct sockaddr *addr, char *addr_out, size_t addr_out_size); | ||
| 67 | |||
| 65 | #endif /* SOCKET_SOCKET_H */ | 68 | #endif /* SOCKET_SOCKET_H */ |
