From 0e51267bc52437d3ae878c5d3beb6ad1e8be4276 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Mon, 30 Jan 2012 02:28:03 +0100 Subject: [PATCH] cec: added tcp client sockets to lib/platform --- project/libcec.vcxproj | 2 + project/libcec.vcxproj.filters | 6 ++ src/lib/platform/posix/os-tcp.h | 88 ++++++++++++++++++ src/lib/platform/posix/serialport.cpp | 4 +- src/lib/platform/sockets/serialport.h | 16 ++-- src/lib/platform/sockets/tcp.h | 96 ++++++++++++++++++++ src/lib/platform/windows/os-tcp.h | 123 ++++++++++++++++++++++++++ 7 files changed, 326 insertions(+), 9 deletions(-) create mode 100644 src/lib/platform/posix/os-tcp.h create mode 100644 src/lib/platform/sockets/tcp.h create mode 100644 src/lib/platform/windows/os-tcp.h diff --git a/project/libcec.vcxproj b/project/libcec.vcxproj index 29d5a77..9c4c896 100644 --- a/project/libcec.vcxproj +++ b/project/libcec.vcxproj @@ -41,6 +41,7 @@ + @@ -48,6 +49,7 @@ + diff --git a/project/libcec.vcxproj.filters b/project/libcec.vcxproj.filters index 636dafc..511d052 100644 --- a/project/libcec.vcxproj.filters +++ b/project/libcec.vcxproj.filters @@ -119,6 +119,12 @@ platform\util + + platform\sockets + + + platform\windows + diff --git a/src/lib/platform/posix/os-tcp.h b/src/lib/platform/posix/os-tcp.h new file mode 100644 index 0000000..df4a2a9 --- /dev/null +++ b/src/lib/platform/posix/os-tcp.h @@ -0,0 +1,88 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "../os.h" +#include "../sockets/socket.h" + +namespace PLATFORM +{ + inline int TcpGetSocketError(socket_t socket) + { + int iReturn(0); + socklen_t optLen = sizeof(socket_t); + getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)&iReturn, &optLen); + return iReturn; + } + + inline bool TcpSetNoDelay(socket_t socket) + { + int iSetTo(1); + setsockopt(socket, SOL_TCP, TCP_NODELAY, &iSetTo, sizeof(iSetTo)); + return true; + } + + inline bool TcpConnectSocket(socket_t socket, struct addrinfo* addr, int *iError, uint64_t iTimeout = 0) + { + bool bConnected = (connect(socket, addr->ai_addr, addr->ai_addrlen) == 0); + if (!bConnected && errno == EINPROGRESS) + { + struct pollfd pfd; + pfd.fd = socket; + pfd.events = POLLOUT; + pfd.revents = 0; + + int iPollResult = poll(&pfd, 1, iTimeout); + if (iPollResult == 0) + *iError = ETIMEDOUT; + else if (iPollResult == -1) + *iError = errno; + else + *iError = TcpGetSocketError(socket); + } + + return bConnected; + } + + inline bool TcpResolveAddress(const char *strHost, uint16_t iPort, int *iError, struct addrinfo *info) + { + struct addrinfo hints; + char service[33]; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + sprintf(service, "%d", iPort); + + return ((*iError = getaddrinfo(strHost, service, &hints, &info)) == 0); + } +} diff --git a/src/lib/platform/posix/serialport.cpp b/src/lib/platform/posix/serialport.cpp index 71405d4..4b3af9a 100644 --- a/src/lib/platform/posix/serialport.cpp +++ b/src/lib/platform/posix/serialport.cpp @@ -52,13 +52,13 @@ using namespace PLATFORM; CSerialPort::CSerialPort() { - m_tostdout = false; + m_bToStdOut = false; } //setting all this stuff up is a pain in the ass bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits /* = 8 */, uint8_t stopbits /* = 1 */, uint8_t parity /* = PAR_NONE */) { - m_name = name; + m_strName = name; CLockObject lock(m_mutex); if (databits < 5 || databits > 8) diff --git a/src/lib/platform/sockets/serialport.h b/src/lib/platform/sockets/serialport.h index bbe0136..c6cb595 100644 --- a/src/lib/platform/sockets/serialport.h +++ b/src/lib/platform/sockets/serialport.h @@ -60,23 +60,23 @@ namespace PLATFORM CStdString GetName(void) const { CStdString strName; - strName = m_name; + strName = m_strName; return strName; } - #ifdef __WINDOWS__ + #ifdef __WINDOWS__ virtual bool IsOpen(void); virtual void Close(void); virtual int64_t Write(uint8_t* data, uint32_t len); virtual int32_t Read(uint8_t* data, uint32_t len, uint64_t iTimeoutMs = 0); + #endif - private: - void FormatWindowsError(int iErrorCode, CStdString &strMessage); + private: bool SetBaudRate(uint32_t baudrate); - std::string m_name; - bool m_tostdout; - + private: + #ifdef __WINDOWS__ + void FormatWindowsError(int iErrorCode, CStdString &strMessage); bool SetTimeouts(bool bBlocking); HANDLE m_handle; @@ -91,5 +91,7 @@ namespace PLATFORM #else struct termios m_options; #endif + std::string m_strName; + bool m_bToStdOut; }; }; diff --git a/src/lib/platform/sockets/tcp.h b/src/lib/platform/sockets/tcp.h new file mode 100644 index 0000000..c69159a --- /dev/null +++ b/src/lib/platform/sockets/tcp.h @@ -0,0 +1,96 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "socket.h" + +#if defined(__WINDOWS__) +#include "../windows/os-tcp.h" +#else +#include "../posix/os-tcp.h" +#endif + +namespace PLATFORM +{ + class CTcpSocket : public CSocket + { + public: + CTcpSocket(void); + virtual ~CTcpSocket(void) {} + + virtual bool Open(const CStdString &strHostname, uint16_t iPort, uint64_t nTimeout) + { + bool bReturn(false); + struct addrinfo *address, *addr; + int iResult = TcpResolveAddress(strHostname, iPort, address); + if (iResult) + { + m_strError = strerror(iResult); + return bReturn; + } + + for(addr = address; !bReturn && addr; addr = addr->ai_next) + { + int iError(0); + m_socket = TcpCreateSocket(addr, &iError, nTimeout); + if (m_socket != INVALID_SOCKET && m_socket != SOCKET_ERROR) + bReturn = true; + else + m_strError = strerror(iError); + } + + freeaddrinfo(address); + return bReturn; + } + + protected: + virtual socket_t TcpCreateSocket(struct addrinfo* addr, int* iError, uint64_t iTimeout) + { + socket_t fdSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (fdSock == -1) + { + *iError = TcpGetSocketError(); + return (socket_t)SOCKET_ERROR; + } + + if (TcpConnectSocket(addr, fdSock, iError, iTimeout) != 0) + { + closesocket(fdSock); + return (socket_t)SOCKET_ERROR; + } + + TcpSetNoDelay(fdSock); + + return fdSock; + } + }; +}; diff --git a/src/lib/platform/windows/os-tcp.h b/src/lib/platform/windows/os-tcp.h new file mode 100644 index 0000000..f16cb69 --- /dev/null +++ b/src/lib/platform/windows/os-tcp.h @@ -0,0 +1,123 @@ +#pragma once +/* + * This file is part of the libCEC(R) library. + * + * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved. + * libCEC(R) is an original work, containing original code. + * + * libCEC(R) is a trademark of Pulse-Eight Limited. + * + * This program is dual-licensed; 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. + * + * This program 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 this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * + * Alternatively, you can license this library under a commercial license, + * please contact Pulse-Eight Licensing for more information. + * + * For more information contact: + * Pulse-Eight Licensing + * http://www.pulse-eight.com/ + * http://www.pulse-eight.net/ + */ + +#include "../os.h" +#include "../sockets/socket.h" + +namespace PLATFORM +{ + inline int TcpResolveAddress(const CStdString &strHostname, uint16_t iPort, struct addrinfo *address) + { + struct addrinfo hints; + char service[33]; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + sprintf(service, "%d", iPort); + + return getaddrinfo(strHostname.c_str(), service, &hints, &address); + } + + inline int TcpGetSocketError() + { + int error = WSAGetLastError(); + switch(error) + { + case WSAEINPROGRESS: return EINPROGRESS; + case WSAECONNRESET : return ECONNRESET; + case WSAETIMEDOUT : return ETIMEDOUT; + case WSAEWOULDBLOCK: return EAGAIN; + default : return error; + } + } + + inline int TcpConnectSocket(struct addrinfo* addr, socket_t socket, int *iError, uint64_t iTimeout) + { + int nRes = 0; + socklen_t errlen = sizeof(int); + + SocketSetBlocking(socket, false); + + /* connect to the other side */ + nRes = connect(socket, addr->ai_addr, addr->ai_addrlen); + + /* poll until a connection is established */ + if (nRes == -1) + { + if (TcpGetSocketError() == EINPROGRESS || TcpGetSocketError() == EAGAIN) + { + fd_set fd_write, fd_except; + struct timeval tv; + tv.tv_sec = (long)(iTimeout / 1000); + tv.tv_usec = (long)(1000 * (iTimeout % 1000)); + + FD_ZERO(&fd_write); + FD_ZERO(&fd_except); + FD_SET(socket, &fd_write); + FD_SET(socket, &fd_except); + + nRes = select(sizeof(socket)*8, NULL, &fd_write, &fd_except, &tv); + if (nRes == 0) + { + *iError = ETIMEDOUT; + return SOCKET_ERROR; + } + else if (nRes == -1) + { + *iError = TcpGetSocketError(); + return SOCKET_ERROR; + } + + /* check for errors */ + getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)iError, &errlen); + } + else + { + *iError = TcpGetSocketError(); + } + } + + SocketSetBlocking(socket, true); + + return 0; + } + + inline bool TcpSetNoDelay(socket_t socket) + { + int nVal = 1; + setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&nVal, sizeof(nVal)); + return true; + } +} -- 2.34.1