From: Chris Tallon Date: Sat, 28 Mar 2020 16:45:05 +0000 (+0000) Subject: Rename TCP class to TCPOld X-Git-Url: https://git.vomp.tv/gitweb/?a=commitdiff_plain;h=b1052b879bf72ab2f5930c5f6ff0fded4a209699;p=vompclient.git Rename TCP class to TCPOld --- diff --git a/objects.mk b/objects.mk index a7b6201..35be1e2 100644 --- a/objects.mk +++ b/objects.mk @@ -1,4 +1,4 @@ -OBJ_COMMON = command.o thread.o timers.o i18n.o tcp.o udp4.o udp6.o vdpc.o \ +OBJ_COMMON = command.o thread.o timers.o i18n.o tcpold.o udp4.o udp6.o vdpc.o \ message.o messagequeue.o wol.o audio.o video.o log.o \ vdr.o recman.o recording.o recinfo.o channel.o rectimer.o event.o \ directory.o mark.o option.o vfeed.o afeed.o \ diff --git a/tcp.cc b/tcp.cc deleted file mode 100644 index 40f1f95..0000000 --- a/tcp.cc +++ /dev/null @@ -1,501 +0,0 @@ -/* - Copyright 2004-2019 Chris Tallon - Copyright 2003-2004 University Of Bradford - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifdef WIN32 -#include -#include -#else -#include -#include -#include -#endif - -#include "log.h" - -#include "tcp.h" - -TCP::TCP() -{ - sock = 0; - connected = 0; - timeoutEnabled = 1; -} - -TCP::~TCP() -{ - if (connected) - { - CLOSESOCKET(sock); - Log::getInstance()->log("TCP", Log::DEBUG, "Have closed"); - } -} - -void TCP::disableTimeout() -{ - timeoutEnabled = 0; -} - -void TCP::getMAC(UCHAR* dest) -{ -#ifndef WIN32 - struct ifreq ifr; - strcpy(ifr.ifr_name, "eth0"); - ioctl(sock, SIOCGIFHWADDR, &ifr); - memcpy(dest, ifr.ifr_hwaddr.sa_data, 6); -#else - //TODO: Get MAC Address for windows - PIP_ADAPTER_INFO daptinfo=NULL; - DWORD size=0; - GetAdaptersInfo(daptinfo,&size); - daptinfo=(PIP_ADAPTER_INFO)new char[size+1]; - memcpy(dest,"ABCDEF", 6);//Dummy Address - sockaddr_in sock_address; - int sockname_len=sizeof(sock_address); - getsockname(sock,(sockaddr*)&sock_address,&sockname_len); - ULONG sockip=sock_address.sin_addr.s_addr; - if (GetAdaptersInfo(daptinfo,&size)==ERROR_SUCCESS) - { - PIP_ADAPTER_INFO daptinfo_it=daptinfo; - while (daptinfo_it!=NULL) - { - ULONG ipaddress=inet_addr(daptinfo_it->IpAddressList.IpAddress.String); - if (ipaddress==sockip) - { //Is it our MAC? - memcpy(dest,daptinfo_it->Address, 6); - break; - } - daptinfo_it=daptinfo_it->Next; - if (daptinfo_it==daptinfo) break; - } - } - else - { - // Marten? - } - - delete [] daptinfo; -#endif -} - -int TCP::connectTo(char* host, unsigned short port) -{ -#ifdef VOMP_PLATFORM_RASPBERRY -#define IPV 6 -#else -#define IPV 4 -#endif - -#if IPV == 4 - - sock = socket(PF_INET, SOCK_STREAM, 0); - if (sock == -1) return 0; - struct sockaddr_in dest_addr; - dest_addr.sin_family = AF_INET; - dest_addr.sin_port = htons(port); - -#ifndef WIN32 - if (!inet_aton(host, &dest_addr.sin_addr)) -#else - dest_addr.sin_addr.s_addr = inet_addr(host); - if (dest_addr.sin_addr.s_addr == INADDR_NONE) -#endif - { - CLOSESOCKET(sock); - return 0; - } - - memset(&(dest_addr.sin_zero), '\0', 8); - -#elif IPV == 6 - - char portstring[10]; - snprintf(portstring, 10, "%u", port); - - struct addrinfo hints; - struct addrinfo* res; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_UNSPEC; - hints.ai_socktype = SOCK_STREAM; - if (getaddrinfo(host, portstring, &hints, &res)) - { - //printf("[%s] [%s]\n", host, portstring); - return 0; - } - - sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (sock == -1) return 0; - -#endif - - - - // set non blocking -#ifndef WIN32 - int oldflags = fcntl (sock, F_GETFL, 0); - oldflags |= O_NONBLOCK; - fcntl(sock, F_SETFL, oldflags); -#else - unsigned long flag=1; - ioctlsocket(sock,FIONBIO,&flag); - -#endif - -// setReceiveWindow(2048); - - // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!) - -#if IPV == 4 - int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); -#elif IPV == 6 - int success = connect(sock, res->ai_addr, res->ai_addrlen); - freeaddrinfo(res); -#endif - - - if (success == 0) // if by some miracle the connection succeeded in no time flat, just return! - { - connected = 1; - return 1; - } - - // first check errno for EINPROGRESS, otherwise it's a fail - // this doesn't work? -#ifndef WIN32 - if (errno != EINPROGRESS) -#else - int wsalasterr = WSAGetLastError(); - if ((wsalasterr != WSAEWOULDBLOCK) && (wsalasterr != WSAEINPROGRESS)) -#endif - { - CLOSESOCKET(sock); - - return 0; - } - - // now do a timeout wait on writability on the socket - - fd_set connectSet; - struct timeval timeout; - FD_ZERO(&connectSet); - FD_SET(sock, &connectSet); - timeout.tv_sec = 10; - timeout.tv_usec = 0; - success = select(sock + 1, NULL, &connectSet, NULL, &timeout); - if (success < 1) - { - // timeout or error - CLOSESOCKET(sock); - return 0; - } - - // so the socket became available for writing. Contrary to expectation, this doesn't actually - // mean it connected... - - int soError; // SO_ERROR optval is int - socklen_t soErrorSize = sizeof(soError); - -#ifdef WIN32 - int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast(&soError), &soErrorSize); -#else - int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast(&soError), &soErrorSize); -#endif - - if ((gso == 0) && (soError == 0)) - { - // success! - connected = 1; - return 1; - } - else - { - CLOSESOCKET(sock); - return 0; - } - -/* -The full documentation: - - EINPROGRESS - The socket is non-blocking and the connection canĀ­ - not be completed immediately. It is possible to - select(2) or poll(2) for completion by selecting - the socket for writing. After select indicates - writability, use getsockopt(2) to read the SO_ERROR - option at level SOL_SOCKET to determine whether - connect completed successfully (SO_ERROR is zero) - or unsuccessfully (SO_ERROR is one of the usual - error codes listed here, explaining the reason for - the failure). -*/ -} - -void TCP::setReceiveWindow(size_t rxBufferSize) -{ - // Set receive window - // According to docs, optval in setsockopt is a pointer to int unless otherwise noted - int rxSize = rxBufferSize; -#ifdef WIN32 - int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&rxSize), sizeof(size_t)); -#else - int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&rxSize), sizeof(size_t)); -#endif - Log::getInstance()->log("TCP", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r); -} - -void TCP::assignSocket(int tsocket) -{ - sock = tsocket; -} - -int TCP::isConnected() -{ - return connected; -} - -int TCP::sendData(void* bufR, size_t count) -{ - size_t bytes_sent = 0; - int this_write; - - unsigned char* buf = static_cast(bufR); - - mutex.lock(); - - while (bytes_sent < count) - { - do - { -#ifndef WIN32 - this_write = write(sock, buf, count - bytes_sent); -// Log::getInstance()->log("TCP", Log::DEBUG, "TCP has written %i bytes", this_write); - } while ( (this_write < 0) && (errno == EINTR) ); -#else - this_write = send(sock,(char*) buf, count- bytes_sent,0); - } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) ); -#endif - if (this_write <= 0) - { - mutex.unlock(); - return(this_write); - } - bytes_sent += this_write; - buf += this_write; - } - - mutex.unlock(); - - return(count); -} - -int TCP::readData(void* targetBuffer, int totalBytes) -{ - UCHAR* buffer = reinterpret_cast(targetBuffer); - int bytesRead = 0; - int thisRead; - int readTries = 0; - int success; - fd_set readSet; - struct timeval timeout; - struct timeval* passToSelect; - - if (timeoutEnabled) passToSelect = &timeout; - else passToSelect = NULL; - - while(1) - { - FD_ZERO(&readSet); - FD_SET(sock, &readSet); - timeout.tv_sec = 2; - timeout.tv_usec = 0; - // Log::getInstance()->log("TCP", Log::DEBUG, "Going to select"); - success = select(sock + 1, &readSet, NULL, NULL, passToSelect); - // Log::getInstance()->log("TCP", Log::DEBUG, "Back from select with success = %i", success); - if (success < 1) - { - return 0; // error, or timeout - } -#ifndef WIN32 - thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead); -#else - thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0); -#endif - //Log::getInstance()->log("TCP", Log::DEBUG, "Read %i", thisRead); - if (!thisRead) - { - // if read returns 0 then connection is closed - // in non-blocking mode if read is called with no data available, it returns -1 - // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway. - Log::getInstance()->log("TCP", Log::ERR, "Detected connection closed"); - CLOSESOCKET(sock); - connected = 0; - return 0; - } - bytesRead += thisRead; - if (bytesRead == totalBytes) - { - return 1; - } - else - { - if (++readTries == 1000) - { - Log::getInstance()->log("TCP", Log::ERR, "Too many reads"); - return 0; - } - } - } -} - -void TCP::dump(unsigned char* data, ULONG size) -{ - printf("Size = %lu\n", size); - - ULONG c = 0; - while(c < size) - { - if ((size - c) > 15) - { - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), - dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15])); - c += 16; - } - else - { - switch (size - c) - { - case 15: - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), - dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14])); - c += 15; - break; - case 14: - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), - dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13])); - c += 14; - break; - case 13: - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), - dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12])); - c += 13; - break; - case 12: - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - data[c+8], data[c+9], data[c+10], data[c+11], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), - dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11])); - c += 12; - break; - case 11: - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - data[c+8], data[c+9], data[c+10], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), - dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10])); - c += 11; - break; - case 10: - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - data[c+8], data[c+9], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), - dcc(data[c+8]), dcc(data[c+9])); - c += 10; - break; - case 9: - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - data[c+8], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), - dcc(data[c+8])); - c += 9; - break; - case 8: - printf(" %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7])); - c += 8; - break; - case 7: - printf(" %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6])); - c += 7; - break; - case 6: - printf(" %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5])); - c += 6; - break; - case 5: - printf(" %02X %02X %02X %02X %02X %c%c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], data[c+4], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4])); - c += 5; - break; - case 4: - printf(" %02X %02X %02X %02X %c%c%c%c\n", - data[c], data[c+1], data[c+2], data[c+3], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3])); - c += 4; - break; - case 3: - printf(" %02X %02X %02X %c%c%c\n", - data[c], data[c+1], data[c+2], - dcc(data[c]), dcc(data[c+1]), dcc(data[c+2])); - c += 3; - break; - case 2: - printf(" %02X %02X %c%c\n", - data[c], data[c+1], - dcc(data[c]), dcc(data[c+1])); - c += 2; - break; - case 1: - printf(" %02X %c\n", - data[c], - dcc(data[c])); - c += 1; - break; - } - } - } -} - -UCHAR TCP::dcc(UCHAR c) -{ - if (isspace(c)) return ' '; - if (isprint(c)) return c; - return '.'; -} diff --git a/tcp.h b/tcp.h deleted file mode 100644 index ceacc3c..0000000 --- a/tcp.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - Copyright 2004-2005 Chris Tallon - Copyright 2003-2004 University Of Bradford - - This file is part of VOMP. - - VOMP is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - VOMP is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with VOMP; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -*/ - -#ifndef TCP_H -#define TCP_H - -#include -#include -#include -#include -#include -#include -#include - -#ifndef WIN32 -#include -#include -#include -#include -#include -#include -#include -#else -#include -#include -#include -#endif - -#include "defines.h" - -class TCP -{ - public: - TCP(); - ~TCP(); - - int connectTo(char *host, unsigned short port); - void assignSocket(int tsocket); - - int isConnected(); - void disableTimeout(); - - int readData(void* buffer, int totalBytes); - int sendData(void*, size_t size); - - static void dump(unsigned char* data, ULONG size); - - void getMAC(UCHAR* dest); // copies 6 MAC bytes to dest - void setReceiveWindow(size_t rxBufferSize); - - private: - int sock; - int connected; - int timeoutEnabled; - int dataLength; - std::mutex mutex; - - static UCHAR dcc(UCHAR c); -}; - -#endif diff --git a/tcpold.cc b/tcpold.cc new file mode 100644 index 0000000..26f6b54 --- /dev/null +++ b/tcpold.cc @@ -0,0 +1,501 @@ +/* + Copyright 2004-2019 Chris Tallon + Copyright 2003-2004 University Of Bradford + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifdef WIN32 +#include +#include +#else +#include +#include +#include +#endif + +#include "log.h" + +#include "tcpold.h" + +TCPOld::TCPOld() +{ + sock = 0; + connected = 0; + timeoutEnabled = 1; +} + +TCPOld::~TCPOld() +{ + if (connected) + { + CLOSESOCKET(sock); + Log::getInstance()->log("TCPOld", Log::DEBUG, "Have closed"); + } +} + +void TCPOld::disableTimeout() +{ + timeoutEnabled = 0; +} + +void TCPOld::getMAC(UCHAR* dest) +{ +#ifndef WIN32 + struct ifreq ifr; + strcpy(ifr.ifr_name, "eth0"); + ioctl(sock, SIOCGIFHWADDR, &ifr); + memcpy(dest, ifr.ifr_hwaddr.sa_data, 6); +#else + //TODO: Get MAC Address for windows + PIP_ADAPTER_INFO daptinfo=NULL; + DWORD size=0; + GetAdaptersInfo(daptinfo,&size); + daptinfo=(PIP_ADAPTER_INFO)new char[size+1]; + memcpy(dest,"ABCDEF", 6);//Dummy Address + sockaddr_in sock_address; + int sockname_len=sizeof(sock_address); + getsockname(sock,(sockaddr*)&sock_address,&sockname_len); + ULONG sockip=sock_address.sin_addr.s_addr; + if (GetAdaptersInfo(daptinfo,&size)==ERROR_SUCCESS) + { + PIP_ADAPTER_INFO daptinfo_it=daptinfo; + while (daptinfo_it!=NULL) + { + ULONG ipaddress=inet_addr(daptinfo_it->IpAddressList.IpAddress.String); + if (ipaddress==sockip) + { //Is it our MAC? + memcpy(dest,daptinfo_it->Address, 6); + break; + } + daptinfo_it=daptinfo_it->Next; + if (daptinfo_it==daptinfo) break; + } + } + else + { + // Marten? + } + + delete [] daptinfo; +#endif +} + +int TCPOld::connectTo(char* host, unsigned short port) +{ +#ifdef VOMP_PLATFORM_RASPBERRY +#define IPV 6 +#else +#define IPV 4 +#endif + +#if IPV == 4 + + sock = socket(PF_INET, SOCK_STREAM, 0); + if (sock == -1) return 0; + struct sockaddr_in dest_addr; + dest_addr.sin_family = AF_INET; + dest_addr.sin_port = htons(port); + +#ifndef WIN32 + if (!inet_aton(host, &dest_addr.sin_addr)) +#else + dest_addr.sin_addr.s_addr = inet_addr(host); + if (dest_addr.sin_addr.s_addr == INADDR_NONE) +#endif + { + CLOSESOCKET(sock); + return 0; + } + + memset(&(dest_addr.sin_zero), '\0', 8); + +#elif IPV == 6 + + char portstring[10]; + snprintf(portstring, 10, "%u", port); + + struct addrinfo hints; + struct addrinfo* res; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + if (getaddrinfo(host, portstring, &hints, &res)) + { + //printf("[%s] [%s]\n", host, portstring); + return 0; + } + + sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (sock == -1) return 0; + +#endif + + + + // set non blocking +#ifndef WIN32 + int oldflags = fcntl (sock, F_GETFL, 0); + oldflags |= O_NONBLOCK; + fcntl(sock, F_SETFL, oldflags); +#else + unsigned long flag=1; + ioctlsocket(sock,FIONBIO,&flag); + +#endif + +// setReceiveWindow(2048); + + // ok, how to open a connection in non blocking mode (and therefore have a self set timeout!!) + +#if IPV == 4 + int success = connect(sock, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); +#elif IPV == 6 + int success = connect(sock, res->ai_addr, res->ai_addrlen); + freeaddrinfo(res); +#endif + + + if (success == 0) // if by some miracle the connection succeeded in no time flat, just return! + { + connected = 1; + return 1; + } + + // first check errno for EINPROGRESS, otherwise it's a fail + // this doesn't work? +#ifndef WIN32 + if (errno != EINPROGRESS) +#else + int wsalasterr = WSAGetLastError(); + if ((wsalasterr != WSAEWOULDBLOCK) && (wsalasterr != WSAEINPROGRESS)) +#endif + { + CLOSESOCKET(sock); + + return 0; + } + + // now do a timeout wait on writability on the socket + + fd_set connectSet; + struct timeval timeout; + FD_ZERO(&connectSet); + FD_SET(sock, &connectSet); + timeout.tv_sec = 10; + timeout.tv_usec = 0; + success = select(sock + 1, NULL, &connectSet, NULL, &timeout); + if (success < 1) + { + // timeout or error + CLOSESOCKET(sock); + return 0; + } + + // so the socket became available for writing. Contrary to expectation, this doesn't actually + // mean it connected... + + int soError; // SO_ERROR optval is int + socklen_t soErrorSize = sizeof(soError); + +#ifdef WIN32 + int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast(&soError), &soErrorSize); +#else + int gso = getsockopt(sock, SOL_SOCKET, SO_ERROR, reinterpret_cast(&soError), &soErrorSize); +#endif + + if ((gso == 0) && (soError == 0)) + { + // success! + connected = 1; + return 1; + } + else + { + CLOSESOCKET(sock); + return 0; + } + +/* +The full documentation: + + EINPROGRESS + The socket is non-blocking and the connection canĀ­ + not be completed immediately. It is possible to + select(2) or poll(2) for completion by selecting + the socket for writing. After select indicates + writability, use getsockopt(2) to read the SO_ERROR + option at level SOL_SOCKET to determine whether + connect completed successfully (SO_ERROR is zero) + or unsuccessfully (SO_ERROR is one of the usual + error codes listed here, explaining the reason for + the failure). +*/ +} + +void TCPOld::setReceiveWindow(size_t rxBufferSize) +{ + // Set receive window + // According to docs, optval in setsockopt is a pointer to int unless otherwise noted + int rxSize = rxBufferSize; +#ifdef WIN32 + int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&rxSize), sizeof(size_t)); +#else + int r = setsockopt(sock, SOL_SOCKET, SO_RCVBUF, reinterpret_cast(&rxSize), sizeof(size_t)); +#endif + Log::getInstance()->log("TCPOld", Log::DEBUG, "Set receive window to %i, success(=0): %i", rxBufferSize, r); +} + +void TCPOld::assignSocket(int tsocket) +{ + sock = tsocket; +} + +int TCPOld::isConnected() +{ + return connected; +} + +int TCPOld::sendData(void* bufR, size_t count) +{ + size_t bytes_sent = 0; + int this_write; + + unsigned char* buf = static_cast(bufR); + + mutex.lock(); + + while (bytes_sent < count) + { + do + { +#ifndef WIN32 + this_write = write(sock, buf, count - bytes_sent); +// Log::getInstance()->log("TCPOld", Log::DEBUG, "TCPOld has written %i bytes", this_write); + } while ( (this_write < 0) && (errno == EINTR) ); +#else + this_write = send(sock,(char*) buf, count- bytes_sent,0); + } while ( (this_write == SOCKET_ERROR) && (WSAGetLastError() == WSAEINTR) ); +#endif + if (this_write <= 0) + { + mutex.unlock(); + return(this_write); + } + bytes_sent += this_write; + buf += this_write; + } + + mutex.unlock(); + + return(count); +} + +int TCPOld::readData(void* targetBuffer, int totalBytes) +{ + UCHAR* buffer = reinterpret_cast(targetBuffer); + int bytesRead = 0; + int thisRead; + int readTries = 0; + int success; + fd_set readSet; + struct timeval timeout; + struct timeval* passToSelect; + + if (timeoutEnabled) passToSelect = &timeout; + else passToSelect = NULL; + + while(1) + { + FD_ZERO(&readSet); + FD_SET(sock, &readSet); + timeout.tv_sec = 2; + timeout.tv_usec = 0; + // Log::getInstance()->log("TCPOld", Log::DEBUG, "Going to select"); + success = select(sock + 1, &readSet, NULL, NULL, passToSelect); + // Log::getInstance()->log("TCPOld", Log::DEBUG, "Back from select with success = %i", success); + if (success < 1) + { + return 0; // error, or timeout + } +#ifndef WIN32 + thisRead = read(sock, &buffer[bytesRead], totalBytes - bytesRead); +#else + thisRead = recv(sock, (char*)&buffer[bytesRead], totalBytes - bytesRead, 0); +#endif + //Log::getInstance()->log("TCPOld", Log::DEBUG, "Read %i", thisRead); + if (!thisRead) + { + // if read returns 0 then connection is closed + // in non-blocking mode if read is called with no data available, it returns -1 + // and sets errno to EGAGAIN. but we use select so it wouldn't do that anyway. + Log::getInstance()->log("TCPOld", Log::ERR, "Detected connection closed"); + CLOSESOCKET(sock); + connected = 0; + return 0; + } + bytesRead += thisRead; + if (bytesRead == totalBytes) + { + return 1; + } + else + { + if (++readTries == 1000) + { + Log::getInstance()->log("TCPOld", Log::ERR, "Too many reads"); + return 0; + } + } + } +} + +void TCPOld::dump(unsigned char* data, ULONG size) +{ + printf("Size = %lu\n", size); + + ULONG c = 0; + while(c < size) + { + if ((size - c) > 15) + { + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], data[c+15], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14]), dcc(data[c+15])); + c += 16; + } + else + { + switch (size - c) + { + case 15: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], data[c+14], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13]), dcc(data[c+14])); + c += 15; + break; + case 14: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], data[c+13], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12]), dcc(data[c+13])); + c += 14; + break; + case 13: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], data[c+12], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11]), dcc(data[c+12])); + c += 13; + break; + case 12: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], data[c+11], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10]), dcc(data[c+11])); + c += 12; + break; + case 11: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], data[c+10], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9]), dcc(data[c+10])); + c += 11; + break; + case 10: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], data[c+9], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8]), dcc(data[c+9])); + c += 10; + break; + case 9: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + data[c+8], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7]), + dcc(data[c+8])); + c += 9; + break; + case 8: + printf(" %02X %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], data[c+7], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6]), dcc(data[c+7])); + c += 8; + break; + case 7: + printf(" %02X %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], data[c+6], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5]), dcc(data[c+6])); + c += 7; + break; + case 6: + printf(" %02X %02X %02X %02X %02X %02X %c%c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], data[c+5], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4]), dcc(data[c+5])); + c += 6; + break; + case 5: + printf(" %02X %02X %02X %02X %02X %c%c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], data[c+4], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3]), dcc(data[c+4])); + c += 5; + break; + case 4: + printf(" %02X %02X %02X %02X %c%c%c%c\n", + data[c], data[c+1], data[c+2], data[c+3], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2]), dcc(data[c+3])); + c += 4; + break; + case 3: + printf(" %02X %02X %02X %c%c%c\n", + data[c], data[c+1], data[c+2], + dcc(data[c]), dcc(data[c+1]), dcc(data[c+2])); + c += 3; + break; + case 2: + printf(" %02X %02X %c%c\n", + data[c], data[c+1], + dcc(data[c]), dcc(data[c+1])); + c += 2; + break; + case 1: + printf(" %02X %c\n", + data[c], + dcc(data[c])); + c += 1; + break; + } + } + } +} + +UCHAR TCPOld::dcc(UCHAR c) +{ + if (isspace(c)) return ' '; + if (isprint(c)) return c; + return '.'; +} diff --git a/tcpold.h b/tcpold.h new file mode 100644 index 0000000..8ec34ea --- /dev/null +++ b/tcpold.h @@ -0,0 +1,79 @@ +/* + Copyright 2004-2005 Chris Tallon + Copyright 2003-2004 University Of Bradford + + This file is part of VOMP. + + VOMP is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + VOMP is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with VOMP; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifndef TCPOLD_H +#define TCPOLD_H + +#include +#include +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#include +#else +#include +#include +#include +#endif + +#include "defines.h" + +class TCPOld +{ + public: + TCPOld(); + ~TCPOld(); + + int connectTo(char *host, unsigned short port); + void assignSocket(int tsocket); + + int isConnected(); + void disableTimeout(); + + int readData(void* buffer, int totalBytes); + int sendData(void*, size_t size); + + static void dump(unsigned char* data, ULONG size); + + void getMAC(UCHAR* dest); // copies 6 MAC bytes to dest + void setReceiveWindow(size_t rxBufferSize); + + private: + int sock; + int connected; + int timeoutEnabled; + int dataLength; + std::mutex mutex; + + static UCHAR dcc(UCHAR c); +}; + +#endif diff --git a/vdr.cc b/vdr.cc index 958ef6f..d091482 100644 --- a/vdr.cc +++ b/vdr.cc @@ -20,7 +20,7 @@ #include "vdr.h" #include "recman.h" -#include "tcp.h" +#include "tcpold.h" #include "log.h" #include "recinfo.h" #include "channel.h" @@ -166,9 +166,9 @@ int VDR::connect() maxChannelNumber = 0; channelNumberWidth = 1; - if (tcp) delete tcp; - tcp = new TCP(); - if (tcp->connectTo(serverIP, serverPort)) + if (tcpold) delete tcpold; + tcpold = new TCPOld(); + if (tcpold->connectTo(serverIP, serverPort)) { connected = true; threadStart(); @@ -183,15 +183,15 @@ int VDR::connect() void VDR::disconnect() { threadCancel(); - if (tcp) delete tcp; - tcp = NULL; + if (tcpold) delete tcpold; + tcpold = NULL; connected = false; logger->log("VDR", Log::DEBUG, "Disconnect"); } void VDR::setReceiveWindow(size_t size) { - if (connected && size) tcp->setReceiveWindow(size); + if (connected && size) tcpold->setReceiveWindow(size); } /////////////////////////////////////////////////////// @@ -222,12 +222,12 @@ void VDR::threadMethod() { timeNow = time(NULL); - readSuccess = tcp->readData(&channelID, sizeof(ULONG)); // 2s timeout atm + readSuccess = tcpold->readData(&channelID, sizeof(ULONG)); // 2s timeout atm if (!readSuccess) { //logger->log("VDR", Log::DEBUG, "Net read timeout"); - if (!tcp->isConnected()) { connectionDied(); return; } // return to stop this thread + if (!tcpold->isConnected()) { connectionDied(); return; } // return to stop this thread } // Error or timeout. @@ -264,9 +264,9 @@ void VDR::threadMethod() if (channelID == CHANNEL_REQUEST_RESPONSE) { - if (!tcp->readData(&requestID, sizeof(ULONG))) break; + if (!tcpold->readData(&requestID, sizeof(ULONG))) break; requestID = ntohl(requestID); - if (!tcp->readData(&userDataLength, sizeof(ULONG))) break; + if (!tcpold->readData(&userDataLength, sizeof(ULONG))) break; userDataLength = ntohl(userDataLength); if (userDataLength > 5000000) break; // how big can these packets get? userData = NULL; @@ -274,7 +274,7 @@ void VDR::threadMethod() { userData = malloc(userDataLength); if (!userData) break; - if (!tcp->readData(userData, userDataLength)) break; + if (!tcpold->readData(userData, userDataLength)) break; } vresp = new VDR_ResponsePacket(); @@ -290,20 +290,20 @@ void VDR::threadMethod() } else if (channelID == CHANNEL_STREAM || channelID == CHANNEL_TVMEDIA) { - if (!tcp->readData(&streamID, sizeof(ULONG))) break; + if (!tcpold->readData(&streamID, sizeof(ULONG))) break; streamID = ntohl(streamID); - if (!tcp->readData(&flag, sizeof(ULONG))) break; + if (!tcpold->readData(&flag, sizeof(ULONG))) break; flag = ntohl(flag); - if (!tcp->readData(&userDataLength, sizeof(ULONG))) break; + if (!tcpold->readData(&userDataLength, sizeof(ULONG))) break; userDataLength = ntohl(userDataLength); userData = NULL; if (userDataLength > 0) { userData = malloc(userDataLength); if (!userData) break; - if (!tcp->readData(userData, userDataLength)) break; + if (!tcpold->readData(userData, userDataLength)) break; } vresp = new VDR_ResponsePacket(); @@ -320,7 +320,7 @@ void VDR::threadMethod() else if (channelID == CHANNEL_KEEPALIVE) { ULONG KAreply = 0; - if (!tcp->readData(&KAreply, sizeof(ULONG))) break; + if (!tcpold->readData(&KAreply, sizeof(ULONG))) break; KAreply = ntohl(KAreply); if (KAreply == lastKAsent) // successful KA response { @@ -460,7 +460,7 @@ VDR_ResponsePacket* VDR::RequestResponse(VDR_RequestPacket* vrp) edMutex.lock(); - if (static_cast(tcp->sendData(vrp->getPtr(), vrp->getLen())) != vrp->getLen()) + if (static_cast(tcpold->sendData(vrp->getPtr(), vrp->getLen())) != vrp->getLen()) { edMutex.unlock(); edUnregister(&vdrpr); @@ -495,7 +495,7 @@ bool VDR::sendKA(ULONG timeStamp) buffer[pos++]=(ul>>16)&0xff; buffer[pos++]=(ul>>8)&0xff; buffer[pos++]=ul &0xff; - if (static_cast(tcp->sendData(buffer, 8)) != 8) return false; + if (static_cast(tcpold->sendData(buffer, 8)) != 8) return false; return true; } @@ -558,7 +558,7 @@ int VDR::doLogin(unsigned int* v_server_min, unsigned int* v_server_max, unsigne if (!vrp.init(VDR_LOGIN, true, 6)) return 0; UCHAR mactemp[6]; - tcp->getMAC(mactemp); + tcpold->getMAC(mactemp); if (!vrp.copyin(mactemp, 6)) return 0; VDR_ResponsePacket* vresp = RequestResponse(&vrp); @@ -661,7 +661,7 @@ bool VDR::LogExtern(const char* logString) strcpy(&buffer[8], logString); - if (tcp->sendData(buffer, packetLength) != packetLength) + if (tcpold->sendData(buffer, packetLength) != packetLength) { connected = false; // stop the rest of the connection delete [] buffer; diff --git a/vdr.h b/vdr.h index 6e4dd30..af2e254 100644 --- a/vdr.h +++ b/vdr.h @@ -43,7 +43,7 @@ #include "log.h" #include "command.h" -class TCP; +class TCPOld; class Log; class RecInfo; class Event; @@ -233,7 +233,7 @@ public ExternLogger Log* logger; int initted{}; int findingServer{}; - TCP* tcp{}; + TCPOld* tcpold{}; char serverIP[40]; USHORT serverPort; bool connected{}; diff --git a/vdrresponsepacket.cc b/vdrresponsepacket.cc index 41ff522..26e2302 100644 --- a/vdrresponsepacket.cc +++ b/vdrresponsepacket.cc @@ -21,7 +21,6 @@ #include "vdrresponsepacket.h" #include "vdr.h" -#include "tcp.h" VDR_ResponsePacket::VDR_ResponsePacket() { @@ -69,7 +68,7 @@ bool VDR_ResponsePacket::end() void VDR_ResponsePacket::dumpUD() { - TCP::dump(userData, userDataLength); + // FIXME TODO - use generic stdout hex printer for userData, userDataLength } int VDR_ResponsePacket::serverError()