1 #include "api/internal/io/TcpSocketEngine_p.h"
2 #include "api/internal/io/NetUnix_p.h"
3 using namespace BamTools;
4 using namespace BamTools::Internal;
11 // ------------------------
12 // static utility methods
13 // ------------------------
19 //void getPortAndAddress(const sockaddr* s, uint16_t& port, HostAddress& address) {
22 // if (s->sa_family == AF_INET6) {
23 // sockaddr_in6* ip6 = (sockaddr_in6*)s;
24 // port = ntohs(ip6->sin6_port);
26 // memcpy(&tmp.data, &(ip6->sin6_addr.s6_addr), sizeof(tmp));
27 // address.SetAddress(tmp);
32 // if ( s->sa_family == AF_INET ) {
33 // sockaddr_in* ip4 = (sockaddr_in*)s;
34 // port = ntohl(ip4->sin_port);
35 // address.SetAddress( ntohl(ip4->sin_addr.s_addr) );
39 // // should be unreachable
40 // BT_ASSERT_X(false, "TcpSocketEngine::getPortAndAddress() : unknown network protocol ");
43 } // namespace Internal
44 } // namespace BamTools
46 // --------------------------------
47 // TcpSocketEngine implementation
48 // --------------------------------
50 void TcpSocketEngine::nativeClose(void) {
51 close(m_socketDescriptor);
54 bool TcpSocketEngine::nativeConnect(const HostAddress& address, const uint16_t port) {
56 // setup connection parameters from address/port
57 sockaddr_in sockAddrIPv4;
58 sockaddr_in6 sockAddrIPv6;
59 sockaddr* sockAddrPtr = 0;
60 BT_SOCKLEN_T sockAddrSize = 0;
63 if ( address.GetProtocol() == HostAddress::IPv6Protocol ) {
65 memset(&sockAddrIPv6, 0, sizeof(sockAddrIPv6));
66 sockAddrIPv6.sin6_family = AF_INET6;
67 sockAddrIPv6.sin6_port = htons(port);
69 IPv6Address ip6 = address.GetIPv6Address();
70 memcpy(&sockAddrIPv6.sin6_addr.s6_addr, &ip6, sizeof(ip6));
72 sockAddrSize = sizeof(sockAddrIPv6);
73 sockAddrPtr = (sockaddr*)&sockAddrIPv6;
77 else if ( address.GetProtocol() == HostAddress::IPv4Protocol ) {
79 memset(&sockAddrIPv4, 0, sizeof(sockAddrIPv4));
80 sockAddrIPv4.sin_family = AF_INET;
81 sockAddrIPv4.sin_port = htons(port);
82 sockAddrIPv4.sin_addr.s_addr = htonl(address.GetIPv4Address());
84 sockAddrSize = sizeof(sockAddrIPv4);
85 sockAddrPtr = (sockaddr*)&sockAddrIPv4;
88 // unknown (should be unreachable)
89 else BT_ASSERT_X(false, "TcpSocketEngine::nativeConnect() : unknown network protocol");
92 int connectResult = connect(m_socketDescriptor, sockAddrPtr, sockAddrSize);
95 if ( connectResult == -1 ) {
97 // see what error was encountered
101 m_socketState = TcpSocket::ConnectedState;
105 m_socketError = TcpSocket::ConnectionRefusedError;
106 m_socketState = TcpSocket::UnconnectedState;
107 m_errorString = "connection refused";
110 m_socketError = TcpSocket::NetworkError;
111 m_errorString = "connection timed out";
114 m_socketError = TcpSocket::NetworkError;
115 m_socketState = TcpSocket::UnconnectedState;
116 m_errorString = "host unreachable";
119 m_socketError = TcpSocket::NetworkError;
120 m_socketState = TcpSocket::UnconnectedState;
121 m_errorString = "network unreachable";
124 m_socketError = TcpSocket::NetworkError;
125 m_errorString = "address already in use";
129 m_socketError = TcpSocket::SocketAccessError;
130 m_socketState = TcpSocket::UnconnectedState;
131 m_errorString = "permission denied";
136 m_socketState = TcpSocket::UnconnectedState;
141 if ( m_socketState != TcpSocket::ConnectedState )
145 // otherwise, we should be good
146 // update state & return success
147 m_socketState = TcpSocket::ConnectedState;
151 bool TcpSocketEngine::nativeCreateSocket(HostAddress::NetworkProtocol protocol) {
153 // get protocol value for requested protocol type
154 const int protocolNum = ( (protocol == HostAddress::IPv6Protocol) ? AF_INET6 : AF_INET );
156 // attempt to create socket
157 int socketFd = socket(protocolNum, SOCK_STREAM, IPPROTO_TCP);
159 // if we fetched an invalid socket descriptor
160 if ( socketFd <= 0 ) {
162 // see what error we got
164 case EPROTONOSUPPORT:
167 m_socketError = TcpSocket::UnsupportedSocketOperationError;
168 m_errorString = "protocol not supported";
174 m_socketError = TcpSocket::SocketResourceError;
175 m_errorString = "out of resources";
178 m_socketError = TcpSocket::SocketAccessError;
179 m_errorString = "permission denied";
189 // otherwise, store our socket FD & return success
190 m_socketDescriptor = socketFd;
194 //bool TcpSocketEngine::nativeFetchConnectionParameters(void) {
196 // // reset addresses/ports
197 //// m_localAddress.Clear();
198 // m_remoteAddress.Clear();
199 //// m_localPort = 0;
202 // // skip (return failure) if invalid socket FD
203 // if ( m_socketDescriptor == -1 )
207 // BT_SOCKLEN_T sockAddrSize = sizeof(sa);
209 // // fetch local address info
210 // memset(&sa, 0, sizeof(sa));
211 // if ( getsockname(m_socketDescriptor, &sa, &sockAddrSize) == 0 )
212 // 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 int64_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<int64_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);