From 996665192725398172263999b88c63663d11db04 Mon Sep 17 00:00:00 2001 From: Lars Op den Kamp Date: Tue, 31 Jan 2012 02:33:42 +0100 Subject: [PATCH] cec: clean up lib/platform --- project/libcec.vcxproj | 2 +- project/libcec.vcxproj.filters | 74 +++--- project/testclient.vcxproj | 8 - project/testclient.vcxproj.filters | 30 --- src/lib/CECProcessor.cpp | 14 +- src/lib/adapter/AdapterCommunication.cpp | 28 +-- src/lib/adapter/AdapterCommunication.h | 10 +- src/lib/implementations/CECCommandHandler.cpp | 2 +- src/lib/platform/posix/os-socket.h | 192 +++++++++++++-- src/lib/platform/posix/os-tcp.h | 105 -------- src/lib/platform/posix/os-types.h | 7 +- src/lib/platform/posix/serialport.cpp | 64 +++-- src/lib/platform/sockets/serialport.h | 92 ++++--- src/lib/platform/sockets/socket.h | 216 ++++++++++++---- src/lib/platform/sockets/tcp.h | 86 ++++--- src/lib/platform/windows/os-socket.h | 231 +++++++++++++----- src/lib/platform/windows/os-tcp.h | 128 ---------- src/lib/platform/windows/os-types.h | 14 +- src/lib/platform/windows/serialport.cpp | 186 +++++--------- 19 files changed, 818 insertions(+), 671 deletions(-) delete mode 100644 src/lib/platform/posix/os-tcp.h delete mode 100644 src/lib/platform/windows/os-tcp.h diff --git a/project/libcec.vcxproj b/project/libcec.vcxproj index 9c4c896..d667d14 100644 --- a/project/libcec.vcxproj +++ b/project/libcec.vcxproj @@ -49,9 +49,9 @@ - + diff --git a/project/libcec.vcxproj.filters b/project/libcec.vcxproj.filters index 511d052..3786504 100644 --- a/project/libcec.vcxproj.filters +++ b/project/libcec.vcxproj.filters @@ -1,9 +1,6 @@  - - {cc48ddc0-be11-43ec-a805-3a9434f443ed} - {01b9c84a-dcfe-4bdc-b983-69e3e3929b0f} @@ -13,20 +10,23 @@ {bfc43a58-636d-4c1a-b191-486cb8509c7c} - - {fa3d5953-d288-45e9-93f4-8419e6b701c7} - - - {38a27e9e-86ad-46f6-a4fb-e1e524267b74} - {51614b77-8a0e-47a8-8500-5beb0fd12d49} - - {4e963de7-5c42-40a0-9c81-bb112d5a24f9} + + {7d05b1b5-e728-4f9e-b78f-d63cac4ded8e} - {e3945145-efa2-4393-b201-f50e1e775008} + {6cfe4bad-ed3a-4a16-8c59-4489089f5fe5} + + + {39a56ebf-ba93-4e7b-bf72-2f57b99a1ee1} + + + {be183456-d61e-4283-b642-fe25ed71e9c5} + + + {65c4a590-4577-40e4-91ad-339e20b99ebe} @@ -74,21 +74,6 @@ devices - - platform - - - platform\windows - - - platform\windows - - - platform\threads - - - platform\threads - adapter @@ -98,31 +83,46 @@ adapter - + + platform + + + platform\sockets + + + platform\sockets + + + platform\sockets + + platform\util platform\util + + platform\util + platform\util - - platform\sockets + + platform\threads - - platform\sockets + + platform\threads platform\windows - - platform\util + + platform\windows - - platform\sockets + + platform\windows - + platform\windows diff --git a/project/testclient.vcxproj b/project/testclient.vcxproj index 0db6eb2..fb19572 100644 --- a/project/testclient.vcxproj +++ b/project/testclient.vcxproj @@ -168,16 +168,8 @@ - - - - - - - - diff --git a/project/testclient.vcxproj.filters b/project/testclient.vcxproj.filters index 45e1fe0..70acf3d 100644 --- a/project/testclient.vcxproj.filters +++ b/project/testclient.vcxproj.filters @@ -7,12 +7,6 @@ {f08c0a80-22d9-4bdd-90de-b9cf5fa88f99} - - {fb28e188-b2a5-48d3-9010-b56024b19850} - - - {a8b22b54-3252-44fb-a499-e42f9bac0e15} - @@ -21,33 +15,9 @@ exports - - platform - - - platform - - - platform\windows - - - platform\windows - - - platform\windows - - - platform\threads - - - platform\threads - - - platform\windows - diff --git a/src/lib/CECProcessor.cpp b/src/lib/CECProcessor.cpp index b54426c..6faf72c 100644 --- a/src/lib/CECProcessor.cpp +++ b/src/lib/CECProcessor.cpp @@ -54,13 +54,13 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, cec m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE), m_lastInitiator(CECDEVICE_UNKNOWN), m_strDeviceName(strDeviceName), + m_communication(NULL), m_controller(controller), m_bMonitor(false), m_iStandardLineTimeout(3), m_iRetryLineTimeout(3), m_iLastTransmission(0) { - m_communication = new CAdapterCommunication(this); m_logicalAddresses.Clear(); m_logicalAddresses.Set(iLogicalAddress); m_types.clear(); @@ -75,13 +75,13 @@ CCECProcessor::CCECProcessor(CLibCEC *controller, const char *strDeviceName, con m_iBaseDevice((cec_logical_address)CEC_DEFAULT_BASE_DEVICE), m_strDeviceName(strDeviceName), m_types(types), + m_communication(NULL), m_controller(controller), m_bMonitor(false), m_iStandardLineTimeout(3), m_iRetryLineTimeout(3), m_iLastTransmission(0) { - m_communication = new CAdapterCommunication(this); m_logicalAddresses.Clear(); for (int iPtr = 0; iPtr < 16; iPtr++) { @@ -133,12 +133,14 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint { bool bReturn(false); CLockObject lock(m_mutex); - if (!m_communication) + if (m_communication) { - CLibCEC::AddLog(CEC_LOG_ERROR, "no connection handler found"); + CLibCEC::AddLog(CEC_LOG_ERROR, "existing connection handler found"); return bReturn; } + m_communication = new CAdapterCommunication(this, strPort, iBaudRate); + /* check for an already opened connection */ if (m_communication->IsOpen()) { @@ -152,7 +154,7 @@ bool CCECProcessor::OpenConnection(const char *strPort, uint16_t iBaudRate, uint bool bConnected(false), bPinged(false); /* open a new connection */ - while (iNow < iTarget && (bConnected = m_communication->Open(strPort, iBaudRate, iTimeoutMs)) == false) + while (iNow < iTarget && (bConnected = m_communication->Open(iTimeoutMs)) == false) { CLibCEC::AddLog(CEC_LOG_ERROR, "could not open a connection (try %d)", ++iConnectTry); Sleep(500); @@ -423,9 +425,7 @@ void *CCECProcessor::Process(void) { CLockObject lock(m_mutex); if (m_commandBuffer.Pop(command)) - { bParseFrame = true; - } else if (m_communication->IsOpen() && m_communication->Read(msg, 50)) { if ((bParseFrame = (ParseMessage(msg) && !IsStopped())) == true) diff --git a/src/lib/adapter/AdapterCommunication.cpp b/src/lib/adapter/AdapterCommunication.cpp index cd112c2..c0f9ea1 100644 --- a/src/lib/adapter/AdapterCommunication.cpp +++ b/src/lib/adapter/AdapterCommunication.cpp @@ -42,13 +42,13 @@ using namespace std; using namespace CEC; using namespace PLATFORM; -CAdapterCommunication::CAdapterCommunication(CCECProcessor *processor) : +CAdapterCommunication::CAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate /* = 38400 */) : m_port(NULL), m_processor(processor), m_iLineTimeout(0), m_iFirmwareVersion(CEC_FW_VERSION_UNKNOWN) { - m_port = new PLATFORM::CSerialPort; + m_port = new PLATFORM::CSerialPort(strPort, iBaudRate); } CAdapterCommunication::~CAdapterCommunication(void) @@ -62,7 +62,7 @@ CAdapterCommunication::~CAdapterCommunication(void) } } -bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38400 */, uint32_t iTimeoutMs /* = 10000 */) +bool CAdapterCommunication::Open(uint32_t iTimeoutMs /* = 10000 */) { uint64_t iNow = GetTimeMs(); uint64_t iTimeout = iNow + iTimeoutMs; @@ -85,9 +85,9 @@ bool CAdapterCommunication::Open(const char *strPort, uint16_t iBaudRate /* = 38 bool bConnected(false); while (!bConnected && iNow < iTimeout) { - if ((bConnected = m_port->Open(strPort, iBaudRate)) == false) + if ((bConnected = m_port->Open(iTimeout)) == false) { - strError.Format("error opening serial port '%s': %s", strPort, m_port->GetError().c_str()); + strError.Format("error opening serial port '%s': %s", m_port->GetName().c_str(), m_port->GetError().c_str()); Sleep(250); iNow = GetTimeMs(); } @@ -439,10 +439,10 @@ bool CAdapterCommunication::WaitForAck(CCECAdapterMessage &message) return bTransmitSucceeded && !bError; } -void CAdapterCommunication::AddData(uint8_t *data, uint8_t iLen) +void CAdapterCommunication::AddData(uint8_t *data, size_t iLen) { CLockObject lock(m_mutex); - for (uint8_t iPtr = 0; iPtr < iLen; iPtr++) + for (size_t iPtr = 0; iPtr < iLen; iPtr++) m_inBuffer.Push(data[iPtr]); m_rcvCondition.Signal(); @@ -450,8 +450,8 @@ void CAdapterCommunication::AddData(uint8_t *data, uint8_t iLen) bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout) { - int32_t iBytesRead; - uint8_t buff[1024]; + ssize_t iBytesRead; + uint8_t buff[256]; if (!m_port) return false; @@ -459,13 +459,13 @@ bool CAdapterCommunication::ReadFromDevice(uint32_t iTimeout) iBytesRead = m_port->Read(buff, sizeof(buff), iTimeout); if (iBytesRead < 0 || iBytesRead > 256) { - CStdString strError; - strError.Format("error reading from serial port: %s", m_port->GetError().c_str()); - CLibCEC::AddLog(CEC_LOG_ERROR, strError); + CLibCEC::AddLog(CEC_LOG_ERROR, "error reading from serial port: %s", m_port->GetError().c_str()); return false; } else if (iBytesRead > 0) - AddData(buff, (uint8_t) iBytesRead); + { + AddData(buff, iBytesRead); + } return iBytesRead > 0; } @@ -474,7 +474,7 @@ void CAdapterCommunication::SendMessageToAdapter(CCECAdapterMessage *msg) { CLockObject adapterLock(m_mutex); CLockObject lock(msg->mutex); - if (m_port->Write(msg->packet.data, msg->Size()) != (int32_t) msg->Size()) + if (m_port->Write(msg->packet.data, msg->Size()) != (ssize_t) msg->Size()) { CStdString strError; strError.Format("error writing to serial port: %s", m_port->GetError().c_str()); diff --git a/src/lib/adapter/AdapterCommunication.h b/src/lib/adapter/AdapterCommunication.h index e8dab2a..54f30ce 100644 --- a/src/lib/adapter/AdapterCommunication.h +++ b/src/lib/adapter/AdapterCommunication.h @@ -38,7 +38,7 @@ namespace PLATFORM { - class CSerialPort; + class ISocket; } namespace CEC @@ -49,10 +49,10 @@ namespace CEC class CAdapterCommunication : private PLATFORM::CThread { public: - CAdapterCommunication(CCECProcessor *processor); + CAdapterCommunication(CCECProcessor *processor, const char *strPort, uint16_t iBaudRate = 38400); virtual ~CAdapterCommunication(); - bool Open(const char *strPort, uint16_t iBaudRate = 38400, uint32_t iTimeoutMs = 10000); + bool Open(uint32_t iTimeoutMs = 10000); bool Read(CCECAdapterMessage &msg, uint32_t iTimeout = 1000); bool Write(CCECAdapterMessage *data); void Close(void); @@ -72,10 +72,10 @@ namespace CEC private: void SendMessageToAdapter(CCECAdapterMessage *msg); void WriteNextCommand(void); - void AddData(uint8_t *data, uint8_t iLen); + void AddData(uint8_t *data, size_t iLen); bool ReadFromDevice(uint32_t iTimeout); - PLATFORM::CSerialPort * m_port; + PLATFORM::ISocket * m_port; CCECProcessor * m_processor; PLATFORM::SyncedBuffer m_inBuffer; PLATFORM::SyncedBuffer m_outBuffer; diff --git a/src/lib/implementations/CECCommandHandler.cpp b/src/lib/implementations/CECCommandHandler.cpp index 5fe3eba..331315d 100644 --- a/src/lib/implementations/CECCommandHandler.cpp +++ b/src/lib/implementations/CECCommandHandler.cpp @@ -959,7 +959,7 @@ bool CCECCommandHandler::Transmit(cec_command &command, bool bExpectResponse /* while (!bReturn && ++iTries <= iMaxTries) { m_expectedResponse = expectedResponse; - if ((bReturn = m_processor->Transmit(command))) + if ((bReturn = m_processor->Transmit(command)) == true) { CLibCEC::AddLog(CEC_LOG_DEBUG, "command transmitted"); if (bExpectResponse) diff --git a/src/lib/platform/posix/os-socket.h b/src/lib/platform/posix/os-socket.h index 9d557c1..468cc3d 100644 --- a/src/lib/platform/posix/os-socket.h +++ b/src/lib/platform/posix/os-socket.h @@ -36,37 +36,48 @@ #include "../util/timeutils.h" #include #include +#include +#include +#include +#include +#include +#include namespace PLATFORM { + // Standard sockets + //@{ inline void SocketClose(socket_t socket) { - if (socket != INVALID_SOCKET) + if (socket != INVALID_SOCKET_VALUE) close(socket); } inline void SocketSetBlocking(socket_t socket, bool bSetTo) { -// return bSetTo ? -// fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK) == 0 : -// fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK) == 0; - fcntl(socket, F_SETFL, bSetTo ? FNDELAY : 0); + if (socket != INVALID_SOCKET_VALUE) + { + if (bSetTo) + fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) & ~O_NONBLOCK); + else + fcntl(socket, F_SETFL, fcntl(socket, F_GETFL) | O_NONBLOCK); + } } - inline int64_t SocketWrite(socket_t socket, int *iError, uint8_t* data, uint32_t len) + inline ssize_t SocketWrite(socket_t socket, int *iError, void* data, size_t len) { fd_set port; - if (socket == -1) + if (socket == INVALID_SOCKET_VALUE) { *iError = EINVAL; return -1; } - int64_t iBytesWritten = 0; + ssize_t iBytesWritten(0); struct timeval *tv(NULL); - while (iBytesWritten < len) + while (iBytesWritten < (ssize_t)len) { FD_ZERO(&port); FD_SET(socket, &port); @@ -82,7 +93,7 @@ namespace PLATFORM return -1; } - returnv = write(socket, data + iBytesWritten, len - iBytesWritten); + returnv = write(socket, (char*)data + iBytesWritten, len - iBytesWritten); if (returnv == -1) { *iError = errno; @@ -94,15 +105,15 @@ namespace PLATFORM return iBytesWritten; } - inline int32_t SocketRead(socket_t socket, int *iError, uint8_t* data, uint32_t len, uint64_t iTimeoutMs /*= 0*/) + inline ssize_t SocketRead(socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/) { fd_set port; struct timeval timeout, *tv; int64_t iNow(0), iTarget(0); - int32_t iBytesRead = 0; + ssize_t iBytesRead(0); *iError = 0; - if (socket == -1) + if (socket == INVALID_SOCKET_VALUE) { *iError = EINVAL; return -1; @@ -114,7 +125,7 @@ namespace PLATFORM iTarget = iNow + (int64_t) iTimeoutMs; } - while (iBytesRead < (int32_t) len && (iTimeoutMs == 0 || iTarget > iNow)) + while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow)) { if (iTimeoutMs == 0) { @@ -141,7 +152,7 @@ namespace PLATFORM break; //nothing to read } - returnv = read(socket, data + iBytesRead, len - iBytesRead); + returnv = read(socket, (char*)data + iBytesRead, len - iBytesRead); if (returnv == -1) { *iError = errno; @@ -156,4 +167,155 @@ namespace PLATFORM return iBytesRead; } + //@} + + // TCP + //@{ + inline void TcpSocketClose(tcp_socket_t socket) + { + SocketClose(socket); + } + + inline void TcpSocketShutdown(tcp_socket_t socket) + { + if (socket != INVALID_SOCKET_VALUE) + shutdown(socket, SHUT_RDWR); + } + + inline ssize_t TcpSocketWrite(tcp_socket_t socket, int *iError, void* data, size_t len) + { + if (socket == INVALID_SOCKET_VALUE) + { + *iError = EINVAL; + return -1; + } + + ssize_t iReturn = send(socket, data, len, 0); + if (iReturn < (ssize_t)len) + *iError = errno; + return iReturn; + } + + inline ssize_t TcpSocketRead(tcp_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/) + { + int64_t iNow(0), iTarget(0); + ssize_t iBytesRead(0); + *iError = 0; + + if (socket == INVALID_SOCKET_VALUE) + { + *iError = EINVAL; + return -1; + } + + if (iTimeoutMs > 0) + { + iNow = GetTimeMs(); + iTarget = iNow + (int64_t) iTimeoutMs; + } + + struct pollfd fds; + fds.fd = socket; + fds.events = POLLIN; + fds.revents = 0; + + while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow)) + { + if (iTimeoutMs > 0) + { + int iPollResult = poll(&fds, 1, iTarget - iNow); + if (iPollResult == 0) + { + *iError = ETIMEDOUT; + return -ETIMEDOUT; + } + } + + ssize_t iReadResult = (iTimeoutMs > 0) ? + recv(socket, (char*)data + iBytesRead, len - iBytesRead, MSG_DONTWAIT) : + recv(socket, data, len, MSG_WAITALL); + if (iReadResult < 0) + { + if (errno == EAGAIN && iTimeoutMs > 0) + continue; + *iError = errno; + return -errno; + } + else if (iReadResult == 0 || (iReadResult != (ssize_t)len && iTimeoutMs == 0)) + { + *iError = ECONNRESET; + return -ECONNRESET; + } + + iBytesRead += iReadResult; + + if (iTimeoutMs > 0) + iNow = GetTimeMs(); + } + + if (iBytesRead < (ssize_t)len) + *iError = ETIMEDOUT; + return iBytesRead; + } + + 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); + + *iError = getaddrinfo(strHost, service, &hints, info); + return !(*iError); + } + + inline int TcpGetSocketError(tcp_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(tcp_socket_t socket) + { + int iSetTo(1); + setsockopt(socket, SOL_TCP, TCP_NODELAY, &iSetTo, sizeof(iSetTo)); + return true; + } + + inline bool TcpConnectSocket(tcp_socket_t socket, struct addrinfo* addr, int *iError, uint64_t iTimeout = 0) + { + *iError = 0; + int iConnectResult = connect(socket, addr->ai_addr, addr->ai_addrlen); + if (iConnectResult == -1) + { + if (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; + + socklen_t errlen = sizeof(int); + getsockopt(socket, SOL_SOCKET, SO_ERROR, (void *)iError, &errlen); + } + else + { + *iError = errno; + } + } + + return *iError == 0; + } + //@} } diff --git a/src/lib/platform/posix/os-tcp.h b/src/lib/platform/posix/os-tcp.h deleted file mode 100644 index 86d0603..0000000 --- a/src/lib/platform/posix/os-tcp.h +++ /dev/null @@ -1,105 +0,0 @@ -#pragma once -/* - * This file is part of the libCEC(R) library. - * - * libCEC(R) is Copyright (C) 2011-2012 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" - -#include -#include -#include -#include -#include -#include - -namespace PLATFORM -{ - inline void TcpShutdownSocket(socket_t socket) - { - shutdown(socket, SHUT_RDWR); - } - - 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 - bConnected = true; - } - else - { - *iError = errno; - } - - 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); - - *iError = getaddrinfo(strHost, service, &hints, info); - return !(*iError); - } -} diff --git a/src/lib/platform/posix/os-types.h b/src/lib/platform/posix/os-types.h index 2b6c50f..631e965 100644 --- a/src/lib/platform/posix/os-types.h +++ b/src/lib/platform/posix/os-types.h @@ -47,6 +47,7 @@ #define DECLSPEC typedef int socket_t; -#define INVALID_SOCKET (-1) -#define SOCKET_ERROR (-1) - +typedef socket_t tcp_socket_t; +#define INVALID_SOCKET_VALUE (-1) +typedef socket_t serial_socket_t; +#define INVALID_SERIAL_SOCKET_VALUE (-1) diff --git a/src/lib/platform/posix/serialport.cpp b/src/lib/platform/posix/serialport.cpp index 7af3d0e..5557064 100644 --- a/src/lib/platform/posix/serialport.cpp +++ b/src/lib/platform/posix/serialport.cpp @@ -35,6 +35,7 @@ #include #include "../sockets/serialport.h" #include "../util/baudrate.h" +#include "../posix/os-socket.h" #if defined(__APPLE__) #ifndef XCASE @@ -50,38 +51,54 @@ using namespace std; using namespace PLATFORM; -CSerialPort::CSerialPort() +void CSerialSocket::Close(void) { - m_bToStdOut = false; + SocketClose(m_socket); +} + +void CSerialSocket::Shutdown(void) +{ + SocketClose(m_socket); +} + +ssize_t CSerialSocket::Write(void* data, size_t len) +{ + return SocketWrite(m_socket, &m_iError, data, len); +} + +ssize_t CSerialSocket::Read(void* data, size_t len, uint64_t iTimeoutMs /* = 0 */) +{ + return SocketRead(m_socket, &m_iError, data, len, iTimeoutMs); } //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 */) +bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */) { - m_strName = name; + iTimeoutMs = 0; CLockObject lock(m_mutex); - if (databits < 5 || databits > 8) + if (m_iDatabits != SERIAL_DATA_BITS_FIVE && m_iDatabits != SERIAL_DATA_BITS_SIX && + m_iDatabits != SERIAL_DATA_BITS_SEVEN && m_iDatabits != SERIAL_DATA_BITS_EIGHT) { m_strError = "Databits has to be between 5 and 8"; return false; } - if (stopbits != 1 && stopbits != 2) + if (m_iStopbits != SERIAL_STOP_BITS_ONE && m_iStopbits != SERIAL_STOP_BITS_TWO) { m_strError = "Stopbits has to be 1 or 2"; return false; } - if (parity != PAR_NONE && parity != PAR_EVEN && parity != PAR_ODD) + if (m_iParity != SERIAL_PARITY_NONE && m_iParity != SERIAL_PARITY_EVEN && m_iParity != SERIAL_PARITY_ODD) { m_strError = "Parity has to be none, even or odd"; return false; } - m_socket = open(name.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); + m_socket = open(m_strName.c_str(), O_RDWR | O_NOCTTY | O_NDELAY); - if (m_socket == INVALID_SOCKET) + if (m_socket == INVALID_SERIAL_SOCKET_VALUE) { m_strError = strerror(errno); return false; @@ -89,22 +106,22 @@ bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits /* = 8 * SocketSetBlocking(m_socket, false); - if (!SetBaudRate(baudrate)) + if (!SetBaudRate(m_iBaudrate)) return false; m_options.c_cflag |= (CLOCAL | CREAD); m_options.c_cflag &= ~HUPCL; m_options.c_cflag &= ~CSIZE; - if (databits == 5) m_options.c_cflag |= CS5; - if (databits == 6) m_options.c_cflag |= CS6; - if (databits == 7) m_options.c_cflag |= CS7; - if (databits == 8) m_options.c_cflag |= CS8; + if (m_iDatabits == SERIAL_DATA_BITS_FIVE) m_options.c_cflag |= CS5; + if (m_iDatabits == SERIAL_DATA_BITS_SIX) m_options.c_cflag |= CS6; + if (m_iDatabits == SERIAL_DATA_BITS_SEVEN) m_options.c_cflag |= CS7; + if (m_iDatabits == SERIAL_DATA_BITS_EIGHT) m_options.c_cflag |= CS8; m_options.c_cflag &= ~PARENB; - if (parity == PAR_EVEN || parity == PAR_ODD) + if (m_iParity == SERIAL_PARITY_EVEN || m_iParity == SERIAL_PARITY_ODD) m_options.c_cflag |= PARENB; - if (parity == PAR_ODD) + if (m_iParity == SERIAL_PARITY_ODD) m_options.c_cflag |= PARODD; #ifdef CRTSCTS @@ -113,20 +130,16 @@ bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits /* = 8 * m_options.c_cflag &= ~CNEW_RTSCTS; #endif - if (stopbits == 1) m_options.c_cflag &= ~CSTOPB; + if (m_iStopbits == SERIAL_STOP_BITS_ONE) m_options.c_cflag &= ~CSTOPB; else m_options.c_cflag |= CSTOPB; //I guessed a little here m_options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG | XCASE | ECHOK | ECHONL | ECHOCTL | ECHOPRT | ECHOKE | TOSTOP); - if (parity == PAR_NONE) - { + if (m_iParity == SERIAL_PARITY_NONE) m_options.c_iflag &= ~INPCK; - } else - { m_options.c_iflag |= INPCK | ISTRIP; - } m_options.c_iflag &= ~(IXON | IXOFF | IXANY | BRKINT | INLCR | IGNCR | ICRNL | IUCLC | IMAXBEL); m_options.c_oflag &= ~(OPOST | ONLCR | OCRNL); @@ -138,11 +151,12 @@ bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits /* = 8 * } SocketSetBlocking(m_socket, true); + m_bIsOpen = true; return true; } -bool CSerialPort::SetBaudRate(uint32_t baudrate) +bool CSerialSocket::SetBaudRate(uint32_t baudrate) { int rate = IntToBaudrate(baudrate); if (rate == -1) @@ -152,7 +166,7 @@ bool CSerialPort::SetBaudRate(uint32_t baudrate) m_strError = buff; return false; } - + //get the current port attributes if (tcgetattr(m_socket, &m_options) != 0) { @@ -165,7 +179,7 @@ bool CSerialPort::SetBaudRate(uint32_t baudrate) m_strError = strerror(errno); return false; } - + if (cfsetospeed(&m_options, rate) != 0) { m_strError = strerror(errno); diff --git a/src/lib/platform/sockets/serialport.h b/src/lib/platform/sockets/serialport.h index 7b0a3a0..c74cc05 100644 --- a/src/lib/platform/sockets/serialport.h +++ b/src/lib/platform/sockets/serialport.h @@ -45,53 +45,71 @@ namespace PLATFORM { - #define PAR_NONE 0 - #define PAR_EVEN 1 - #define PAR_ODD 2 + enum SerialParity + { + SERIAL_PARITY_NONE = 0, + SERIAL_PARITY_EVEN, + SERIAL_PARITY_ODD + }; + + enum SerialStopBits + { + SERIAL_STOP_BITS_ONE = 1, + SERIAL_STOP_BITS_TWO = 2 + }; + + enum SerialDataBits + { + SERIAL_DATA_BITS_FIVE = 5, + SERIAL_DATA_BITS_SIX = 6, + SERIAL_DATA_BITS_SEVEN = 7, + SERIAL_DATA_BITS_EIGHT = 8 + }; - class CSerialPort : public CSocket + class CSerialSocket : public CCommonSocket { public: - CSerialPort(void); - virtual ~CSerialPort(void) {} + CSerialSocket(const CStdString &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) : + CCommonSocket(INVALID_SERIAL_SOCKET_VALUE, strName), + m_bIsOpen(false), + m_iBaudrate(iBaudrate), + m_iDatabits(iDatabits), + m_iStopbits(iStopbits), + m_iParity(iParity) {} - bool Open(std::string name, uint32_t baudrate, uint8_t databits = 8, uint8_t stopbits = 1, uint8_t parity = PAR_NONE); + virtual ~CSerialSocket(void) {} - CStdString GetName(void) const + virtual bool Open(uint64_t iTimeoutMs = 0); + virtual void Close(void); + virtual void Shutdown(void); + virtual ssize_t Write(void* data, size_t len); + virtual ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0); + + virtual bool IsOpen(void) { - CStdString strName; - strName = m_strName; - return strName; + return m_socket != INVALID_SERIAL_SOCKET_VALUE && + m_bIsOpen; } - #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 + virtual bool SetBaudRate(uint32_t baudrate); - private: - bool SetBaudRate(uint32_t baudrate); + protected: + #ifndef __WINDOWS__ + struct termios m_options; + #endif - private: - #ifdef __WINDOWS__ - void FormatWindowsError(int iErrorCode, CStdString &strMessage); - bool SetTimeouts(bool bBlocking); + bool m_bIsOpen; + uint32_t m_iBaudrate; + SerialDataBits m_iDatabits; + SerialStopBits m_iStopbits; + SerialParity m_iParity; + }; - HANDLE m_handle; - bool m_bIsOpen; - uint32_t m_iBaudrate; - uint8_t m_iDatabits; - uint8_t m_iStopbits; - uint8_t m_iParity; - int64_t m_iTimeout; - SyncedBuffer m_buffer; - HANDLE m_ovHandle; - #else - struct termios m_options; - #endif - std::string m_strName; - bool m_bToStdOut; + class CSerialPort : public CProtectedSocket + { + public: + CSerialPort(const CStdString &strName, uint32_t iBaudrate, SerialDataBits iDatabits = SERIAL_DATA_BITS_EIGHT, SerialStopBits iStopbits = SERIAL_STOP_BITS_ONE, SerialParity iParity = SERIAL_PARITY_NONE) : + CProtectedSocket (new CSerialSocket(strName, iBaudrate, iDatabits, iStopbits, iParity)) {} + virtual ~CSerialPort(void) {} }; }; diff --git a/src/lib/platform/sockets/socket.h b/src/lib/platform/sockets/socket.h index 2e8acdb..388bb2d 100644 --- a/src/lib/platform/sockets/socket.h +++ b/src/lib/platform/sockets/socket.h @@ -44,65 +44,191 @@ namespace PLATFORM { - class CSocket : public PreventCopy + class ISocket : public PreventCopy { - public: - CSocket(void) : - m_socket(INVALID_SOCKET), - m_iError(0) {}; + public: + ISocket(void) {}; + virtual ~ISocket(void) {} - virtual ~CSocket(void) - { - Close(); - } + virtual bool Open(uint64_t iTimeoutMs = 0) = 0; + virtual void Close(void) = 0; + virtual void Shutdown(void) = 0; + virtual bool IsOpen(void) = 0; + virtual ssize_t Write(void* data, size_t len) = 0; + virtual ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0) = 0; + virtual CStdString GetError(void) = 0; + virtual int GetErrorNumber(void) = 0; + virtual CStdString GetName(void) = 0; + }; - virtual bool IsOpen(void) - { - CLockObject lock(m_mutex); - return m_socket != INVALID_SOCKET && - m_socket != SOCKET_ERROR; - } + template + class CCommonSocket : public ISocket + { + public: + CCommonSocket(_SType initialSocketValue, const CStdString &strName) : + m_socket(initialSocketValue), + m_strName(strName), + m_iError(0) {} - virtual void Close(void) - { - CLockObject lock(m_mutex); - SocketClose(m_socket); - m_socket = INVALID_SOCKET; - m_strError = ""; - } + virtual ~CCommonSocket(void) {} - virtual int64_t Write(uint8_t* data, uint32_t len) - { - CLockObject lock(m_mutex); - int64_t iReturn = SocketWrite(m_socket, &m_iError, data, len); - m_strError = strerror(m_iError); - return iReturn; - } + virtual CStdString GetError(void) + { + CStdString strError; + strError = m_strError.IsEmpty() && m_iError != 0 ? strerror(m_iError) : m_strError; + return strError; + } + + virtual int GetErrorNumber(void) + { + return m_iError; + } + + virtual CStdString GetName(void) + { + CStdString strName; + strName = m_strName; + return strName; + } + + protected: + _SType m_socket; + CStdString m_strError; + CStdString m_strName; + int m_iError; + CMutex m_mutex; + }; + + template + class CProtectedSocket : public ISocket + { + public: + CProtectedSocket(_Socket *socket) : + m_socket(socket), + m_iUseCount(0) {} + + virtual ~CProtectedSocket(void) + { + Close(); + delete m_socket; + } - virtual int32_t Read(uint8_t* data, uint32_t len, uint64_t iTimeoutMs = 0) + virtual bool Open(uint64_t iTimeoutMs = 0) + { + bool bReturn(false); + if (m_socket && WaitReady()) { - CLockObject lock(m_mutex); - int32_t iReturn = SocketRead(m_socket, &m_iError, data, len, iTimeoutMs); - m_strError = strerror(m_iError); - return iReturn; + bReturn = m_socket->Open(iTimeoutMs); + MarkReady(); } + return bReturn; + } - virtual CStdString GetError(void) const + virtual void Close(void) + { + if (m_socket && WaitReady()) { - CStdString strReturn; - strReturn = m_strError; - return strReturn; + m_socket->Close(); + MarkReady(); } + } - virtual int GetErrorNumber(void) const + virtual void Shutdown(void) + { + if (m_socket && WaitReady()) { - return m_iError; + m_socket->Shutdown(); + MarkReady(); } + } + + virtual bool IsOpen(void) + { + CLockObject lock(m_mutex); + return m_socket && m_socket->IsOpen(); + } + + virtual bool IsBusy(void) + { + CLockObject lock(m_mutex); + return m_socket && m_iUseCount > 0; + } + + virtual int GetUseCount(void) + { + CLockObject lock(m_mutex); + return m_iUseCount; + } + + virtual ssize_t Write(void* data, size_t len) + { + if (!m_socket || !WaitReady()) + return EINVAL; + + ssize_t iReturn = m_socket->Write(data, len); + MarkReady(); + + return iReturn; + } + + virtual ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0) + { + if (!m_socket || !WaitReady()) + return EINVAL; + + ssize_t iReturn = m_socket->Read(data, len, iTimeoutMs); + MarkReady(); + + return iReturn; + } + + virtual CStdString GetError(void) + { + CStdString strError; + CLockObject lock(m_mutex); + strError = m_socket ? m_socket->GetError() : ""; + return strError; + } + + virtual int GetErrorNumber(void) + { + CLockObject lock(m_mutex); + return m_socket ? m_socket->GetErrorNumber() : EINVAL; + } + + virtual CStdString GetName(void) + { + CStdString strName; + CLockObject lock(m_mutex); + strName = m_socket ? m_socket->GetName() : ""; + return strName; + } + + private: + bool WaitReady(void) + { + CLockObject lock(m_mutex); + if (m_iUseCount > 0) + m_condition.Wait(m_mutex); + + if (m_iUseCount > 0) + return false; + + ++m_iUseCount; + return true; + } + + void MarkReady(void) + { + CLockObject lock(m_mutex); + if (m_iUseCount > 0) + --m_iUseCount; + m_condition.Broadcast(); + } - protected: - socket_t m_socket; - CStdString m_strError; - int m_iError; - CMutex m_mutex; + _Socket *m_socket; + CMutex m_mutex; + CCondition m_condition; + int m_iUseCount; }; }; diff --git a/src/lib/platform/sockets/tcp.h b/src/lib/platform/sockets/tcp.h index ef9c418..ffc372c 100644 --- a/src/lib/platform/sockets/tcp.h +++ b/src/lib/platform/sockets/tcp.h @@ -33,28 +33,24 @@ #include "socket.h" -#if defined(__WINDOWS__) -#include "../windows/os-tcp.h" -#else -#include "../posix/os-tcp.h" -#endif - using namespace std; namespace PLATFORM { - class CTcpSocket : public CSocket + class CTcpSocket : public CCommonSocket { public: - CTcpSocket(void) {}; + CTcpSocket(const CStdString &strHostname, uint16_t iPort) : + CCommonSocket(INVALID_SOCKET_VALUE, strHostname), + m_iPort(iPort) {} + virtual ~CTcpSocket(void) {} - virtual bool Open(const CStdString &strHostname, uint16_t iPort, uint64_t nTimeout) + virtual bool Open(uint64_t iTimeoutMs = 0) { bool bReturn(false); struct addrinfo *address(NULL), *addr(NULL); - CLockObject lock(m_mutex); - if (!TcpResolveAddress(strHostname.c_str(), iPort, &m_iError, &address)) + if (!TcpResolveAddress(m_strName.c_str(), m_iPort, &m_iError, &address)) { m_strError = strerror(m_iError); return bReturn; @@ -62,8 +58,8 @@ namespace PLATFORM for(addr = address; !bReturn && addr; addr = addr->ai_next) { - m_socket = TcpCreateSocket(addr, &m_iError, nTimeout); - if (m_socket != INVALID_SOCKET && m_socket != SOCKET_ERROR) + m_socket = TcpCreateSocket(addr, &m_iError, iTimeoutMs); + if (m_socket != INVALID_SOCKET_VALUE) bReturn = true; else m_strError = strerror(m_iError); @@ -73,34 +69,62 @@ namespace PLATFORM return bReturn; } + virtual void Close(void) + { + TcpSocketClose(m_socket); + m_socket = INVALID_SOCKET_VALUE; + } + virtual void Shutdown(void) { - CLockObject lock(m_mutex); - if (m_socket != INVALID_SOCKET && m_socket != SOCKET_ERROR) - TcpShutdownSocket(m_socket); - m_socket = INVALID_SOCKET; - m_strError = ""; + TcpSocketShutdown(m_socket); + m_socket = INVALID_SOCKET_VALUE; + } + + virtual ssize_t Write(void* data, size_t len) + { + return TcpSocketWrite(m_socket, &m_iError, data, len); + } + + virtual ssize_t Read(void* data, size_t len, uint64_t iTimeoutMs = 0) + { + return TcpSocketRead(m_socket, &m_iError, data, len, iTimeoutMs); } - 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 == INVALID_SOCKET || fdSock == SOCKET_ERROR) + virtual bool IsOpen(void) { - *iError = errno; - return (socket_t)SOCKET_ERROR; + return m_socket != INVALID_SOCKET_VALUE; } - if (!TcpConnectSocket(fdSock, addr, iError, iTimeout)) + protected: + virtual tcp_socket_t TcpCreateSocket(struct addrinfo* addr, int* iError, uint64_t iTimeout) { - SocketClose(fdSock); - return (socket_t)SOCKET_ERROR; + tcp_socket_t fdSock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); + if (fdSock == INVALID_SOCKET_VALUE) + { + *iError = errno; + return (tcp_socket_t)INVALID_SOCKET_VALUE; + } + + if (!TcpConnectSocket(fdSock, addr, iError, iTimeout)) + { + TcpSocketClose(fdSock); + return (tcp_socket_t)INVALID_SOCKET_VALUE; + } + + TcpSetNoDelay(fdSock); + + return fdSock; } - TcpSetNoDelay(fdSock); + uint16_t m_iPort; + }; - return fdSock; - } + class CTcpConnection : public CProtectedSocket + { + public: + CTcpConnection(const CStdString &strHostname, uint16_t iPort) : + CProtectedSocket (new CTcpSocket(strHostname, iPort)) {} + virtual ~CTcpConnection(void) {} }; }; diff --git a/src/lib/platform/windows/os-socket.h b/src/lib/platform/windows/os-socket.h index 95883e2..ad98edb 100644 --- a/src/lib/platform/windows/os-socket.h +++ b/src/lib/platform/windows/os-socket.h @@ -64,101 +64,214 @@ namespace PLATFORM } } - inline void SocketClose(socket_t socket) + // Serial port + //@{ + inline void SerialSocketClose(serial_socket_t socket) { - if (socket != SOCKET_ERROR && socket != INVALID_SOCKET) - closesocket(socket); + if (socket != INVALID_HANDLE_VALUE) + CloseHandle(socket); } - inline void SocketSetBlocking(socket_t socket, bool bSetTo) + inline ssize_t SerialSocketWrite(serial_socket_t socket, int *iError, void* data, size_t len) { - u_long nVal = bSetTo ? 1 : 0; - ioctlsocket(socket, FIONBIO, &nVal); + DWORD iBytesWritten(0); + if (socket != INVALID_HANDLE_VALUE) + { + if (!WriteFile(socket, data, len, &iBytesWritten, NULL)) + { + *iError = GetLastError(); + return -1; + } + return (ssize_t)iBytesWritten; + } + + return -1; } - inline int64_t SocketWrite(socket_t socket, int *iError, uint8_t* data, uint32_t len) + inline ssize_t SerialSocketRead(serial_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/) { - int64_t iReturn(-1); - if (socket != SOCKET_ERROR && socket != INVALID_SOCKET) + DWORD iBytesRead(0); + if (socket != INVALID_HANDLE_VALUE) { - iReturn = send(socket, (char*)data, len, 0); - if (iReturn <= 0) - *iError = GetSocketError(); + if(!ReadFile(socket, data, len, &iBytesRead, NULL) != 0) + { + *iError = GetLastError(); + return -1; + } + return (ssize_t)iBytesRead; } - return iReturn; + return -1; } + //@} - inline int SocketReadFixed(socket_t socket, char *buf, int iLength, int iFlags) + // TCP + //@{ + inline void TcpSocketSetBlocking(tcp_socket_t socket, bool bSetTo) { - int iReadResult(1), iBytesRead(0); + u_long iSetTo = bSetTo ? 0 : 1; + ioctlsocket(socket, FIONBIO, &iSetTo); + } - if ((iFlags & MSG_WAITALL) == 0) - return recv(socket, buf, iLength, iFlags); + inline void TcpSocketClose(tcp_socket_t socket) + { + closesocket(socket); + } - iFlags &= ~MSG_WAITALL; - while(iBytesRead < iLength && iReadResult > 0) + inline void TcpSocketShutdown(tcp_socket_t socket) + { + if (socket != INVALID_SOCKET && + socket != SOCKET_ERROR) + shutdown(socket, SHUT_RDWR); + } + + inline ssize_t TcpSocketWrite(tcp_socket_t socket, int *iError, void* data, size_t len) + { + if (socket == INVALID_SOCKET || + socket == SOCKET_ERROR) { - if ((iReadResult = recv(socket, buf + iBytesRead, iLength - iBytesRead, iFlags)) < 0) - return iReadResult; + *iError = EINVAL; + return -1; } - return iLength - iBytesRead; + + ssize_t iReturn = send(socket, (char*)data, len, 0); + if (iReturn < (ssize_t)len) + *iError = errno; + return iReturn; } - inline int32_t SocketRead(socket_t socket, void *buf, uint32_t nLen) + inline ssize_t TcpSocketRead(tcp_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/) { - int iReadResult = SocketReadFixed(socket, (char *)buf, nLen, MSG_WAITALL); + int64_t iNow(0), iTarget(0); + ssize_t iBytesRead(0); + *iError = 0; - if (iReadResult == -1) - return GetSocketError(); - if (iReadResult < (int)nLen) - return ECONNRESET; + if (socket == INVALID_SOCKET || + socket == SOCKET_ERROR) + { + *iError = EINVAL; + return -1; + } - return 0; - } + if (iTimeoutMs > 0) + { + iNow = GetTimeMs(); + iTarget = iNow + (int64_t) iTimeoutMs; + } - inline int32_t SocketRead(socket_t socket, int *iError, uint8_t* data, uint32_t iLength, uint64_t iTimeoutMs) - { - int iReadResult(0); - uint32_t iBytesRead(0); fd_set fd_read; struct timeval tv; + while (iBytesRead >= 0 && iBytesRead < (ssize_t)len && (iTimeoutMs == 0 || iTarget > iNow)) + { + if (iTimeoutMs > 0) + { + tv.tv_sec = (long)(iTimeoutMs / 1000); + tv.tv_usec = 1000 * (long)(iTimeoutMs % 1000); - if (iTimeoutMs <= 0) - return EINVAL; + FD_ZERO(&fd_read); + FD_SET(socket, &fd_read); - uint64_t iNow = GetTimeMs(); - uint64_t iTarget = iNow + iTimeoutMs; + if (select(socket + 1, &fd_read, NULL, NULL, &tv) == 0) + return ETIMEDOUT; + TcpSocketSetBlocking(socket, false); + } - while(iNow < iTarget && iBytesRead < iLength) - { - tv.tv_sec = (long)(iTarget - iNow / 1000); - tv.tv_usec = (long)(1000 * (iTarget - iNow % 1000)); + ssize_t iReadResult = (iTimeoutMs > 0) ? + recv(socket, (char*)data + iBytesRead, len - iBytesRead, MSG_WAITALL) : + recv(socket, (char*)data, len, MSG_WAITALL); + *iError = GetSocketError(); + if (iReadResult < 0) + { + if (errno == EAGAIN && iTimeoutMs > 0) + continue; + *iError = errno; + return -1; + } + else if (iReadResult == 0 || (iReadResult != (ssize_t)len && iTimeoutMs == 0)) + { + *iError = ECONNRESET; + return -1; + } - FD_ZERO(&fd_read); - FD_SET(socket, &fd_read); + iBytesRead += iReadResult; - if ((iReadResult = select(socket + 1, &fd_read, NULL, NULL, &tv)) == 0) - return ETIMEDOUT; + if (iTimeoutMs > 0) + { + TcpSocketSetBlocking(socket, true); + iNow = GetTimeMs(); + } + } + return 0; + } - SocketSetBlocking(socket, false); + 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); - iReadResult = SocketReadFixed(socket, (char *)data + iBytesRead, iLength - iBytesRead, 0); + *iError = getaddrinfo(strHost, service, &hints, info); + return !(*iError); + } - SocketSetBlocking(socket, true); + inline int TcpGetSocketError(tcp_socket_t socket) + { + int iReturn(0); + socklen_t optLen = sizeof(tcp_socket_t); + getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)&iReturn, &optLen); + return iReturn; + } - if (iReadResult == -1) + inline bool TcpSetNoDelay(tcp_socket_t socket) + { + int iSetTo(1); + setsockopt(socket, IPPROTO_TCP, TCP_NODELAY, (const char*)&iSetTo, sizeof(iSetTo)); + return true; + } + + inline bool TcpConnectSocket(tcp_socket_t socket, struct addrinfo* addr, int *iError, uint64_t iTimeout = 0) + { + TcpSocketSetBlocking(socket, false); + + *iError = 0; + int iConnectResult = connect(socket, addr->ai_addr, addr->ai_addrlen); + if (iConnectResult == -1) + { + if (GetSocketError() == EINPROGRESS || + GetSocketError() == EAGAIN) { - int iError = GetSocketError(); - if (iError == EAGAIN) - continue; - return iError; - } - else if (iReadResult == 0) - return ECONNRESET; + fd_set fd_write, fd_except; + struct timeval tv; + tv.tv_sec = (long)(iTimeout / 1000); + tv.tv_usec = 1000 * (long)(iTimeout % 1000); - iBytesRead += iReadResult; + FD_ZERO(&fd_write); + FD_ZERO(&fd_except); + FD_SET(socket, &fd_write); + FD_SET(socket, &fd_except); + + int iPollResult = select(sizeof(socket)*8, NULL, &fd_write, &fd_except, &tv); + if (iPollResult == 0) + *iError = ETIMEDOUT; + else if (iPollResult == -1) + *iError = GetSocketError(); + else + { + socklen_t errlen = sizeof(int); + getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)iError, &errlen); + } + } + else + { + *iError = errno; + } } - return iBytesRead == iLength ? 0 : ECONNRESET; + TcpSocketSetBlocking(socket, true); + + return *iError == 0; } } diff --git a/src/lib/platform/windows/os-tcp.h b/src/lib/platform/windows/os-tcp.h deleted file mode 100644 index b05a3dd..0000000 --- a/src/lib/platform/windows/os-tcp.h +++ /dev/null @@ -1,128 +0,0 @@ -#pragma once -/* - * This file is part of the libCEC(R) library. - * - * libCEC(R) is Copyright (C) 2011-2012 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 void TcpShutdownSocket(socket_t socket) - { - shutdown(socket, SHUT_RDWR); - } - - 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; - } -} diff --git a/src/lib/platform/windows/os-types.h b/src/lib/platform/windows/os-types.h index de12f08..84edac9 100644 --- a/src/lib/platform/windows/os-types.h +++ b/src/lib/platform/windows/os-types.h @@ -50,7 +50,10 @@ #include #include -typedef SOCKET socket_t; +typedef SOCKET tcp_socket_t; +#define INVALID_SOCKET_VALUE INVALID_SOCKET +typedef HANDLE serial_socket_t; +#define INVALID_SERIAL_SOCKET_VALUE INVALID_HANDLE_VALUE typedef signed __int8 int8_t; typedef signed __int16 int16_t; @@ -61,6 +64,15 @@ typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; typedef unsigned __int64 uint64_t; +#ifndef _SSIZE_T_DEFINED +#ifdef _WIN64 +typedef __int64 ssize_t; +#else +typedef _W64 int ssize_t; +#endif +#define _SSIZE_T_DEFINED +#endif + #define snprintf _snprintf #if defined(_MSC_VER) diff --git a/src/lib/platform/windows/serialport.cpp b/src/lib/platform/windows/serialport.cpp index dba9631..680b1f0 100644 --- a/src/lib/platform/windows/serialport.cpp +++ b/src/lib/platform/windows/serialport.cpp @@ -37,7 +37,7 @@ using namespace std; using namespace PLATFORM; -void CSerialPort::FormatWindowsError(int iErrorCode, CStdString &strMessage) +void FormatWindowsError(int iErrorCode, CStdString &strMessage) { if (iErrorCode != ERROR_SUCCESS) { @@ -48,22 +48,67 @@ void CSerialPort::FormatWindowsError(int iErrorCode, CStdString &strMessage) } } -CSerialPort::CSerialPort(void) : - m_handle(INVALID_HANDLE_VALUE), - m_bIsOpen(false), - m_iBaudrate(0), - m_iDatabits(0), - m_iStopbits(0), - m_iParity(0) +bool SetTimeouts(serial_socket_t socket, int* iError, bool bBlocking) { + if (socket == INVALID_HANDLE_VALUE) + return false; + + COMMTIMEOUTS cto; + if (!GetCommTimeouts(socket, &cto)) + { + *iError = GetLastError(); + return false; + } + + if (bBlocking) + { + cto.ReadIntervalTimeout = 0; + cto.ReadTotalTimeoutConstant = 0; + cto.ReadTotalTimeoutMultiplier = 0; + } + else + { + cto.ReadIntervalTimeout = MAXDWORD; + cto.ReadTotalTimeoutConstant = 0; + cto.ReadTotalTimeoutMultiplier = 0; + } + + if (!SetCommTimeouts(socket, &cto)) + { + *iError = GetLastError(); + return false; + } + + return true; } -bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits, uint8_t stopbits, uint8_t parity) +void CSerialSocket::Close(void) { - CStdString strComPath = "\\\\.\\" + name; + SerialSocketClose(m_socket); +} + +void CSerialSocket::Shutdown(void) +{ + SerialSocketClose(m_socket); +} + +ssize_t CSerialSocket::Write(void* data, size_t len) +{ + return SerialSocketWrite(m_socket, &m_iError, data, len); +} + +ssize_t CSerialSocket::Read(void* data, size_t len, uint64_t iTimeoutMs /* = 0 */) +{ + return SerialSocketRead(m_socket, &m_iError, data, len, iTimeoutMs); +} + +bool CSerialSocket::Open(uint64_t iTimeoutMs /* = 0 */) +{ + iTimeoutMs = 0; + CStdString strComPath = "\\\\.\\" + m_strName; CLockObject lock(m_mutex); - m_handle = CreateFile(strComPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); - if (m_handle == INVALID_HANDLE_VALUE) + m_socket = CreateFile(strComPath.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + if (m_socket == INVALID_HANDLE_VALUE) { m_strError = "Unable to open COM port"; FormatWindowsError(GetLastError(), m_strError); @@ -75,7 +120,7 @@ bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits, uint8_t commConfig.dwSize = dwSize; if (GetDefaultCommConfig(strComPath.c_str(), &commConfig,&dwSize)) { - if (!SetCommConfig(m_handle, &commConfig,dwSize)) + if (!SetCommConfig(m_socket, &commConfig,dwSize)) { m_strError = "unable to set default config"; FormatWindowsError(GetLastError(), m_strError); @@ -87,16 +132,13 @@ bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits, uint8_t FormatWindowsError(GetLastError(), m_strError); } - if (!SetupComm(m_handle, 64, 64)) + if (!SetupComm(m_socket, 64, 64)) { m_strError = "unable to set up the com port"; FormatWindowsError(GetLastError(), m_strError); } - m_iDatabits = databits; - m_iStopbits = stopbits; - m_iParity = parity; - if (!SetBaudRate(baudrate)) + if (!SetBaudRate(m_iBaudrate)) { m_strError = "unable to set baud rate"; FormatWindowsError(GetLastError(), m_strError); @@ -104,7 +146,7 @@ bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits, uint8_t return false; } - if (!SetTimeouts(false)) + if (!SetTimeouts(m_socket, &m_iError, false)) { m_strError = "unable to set timeouts"; FormatWindowsError(GetLastError(), m_strError); @@ -116,95 +158,7 @@ bool CSerialPort::Open(string name, uint32_t baudrate, uint8_t databits, uint8_t return m_bIsOpen; } -bool CSerialPort::SetTimeouts(bool bBlocking) -{ - if (m_handle == INVALID_HANDLE_VALUE) - return false; - - COMMTIMEOUTS cto; - if (!GetCommTimeouts(m_handle, &cto)) - { - m_strError = "GetCommTimeouts failed"; - FormatWindowsError(GetLastError(), m_strError); - return false; - } - - if (bBlocking) - { - cto.ReadIntervalTimeout = 0; - cto.ReadTotalTimeoutConstant = 0; - cto.ReadTotalTimeoutMultiplier = 0; - } - else - { - cto.ReadIntervalTimeout = MAXDWORD; - cto.ReadTotalTimeoutConstant = 0; - cto.ReadTotalTimeoutMultiplier = 0; - } - - if (!SetCommTimeouts(m_handle, &cto)) - { - m_strError = "SetCommTimeouts failed"; - FormatWindowsError(GetLastError(), m_strError); - return false; - } - - return true; -} - -void CSerialPort::Close(void) -{ - CLockObject lock(m_mutex); - if (m_bIsOpen) - { - CloseHandle(m_handle); - m_bIsOpen = false; - } -} - -int64_t CSerialPort::Write(uint8_t* data, uint32_t len) -{ - CLockObject lock(m_mutex); - DWORD iBytesWritten = 0; - if (!m_bIsOpen) - return -1; - - if (!WriteFile(m_handle, data, len, &iBytesWritten, NULL)) - { - m_strError = "Error while writing to COM port"; - FormatWindowsError(GetLastError(), m_strError); - return -1; - } - - return (int64_t)iBytesWritten; -} - -int32_t CSerialPort::Read(uint8_t* data, uint32_t len, uint64_t iTimeoutMs /* = 0 */) -{ - CLockObject lock(m_mutex); - int32_t iReturn(-1); - DWORD iBytesRead = 0; - if (m_handle == 0) - { - m_strError = "Error while reading from COM port: invalid handle"; - return iReturn; - } - - if(!ReadFile(m_handle, data, len, &iBytesRead, NULL) != 0) - { - m_strError = "unable to read from device"; - FormatWindowsError(GetLastError(), m_strError); - iReturn = -1; - } - else - { - iReturn = (int32_t) iBytesRead; - } - - return iReturn; -} - -bool CSerialPort::SetBaudRate(uint32_t baudrate) +bool CSerialSocket::SetBaudRate(uint32_t baudrate) { int32_t rate = IntToBaudrate(baudrate); if (rate < 0) @@ -225,21 +179,21 @@ bool CSerialPort::SetBaudRate(uint32_t baudrate) dcb.fInX = false; dcb.fAbortOnError = true; - if (m_iParity == PAR_NONE) + if (m_iParity == SERIAL_PARITY_NONE) dcb.Parity = NOPARITY; - else if (m_iParity == PAR_EVEN) + else if (m_iParity == SERIAL_PARITY_EVEN) dcb.Parity = EVENPARITY; else dcb.Parity = ODDPARITY; - if (m_iStopbits == 2) + if (m_iStopbits == SERIAL_STOP_BITS_TWO) dcb.StopBits = TWOSTOPBITS; else dcb.StopBits = ONESTOPBIT; - dcb.ByteSize = m_iDatabits; + dcb.ByteSize = (BYTE)m_iDatabits; - if(!SetCommState(m_handle,&dcb)) + if(!SetCommState(m_socket,&dcb)) { m_strError = "SetCommState failed"; FormatWindowsError(GetLastError(), m_strError); @@ -248,9 +202,3 @@ bool CSerialPort::SetBaudRate(uint32_t baudrate) return true; } - -bool CSerialPort::IsOpen(void) -{ - CLockObject lock(m_mutex); - return m_bIsOpen; -} -- 2.34.1