From f4dce49c5bf16ac6429dcf02536d0759f6c4dadb Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Sun, 28 Aug 2016 21:37:17 -0300 Subject: [PATCH 01/12] Add bidirectional udp test cases --- test/test.cpp | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/test/test.cpp b/test/test.cpp index 34fc495..ecf74ea 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -4,7 +4,7 @@ #define BOOST_AUTO_TEST_MAIN #include #include - +#include #include #include #include @@ -310,3 +310,76 @@ BOOST_AUTO_TEST_CASE(test_hasPacket_returns_false_on_internal_buffer_with_garbag BOOST_REQUIRE_EQUAL(4, test.readPacket(buffer, 100, 10, 1)); BOOST_REQUIRE(!test.hasPacket()); } + +BOOST_AUTO_TEST_CASE(test_open_bidirectional_udp) +{ + DriverTest test; + + BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:3135:4145")); + test.close(); +} + +void recv_test() +{ + DriverTest test; + uint8_t msg[4] = { 0, 'a', 'b', 0 }; + + test.openURI("udp://127.0.0.1:4145"); + + test.writePacket(msg, 4); + test.close(); +} + +BOOST_AUTO_TEST_CASE(test_recv_from_bidirectional_udp) +{ + DriverTest test; + uint8_t buffer[100]; + boost::thread send_thread; + + BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:3135:4145")); + + send_thread = boost::thread(recv_test); + + BOOST_REQUIRE_NO_THROW(test.readPacket(buffer, 100, 200)); + + test.close(); +} + +void send_test(bool *got) +{ + DriverTest test; + uint8_t buffer[100]; + + test.openURI("udpserver://5155"); + + try { + test.readPacket(buffer, 100, 200); + } + catch (...) { + *got = false; + } + + *got = true; + test.close(); +} + +BOOST_AUTO_TEST_CASE(test_send_from_bidirectional_udp) +{ + DriverTest test; + uint8_t msg[4] = { 0, 'a', 'b', 0 }; + bool got = false; + + boost::thread recv_thread; + + BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:5155:3135")); + + recv_thread = boost::thread(send_test, &got); + + BOOST_REQUIRE_NO_THROW(test.writePacket(msg, 4)); + + recv_thread.join(); + BOOST_REQUIRE(got == true); + + test.close(); +} + From b9c9549ee2ca9440ab0a302d8eed10a5392d2ba7 Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Sun, 28 Aug 2016 23:11:33 -0300 Subject: [PATCH 02/12] Implement bidirectional udp uri parser --- src/Driver.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Driver.cpp b/src/Driver.cpp index fca2a9f..da5059e 100644 --- a/src/Driver.cpp +++ b/src/Driver.cpp @@ -194,6 +194,18 @@ void Driver::openURI(std::string const& uri) { // UDP udp://hostname:remoteport if (marker == string::npos) throw std::runtime_error("missing port specification in udp:// URI"); + + string::size_type second_marker = device.find_last_of(":"); + int extended_info = 0; + + if (second_marker != string::npos) + { + extended_info = boost::lexical_cast(device.substr(second_marker + 1)); + device = device.substr(0, second_marker); + + return openUDP(device, extended_info); + } + return openUDP(device, additional_info); } else if (mode_idx == 3) From a25cbff198e858b7d840fa13e196b88601d6a2f5 Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Mon, 29 Aug 2016 08:55:49 -0300 Subject: [PATCH 03/12] Implement bidirectional udp handler --- src/Driver.cpp | 85 +++++++++++++++++++++++++++++++++++++++++++++++- src/Driver.hpp | 3 ++ src/IOStream.cpp | 19 +++++++++-- src/IOStream.hpp | 2 ++ test/test.cpp | 10 ++++-- 5 files changed, 113 insertions(+), 6 deletions(-) diff --git a/src/Driver.cpp b/src/Driver.cpp index da5059e..5b0239c 100644 --- a/src/Driver.cpp +++ b/src/Driver.cpp @@ -203,7 +203,7 @@ void Driver::openURI(std::string const& uri) extended_info = boost::lexical_cast(device.substr(second_marker + 1)); device = device.substr(0, second_marker); - return openUDP(device, extended_info); + return openUDPBidirectional(device, extended_info, additional_info); } return openUDP(device, additional_info); @@ -259,6 +259,73 @@ void Driver::openIPServer(int port, addrinfo const& hints) setMainStream(new UDPServerStream(sfd,true)); } +void find_addr(const char *hostname, const char *port, addrinfo const& hints, struct sockaddr *addr, size_t *addr_len) +{ + struct addrinfo *result; + int ret = getaddrinfo(hostname, port, &hints, &result); + if (ret != 0) + throw UnixError("cannot resolve client port " + string(port)); + + int sfd = -1; + struct addrinfo *rp; + for (rp = result; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (sfd == -1) + continue; + + if (connect(sfd, rp->ai_addr, rp->ai_addrlen) == 0) + break; /* Success */ + + ::close(sfd); + } + + if (rp == NULL) + { + freeaddrinfo(result); + throw UnixError("cannot open client socket on port " + string(port)); + } + + memcpy(addr, rp->ai_addr, rp->ai_addrlen); + *addr_len = rp->ai_addrlen; + + freeaddrinfo(result); + close(sfd); +} + +void Driver::openIPBidirectional(std::string const& hostname, int out_port, addrinfo const& out_hints, int in_port, addrinfo const& in_hints) +{ + struct addrinfo *result; + string in_port_as_string = boost::lexical_cast(in_port); + int ret = getaddrinfo(NULL, in_port_as_string.c_str(), &in_hints, &result); + if (ret != 0) + throw UnixError("cannot resolve server port " + in_port_as_string); + + int sfd = -1; + struct addrinfo *rp; + for (rp = result; rp != NULL; rp = rp->ai_next) { + sfd = socket(rp->ai_family, rp->ai_socktype, + rp->ai_protocol); + if (sfd == -1) + continue; + + if (::bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) + break; /* Success */ + + ::close(sfd); + } + freeaddrinfo(result); + + if (rp == NULL) + throw UnixError("cannot open server socket on port " + in_port_as_string); + + struct sockaddr peer; + size_t peer_len; + + find_addr(hostname.c_str(), boost::lexical_cast(out_port).c_str(), out_hints, &peer, &peer_len); + setMainStream(new UDPServerStream(sfd, true, &peer, &peer_len)); +} + void Driver::openIPClient(std::string const& hostname, int port, addrinfo const& hints) { struct addrinfo *result; @@ -328,6 +395,22 @@ void Driver::openUDP(std::string const& hostname, int port) } } +void Driver::openUDPBidirectional(std::string const& hostname, int out_port, int in_port) +{ + struct addrinfo in_hints; + memset(&in_hints, 0, sizeof(struct addrinfo)); + in_hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + in_hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + in_hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ + + struct addrinfo out_hints; + memset(&out_hints, 0, sizeof(struct addrinfo)); + out_hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ + out_hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ + + openIPBidirectional(hostname, out_port, out_hints, in_port, in_hints); +} + int Driver::openSerialIO(std::string const& port, int baud_rate) { int fd = ::open(port.c_str(), O_RDWR | O_NOCTTY | O_SYNC | O_NONBLOCK ); diff --git a/src/Driver.hpp b/src/Driver.hpp index cc168a5..db743a2 100644 --- a/src/Driver.hpp +++ b/src/Driver.hpp @@ -157,6 +157,7 @@ class Driver void openIPServer(int port, addrinfo const& hints); void openIPClient(std::string const& hostname, int port, addrinfo const& hints); + void openIPBidirectional(std::string const& hostname, int out_port, addrinfo const& out_hints, int in_port, addrinfo const& in_hints); public: /** Creates an Driver class for a packet-based protocol @@ -253,6 +254,8 @@ class Driver * The read_port port can be 0 if the local port does not need to be fixed. */ void openUDP(std::string const& hostname, int remote_port); + void openUDPBidirectional(std::string const& hostname, int out_port, int in_port); + /** Opens a serial port and sets it up to a sane configuration. Use * then setSerialBaudrate() to change the actual baudrate of the diff --git a/src/IOStream.cpp b/src/IOStream.cpp index 397366f..8539e0f 100644 --- a/src/IOStream.cpp +++ b/src/IOStream.cpp @@ -99,11 +99,26 @@ UDPServerStream::UDPServerStream(int fd, bool auto_close) : FDStream(fd,auto_close) { m_s_len = sizeof(m_si_other); + m_si_other_dynamic = true; } - + +UDPServerStream::UDPServerStream(int fd, bool auto_close, struct sockaddr *si_other, size_t *s_len) + : FDStream(fd,auto_close) +{ + m_si_other = *si_other; + m_s_len = *s_len; + m_si_other_dynamic = false; +} + size_t UDPServerStream::read(uint8_t* buffer, size_t buffer_size) { - ssize_t ret = recvfrom(m_fd, buffer, buffer_size, 0, &m_si_other, &m_s_len); + ssize_t ret; + + if (m_si_other_dynamic) + ret = recvfrom(m_fd, buffer, buffer_size, 0, &m_si_other, &m_s_len); + else + ret = recvfrom(m_fd, buffer, buffer_size, 0, NULL, NULL); + if (ret >= 0){ return ret; } diff --git a/src/IOStream.hpp b/src/IOStream.hpp index 18a60df..5758597 100644 --- a/src/IOStream.hpp +++ b/src/IOStream.hpp @@ -65,10 +65,12 @@ namespace iodrivers_base { public: UDPServerStream(int fd, bool auto_close); + UDPServerStream(int fd, bool auto_close, struct sockaddr *si_other, size_t *s_len); virtual size_t read(uint8_t* buffer, size_t buffer_size); virtual size_t write(uint8_t const* buffer, size_t buffer_size); protected: struct sockaddr m_si_other; + bool m_si_other_dynamic; unsigned int m_s_len; }; } diff --git a/test/test.cpp b/test/test.cpp index ecf74ea..e31464d 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -334,13 +334,15 @@ BOOST_AUTO_TEST_CASE(test_recv_from_bidirectional_udp) { DriverTest test; uint8_t buffer[100]; + int count; boost::thread send_thread; BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:3135:4145")); send_thread = boost::thread(recv_test); - BOOST_REQUIRE_NO_THROW(test.readPacket(buffer, 100, 200)); + BOOST_REQUIRE_NO_THROW((count = test.readPacket(buffer, 100, 200))); + BOOST_REQUIRE_EQUAL(count, 4); test.close(); } @@ -349,17 +351,19 @@ void send_test(bool *got) { DriverTest test; uint8_t buffer[100]; + int count = 0; test.openURI("udpserver://5155"); try { - test.readPacket(buffer, 100, 200); + count = test.readPacket(buffer, 100, 200); } catch (...) { *got = false; } - *got = true; + *got = (count == 4); + cout << "Got: " << count << endl; test.close(); } From 9d5b26b33b0c585ffc1026e0c49b3669519fd917 Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Mon, 29 Aug 2016 11:52:38 -0300 Subject: [PATCH 04/12] Fix tests --- test/test.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index e31464d..ab8a6f1 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -315,7 +315,7 @@ BOOST_AUTO_TEST_CASE(test_open_bidirectional_udp) { DriverTest test; - BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:3135:4145")); + BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:1111:2222")); test.close(); } @@ -324,7 +324,7 @@ void recv_test() DriverTest test; uint8_t msg[4] = { 0, 'a', 'b', 0 }; - test.openURI("udp://127.0.0.1:4145"); + test.openURI("udp://127.0.0.1:2125"); test.writePacket(msg, 4); test.close(); @@ -335,15 +335,18 @@ BOOST_AUTO_TEST_CASE(test_recv_from_bidirectional_udp) DriverTest test; uint8_t buffer[100]; int count; + uint8_t msg[4] = { 0, 'a', 'b', 0 }; boost::thread send_thread; - BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:3135:4145")); + BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:3135:2125")); send_thread = boost::thread(recv_test); BOOST_REQUIRE_NO_THROW((count = test.readPacket(buffer, 100, 200))); BOOST_REQUIRE_EQUAL(count, 4); + BOOST_REQUIRE_EQUAL(memcmp(buffer, msg, count), 0); + send_thread.join(); test.close(); } @@ -351,19 +354,21 @@ void send_test(bool *got) { DriverTest test; uint8_t buffer[100]; + uint8_t msg[4] = { 0, 'a', 'b', 0 }; int count = 0; - test.openURI("udpserver://5155"); + test.openURI("udpserver://4145"); try { - count = test.readPacket(buffer, 100, 200); + count = test.readPacket(buffer, 100, 500); } - catch (...) { + catch (std::runtime_error e) { *got = false; + test.close(); + return; } - *got = (count == 4); - cout << "Got: " << count << endl; + *got = ((count == 4) && (memcmp(buffer, msg, count) == 0)); test.close(); } @@ -373,11 +378,10 @@ BOOST_AUTO_TEST_CASE(test_send_from_bidirectional_udp) uint8_t msg[4] = { 0, 'a', 'b', 0 }; bool got = false; - boost::thread recv_thread; - - BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:5155:3135")); + boost::thread recv_thread(send_test, &got);; - recv_thread = boost::thread(send_test, &got); + BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:4145:5155")); + boost::this_thread::sleep(boost::posix_time::milliseconds(100)); BOOST_REQUIRE_NO_THROW(test.writePacket(msg, 4)); From 4abf70dad11b9fcbd2a66fff13eecb6e43de1b1e Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Mon, 29 Aug 2016 15:22:48 -0300 Subject: [PATCH 05/12] Update documentation --- src/Driver.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Driver.hpp b/src/Driver.hpp index db743a2..6965395 100644 --- a/src/Driver.hpp +++ b/src/Driver.hpp @@ -228,7 +228,7 @@ class Driver * * * serial://path/to/device:baudrate * * tcp://hostname:port - * * udp://hostname:port + * * udp://hostname:remote_port[:local_port] * * udpserver://port */ virtual void openURI(std::string const& uri); From 7bb0275015c5429a5173040af6542f5cba345178 Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Wed, 31 Aug 2016 09:51:10 -0300 Subject: [PATCH 06/12] Add documentation to openUDPBidirectional() --- src/Driver.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Driver.hpp b/src/Driver.hpp index 6965395..b6b2533 100644 --- a/src/Driver.hpp +++ b/src/Driver.hpp @@ -254,6 +254,14 @@ class Driver * The read_port port can be 0 if the local port does not need to be fixed. */ void openUDP(std::string const& hostname, int remote_port); + + /** + * Opens a UDP connection + * + * All parameters are required. The driver will be available to + * write data to a specified host and output port. Data will be read + * from the input port. + */ void openUDPBidirectional(std::string const& hostname, int out_port, int in_port); From dc44533491e802cbd35997b5ee41d2770d75ba69 Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Tue, 6 Sep 2016 10:05:34 -0300 Subject: [PATCH 07/12] Rename extended_info to remote_port --- src/Driver.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Driver.cpp b/src/Driver.cpp index 5b0239c..1b933ab 100644 --- a/src/Driver.cpp +++ b/src/Driver.cpp @@ -196,14 +196,13 @@ void Driver::openURI(std::string const& uri) throw std::runtime_error("missing port specification in udp:// URI"); string::size_type second_marker = device.find_last_of(":"); - int extended_info = 0; - if (second_marker != string::npos) { - extended_info = boost::lexical_cast(device.substr(second_marker + 1)); + int remote_port = 0; + remote_port = boost::lexical_cast(device.substr(second_marker + 1)); device = device.substr(0, second_marker); - return openUDPBidirectional(device, extended_info, additional_info); + return openUDPBidirectional(device, remote_port, additional_info); } return openUDP(device, additional_info); From 6af280a0d71a4548ed601e479992b49d38ac8cf7 Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Tue, 6 Sep 2016 18:02:51 -0300 Subject: [PATCH 08/12] Do not use threads in tests --- test/test.cpp | 40 +++++++++------------------------------- 1 file changed, 9 insertions(+), 31 deletions(-) diff --git a/test/test.cpp b/test/test.cpp index ab8a6f1..ba57529 100644 --- a/test/test.cpp +++ b/test/test.cpp @@ -336,58 +336,36 @@ BOOST_AUTO_TEST_CASE(test_recv_from_bidirectional_udp) uint8_t buffer[100]; int count; uint8_t msg[4] = { 0, 'a', 'b', 0 }; - boost::thread send_thread; BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:3135:2125")); - send_thread = boost::thread(recv_test); + recv_test(); BOOST_REQUIRE_NO_THROW((count = test.readPacket(buffer, 100, 200))); BOOST_REQUIRE_EQUAL(count, 4); BOOST_REQUIRE_EQUAL(memcmp(buffer, msg, count), 0); - send_thread.join(); test.close(); } -void send_test(bool *got) +BOOST_AUTO_TEST_CASE(test_send_from_bidirectional_udp) { DriverTest test; + DriverTest peer; + uint8_t buffer[100]; - uint8_t msg[4] = { 0, 'a', 'b', 0 }; int count = 0; - - test.openURI("udpserver://4145"); - - try { - count = test.readPacket(buffer, 100, 500); - } - catch (std::runtime_error e) { - *got = false; - test.close(); - return; - } - - *got = ((count == 4) && (memcmp(buffer, msg, count) == 0)); - test.close(); -} - -BOOST_AUTO_TEST_CASE(test_send_from_bidirectional_udp) -{ - DriverTest test; uint8_t msg[4] = { 0, 'a', 'b', 0 }; - bool got = false; - - boost::thread recv_thread(send_test, &got);; + BOOST_REQUIRE_NO_THROW(peer.openURI("udpserver://4145")); BOOST_REQUIRE_NO_THROW(test.openURI("udp://127.0.0.1:4145:5155")); - boost::this_thread::sleep(boost::posix_time::milliseconds(100)); BOOST_REQUIRE_NO_THROW(test.writePacket(msg, 4)); - - recv_thread.join(); - BOOST_REQUIRE(got == true); + BOOST_REQUIRE_NO_THROW(count = peer.readPacket(buffer, 100, 500)); test.close(); + peer.close(); + + BOOST_REQUIRE((count == 4) && (memcmp(buffer, msg, count) == 0)); } From e95928aed2ae9713a9ea2e1546c58ce45469be7a Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Tue, 6 Sep 2016 18:04:04 -0300 Subject: [PATCH 09/12] Fix var names and initialization in openURI --- src/Driver.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Driver.cpp b/src/Driver.cpp index 1b933ab..13920ba 100644 --- a/src/Driver.cpp +++ b/src/Driver.cpp @@ -195,12 +195,11 @@ void Driver::openURI(std::string const& uri) if (marker == string::npos) throw std::runtime_error("missing port specification in udp:// URI"); - string::size_type second_marker = device.find_last_of(":"); - if (second_marker != string::npos) + string::size_type remote_port_marker = device.find_last_of(":"); + if (remote_port_marker != string::npos) { - int remote_port = 0; - remote_port = boost::lexical_cast(device.substr(second_marker + 1)); - device = device.substr(0, second_marker); + int remote_port = boost::lexical_cast(device.substr(remote_port_marker + 1)); + device = device.substr(0, remote_port_marker); return openUDPBidirectional(device, remote_port, additional_info); } From c073cf7cf60c2a0ce70eee7d79f7837a359f8e18 Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Thu, 8 Sep 2016 12:57:36 -0300 Subject: [PATCH 10/12] Make find_addr static --- src/Driver.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Driver.cpp b/src/Driver.cpp index 13920ba..636e653 100644 --- a/src/Driver.cpp +++ b/src/Driver.cpp @@ -257,7 +257,7 @@ void Driver::openIPServer(int port, addrinfo const& hints) setMainStream(new UDPServerStream(sfd,true)); } -void find_addr(const char *hostname, const char *port, addrinfo const& hints, struct sockaddr *addr, size_t *addr_len) +static void find_addr(const char *hostname, const char *port, addrinfo const& hints, struct sockaddr *addr, size_t *addr_len) { struct addrinfo *result; int ret = getaddrinfo(hostname, port, &hints, &result); From e27bf48fa7e6d3c899f5fc04ec3b4a95e8f57423 Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Thu, 8 Sep 2016 15:11:00 -0300 Subject: [PATCH 11/12] Refactor to reduce repeated code --- src/Driver.cpp | 84 ++++++++++++-------------------------------------- src/Driver.hpp | 2 -- 2 files changed, 19 insertions(+), 67 deletions(-) diff --git a/src/Driver.cpp b/src/Driver.cpp index 636e653..bd0cd86 100644 --- a/src/Driver.cpp +++ b/src/Driver.cpp @@ -228,7 +228,7 @@ bool Driver::openInet(const char *hostname, int port) return true; } -void Driver::openIPServer(int port, addrinfo const& hints) +static int createIPServerSocket(int port, addrinfo const& hints) { struct addrinfo *result; string port_as_string = boost::lexical_cast(port); @@ -254,10 +254,10 @@ void Driver::openIPServer(int port, addrinfo const& hints) if (rp == NULL) throw UnixError("cannot open server socket on port " + port_as_string); - setMainStream(new UDPServerStream(sfd,true)); + return sfd; } -static void find_addr(const char *hostname, const char *port, addrinfo const& hints, struct sockaddr *addr, size_t *addr_len) +static int createIPClientSocket(const char *hostname, const char *port, addrinfo const& hints, struct sockaddr *addr, size_t *addr_len) { struct addrinfo *result; int ret = getaddrinfo(hostname, port, &hints, &result); @@ -284,72 +284,17 @@ static void find_addr(const char *hostname, const char *port, addrinfo const& hi throw UnixError("cannot open client socket on port " + string(port)); } - memcpy(addr, rp->ai_addr, rp->ai_addrlen); - *addr_len = rp->ai_addrlen; + if (addr != NULL) *addr = *(rp->ai_addr); + if (addr_len != NULL) *addr_len = rp->ai_addrlen; freeaddrinfo(result); - close(sfd); -} - -void Driver::openIPBidirectional(std::string const& hostname, int out_port, addrinfo const& out_hints, int in_port, addrinfo const& in_hints) -{ - struct addrinfo *result; - string in_port_as_string = boost::lexical_cast(in_port); - int ret = getaddrinfo(NULL, in_port_as_string.c_str(), &in_hints, &result); - if (ret != 0) - throw UnixError("cannot resolve server port " + in_port_as_string); - - int sfd = -1; - struct addrinfo *rp; - for (rp = result; rp != NULL; rp = rp->ai_next) { - sfd = socket(rp->ai_family, rp->ai_socktype, - rp->ai_protocol); - if (sfd == -1) - continue; - - if (::bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) - break; /* Success */ - - ::close(sfd); - } - freeaddrinfo(result); - - if (rp == NULL) - throw UnixError("cannot open server socket on port " + in_port_as_string); - - struct sockaddr peer; - size_t peer_len; - - find_addr(hostname.c_str(), boost::lexical_cast(out_port).c_str(), out_hints, &peer, &peer_len); - setMainStream(new UDPServerStream(sfd, true, &peer, &peer_len)); + + return sfd; } void Driver::openIPClient(std::string const& hostname, int port, addrinfo const& hints) { - struct addrinfo *result; - string port_as_string = boost::lexical_cast(port); - int ret = getaddrinfo(hostname.c_str(), port_as_string.c_str(), &hints, &result); - if (ret != 0) - throw UnixError("cannot resolve host/port " + hostname + "/" + port_as_string); - - int sfd = -1; - struct addrinfo *rp; - for (rp = result; rp != NULL; rp = rp->ai_next) { - sfd = socket(rp->ai_family, rp->ai_socktype, - rp->ai_protocol); - if (sfd == -1) - continue; - - if (connect(sfd, rp->ai_addr, rp->ai_addrlen) == 0) - break; /* Success */ - - ::close(sfd); - } - freeaddrinfo(result); - - if (rp == NULL) - throw UnixError("cannot open client socket to " + hostname + " port=" + boost::lexical_cast(port)); - + int sfd = createIPClientSocket(hostname.c_str(), boost::lexical_cast(port).c_str(), hints, NULL, NULL); setFileDescriptor(sfd); } @@ -381,7 +326,9 @@ void Driver::openUDP(std::string const& hostname, int port) hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ - openIPServer(port, hints); + + int sfd = createIPServerSocket(port, hints); + setMainStream(new UDPServerStream(sfd,true)); } else { @@ -406,7 +353,14 @@ void Driver::openUDPBidirectional(std::string const& hostname, int out_port, int out_hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ out_hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ - openIPBidirectional(hostname, out_port, out_hints, in_port, in_hints); + int sfd = createIPServerSocket(in_port, in_hints); + + struct sockaddr peer; + size_t peer_len; + int peerfd = createIPClientSocket(hostname.c_str(), boost::lexical_cast(out_port).c_str(), out_hints, &peer, &peer_len); + + ::close(peerfd); + setMainStream(new UDPServerStream(sfd, true, &peer, &peer_len)); } int Driver::openSerialIO(std::string const& port, int baud_rate) diff --git a/src/Driver.hpp b/src/Driver.hpp index b6b2533..8c79ab7 100644 --- a/src/Driver.hpp +++ b/src/Driver.hpp @@ -155,9 +155,7 @@ class Driver mutable Status m_stats; - void openIPServer(int port, addrinfo const& hints); void openIPClient(std::string const& hostname, int port, addrinfo const& hints); - void openIPBidirectional(std::string const& hostname, int out_port, addrinfo const& out_hints, int in_port, addrinfo const& in_hints); public: /** Creates an Driver class for a packet-based protocol From bda30421d7101b3a6fcde90fabb61d1482fa7ead Mon Sep 17 00:00:00 2001 From: Gabriel Arjones Date: Thu, 8 Sep 2016 15:25:57 -0300 Subject: [PATCH 12/12] Resolve remote peer prior to opening server socket This is important to prevent leaking server socket descriptor in case createIPClientSocket throws --- src/Driver.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/Driver.cpp b/src/Driver.cpp index bd0cd86..a15e59b 100644 --- a/src/Driver.cpp +++ b/src/Driver.cpp @@ -353,13 +353,12 @@ void Driver::openUDPBidirectional(std::string const& hostname, int out_port, int out_hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ out_hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ - int sfd = createIPServerSocket(in_port, in_hints); - struct sockaddr peer; size_t peer_len; int peerfd = createIPClientSocket(hostname.c_str(), boost::lexical_cast(out_port).c_str(), out_hints, &peer, &peer_len); - ::close(peerfd); + + int sfd = createIPServerSocket(in_port, in_hints); setMainStream(new UDPServerStream(sfd, true, &peer, &peer_len)); }