1 #include "api/internal/io/TcpSocketEngine_p.h"
2 #include "api/internal/io/NetWin_p.h"
3 using namespace BamTools;
4 using namespace BamTools::Internal;
9 // ------------------------
10 // static utility methods
11 // ------------------------
17 void getPortAndAddress(const sockaddr* s, uint16_t& port, HostAddress& address) {
20 if (s->sa_family == AF_INET6) {
21 sockaddr_in6* ip6 = (sockaddr_in6*)s;
22 port = ntohs(ip6->sin6_port);
24 memcpy(&tmp, &ip6->sin6_addr.in6_addr, sizeof(tmp));
25 address.SetAddress(tmp);
30 if ( s->sa_family == AF_INET ) {
31 sockaddr_in* ip4 = (sockaddr_in*)s;
32 port = ntohl(ip4->sin_port);
33 address.SetAddress( ntohl(ip4->sin_addr) );
37 // should be unreachable
38 BT_ASSERT_X(false, "TcpSocketEngine::getPortAndAddress() : unknown network protocol ");
42 } // namespace Internal
43 } // namespace BamTools
45 // --------------------------------
46 // TcpSocketEngine implementation
47 // --------------------------------
49 void TcpSocketEngine::nativeClose(void) {
50 close(m_socketDescriptor);
53 bool TcpSocketEngine::nativeConnect(const HostAddress& address, const uint16_t port) {
55 // setup connection parameters from address/port
56 sockaddr_in sockAddrIPv4;
57 sockaddr_in6 sockAddrIPv6;
58 sockaddr* sockAddrPtr = 0;
59 BT_SOCKLEN_T sockAddrSize = 0;
62 if ( address.GetProtocol() == HostAddress::IPv6Protocol ) {
64 memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
65 sockAddrIPv6.sin6_family = AF_INET6;
66 sockAddrIPv6.sin6_port = htons(port);
68 IPv6Address ip6 = address.GetIPv6Address();
69 memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &ip6, sizeof(ip6));
71 sockAddrSize = sizeof(sockAddrIPv6);
72 sockAddrPtr = (sockaddr*)&sockAddrIPv6;
76 else if ( address.GetProtocol() == HostAddress::IPv4Protocol ) {
78 memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
79 sockAddrIPv4.sin_family = AF_INET;
80 sockAddrIPv4.sin_port = htons(port);
81 sockAddrIPv4.sin_addr.s_addr = htonl(address.GetIPv4Address());
83 sockAddrSize = sizeof(sockAddrIPv4);
84 sockAddrPtr = (sockaddr*)&sockAddrIPv4;
87 // unknown (should be unreachable)
88 else BT_ASSERT_X(false, "TcpSocketEngine::nativeConnect() : unknown network protocol");
91 int connectResult = connect(socketDescriptor, sockAddrPtr, sockAddrSize);
94 if ( connectResult == -1 ) {
96 // see what error was encountered
100 m_socketState = TcpSocket::ConnectedState;
104 m_socketError = TcpSocket::ConnectionRefusedError;
105 m_socketState = TcpSocket::UnconnectedState;
106 m_errorString = "connection refused";
109 m_socketError = TcpSocket::NetworkError;
110 m_errorString = "connection timed out";
113 m_socketError = TcpSocket::NetworkError;
114 m_socketState = TcpSocket::UnconnectedState;
115 m_errorString = "host unreachable";
118 m_socketError = TcpSocket::NetworkError;
119 m_socketState = TcpSocket::UnconnectedState;
120 m_errorString = "network unreachable";
123 m_socketError = TcpSocket::NetworkError;
124 m_errorString = "address already in use";
128 m_socketError = TcpSocket::SocketAccessError;
129 m_socketState = TcpSocket::UnconnectedState;
130 m_errorString = "permission denied";
135 m_socketState = TcpSocket::UnconnectedState;
140 if ( m_socketState != TcpSocket::ConnectedState )
144 // otherwise, we should be good
145 // update state & return success
146 m_socketState = TcpSocket::ConnectedState;
150 bool TcpSocketEngine::nativeCreateSocket(HostAddress::NetworkProtocol protocol) {
152 // get protocol value for requested protocol type
153 const int protocolNum = ( (protocol == HostAddress::IPv6Protocol) ? AF_INET6 : AF_INET );
155 // attempt to create socket
156 int socketFd = socket(protocolNum, SOCK_STREAM, IPPROTO_TCP);
158 // if we fetched an invalid socket descriptor
159 if ( socketFd <= 0 ) {
161 // see what error we got
163 case EPROTONOSUPPORT:
166 m_socketError = TcpSocket::UnsupportedSocketOperationError;
167 m_errorString = "protocol not supported";
173 m_socketError = TcpSocket::SocketResourceError;
174 m_errorString = "out of resources";
177 m_socketError = TcpSocket::SocketAccessError;
178 m_errorString = "permission denied";
188 // otherwise, store our socket FD & return success
189 m_socketDescriptor = socketFd;
193 bool TcpSocketEngine::nativeFetchConnectionParameters(void) {
195 // reset addresses/ports
196 m_localAddress.Clear();
197 m_remoteAddress.Clear();
201 // skip (return failure) if invalid socket FD
202 if ( m_socketDescriptor == -1 )
206 BT_SOCKLEN_T sockAddrSize = sizeof(sa);
208 // fetch local address info
209 memset(&sa, 0, sizeof(sa));
210 if ( getsockname(m_socketDescriptor, &sa, &sockAddrSize) == 0 ) {
211 getPortAndAddress(&sa, m_localPort, m_localAddress);
213 else if ( errno == EBADF ) {
214 m_socketError = TcpSocket::UnsupportedSocketOperationError;
215 m_errorString = "invalid socket descriptor";
219 // fetch remote address
220 if ( getpeername(m_socketDescriptor, &sa, &sockAddrSize) == 0 )
221 getPortAndAddress(&sa, m_remotePort, m_remoteAddress);
227 size_t TcpSocketEngine::nativeNumBytesAvailable(void) const {
229 // fetch number of bytes, return 0 on error
231 if ( ioctl(m_socketDescriptor, FIONREAD, (char*)&numBytes) < 0 )
233 return static_cast<size_t>(numBytes);
236 int64_t TcpSocketEngine::nativeRead(char* dest, size_t max) {
241 ssize_t ret = read(m_socketDescriptor, dest, max);
246 // No data was available for reading
257 return static_cast<int64_t>(ret);
260 // negative value for msecs will block (forever) until
261 int TcpSocketEngine::nativeSelect(int msecs, bool isRead) const {
266 FD_SET(m_socketDescriptor, &fds);
270 tv.tv_sec = msecs / 1000;
271 tv.tv_usec = (msecs % 1000) * 1000;
276 ret = select(m_socketDescriptor + 1, &fds, 0, 0, (msecs < 0 ? 0 : &tv));
278 ret = select(m_socketDescriptor + 1, 0, &fds, 0, (msecs < 0 ? 0 : &tv));
282 int64_t TcpSocketEngine::nativeWrite(const char* data, size_t length) {
284 ssize_t writtenBytes = write(m_socketDescriptor, data, length);
285 if ( writtenBytes < 0 ) {
290 m_socketError = TcpSocket::RemoteHostClosedError;
291 m_errorString = "remote host closed connection";
302 return static_cast<int64_t>(writtenBytes);