16 #include <netinet/in.h>
19 #include <sys/types.h>
20 #include <sys/socket.h>
44 bzero(
void* addr,
size_t len )
46 ::memset( addr, 0, len );
60 WORD wVersionRequested;
63 wVersionRequested = MAKEWORD( 2, 0 );
64 if ( WSAStartup( wVersionRequested, &wsaData ) != 0 )
66 throw std::runtime_error(
67 "Unable to initialize winsock library" );
77 static wsa_init _init_obj;
104 decltype(::sockaddr_in::sin_addr.s_addr )
node;
165 void bind(
const std::string& address );
171 throw std::runtime_error(
172 "Need to bind a port before listening" );
173 auto rc =
::listen(
get( ), queue_depth );
177 if ( err == EADDRINUSE )
178 throw std::runtime_error(
179 "Listen reported address in use" );
180 throw std::runtime_error(
"Error on listen" );
184 if ( getsockname(
s_, (struct ::sockaddr*)&sock, &len ) != 0 )
186 throw std::runtime_error(
187 "Unable to retrieve socket info after listen call" );
190 return sock.sin_port;
193 listen(
const std::string& address,
int queue_depth = 100 )
196 return ntohs(
listen( queue_depth ) );
201 void connect(
const std::string& target );
203 void write_all(
const char* start,
const char* end );
207 template <
typename Cont >
208 static std::vector< FullSocket* >
209 select( Cont& sockets,
long secs,
long usec )
221 for (
auto& s : sockets )
223 FD_SET( s->get( ), &rd_set );
224 FD_SET( s->get( ), &wr_set );
225 nfds = ( s->get( ) > nfds ? s->get( ) : nfds );
232 ( secs >= 0 ? &tv :
nullptr ) );
233 std::vector< FullSocket* > results;
234 for (
auto& s : sockets )
236 if ( FD_ISSET( s->get( ), &rd_set ) ||
237 FD_ISSET( s->get( ), &wr_set ) )
239 results.push_back( s );
302 void write_all(
const char* start,
const char* end );
316 std::string::size_type inx = addr.find(
":" );
317 std::string host = addr;
318 if ( inx != std::string::npos )
320 host = addr.substr( 0, inx );
321 std::istringstream is( addr.substr( inx + 1 ) );
326 if ( host.size( ) == 0 )
328 result.node = INADDR_ANY;
332 struct hostent* hentp = ::gethostbyname( host.c_str( ) );
335 throw std::runtime_error(
"Error in gethostbyname" );
340 &result.node, *hentp->h_addr_list,
sizeof( result.node ) );
348 int rc = ::setsockopt(
352 reinterpret_cast< detail::sockopt_ptr_type >( &val ),
355 throw std::runtime_error(
"Error setting socket options" );
366 sock.sin_family = AF_INET;
367 sock.sin_addr.s_addr = 0;
371 client.reset(::
accept(
s_, (struct ::sockaddr*)&sock, &len ) );
379 throw std::runtime_error(
380 "You cannot bind to a connected socket" );
384 sock.sin_addr.s_addr = addr_info.node;
385 sock.sin_port = addr_info.port;
387 if ( (
s_ = ::socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
389 throw std::runtime_error(
"Unable to create socket" );
391 sock.sin_family = AF_INET;
396 if (::
bind(
s_, (struct ::sockaddr*)&sock, len ) < 0 )
397 throw std::runtime_error(
398 "Unable to bind to requested address" );
404 class address_cleanup
408 operator( )( struct ::addrinfo* p )
416 throw std::runtime_error(
417 "Cannot connect a socket that is already initialized" );
419 std::string::size_type sep = target.find(
':' );
420 if ( sep == std::string::npos )
422 throw std::runtime_error(
423 "Socket connect target has no port specifier" );
425 std::string hostname = target.substr( 0, sep );
426 std::string port = target.substr( sep + 1 );
428 struct ::addrinfo hints;
429 struct ::addrinfo *result =
nullptr, *rp =
nullptr;
430 std::memset( &hints, 0,
sizeof( hints ) );
431 hints.ai_family = AF_UNSPEC;
432 hints.ai_socktype = SOCK_STREAM;
433 hints.ai_protocol = IPPROTO_TCP;
435 if (
int rc = ::getaddrinfo( hostname.c_str( ),
440 throw std::runtime_error(
"Unable to lookup address "
441 "information during connect "
444 std::unique_ptr< struct ::addrinfo, address_cleanup > result_(
446 for ( rp = result; rp !=
nullptr; rp = rp->ai_next )
449 rp->ai_family, rp->ai_socktype, rp->ai_protocol ) );
454 if (::
connect( tmp.
get( ), rp->ai_addr, rp->ai_addrlen ) == 0 )
460 throw std::runtime_error(
"Unable to connecto to target address" );
467 throw std::runtime_error(
468 "Cannot send data on a socket that is not opened" );
474 static_cast< detail::send_ptr_type >( cur ),
480 if ( err == EINTR || err == EAGAIN )
482 throw std::runtime_error(
"Unable to send on socket" );
484 else if ( count == 0 )
486 throw std::runtime_error(
"Connection closed" );
499 throw std::runtime_error(
500 "Cannot read data on a socket that is not opened" );
502 auto count = ::recv(
s_,
503 static_cast< detail::recv_ptr_type >( start ),
508 throw std::runtime_error(
"Unable to read data from socket" );
510 return start + count;
517 throw std::runtime_error(
518 "Cannot send data on a socket that is not opened" );
524 static_cast< detail::send_ptr_type >( cur ),
530 if ( err == EINTR || err == EAGAIN )
532 throw std::runtime_error(
"Unable to send on socket" );
534 else if ( count == 0 )
536 throw std::runtime_error(
"Connection closed" );
549 throw std::runtime_error(
550 "Cannot read data on a socket that is not opened" );
552 auto count = ::recv(
s_,
553 static_cast< detail::recv_ptr_type >( start ),
558 throw std::runtime_error(
"Unable to read data from socket" );
560 return start + count;
569 #ifdef _NDS_IMPL_ENABLE_CATCH_TESTS_
575 TEST_CASE(
"Can create a socket object",
"[create_basic]" )
578 REQUIRE( !s.
good( ) );
581 TEST_CASE(
"Can create a socket from a fd number",
"[create_from_fd]" )
584 REQUIRE( s.
good( ) );
585 REQUIRE( s.
get( ) == 4 );
587 REQUIRE( !s.
good( ) );
588 REQUIRE( s.
get( ) == -1 );
591 TEST_CASE(
"Can parse and lookup a name",
"[ext_network]" )
595 REQUIRE( addr.
port == 10000 );
596 REQUIRE( addr.
node == htonl( 0x7f000001 ) );
599 REQUIRE( addr.
port == 0 );
600 REQUIRE( addr.
node == htonl( 0x7f000001 ) );
603 REQUIRE( addr.
port == 5050 );
604 REQUIRE( addr.
node == 0 );
615 REQUIRE( s.
get( ) == 4 );
625 REQUIRE( s1.get( ) == 5 );
626 REQUIRE( s2.
get( ) == -1 );
628 s2.
reset( s1.release( ) );
629 REQUIRE( s1.get( ) == -1 );
630 REQUIRE( s2.
get( ) == 5 );
633 REQUIRE( s2.
get( ) == -1 );
636 TEST_CASE(
"Test connect with an initialized socket",
"[connect]" )
639 REQUIRE_THROWS( s.
connect(
"localhost:5000" ) );
643 TEST_CASE(
"Test connect with out a port specified",
"[connect_no_port]" )
646 REQUIRE_THROWS( s.
connect(
"localhost" ) );
649 TEST_CASE(
"Test connect with out a host specified",
"[connect_no_host]" )
652 REQUIRE_THROWS( s.
connect(
":5000" ) );
655 TEST_CASE(
"Test connect with no address",
"[connect_no_address]" )
658 REQUIRE_THROWS( s1.
connect(
"" ) );
659 REQUIRE_THROWS( s2.
connect(
":" ) );
666 unsigned short port = server.
listen(
"127.0.0.1" );
667 REQUIRE( port != 0 );
668 std::string target_address =
"127.0.0.1:";
669 target_address += std::to_string( port );
671 std::thread server_thread( [&server]( ) {
672 std::vector< nds_impl::Socket::FullSocket* > sockets;
673 sockets.push_back( &server );
675 if ( results.empty( ) )
677 throw std::runtime_error(
"Client did not connect in time" );
679 auto client = server.
accept( );
680 std::string data{
"hi there" };
681 client.
write_all( data.data( ), data.data( ) + data.size( ) );
684 client.
connect( target_address );
685 std::vector< char > buf( 8 );
686 auto end = client.read_available( buf.data( ), buf.data( ) + buf.size( ) );
687 REQUIRE( end != buf.data( ) );
693 server_thread.join( );
700 unsigned short port = server.
listen(
"127.0.0.1" );
701 REQUIRE( port != 0 );
702 std::string target_address =
"127.0.0.1:";
703 target_address += std::to_string( port );
705 std::thread server_thread( [&server]( ) {
706 std::vector< nds_impl::Socket::FullSocket* > sockets;
707 sockets.push_back( &server );
709 if ( results.empty( ) )
711 throw std::runtime_error(
"Client did not connect in time" );
713 auto client = server.
accept( );
714 std::string data{
"hi there" };
715 client.
write_all( data.data( ), data.data( ) + data.size( ) );
718 client_.
connect( target_address );
721 std::vector< char > buf( 8 );
722 auto end = client.read_available( buf.data( ), buf.data( ) + buf.size( ) );
723 REQUIRE( end != buf.data( ) );
729 server_thread.join( );
732 #endif // _NDS_IMPL_ENABLE_CATCH_TESTS_
734 #endif // NDS_SOCKET_HH
socket_type s_
Definition: socket.hh:307
Definition: socket.hh:108
static const socket_type BAD_SOCKET
Definition: socket.hh:86
static std::vector< FullSocket * > select(Cont &sockets, long secs, long usec)
Definition: socket.hh:209
Definition: socket.hh:102
Definition: socket.hh:254
void connect(const std::string &target)
Definition: socket.hh:402
bool good() const
Definition: socket.hh:297
TEST_CASE("daq_strlcpy copies strings safely when buffers are sufficiently large")
Definition: test_bsd_string.cc:9
void bind(const std::string &address)
Definition: socket.hh:376
void closesocket(socket_type s)
Definition: socket.hh:95
void bzero(void *addr, size_t len)
Definition: socket.hh:89
unsigned short port
Definition: socket.hh:105
void swap(FullSocket &other)
Definition: socket.hh:152
decltype(::sockaddr_in::sin_addr.s_addr) node
Definition: socket.hh:104
char * read_available(char *start, char *end)
Definition: socket.hh:496
bool good() const
Definition: socket.hh:160
void write_all(const char *start, const char *end)
Definition: socket.hh:514
detail::socket_type socket_type
Definition: socket.hh:257
const void * send_ptr_type
Definition: socket.hh:82
socket_type get() const
Definition: socket.hh:283
FullSocket()
Definition: socket.hh:113
socket_type release()
Definition: socket.hh:275
FullSocket & operator=(const FullSocket &other)
::socklen_t socklen_t
Definition: socket.hh:81
~FullSocket()
Definition: socket.hh:124
socket_type release()
Definition: socket.hh:138
Address parse_address(const std::string &addr)
Definition: socket.hh:311
void reset(socket_type fd)
Definition: socket.hh:133
detail::socket_type socket_type
Definition: socket.hh:111
void swap(SocketHandle &other)
Definition: socket.hh:289
unsigned short listen(const std::string &address, int queue_depth=100)
Definition: socket.hh:193
const void * sockopt_ptr_type
Definition: socket.hh:84
socket_type s_
Definition: socket.hh:246
SocketHandle(socket_type s)
Definition: socket.hh:263
void * recv_ptr_type
Definition: socket.hh:83
void write_all(const char *start, const char *end)
Definition: socket.hh:464
FullSocket(socket_type s)
Definition: socket.hh:120
SocketHandle()
Definition: socket.hh:259
char * read_available(char *start, char *end)
Definition: socket.hh:546
#define INVALID_SOCKET
Definition: daqc_private.c:44
void reset(socket_type fd)
Definition: socket.hh:269
unsigned short listen(int queue_depth=100)
Definition: socket.hh:168
void set_option(int id, int val)
Definition: socket.hh:346
int socket_type
Definition: socket.hh:80
FullSocket(FullSocket &&other)
Definition: socket.hh:116
socket_type get() const
Definition: socket.hh:146
FullSocket accept()
Definition: socket.hh:359