diff options
author | Maxim Biro <nurupo.contributions@gmail.com> | 2018-04-07 22:09:42 -0400 |
---|---|---|
committer | Maxim Biro <nurupo.contributions@gmail.com> | 2018-04-17 19:07:50 -0400 |
commit | 7d399cedcfd20f0d91a8caf386ae3c63f4dcf285 (patch) | |
tree | a0f4134961bb163151532afe3fb5e98927965738 | |
parent | 2824daf74a6d2bd60ebaf387a30f1b7719b6b67c (diff) |
Improve network error reporting on Windows
Windows doesn't report network errors though errno, it has its own facilities.
-rw-r--r-- | auto_tests/network_test.c | 17 | ||||
-rw-r--r-- | testing/av_test.c | 1 | ||||
-rw-r--r-- | toxav/bwcontroller.c | 6 | ||||
-rw-r--r-- | toxav/rtp.c | 18 | ||||
-rw-r--r-- | toxcore/network.c | 73 | ||||
-rw-r--r-- | toxcore/network.h | 28 |
6 files changed, 119 insertions, 24 deletions
diff --git a/auto_tests/network_test.c b/auto_tests/network_test.c index 15757d4d..6f535ee1 100644 --- a/auto_tests/network_test.c +++ b/auto_tests/network_test.c | |||
@@ -38,7 +38,10 @@ START_TEST(test_addr_resolv_localhost) | |||
38 | 38 | ||
39 | int res = addr_resolve(localhost, &ip, nullptr); | 39 | int res = addr_resolve(localhost, &ip, nullptr); |
40 | 40 | ||
41 | ck_assert_msg(res > 0, "Resolver failed: %u, %s", errno, strerror(errno)); | 41 | int error = net_error(); |
42 | const char *strerror = net_new_strerror(error); | ||
43 | ck_assert_msg(res > 0, "Resolver failed: %d, %s", error, strerror); | ||
44 | net_kill_strerror(strerror); | ||
42 | 45 | ||
43 | char ip_str[IP_NTOA_LEN]; | 46 | char ip_str[IP_NTOA_LEN]; |
44 | ck_assert_msg(ip.family == TOX_AF_INET, "Expected family TOX_AF_INET, got %u.", ip.family); | 47 | ck_assert_msg(ip.family == TOX_AF_INET, "Expected family TOX_AF_INET, got %u.", ip.family); |
@@ -54,7 +57,10 @@ START_TEST(test_addr_resolv_localhost) | |||
54 | localhost_split = 1; | 57 | localhost_split = 1; |
55 | } | 58 | } |
56 | 59 | ||
57 | ck_assert_msg(res > 0, "Resolver failed: %u, %s", errno, strerror(errno)); | 60 | error = net_error(); |
61 | strerror = net_new_strerror(error); | ||
62 | ck_assert_msg(res > 0, "Resolver failed: %d, %s", error, strerror); | ||
63 | net_kill_strerror(strerror); | ||
58 | 64 | ||
59 | ck_assert_msg(ip.family == TOX_AF_INET6, "Expected family TOX_AF_INET6 (%u), got %u.", TOX_AF_INET6, ip.family); | 65 | ck_assert_msg(ip.family == TOX_AF_INET6, "Expected family TOX_AF_INET6 (%u), got %u.", TOX_AF_INET6, ip.family); |
60 | IP6 ip6_loopback = get_ip6_loopback(); | 66 | IP6 ip6_loopback = get_ip6_loopback(); |
@@ -71,7 +77,10 @@ START_TEST(test_addr_resolv_localhost) | |||
71 | IP extra; | 77 | IP extra; |
72 | ip_reset(&extra); | 78 | ip_reset(&extra); |
73 | res = addr_resolve(localhost, &ip, &extra); | 79 | res = addr_resolve(localhost, &ip, &extra); |
74 | ck_assert_msg(res > 0, "Resolver failed: %u, %s", errno, strerror(errno)); | 80 | error = net_error(); |
81 | strerror = net_new_strerror(error); | ||
82 | ck_assert_msg(res > 0, "Resolver failed: %d, %s", error, strerror); | ||
83 | net_kill_strerror(strerror); | ||
75 | 84 | ||
76 | #if USE_IPV6 | 85 | #if USE_IPV6 |
77 | ck_assert_msg(ip.family == TOX_AF_INET6, "Expected family TOX_AF_INET6 (%u), got %u.", TOX_AF_INET6, ip.family); | 86 | ck_assert_msg(ip.family == TOX_AF_INET6, "Expected family TOX_AF_INET6 (%u), got %u.", TOX_AF_INET6, ip.family); |
@@ -157,6 +166,8 @@ static Suite *network_suite(void) | |||
157 | { | 166 | { |
158 | Suite *s = suite_create("Network"); | 167 | Suite *s = suite_create("Network"); |
159 | 168 | ||
169 | networking_at_startup(); | ||
170 | |||
160 | DEFTESTCASE(addr_resolv_localhost); | 171 | DEFTESTCASE(addr_resolv_localhost); |
161 | DEFTESTCASE(ip_equal); | 172 | DEFTESTCASE(ip_equal); |
162 | 173 | ||
diff --git a/testing/av_test.c b/testing/av_test.c index 0d61edec..5cc3b5dd 100644 --- a/testing/av_test.c +++ b/testing/av_test.c | |||
@@ -64,7 +64,6 @@ extern "C" { | |||
64 | #include <opencv/highgui.h> | 64 | #include <opencv/highgui.h> |
65 | 65 | ||
66 | #include <assert.h> | 66 | #include <assert.h> |
67 | #include <errno.h> | ||
68 | #include <sched.h> | 67 | #include <sched.h> |
69 | #include <stdio.h> | 68 | #include <stdio.h> |
70 | #include <stdlib.h> | 69 | #include <stdlib.h> |
diff --git a/toxav/bwcontroller.c b/toxav/bwcontroller.c index 5c6782ba..d786080e 100644 --- a/toxav/bwcontroller.c +++ b/toxav/bwcontroller.c | |||
@@ -145,8 +145,10 @@ void send_update(BWController *bwc) | |||
145 | msg->recv = net_htonl(bwc->cycle.recv); | 145 | msg->recv = net_htonl(bwc->cycle.recv); |
146 | 146 | ||
147 | if (-1 == m_send_custom_lossy_packet(bwc->m, bwc->friend_number, bwc_packet, sizeof(bwc_packet))) { | 147 | if (-1 == m_send_custom_lossy_packet(bwc->m, bwc->friend_number, bwc_packet, sizeof(bwc_packet))) { |
148 | LOGGER_WARNING(bwc->m->log, "BWC send failed (len: %u)! std error: %s", | 148 | const char *netstrerror = net_new_strerror(net_error()); |
149 | (unsigned)sizeof(bwc_packet), strerror(errno)); | 149 | LOGGER_WARNING(bwc->m->log, "BWC send failed (len: %u)! std error: %s, net error %s", |
150 | (unsigned)sizeof(bwc_packet), strerror(errno), netstrerror); | ||
151 | net_kill_strerror(netstrerror); | ||
150 | } | 152 | } |
151 | } | 153 | } |
152 | 154 | ||
diff --git a/toxav/rtp.c b/toxav/rtp.c index c760d333..a65dbafe 100644 --- a/toxav/rtp.c +++ b/toxav/rtp.c | |||
@@ -802,8 +802,10 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length, | |||
802 | memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length); | 802 | memcpy(rdata + 1 + RTP_HEADER_SIZE, data, length); |
803 | 803 | ||
804 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, SIZEOF_VLA(rdata))) { | 804 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, SIZEOF_VLA(rdata))) { |
805 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %u)! std error: %s", | 805 | const char *netstrerror = net_new_strerror(net_error()); |
806 | (unsigned)SIZEOF_VLA(rdata), strerror(errno)); | 806 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %u)! std error: %s, net error: %s", |
807 | (unsigned)SIZEOF_VLA(rdata), strerror(errno), netstrerror); | ||
808 | net_kill_strerror(netstrerror); | ||
807 | } | 809 | } |
808 | } else { | 810 | } else { |
809 | /** | 811 | /** |
@@ -819,8 +821,10 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length, | |||
819 | 821 | ||
820 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, | 822 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, |
821 | rdata, piece + RTP_HEADER_SIZE + 1)) { | 823 | rdata, piece + RTP_HEADER_SIZE + 1)) { |
822 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", | 824 | const char *netstrerror = net_new_strerror(net_error()); |
823 | piece + RTP_HEADER_SIZE + 1, strerror(errno)); | 825 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s, net error: %s", |
826 | piece + RTP_HEADER_SIZE + 1, strerror(errno), netstrerror); | ||
827 | net_kill_strerror(netstrerror); | ||
824 | } | 828 | } |
825 | 829 | ||
826 | sent += piece; | 830 | sent += piece; |
@@ -837,8 +841,10 @@ int rtp_send_data(RTPSession *session, const uint8_t *data, uint32_t length, | |||
837 | 841 | ||
838 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, | 842 | if (-1 == m_send_custom_lossy_packet(session->m, session->friend_number, rdata, |
839 | piece + RTP_HEADER_SIZE + 1)) { | 843 | piece + RTP_HEADER_SIZE + 1)) { |
840 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s", | 844 | const char *netstrerror = net_new_strerror(net_error()); |
841 | piece + RTP_HEADER_SIZE + 1, strerror(errno)); | 845 | LOGGER_WARNING(session->m->log, "RTP send failed (len: %d)! std error: %s, net error: %s", |
846 | piece + RTP_HEADER_SIZE + 1, strerror(errno), netstrerror); | ||
847 | net_kill_strerror(netstrerror); | ||
842 | } | 848 | } |
843 | } | 849 | } |
844 | } | 850 | } |
diff --git a/toxcore/network.c b/toxcore/network.c index d88ba816..984071d4 100644 --- a/toxcore/network.c +++ b/toxcore/network.c | |||
@@ -63,15 +63,15 @@ | |||
63 | #include <sys/time.h> | 63 | #include <sys/time.h> |
64 | #include <sys/types.h> | 64 | #include <sys/types.h> |
65 | 65 | ||
66 | #define TOX_EWOULDBLOCK EWOULDBLOCK | ||
67 | |||
66 | #else | 68 | #else |
67 | 69 | ||
68 | #ifndef IPV6_V6ONLY | 70 | #ifndef IPV6_V6ONLY |
69 | #define IPV6_V6ONLY 27 | 71 | #define IPV6_V6ONLY 27 |
70 | #endif | 72 | #endif |
71 | 73 | ||
72 | #ifndef EWOULDBLOCK | 74 | #define TOX_EWOULDBLOCK WSAEWOULDBLOCK |
73 | #define EWOULDBLOCK WSAEWOULDBLOCK | ||
74 | #endif | ||
75 | 75 | ||
76 | static const char *inet_ntop(Family family, const void *addr, char *buf, size_t bufsize) | 76 | static const char *inet_ntop(Family family, const void *addr, char *buf, size_t bufsize) |
77 | { | 77 | { |
@@ -376,10 +376,13 @@ static void loglogdata(Logger *log, const char *message, const uint8_t *buffer, | |||
376 | char ip_str[IP_NTOA_LEN]; | 376 | char ip_str[IP_NTOA_LEN]; |
377 | 377 | ||
378 | if (res < 0) { /* Windows doesn't necessarily know %zu */ | 378 | if (res < 0) { /* Windows doesn't necessarily know %zu */ |
379 | int error = net_error(); | ||
380 | const char *strerror = net_new_strerror(error); | ||
379 | LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x", | 381 | LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x", |
380 | buffer[0], message, (buflen < 999 ? buflen : 999), 'E', | 382 | buffer[0], message, (buflen < 999 ? buflen : 999), 'E', |
381 | ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), errno, | 383 | ip_ntoa(&ip_port.ip, ip_str, sizeof(ip_str)), net_ntohs(ip_port.port), error, |
382 | strerror(errno), data_0(buflen, buffer), data_1(buflen, buffer)); | 384 | strerror, data_0(buflen, buffer), data_1(buflen, buffer)); |
385 | net_kill_strerror(strerror); | ||
383 | } else if ((res > 0) && ((size_t)res <= buflen)) { | 386 | } else if ((res > 0) && ((size_t)res <= buflen)) { |
384 | LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x", | 387 | LOGGER_TRACE(log, "[%2u] %s %3u%c %s:%u (%u: %s) | %04x%04x", |
385 | buffer[0], message, (res < 999 ? res : 999), ((size_t)res < buflen ? '<' : '='), | 388 | buffer[0], message, (res < 999 ? res : 999), ((size_t)res < buflen ? '<' : '='), |
@@ -498,9 +501,12 @@ static int receivepacket(Logger *log, Socket sock, IP_Port *ip_port, uint8_t *da | |||
498 | int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); | 501 | int fail_or_len = recvfrom(sock, (char *) data, MAX_UDP_PACKET_SIZE, 0, (struct sockaddr *)&addr, &addrlen); |
499 | 502 | ||
500 | if (fail_or_len < 0) { | 503 | if (fail_or_len < 0) { |
504 | int error = net_error(); | ||
501 | 505 | ||
502 | if (fail_or_len < 0 && errno != EWOULDBLOCK) { | 506 | if (fail_or_len < 0 && error != TOX_EWOULDBLOCK) { |
503 | LOGGER_ERROR(log, "Unexpected error reading from socket: %u, %s", errno, strerror(errno)); | 507 | const char *strerror = net_new_strerror(error); |
508 | LOGGER_ERROR(log, "Unexpected error reading from socket: %u, %s", error, strerror); | ||
509 | net_kill_strerror(strerror); | ||
504 | } | 510 | } |
505 | 511 | ||
506 | return -1; /* Nothing received. */ | 512 | return -1; /* Nothing received. */ |
@@ -681,7 +687,10 @@ Networking_Core *new_networking_ex(Logger *log, IP ip, uint16_t port_from, uint1 | |||
681 | 687 | ||
682 | /* Check for socket error. */ | 688 | /* Check for socket error. */ |
683 | if (!sock_valid(temp->sock)) { | 689 | if (!sock_valid(temp->sock)) { |
684 | LOGGER_ERROR(log, "Failed to get a socket?! %u, %s", errno, strerror(errno)); | 690 | int neterror = net_error(); |
691 | const char *strerror = net_new_strerror(neterror); | ||
692 | LOGGER_ERROR(log, "Failed to get a socket?! %d, %s", neterror, strerror); | ||
693 | net_kill_strerror(strerror); | ||
685 | free(temp); | 694 | free(temp); |
686 | 695 | ||
687 | if (error) { | 696 | if (error) { |
@@ -769,8 +778,11 @@ Networking_Core *new_networking_ex(Logger *log, IP ip, uint16_t port_from, uint1 | |||
769 | mreq.ipv6mr_interface = 0; | 778 | mreq.ipv6mr_interface = 0; |
770 | int res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq)); | 779 | int res = setsockopt(temp->sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP, (const char *)&mreq, sizeof(mreq)); |
771 | 780 | ||
772 | LOGGER_DEBUG(log, res < 0 ? "Failed to activate local multicast membership. (%u, %s)" : | 781 | int neterror = net_error(); |
773 | "Local multicast group FF02::1 joined successfully", errno, strerror(errno)); | 782 | const char *strerror = net_new_strerror(neterror); |
783 | LOGGER_DEBUG(log, res < 0 ? "Failed to activate local multicast membership. (%d, %s)" : | ||
784 | "Local multicast group FF02::1 joined successfully", neterror, strerror); | ||
785 | net_kill_strerror(strerror); | ||
774 | } | 786 | } |
775 | 787 | ||
776 | /* a hanging program or a different user might block the standard port; | 788 | /* a hanging program or a different user might block the standard port; |
@@ -827,9 +839,11 @@ Networking_Core *new_networking_ex(Logger *log, IP ip, uint16_t port_from, uint1 | |||
827 | } | 839 | } |
828 | 840 | ||
829 | char ip_str[IP_NTOA_LEN]; | 841 | char ip_str[IP_NTOA_LEN]; |
830 | LOGGER_ERROR(log, "Failed to bind socket: %u, %s IP: %s port_from: %u port_to: %u", errno, strerror(errno), | 842 | int neterror = net_error(); |
843 | const char *strerror = net_new_strerror(neterror); | ||
844 | LOGGER_ERROR(log, "Failed to bind socket: %d, %s IP: %s port_from: %u port_to: %u", neterror, strerror, | ||
831 | ip_ntoa(&ip, ip_str, sizeof(ip_str)), port_from, port_to); | 845 | ip_ntoa(&ip, ip_str, sizeof(ip_str)), port_from, port_to); |
832 | 846 | net_kill_strerror(strerror); | |
833 | kill_networking(temp); | 847 | kill_networking(temp); |
834 | 848 | ||
835 | if (error) { | 849 | if (error) { |
@@ -1520,3 +1534,38 @@ size_t net_unpack_u64(const uint8_t *bytes, uint64_t *v) | |||
1520 | *v = ((uint64_t)hi << 32) | lo; | 1534 | *v = ((uint64_t)hi << 32) | lo; |
1521 | return p - bytes; | 1535 | return p - bytes; |
1522 | } | 1536 | } |
1537 | |||
1538 | int net_error(void) | ||
1539 | { | ||
1540 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) | ||
1541 | return WSAGetLastError(); | ||
1542 | #else | ||
1543 | return errno; | ||
1544 | #endif | ||
1545 | } | ||
1546 | |||
1547 | const char *net_new_strerror(int error) | ||
1548 | { | ||
1549 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) | ||
1550 | char *str = nullptr; | ||
1551 | // Windows API is weird. The 5th function arg is of char* type, but we | ||
1552 | // have to pass char** so that it could assign new memory block to our | ||
1553 | // pointer, so we have to cast our char** to char* for the compilation | ||
1554 | // not to fail (otherwise it would fail to find a variant of this function | ||
1555 | // accepting char** as the 5th arg) and Windows inside casts it back | ||
1556 | // to char** to do the assignment. So no, this cast you see here, although | ||
1557 | // it looks weird, is not a mistake. | ||
1558 | FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, nullptr, | ||
1559 | error, 0, (char *)&str, 0, nullptr); | ||
1560 | return str; | ||
1561 | #else | ||
1562 | return strerror(error); | ||
1563 | #endif | ||
1564 | } | ||
1565 | |||
1566 | void net_kill_strerror(const char *strerror) | ||
1567 | { | ||
1568 | #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) | ||
1569 | LocalFree((char *)strerror); | ||
1570 | #endif | ||
1571 | } | ||
diff --git a/toxcore/network.h b/toxcore/network.h index 405721b2..10ddef02 100644 --- a/toxcore/network.h +++ b/toxcore/network.h | |||
@@ -404,6 +404,34 @@ void net_freeipport(IP_Port *ip_ports); | |||
404 | */ | 404 | */ |
405 | int bind_to_port(Socket sock, int family, uint16_t port); | 405 | int bind_to_port(Socket sock, int family, uint16_t port); |
406 | 406 | ||
407 | /* Get the last networking error code. | ||
408 | * | ||
409 | * Similar to Unix's errno, but cross-platform, as not all platforms use errno | ||
410 | * to indicate networking errors. | ||
411 | * | ||
412 | * Note that different platforms may return different codes for the same error, | ||
413 | * so you likely shouldn't be checking the value returned by this function | ||
414 | * unless you know what you are doing, you likely just want to use it in | ||
415 | * combination with net_new_strerror() to print the error. | ||
416 | * | ||
417 | * return platform-dependent network error code, if any. | ||
418 | */ | ||
419 | int net_error(void); | ||
420 | |||
421 | /* Get a text explanation for the error code from net_error(). | ||
422 | * | ||
423 | * return NULL on failure. | ||
424 | * return pointer to a NULL-terminated string describing the error code on | ||
425 | * success. The returned string must be freed using net_kill_strerror(). | ||
426 | */ | ||
427 | const char *net_new_strerror(int error); | ||
428 | |||
429 | /* Frees the string returned by net_new_strerror(). | ||
430 | * It's valid to pass NULL as the argument, the function does nothing in this | ||
431 | * case. | ||
432 | */ | ||
433 | void net_kill_strerror(const char *strerror); | ||
434 | |||
407 | /* Initialize networking. | 435 | /* Initialize networking. |
408 | * bind to ip and port. | 436 | * bind to ip and port. |
409 | * ip must be in network order EX: 127.0.0.1 = (7F000001). | 437 | * ip must be in network order EX: 127.0.0.1 = (7F000001). |