/*
* 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.
#include "../os.h"
#include "../util/timeutils.h"
-#pragma comment(lib, "Ws2_32.lib")
#include <ws2spi.h>
#include <ws2ipdef.h>
#include <ws2tcpip.h>
}
}
- 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);
- }
+ if (len != (DWORD)len)
+ {
+ *iError = EINVAL;
+ return -1;
+ }
- inline int64_t SocketWrite(socket_t socket, int *iError, uint8_t* data, uint32_t len)
- {
- int64_t iReturn(-1);
- if (socket != SOCKET_ERROR && socket != INVALID_SOCKET)
+ DWORD iBytesWritten(0);
+ if (socket != INVALID_HANDLE_VALUE)
{
- iReturn = send(socket, (char*)data, len, 0);
- if (iReturn <= 0)
- *iError = GetSocketError();
+ if (!WriteFile(socket, data, (DWORD)len, &iBytesWritten, NULL))
+ {
+ *iError = GetLastError();
+ return -1;
+ }
+ return (ssize_t)iBytesWritten;
}
- return iReturn;
+
+ return -1;
}
- inline int SocketReadFixed(socket_t socket, char *buf, int iLength, int iFlags)
+ inline ssize_t SerialSocketRead(serial_socket_t socket, int *iError, void* data, size_t len, uint64_t iTimeoutMs /*= 0*/)
{
- char* org = buf;
- int nRes = 1;
-
- if ((iFlags & MSG_WAITALL) == 0)
- return recv(socket, buf, iLength, iFlags);
-
- iFlags &= ~MSG_WAITALL;
- while(iLength > 0 && nRes > 0)
+ if (len != (DWORD)len)
{
- nRes = recv(socket, buf, iLength, iFlags);
- if (nRes < 0)
- return nRes;
+ *iError = EINVAL;
+ return -1;
+ }
- buf += nRes;
- iLength -= nRes;
+ 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 buf - org;
+ return -1;
}
+ //@}
- inline int32_t SocketRead(socket_t socket, void *buf, uint32_t nLen)
+ // TCP
+ //@{
+ inline void TcpSocketSetBlocking(tcp_socket_t socket, bool bSetTo)
{
- int x = SocketReadFixed(socket, (char *)buf, nLen, MSG_WAITALL);
+ u_long iSetTo = bSetTo ? 0 : 1;
+ ioctlsocket(socket, FIONBIO, &iSetTo);
+ }
- if (x == -1)
- return GetSocketError();
- if (x != (int)nLen)
- return ECONNRESET;
+ inline void TcpSocketClose(tcp_socket_t socket)
+ {
+ closesocket(socket);
+ }
- return 0;
+ inline void TcpSocketShutdown(tcp_socket_t socket)
+ {
+ if (socket != INVALID_SOCKET &&
+ socket != SOCKET_ERROR)
+ shutdown(socket, SHUT_RDWR);
}
- inline int32_t SocketRead(socket_t socket, int *iError, uint8_t* data, uint32_t iLength, uint64_t iTimeoutMs)
+ inline ssize_t TcpSocketWrite(tcp_socket_t socket, int *iError, void* data, size_t len)
{
- int x, tot = 0, nErr;
- fd_set fd_read;
- struct timeval tv;
+ 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;
+ }
- if (iTimeoutMs <= 0)
- return EINVAL;
+ 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;
- while(tot != (int)iLength)
+ if (socket == INVALID_SOCKET ||
+ socket == SOCKET_ERROR ||
+ len != (int)len)
{
- tv.tv_sec = (long)(iTimeoutMs / 1000);
- tv.tv_usec = (long)(1000 * (iTimeoutMs % 1000));
+ *iError = EINVAL;
+ return -1;
+ }
- FD_ZERO(&fd_read);
- FD_SET(socket, &fd_read);
+ if (iTimeoutMs > 0)
+ {
+ iNow = GetTimeMs();
+ iTarget = iNow + (int64_t) iTimeoutMs;
+ }
- x = select(socket + 1, &fd_read, NULL, NULL, &tv);
+ 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 (x == 0)
- return ETIMEDOUT;
+ FD_ZERO(&fd_read);
+ FD_SET(socket, &fd_read);
- SocketSetBlocking(socket, false);
+ if (select((int)socket + 1, &fd_read, NULL, NULL, &tv) == 0)
+ {
+ *iError = ETIMEDOUT;
+ return ETIMEDOUT;
+ }
+ TcpSocketSetBlocking(socket, false);
+ }
- x = SocketReadFixed(socket, (char *)data + tot, iLength - tot, 0);
- nErr = GetSocketError();
+ ssize_t iReadResult = (iTimeoutMs > 0) ?
+ recv(socket, (char*)data + iBytesRead, (int)(len - iBytesRead), 0) :
+ recv(socket, (char*)data, (int)len, MSG_WAITALL);
+ *iError = GetSocketError();
- SocketSetBlocking(socket, true);
+ if (iTimeoutMs > 0)
+ {
+ TcpSocketSetBlocking(socket, true);
+ iNow = GetTimeMs();
+ }
- if (x == -1)
+ if (iReadResult < 0)
{
- if (nErr == EAGAIN)
+ if (*iError == EAGAIN && iTimeoutMs > 0)
continue;
- return nErr;
+ return -1;
}
+ else if (iReadResult == 0 || (iReadResult != (ssize_t)len && iTimeoutMs == 0))
+ {
+ *iError = ECONNRESET;
+ return -1;
+ }
+
+ iBytesRead += iReadResult;
+ }
- if (x == 0)
- return ECONNRESET;
+ if (iBytesRead < (ssize_t)len && *iError == 0)
+ *iError = ETIMEDOUT;
- tot += x;
+ 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);
+ 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 = GetSocketError();
+ }
}
- return 0;
+
+ TcpSocketSetBlocking(socket, true);
+
+ return *iError == 0;
}
}