diff options
Diffstat (limited to 'src/TcpSocket.cpp')
-rw-r--r-- | src/TcpSocket.cpp | 366 |
1 files changed, 366 insertions, 0 deletions
diff --git a/src/TcpSocket.cpp b/src/TcpSocket.cpp new file mode 100644 index 0000000..723d06b --- /dev/null +++ b/src/TcpSocket.cpp @@ -0,0 +1,366 @@ +/* + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Her Majesty the Queen in + Right of Canada (Communications Research Center Canada) + */ +/* + This file is part of CRC-DabMux. + + CRC-DabMux 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 3 of the + License, or (at your option) any later version. + + CRC-DabMux 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 CRC-DabMux. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "TcpSocket.h" +#include <iostream> +#include <stdio.h> +#include <errno.h> +#include <string.h> +#include <signal.h> + +#ifdef _WIN32 +#else +# include <unistd.h> +#endif + +#ifdef TRACE_ON +# ifndef TRACE_CLASS +# define TRACE_CLASS(class, func) cout <<"-" <<(class) <<"\t(" <<this <<")::" <<(func) <<endl +# define TRACE_STATIC(class, func) cout <<"-" <<(class) <<"\t(static)::" <<(func) <<endl +# endif +#else +# ifndef TRACE_CLASS +# define TRACE_CLASS(class, func) +# define TRACE_STATIC(class, func) +# endif +#endif + + +/// Must be call once before doing any operation on sockets +int TcpSocket::init() +{ +#ifdef _WIN32 + WSADATA wsaData; + WORD wVersionRequested = wVersionRequested = MAKEWORD( 2, 2 ); + + int res = WSAStartup( wVersionRequested, &wsaData ); + if (res) { + setInetError("Can't initialize winsock"); + return -1; + } +#endif + return 0; +} + + +/// Must be call once before leaving application +int TcpSocket::clean() +{ +#ifdef _WIN32 + int res = WSACleanup(); + if (res) { + setInetError("Can't initialize winsock"); + return -1; + } +#endif + return 0; +} + + +/** + * Two step constructor. Create must be called prior to use this + * socket. + */ +TcpSocket::TcpSocket() : + listenSocket(INVALID_SOCKET) +{ + TRACE_CLASS("TcpSocket", "TcpSocket()"); +} + + +/** + * One step constructor. + * @param port The port number on which the socket will be bind + * @param name The IP address on which the socket will be bind. + * It is used to bind the socket on a specific interface if + * the computer have many NICs. + */ +TcpSocket::TcpSocket(int port, char *name) : + listenSocket(INVALID_SOCKET) +{ + TRACE_CLASS("TcpSocket", "TcpSocket(int, char*)"); + create(port, name); +} + + +/** + * Close the underlying socket. + * @return 0 if ok + * -1 if error + */ +int TcpSocket::close() +{ + TRACE_CLASS("TcpSocket", "close()"); + if (listenSocket != INVALID_SOCKET) { + int res = closesocket(listenSocket); + if (res != 0) { + setInetError("Can't close socket"); + return -1; + } + listenSocket = INVALID_SOCKET; + } + return 0; +} + + +/** + * Two step initializer. This function must be called after the constructor + * without argument as been called. + * @param port The port number on which the socket will be bind + * @param name The IP address on which the socket will be bind. + * It is used to bind the socket on a specific interface if + * the computer have many NICs. + * @return 0 if ok + * -1 if error + */ +int TcpSocket::create(int port, char *name) +{ + TRACE_CLASS("TcpSocket", "create(int, char*)"); + if (listenSocket != INVALID_SOCKET) + closesocket(listenSocket); + address.setAddress(name); + address.setPort(port); + if ((listenSocket = socket(PF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + setInetError("Can't create socket"); + return -1; + } + reuseopt_t reuse = 1; + if (setsockopt(listenSocket, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) + == SOCKET_ERROR) { + setInetError("Can't reuse address"); + return -1; + } + if (bind(listenSocket, address.getAddress(), sizeof(sockaddr_in)) == SOCKET_ERROR) { + setInetError("Can't bind socket"); + closesocket(listenSocket); + listenSocket = INVALID_SOCKET; + return -1; + } + return 0; +} + + +/// Destructor +TcpSocket::~TcpSocket() { + TRACE_CLASS("TcpSocket", "~TcpSocket()"); + close(); +} + + +/** + * Receive an telnet packet, i.e a TCP stream ending with carriage return. + * @param data The buffer that will receive data. + * @param size The buffer size. + * @return > 0 if ok, -1 (SOCKET_ERROR) if error + */ +int TcpSocket::telnetRead(void* data, int size) +{ + TRACE_CLASS("TcpSocket", "read(void*, size)"); + int ret; + + printf("selectCall\n"); + + printf("readread 1\n"); + char *line=GetLine(listenSocket); + ret=strlen(line); + printf("readread 2\n"); + if (ret <= size) + { + strcpy((char*)data, line); + } + else + { +// size_t n = size; + strcpy((char*)data, line); + ret = size; + } + printf("TELNET READ returned %d\n", ret); + return ret; +} + +/** + * Receive a TCP stream. + * @param data The buffer that will receive data. + * @param size The buffer size. + * @return > 0 if ok, -1 (SOCKET_ERROR) if error + */ +int TcpSocket::read(void* data, int size) +{ + TRACE_CLASS("TcpSocket", "read(void*, size)"); + + int ret = recv(listenSocket, (char*)data, size, 0); + if (ret == SOCKET_ERROR) { + setInetError("Can't receive TCP packet"); + return -1; + } + return ret; +} + + +#define MAX 512 +char* TcpSocket::GetLine(int fd) +{ + static char line[MAX]; + static char netread[MAX] = ""; + int n, len; + char *p; + + len = strlen(netread); + + /* look for \r\n in netread buffer */ + p = strstr(netread, "\r\n"); + if (p == NULL) { + /* fill buff - no \r\n found */ + //n = ::read(fd, (void*)(netread+len), (size_t)(MAX-len)); + n = recv(fd, (netread+len), MAX-len, 0); + if (n == SOCKET_ERROR) { + setInetError("Can't receive TCP packet"); + return NULL; + } + len += n; + netread[len] = '\0'; + if (n>0) + return GetLine(fd); + } + if (p!=NULL) + { + *p = '\0'; + strcpy(line, netread); + /* copy rest of buf down */ + memmove(netread, p+2, strlen(p+2)+1); + } + return line; +} + + +/** + * Send an TCP packet. + * @param data The buffer taht will be sent. + * @param size Number of bytes to send. + * return 0 if ok, -1 if error + */ +int TcpSocket::write(const void* data, int size) +{ +#ifdef DUMP + TRACE_CLASS("TcpSocket", "write(const void*, int)"); +#endif + + // ignore BROKENPIPE signal (we handle it instead) +// void* old_sigpipe = signal ( SIGPIPE, SIG_IGN ); + // try to send data + int ret = send(listenSocket, (char*)data, size, 0 /*MSG_NOSIGNAL*/ ); + // restore the BROKENPIPE handling +// signal ( SIGPIPE, (__sighandler_t)old_sigpipe ); + if (ret == SOCKET_ERROR) { + setInetError("Can't send TCP packet"); + return -1; + } + return ret; +} + + +int TcpSocket::setDestination(InetAddress &addr) +{ + address = addr; + int ret = connect(listenSocket, addr.getAddress(), sizeof(*addr.getAddress())); + // A etre verifier: code de retour differend entre Linux et Windows + return ret; +} + + +void TcpSocket::setSocket(SOCKET socket, InetAddress &addr) +{ + if (listenSocket != INVALID_SOCKET) + closesocket(listenSocket); + listenSocket = socket; + address = addr; +} + + +InetAddress TcpSocket::getAddress() +{ + return address; +} + + +int TcpSocket::PeekCount() +{ + int count; + char tempBuffer[3]; + int size=3; + + count = recv(listenSocket, tempBuffer, size, MSG_PEEK); + if (count == -1) + { + printf("ERROR WHEN PEEKING SOCKET\n"); + } + return count; +} + +/* +WSAEINTR +WSAEBADF +WSAEACCES +WSAEFAULT +WSAEINVAL +WSAEMFILE +WSAEWOULDBLOCK +WSAEINPROGRESS +WSAEALREADY +WSAENOTSOCK +WSAEDESTADDRREQ +WSAEMSGSIZE +WSAEPROTOTYPE +WSAENOPROTOOPT +WSAEPROTONOSUPPORT +WSAESOCKTNOSUPPORT +WSAEOPNOTSUPP +WSAEPFNOSUPPORT +WSAEAFNOSUPPORT +WSAEADDRINUSE +WSAEADDRNOTAVAIL +WSAENETDOWN +WSAENETUNREACH +WSAENETRESET +WSAECONNABORTED +WSAECONNRESET +WSAENOBUFS +WSAEISCONN +WSAENOTCONN +WSAESHUTDOWN +WSAETOOMANYREFS +WSAETIMEDOUT +WSAECONNREFUSED +WSAELOOP +WSAENAMETOOLONG +WSAEHOSTDOWN +WSAEHOSTUNREACH +WSAENOTEMPTY +WSAEPROCLIM +WSAEUSERS +WSAEDQUOT +WSAESTALE +WSAEREMOTE +WSAEDISCON +WSASYSNOTREADY +WSAVERNOTSUPPORTED +WSANOTINITIALISED +*/ |