/*
* 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 "../util/timeutils.h"
#include <stdio.h>
#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <poll.h>
+
+/* Needed on Mac OS/X */
+#ifndef SOL_TCP
+#define SOL_TCP IPPROTO_TCP
+#endif
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;
+ return -EINVAL;
}
- int64_t iBytesWritten = 0;
- struct timeval *tv;
+ ssize_t iBytesWritten(0);
+ struct timeval *tv(NULL);
- while (iBytesWritten < len)
+ while (iBytesWritten < (ssize_t)len)
{
FD_ZERO(&port);
FD_SET(socket, &port);
if (returnv < 0)
{
*iError = errno;
- return -1;
+ return -errno;
}
else if (returnv == 0)
{
*iError = ETIMEDOUT;
- return -1;
+ return -ETIMEDOUT;
}
- returnv = write(socket, data + iBytesWritten, len - iBytesWritten);
+ returnv = write(socket, (char*)data + iBytesWritten, len - iBytesWritten);
if (returnv == -1)
{
*iError = errno;
- return -1;
+ return -errno;
}
iBytesWritten += returnv;
}
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;
+ return -EINVAL;
}
if (iTimeoutMs > 0)
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)
{
if (returnv == -1)
{
*iError = errno;
- return -1;
+ return -errno;
}
else if (returnv == 0)
{
break; //nothing to read
}
- returnv = read(socket, data + iBytesRead, len - iBytesRead);
+ returnv = read(socket, (char*)data + iBytesRead, len - iBytesRead);
if (returnv == -1)
{
*iError = errno;
- return -1;
+ return -errno;
}
iBytesRead += returnv;
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 -EINVAL;
+ }
+
+ 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;
+ }
+ //@}
}