diff --git a/Cube4Fun/tcpconnector.cpp b/Cube4Fun/tcpconnector.cpp new file mode 100755 index 0000000..9615fdd --- /dev/null +++ b/Cube4Fun/tcpconnector.cpp @@ -0,0 +1,119 @@ +/* + TCPConnector.h + + TCPConnector class definition. TCPConnector provides methods to actively + establish TCP/IP connections with a server. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License +*/ + +#include +#include +#include +#include +#include +#include +#include "tcpconnector.h" + +TCPStream* TCPConnector::connect(const char* server, int port) +{ + struct sockaddr_in address; + + memset (&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + if (resolveHostName(server, &(address.sin_addr)) != 0 ) { + inet_pton(PF_INET, server, &(address.sin_addr)); + } + int sd = socket(AF_INET, SOCK_STREAM, 0); + if (::connect(sd, (struct sockaddr*)&address, sizeof(address)) != 0) { + perror("connect() failed"); + return NULL; + } + return new TCPStream(sd, &address); +} + +TCPStream* TCPConnector::connect(const char* server, int port, int timeout) +{ + if (timeout == 0) return connect(server, port); + + struct sockaddr_in address; + + memset (&address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_port = htons(port); + if (resolveHostName(server, &(address.sin_addr)) != 0 ) { + inet_pton(PF_INET, server, &(address.sin_addr)); + } + + long arg; + fd_set sdset; + struct timeval tv; + socklen_t len; + int result = -1, valopt, sd = socket(AF_INET, SOCK_STREAM, 0); + + // Set socket to non-blocking + arg = fcntl(sd, F_GETFL, NULL); + arg |= O_NONBLOCK; + fcntl(sd, F_SETFL, arg); + + // Connect with time limit + string message; + if ((result = ::connect(sd, (struct sockaddr *)&address, sizeof(address))) < 0) + { + if (errno == EINPROGRESS) + { + tv.tv_sec = timeout; + tv.tv_usec = 0; + FD_ZERO(&sdset); + FD_SET(sd, &sdset); + if (select(sd+1, NULL, &sdset, NULL, &tv) > 0) + { + len = sizeof(int); + getsockopt(sd, SOL_SOCKET, SO_ERROR, (void*)(&valopt), &len); + if (valopt) { + fprintf(stderr, "connect() error %d - %s\n", valopt, strerror(valopt)); + } + // connection established + else result = 0; + } + else fprintf(stderr, "connect() timed out\n"); + } + else fprintf(stderr, "connect() error %d - %s\n", errno, strerror(errno)); + } + + // Return socket to blocking mode + arg = fcntl(sd, F_GETFL, NULL); + arg &= (~O_NONBLOCK); + fcntl(sd, F_SETFL, arg); + + // Create stream object if connected + if (result == -1) return NULL; + return new TCPStream(sd, &address); +} + +int TCPConnector::resolveHostName(const char* hostname, struct in_addr* addr) +{ + struct addrinfo *res; + + int result = getaddrinfo (hostname, NULL, NULL, &res); + if (result == 0) { + memcpy(addr, &((struct sockaddr_in *) res->ai_addr)->sin_addr, sizeof(struct in_addr)); + freeaddrinfo(res); + } + return result; +} diff --git a/Cube4Fun/tcpconnector.h b/Cube4Fun/tcpconnector.h new file mode 100755 index 0000000..ed36a70 --- /dev/null +++ b/Cube4Fun/tcpconnector.h @@ -0,0 +1,40 @@ +/* + TCPConnector.h + + TCPConnector class interface. TCPConnector provides methods to actively + establish TCP/IP connections with a server. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License +*/ + +#ifndef __tcpconnector_h__ +#define __tcpconnector_h__ + +#include +#include "tcpstream.h" + +class TCPConnector +{ + public: + TCPStream* connect(const char* server, int port); + TCPStream* connect(const char* server, int port, int timeout); + + private: + int resolveHostName(const char* host, struct in_addr* addr); +}; + +#endif diff --git a/Cube4Fun/tcpstream.cpp b/Cube4Fun/tcpstream.cpp new file mode 100755 index 0000000..171e48e --- /dev/null +++ b/Cube4Fun/tcpstream.cpp @@ -0,0 +1,80 @@ +/* + TCPStream.h + + TCPStream class definition. TCPStream provides methods to trasnfer + data between peers over a TCP/IP connection. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#include +#include "tcpstream.h" + +TCPStream::TCPStream(int sd, struct sockaddr_in* address) : m_sd(sd) { + char ip[50]; + inet_ntop(PF_INET, (struct in_addr*)&(address->sin_addr.s_addr), ip, sizeof(ip)-1); + m_peerIP = ip; + m_peerPort = ntohs(address->sin_port); +} + +TCPStream::~TCPStream() +{ + close(m_sd); +} + +ssize_t TCPStream::send(const char* buffer, size_t len) +{ + return write(m_sd, buffer, len); +} + +ssize_t TCPStream::receive(char* buffer, size_t len, int timeout) +{ + if (timeout <= 0) return read(m_sd, buffer, len); + + if (waitForReadEvent(timeout) == true) + { + return read(m_sd, buffer, len); + } + return connectionTimedOut; + +} + +string TCPStream::getPeerIP() +{ + return m_peerIP; +} + +int TCPStream::getPeerPort() +{ + return m_peerPort; +} + +bool TCPStream::waitForReadEvent(int timeout) +{ + fd_set sdset; + struct timeval tv; + + tv.tv_sec = timeout; + tv.tv_usec = 0; + FD_ZERO(&sdset); + FD_SET(m_sd, &sdset); + if (select(m_sd+1, &sdset, NULL, NULL, &tv) > 0) + { + return true; + } + return false; +} diff --git a/Cube4Fun/tcpstream.h b/Cube4Fun/tcpstream.h new file mode 100755 index 0000000..f3df94e --- /dev/null +++ b/Cube4Fun/tcpstream.h @@ -0,0 +1,66 @@ +/* + TCPStream.h + + TCPStream class interface. TCPStream provides methods to trasnfer + data between peers over a TCP/IP connection. + + ------------------------------------------ + + Copyright © 2013 [Vic Hargrave - http://vichargrave.com] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +#ifndef __tcpstream_h__ +#define __tcpstream_h__ + +#include +#include +#include +#include + +using namespace std; + +class TCPStream +{ + int m_sd; + string m_peerIP; + int m_peerPort; + + public: + friend class TCPAcceptor; + friend class TCPConnector; + + ~TCPStream(); + + ssize_t send(const char* buffer, size_t len); + ssize_t receive(char* buffer, size_t len, int timeout=0); + + string getPeerIP(); + int getPeerPort(); + + enum { + connectionClosed = 0, + connectionReset = -1, + connectionTimedOut = -2 + }; + + private: + bool waitForReadEvent(int timeout); + + TCPStream(int sd, struct sockaddr_in* address); + TCPStream(); + TCPStream(const TCPStream& stream); +}; + +#endif