X-Git-Url: https://git.piment-noir.org/?a=blobdiff_plain;f=src%2Flib%2Fplatform%2Fwindows%2Fos-socket.h;h=0c3855558ddeb7b164d151cb3e1e50ca0fa1cdee;hb=2b44051cbfa70deafc30d9767323214debbc1a75;hp=bc6c08cf72c9c1b666a65afba9034cde6eb4178d;hpb=24048d575419fe909fade9110fab48d17370ee6f;p=deb_libcec.git diff --git a/src/lib/platform/windows/os-socket.h b/src/lib/platform/windows/os-socket.h index bc6c08c..0c38555 100644 --- a/src/lib/platform/windows/os-socket.h +++ b/src/lib/platform/windows/os-socket.h @@ -2,7 +2,7 @@ /* * This file is part of the libCEC(R) library. * - * libCEC(R) is Copyright (C) 2011 Pulse-Eight Limited. All rights reserved. + * 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. @@ -31,30 +31,271 @@ * http://www.pulse-eight.net/ */ -#include "../os.h" -#include "../util/timeutils.h" +#include "lib/platform/os.h" +#include "lib/platform/util/timeutils.h" + +#include +#include +#include + +#define SHUT_RDWR SD_BOTH + +#ifndef ETIMEDOUT +#define ETIMEDOUT 138 +#endif namespace PLATFORM { - inline void SocketClose(socket_t socket) + #ifndef MSG_WAITALL + #define MSG_WAITALL 0x8 + #endif + + inline int GetSocketError(void) { - //TODO + 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 void SocketSetBlocking(socket_t socket, bool bSetTo) + // Serial port + //@{ + inline void SerialSocketClose(serial_socket_t socket) { - //TODO + if (socket != INVALID_HANDLE_VALUE) + CloseHandle(socket); } - inline int64_t SocketWrite(socket_t socket, int *iError, uint8_t* data, uint32_t len) + inline ssize_t SerialSocketWrite(serial_socket_t socket, int *iError, void* data, size_t len) { - //TODO + if (len != (DWORD)len) + { + *iError = EINVAL; + return -1; + } + + DWORD iBytesWritten(0); + if (socket != INVALID_HANDLE_VALUE) + { + if (!WriteFile(socket, data, (DWORD)len, &iBytesWritten, NULL)) + { + *iError = GetLastError(); + return -1; + } + return (ssize_t)iBytesWritten; + } + return -1; } - inline int32_t SocketRead(socket_t socket, int *iError, uint8_t* data, uint32_t len, uint64_t iTimeoutMs /*= 0*/) + inline ssize_t SerialSocketRead(serial_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/) { - // TODO + if (len != (DWORD)len) + { + *iError = EINVAL; + return -1; + } + + DWORD iBytesRead(0); + if (socket != INVALID_HANDLE_VALUE) + { + if(!ReadFile(socket, data, (DWORD)len, &iBytesRead, NULL) != 0) + { + *iError = GetLastError(); + return -1; + } + return (ssize_t)iBytesRead; + } return -1; } + //@} + + // TCP + //@{ + inline void TcpSocketSetBlocking(tcp_socket_t socket, bool bSetTo) + { + u_long iSetTo = bSetTo ? 0 : 1; + ioctlsocket(socket, FIONBIO, &iSetTo); + } + + inline void TcpSocketClose(tcp_socket_t socket) + { + closesocket(socket); + } + + 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 || + len != (int)len) + { + *iError = EINVAL; + return -1; + } + + ssize_t iReturn = send(socket, (char*)data, (int)len, 0); + if (iReturn < (ssize_t)len) + *iError = GetSocketError(); + 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 || + socket == SOCKET_ERROR || + len != (int)len) + { + *iError = EINVAL; + return -1; + } + + if (iTimeoutMs > 0) + { + iNow = GetTimeMs(); + iTarget = iNow + (int64_t) iTimeoutMs; + } + + 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); + + FD_ZERO(&fd_read); + #pragma warning(disable:4127) /* disable 'conditional expression is constant' */ + FD_SET(socket, &fd_read); + #pragma warning(default:4127) + + if (select((int)socket + 1, &fd_read, NULL, NULL, &tv) == 0) + { + *iError = ETIMEDOUT; + return ETIMEDOUT; + } + TcpSocketSetBlocking(socket, false); + } + + ssize_t iReadResult = (iTimeoutMs > 0) ? + recv(socket, (char*)data + iBytesRead, (int)(len - iBytesRead), 0) : + recv(socket, (char*)data, (int)len, MSG_WAITALL); + *iError = GetSocketError(); + + if (iTimeoutMs > 0) + { + TcpSocketSetBlocking(socket, true); + iNow = GetTimeMs(); + } + + if (iReadResult < 0) + { + if (*iError == EAGAIN && iTimeoutMs > 0) + continue; + return -1; + } + else if (iReadResult == 0 || (iReadResult != (ssize_t)len && iTimeoutMs == 0)) + { + *iError = ECONNRESET; + return -1; + } + + iBytesRead += iReadResult; + } + + if (iBytesRead < (ssize_t)len && *iError == 0) + *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(tcp_socket_t); + getsockopt(socket, SOL_SOCKET, SO_ERROR, (char *)&iReturn, &optLen); + return iReturn; + } + + 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, (int)addr->ai_addrlen); + if (iConnectResult == -1) + { + if (GetSocketError() == EINPROGRESS || + GetSocketError() == EAGAIN) + { + fd_set fd_write, fd_except; + struct timeval tv; + tv.tv_sec = (long)(iTimeout / 1000); + tv.tv_usec = 1000 * (long)(iTimeout % 1000); + + FD_ZERO(&fd_write); + FD_ZERO(&fd_except); + #pragma warning(disable:4127) /* disable 'conditional expression is constant' */ + FD_SET(socket, &fd_write); + FD_SET(socket, &fd_except); + #pragma warning(default:4127) + + 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 = GetSocketError(); + } + } + + TcpSocketSetBlocking(socket, true); + + return *iError == 0; + } }