summaryrefslogtreecommitdiffstats
path: root/xbmc/network/Socket.h
diff options
context:
space:
mode:
Diffstat (limited to 'xbmc/network/Socket.h')
-rw-r--r--xbmc/network/Socket.h253
1 files changed, 253 insertions, 0 deletions
diff --git a/xbmc/network/Socket.h b/xbmc/network/Socket.h
new file mode 100644
index 0000000..b945533
--- /dev/null
+++ b/xbmc/network/Socket.h
@@ -0,0 +1,253 @@
+/*
+ * Socket classes
+ * Copyright (c) 2008 d4rk
+ * Copyright (C) 2008-2018 Team Kodi
+ * This file is part of Kodi - https://kodi.tv
+ *
+ * SPDX-License-Identifier: GPL-2.0-or-later
+ * See LICENSES/README.md for more information.
+ */
+
+#pragma once
+
+#include <map>
+#include <memory>
+#include <string.h>
+#include <vector>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "PlatformDefs.h"
+#ifdef TARGET_POSIX
+typedef int SOCKET;
+#endif
+
+namespace SOCKETS
+{
+ // types of sockets
+ enum SocketType
+ {
+ ST_TCP,
+ ST_UDP,
+ ST_UNIX
+ };
+
+ /**********************************************************************/
+ /* IP address abstraction class */
+ /**********************************************************************/
+ class CAddress
+ {
+ public:
+ union
+ {
+ sockaddr_in saddr4;
+ sockaddr_in6 saddr6;
+ sockaddr saddr_generic;
+ } saddr;
+ socklen_t size;
+
+ public:
+ CAddress()
+ {
+ memset(&saddr, 0, sizeof(saddr));
+ saddr.saddr4.sin_family = AF_INET;
+ saddr.saddr4.sin_addr.s_addr = htonl(INADDR_ANY);
+ size = sizeof(saddr.saddr4);
+ }
+
+ explicit CAddress(const char *address)
+ {
+ SetAddress(address);
+ }
+
+ void SetAddress(const char *address)
+ {
+ in6_addr addr6;
+ memset(&saddr, 0, sizeof(saddr));
+ if (inet_pton(AF_INET6, address, &addr6) == 1)
+ {
+ saddr.saddr6.sin6_family = AF_INET6;
+ saddr.saddr6.sin6_addr = addr6;
+ size = sizeof(saddr.saddr6);
+ }
+ else
+ {
+ saddr.saddr4.sin_family = AF_INET;
+ saddr.saddr4.sin_addr.s_addr = inet_addr(address);
+ size = sizeof(saddr.saddr4);
+ }
+ }
+
+ // returns statically alloced buffer, do not free
+ const char *Address()
+ {
+ if (saddr.saddr_generic.sa_family == AF_INET6)
+ {
+ static char buf[INET6_ADDRSTRLEN];
+ return inet_ntop(AF_INET6, &saddr.saddr6.sin6_addr, buf, size);
+ }
+ else
+ return inet_ntoa(saddr.saddr4.sin_addr);
+ }
+
+ unsigned long ULong()
+ {
+ if (saddr.saddr_generic.sa_family == AF_INET6)
+ {
+ // IPv4 coercion (see http://home.samfundet.no/~sesse/ipv6-porting.pdf).
+ // We hash the entire IPv6 address because XBMC might conceivably need to
+ // distinguish between different hosts in the same subnet.
+ // This hash function (djbhash) is not too strong, but good enough.
+ uint32_t hash = 5381;
+ for (int i = 0; i < 16; ++i)
+ {
+ hash = hash * 33 + saddr.saddr6.sin6_addr.s6_addr[i];
+ }
+ // Move into 224.0.0.0/3. As a special safeguard, make sure we don't
+ // end up with the the special broadcast address 255.255.255.255.
+ hash |= 0xe0000000u;
+ if (hash == 0xffffffffu)
+ hash = 0xfffffffeu;
+ return (unsigned long)htonl(hash);
+ }
+ else
+ return (unsigned long)saddr.saddr4.sin_addr.s_addr;
+ }
+ };
+
+ /**********************************************************************/
+ /* Base class for all sockets */
+ /**********************************************************************/
+ class CBaseSocket
+ {
+ public:
+ CBaseSocket()
+ {
+ m_Type = ST_TCP;
+ m_bReady = false;
+ m_bBound = false;
+ m_iPort = 0;
+ }
+ virtual ~CBaseSocket() { Close(); }
+
+ // socket functions
+ virtual bool Bind(bool localOnly, int port, int range=0) = 0;
+ virtual bool Connect() = 0;
+ virtual void Close() {}
+
+ // state functions
+ bool Ready() { return m_bReady; }
+ bool Bound() { return m_bBound; }
+ SocketType Type() { return m_Type; }
+ int Port() { return m_iPort; }
+ virtual SOCKET Socket() = 0;
+
+ protected:
+ virtual void SetBound(bool set=true) { m_bBound = set; }
+ virtual void SetReady(bool set=true) { m_bReady = set; }
+
+ protected:
+ SocketType m_Type;
+ bool m_bReady;
+ bool m_bBound;
+ int m_iPort;
+ };
+
+ /**********************************************************************/
+ /* Base class for UDP socket implementations */
+ /**********************************************************************/
+ class CUDPSocket : public CBaseSocket
+ {
+ public:
+ CUDPSocket()
+ {
+ m_Type = ST_UDP;
+ }
+ // I/O functions
+ virtual int SendTo(const CAddress& addr, const int bufferlength,
+ const void* buffer) = 0;
+
+ // read datagrams, return no. of bytes read or -1 or error
+ virtual int Read(CAddress& addr, const int buffersize, void *buffer) = 0;
+ virtual bool Broadcast(const CAddress& addr, const int datasize,
+ const void* data) = 0;
+ };
+
+ // Implementation specific classes
+
+ /**********************************************************************/
+ /* POSIX based UDP socket implementation */
+ /**********************************************************************/
+ class CPosixUDPSocket : public CUDPSocket
+ {
+ public:
+ CPosixUDPSocket()
+ {
+ m_iSock = INVALID_SOCKET;
+ m_ipv6Socket = false;
+ }
+
+ bool Bind(bool localOnly, int port, int range=0) override;
+ bool Connect() override { return false; }
+ bool Listen(int timeout);
+ int SendTo(const CAddress& addr, const int datasize, const void* data) override;
+ int Read(CAddress& addr, const int buffersize, void *buffer) override;
+ bool Broadcast(const CAddress& addr, const int datasize, const void* data) override
+ {
+ //! @todo implement
+ return false;
+ }
+ SOCKET Socket() override { return m_iSock; }
+ void Close() override;
+
+ protected:
+ SOCKET m_iSock;
+ CAddress m_addr;
+
+ private:
+ bool CheckIPv6(int port, int range);
+
+ bool m_ipv6Socket;
+ };
+
+ /**********************************************************************/
+ /* Create and return platform dependent sockets */
+ /**********************************************************************/
+ class CSocketFactory
+ {
+ public:
+ static std::unique_ptr<CUDPSocket> CreateUDPSocket();
+ };
+
+ /**********************************************************************/
+ /* Listens on multiple sockets for reads */
+ /**********************************************************************/
+
+#define LISTENERROR 1
+#define LISTENEMPTY 2
+
+ class CSocketListener
+ {
+ public:
+ CSocketListener();
+ void AddSocket(CBaseSocket *);
+ bool Listen(int timeoutMs); // in ms, -1=>never timeout, 0=>poll
+ void Clear();
+ CBaseSocket* GetFirstReadySocket();
+ CBaseSocket* GetNextReadySocket();
+
+ protected:
+ std::vector<CBaseSocket*> m_sockets;
+ int m_iReadyCount;
+ int m_iMaxSockets;
+ int m_iCurrentSocket;
+ fd_set m_fdset;
+ };
+
+}
+