Newer
Older
#include "tcplistener.hpp"
#include <stdexcept>
#include <unistd.h>
#include <sys/socket.h>
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
// TODO: More and better error handling
TcpListener::TcpListener(SockAddr _local)
: local{_local}, sockfd{0}
{ }
TcpListener::TcpListener(IpAddr localAddress, uint16_t port)
: TcpListener{SockAddr{localAddress, port}}
{ }
TcpListener::TcpListener(const std::string &localAddress, uint16_t port)
: TcpListener{SockAddr{localAddress, port}}
{ }
TcpListener::TcpListener(const std::string &localAddressPort)
: TcpListener{SockAddr{localAddressPort}}
{ }
TcpListener::~TcpListener()
{
// Close the socket to prevent leaking open file descriptors
close();
}
void TcpListener::listen(int connectionQueue)
{
if (sockfd > 0)
throw std::runtime_error("Can't call listen on open socket");
int af;
socklen_t sock_len;
if (local.address.type == IpAddr::Type::V4)
{
af = AF_INET;
sock_len = sizeof(sockaddr_in);
}
else if (local.address.type == IpAddr::Type::V6)
{
af = AF_INET6;
sock_len = sizeof(sockaddr_in6);
}
else
{
throw std::runtime_error("Can't bind to IpAddr::Type::Undef");
}
// Create the socket and get the socket file descriptor
sockfd = socket(af, SOCK_STREAM, 0);
if (sockfd <= 0)
{
throw std::runtime_error("Creating TCP Socket failed");
}
// Bind the socket to the local address and port
if (bind(sockfd, &local.raw_sockaddr.generic, sock_len) != 0)
{
close();
throw std::runtime_error("Binding TCP Socket failed");
}
// Start listening on the local address and port with the specified number
// queued connections
if (::listen(sockfd, connectionQueue) != 0)
{
close();
throw std::runtime_error("Listening TCP Socket failed");
}
}
TcpStream TcpListener::accept()
{
SockAddr::RawSockAddr remote_raw_saddr = {0};
socklen_t remote_raw_saddr_len = sizeof(remote_raw_saddr);
int remote_sockfd = ::accept(sockfd, &remote_raw_saddr.generic, &remote_raw_saddr_len);
if (remote_sockfd <= 0)
{
throw std::runtime_error("Accepting TCP Connection failed");
}
// Parse the raw remote sockaddr to a SockAddr
SockAddr remote_saddr(&remote_raw_saddr.generic, local.address.type);
// Create a TcpStream and set the remote SockAddr
TcpStream stream(remote_saddr);
// Transfer the socket filedescriptor
stream.sockfd = remote_sockfd;
// TcpStream can't be copied, so this has to move
return stream;
}
void TcpListener::close()
{
if (sockfd != 0)
{
::close(sockfd);
}
sockfd = 0;
}