TDME2  1.9.200
TCPSocket.cpp
Go to the documentation of this file.
2 
3 #include <memory>
4 #include <string>
5 
6 #include <tdme/tdme.h>
11 
12 #include <errno.h>
13 #include <fcntl.h>
14 #include <string.h>
15 
16 #if defined(_WIN32)
17  #include <winsock2.h>
18  #include <ws2tcpip.h>
19  #define socklen_t int
20  #define BUF_CAST(buf) ((char*)buf)
21  #if defined(_MSC_VER)
22  #define ssize_t int
23  #endif
24 #else
25  #include <arpa/inet.h>
26  #include <netinet/tcp.h>
27  #include <netinet/in.h>
28  #include <sys/socket.h>
29  #define BUF_CAST(buf) ((void*)buf)
30 #endif
31 
33 
34 using std::make_unique;
35 using std::string;
36 using std::to_string;
37 
42 
43 TCPSocket* TCPSocket::createServerSocket(const string& ip, const unsigned int port, const int backlog) {
44  // create socket
45  auto socket = make_unique<TCPSocket>();
46  auto ipVersion = determineIpVersion(ip);
47  socket->descriptor = ::socket(ipVersion == IPV6?PF_INET6:PF_INET, SOCK_STREAM, IPPROTO_TCP);
48  if (socket->descriptor == -1) {
49  throw NetworkSocketException("Could not create socket: " + string(strerror(errno)));
50  }
51  #if defined(__APPLE__)
52  int flag = 1;
53  if (setsockopt(socket->descriptor, SOL_SOCKET, SO_NOSIGPIPE, (void*)&flag, sizeof(flag)) == -1) {
54  throw NetworkSocketException("Could not set no sig pipe on socket: " + string(strerror(errno)));
55  }
56  #endif
57 
58  //
59  try {
60  // set non blocked
61  socket->setNonBlocked();
62 
63  // bind
64  socket->bind(ip, port);
65 
66  // make socket listen, backlog is 10% of max CCU
67  if (listen(socket->descriptor, backlog) == -1) {
68  throw NetworkSocketException("Could not set socket to listen: " + string(strerror(errno)));
69  }
70  //
71  } catch (NetworkSocketException &exception) {
72  socket->close();
73  throw;
74  }
75  //
76  return socket.release();
77 }
78 
80 }
81 
83 }
84 
86  int flag = 1;
87  #if defined(_WIN32)
88  if (setsockopt(descriptor, IPPROTO_TCP, TCP_NODELAY, (const char*)&flag, sizeof(flag)) == -1) {
89  #else
90  if (setsockopt(descriptor, IPPROTO_TCP, TCP_NODELAY, (void*)&flag, sizeof(flag)) == -1) {
91  #endif
92  throw NetworkSocketException("Could not set tcp no delay: " + string(strerror(errno)));
93  }
94 }
95 
96 void TCPSocket::connect(const string& ip, const unsigned int port) {
97  // determine IP version
98  auto ipVersion = determineIpVersion(ip);
99 
100  //
101  descriptor = ::socket(ipVersion == IPV6?PF_INET6:PF_INET, SOCK_STREAM, IPPROTO_TCP);
102  if (descriptor == -1) {
103  throw NetworkSocketException("Could not create socket: " + string(strerror(errno)));
104  }
105  #if defined(__APPLE__)
106  int flag = 1;
107  if (setsockopt(descriptor, SOL_SOCKET, SO_NOSIGPIPE, (void*)&flag, sizeof(flag)) == -1) {
108  throw NetworkSocketException("Could not set no sig pipe on socket: " + string(strerror(errno)));
109  }
110  #endif
111 
112  // socket address in setup
113  socklen_t sinLen = 0;
114  void* sin;
115  sockaddr_in sinIPV4;
116  sockaddr_in6 sinIPV6;
117  switch(ipVersion) {
118  case IPV4:
119  {
120  sinLen = sizeof(sinIPV4);
121  memset(&sinIPV4, 0, sinLen);
122  sinIPV4.sin_family = AF_INET;
123  sinIPV4.sin_port = htons(port);
124  sinIPV4.sin_addr.s_addr = inet_addr(ip.c_str());
125  sin = &sinIPV4;
126  }
127  break;
128  case IPV6:
129  {
130  sinLen = sizeof(sinIPV6);
131  memset(&sinIPV6, 0, sinLen);
132  sinIPV6.sin6_family = AF_INET6;
133  sinIPV6.sin6_port = htons(port);
134  inet_pton(AF_INET6, ip.c_str(), &sinIPV6.sin6_addr);
135  sin = &sinIPV6;
136  }
137  break;
138  }
139 
140  // bind
141  if (::connect(descriptor, (const struct sockaddr*)sin, sinLen) == -1) {
142  #if defined(_WIN32)
143  throw NetworkSocketException("Could not connect socket: " + to_string(WSAGetLastError()));
144  #else
145  throw NetworkSocketException("Could not connect socket: " + string(strerror(errno)));
146  #endif
147  }
148 
149  // set address
150  this->ip = ip;
151  this->port = port;
152 }
153 
154 bool TCPSocket::accept(TCPSocket *_socket) {
155  struct sockaddr_in _sin;
156  socklen_t _sinSize = sizeof(_sin);
157 
158  // accept socket
159  int _descriptor = ::accept(descriptor, (struct sockaddr *)&_sin, &_sinSize);
160  if (_descriptor == -1) {
161  // no more connections are present
162  if (errno == EAGAIN ||
163  errno == EWOULDBLOCK) {
164  return false;
165  }
166  throw NetworkSocketException("Could not accept socket: " + string(strerror(errno)));
167  }
168 
169  // create client socket, return it
170  _socket->descriptor = _descriptor;
171  _socket->ip = inet_ntoa(_sin.sin_addr);
172  _socket->port = ntohs(_sin.sin_port);
173  _socket->setNonBlocked();
174  _socket->setTCPNoDelay();
175 
176  // success
177  return true;
178 }
179 
180 size_t TCPSocket::read(void* buf, const size_t bytes) {
181  ssize_t bytesRead = ::recv(descriptor, BUF_CAST(buf), bytes, 0);
182  if (bytesRead == -1) {
183  throw NetworkIOException("Error while reading from socket: " + string(strerror(errno)));
184  } else
185  if (bytesRead == 0) {
186  throw NetworkSocketClosedException("End of stream");
187  }
188  //
189  return (size_t)bytesRead;
190 }
191 
192 size_t TCPSocket::write(void* buf, const size_t bytes) {
193  #if defined(__APPLE__) || defined(_WIN32)
194  ssize_t bytesWritten = ::send(descriptor, BUF_CAST(buf), bytes, 0);
195  #else
196  ssize_t bytesWritten = ::send(descriptor, BUF_CAST(buf), bytes, MSG_NOSIGNAL);
197  #endif
198  if (bytesWritten == -1) {
199  if (errno == ECONNRESET || errno == EPIPE) {
200  throw NetworkSocketClosedException("End of stream: " + string(strerror(errno)));
201  } else {
202  throw NetworkIOException("Error while writing to socket: " + string(strerror(errno)));
203  }
204  }
205  //
206  return (size_t)bytesWritten;
207 }
208 
#define BUF_CAST(buf)
Definition: TCPSocket.cpp:29
Base exception class for network IO exceptions.
Base class of network sockets.
Definition: NetworkSocket.h:17
static IpVersion determineIpVersion(const string &ip)
Determine IP version.
void setNonBlocked()
sets the socket non blocked
Class representing a TCP socket.
Definition: TCPSocket.h:15
virtual size_t read(void *buf, const size_t bytes)
Reads up to "bytes" bytes from socket.
Definition: TCPSocket.cpp:180
virtual size_t write(void *buf, const size_t bytes)
Writes up to "bytes" bytes to socket.
Definition: TCPSocket.cpp:192
virtual bool accept(TCPSocket *_socket)
Accepts a socket from a server socket.
Definition: TCPSocket.cpp:154
virtual ~TCPSocket()
Destructor.
Definition: TCPSocket.cpp:82
void setTCPNoDelay()
Disables nagle's algorithm.
Definition: TCPSocket.cpp:85
virtual void connect(const string &ip, const unsigned int port)
Connects a socket to given remote IP and port.
Definition: TCPSocket.cpp:96