forked from 0ad/0ad
IPv6 Compatability (DLL-detection aware), added GetString() and GetPort() to SocketAddress, Documentation
This was SVN commit r138.
This commit is contained in:
parent
50ad3a0e42
commit
73771118b7
@ -2,6 +2,7 @@
|
|||||||
#include "NetworkInternal.h"
|
#include "NetworkInternal.h"
|
||||||
|
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
#include "CStr.h"
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
@ -41,46 +42,106 @@ PS_RESULT GetPS_RESULT(int error)
|
|||||||
|
|
||||||
SocketAddress::SocketAddress(int port, SocketProtocol proto)
|
SocketAddress::SocketAddress(int port, SocketProtocol proto)
|
||||||
{
|
{
|
||||||
|
memset(&m_Union, 0, sizeof(m_Union));
|
||||||
switch (proto)
|
switch (proto)
|
||||||
{
|
{
|
||||||
case IPv4:
|
case IPv4:
|
||||||
memset(&m_IPv4, 0, sizeof(m_IPv4));
|
m_Union.m_IPv4.sin_family=PF_INET;
|
||||||
m_IPv4.sin_family=PF_INET;
|
m_Union.m_IPv4.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||||
m_IPv4.sin_addr.s_addr=htonl(INADDR_ANY);
|
m_Union.m_IPv4.sin_port=htons(port);
|
||||||
m_IPv4.sin_port=htons(port);
|
|
||||||
break;
|
break;
|
||||||
#ifdef USE_INET6
|
|
||||||
case IPv6:
|
case IPv6:
|
||||||
|
m_Union.m_IPv6.sin6_family=PF_INET6;
|
||||||
|
memcpy(&m_Union.m_IPv6.sin6_addr, &in6addr_any, sizeof(in6addr_any));
|
||||||
|
m_Union.m_IPv6.sin6_port=htons(port);
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PS_RESULT SocketAddress::Resolve(const char *name, int port, SocketAddress &addr)
|
PS_RESULT SocketAddress::Resolve(const char *name, int port, SocketAddress &addr)
|
||||||
{
|
{
|
||||||
hostent *he;
|
if ((getaddrinfo) != NULL)
|
||||||
|
|
||||||
//FIXME IPv6 compatibilitise
|
|
||||||
|
|
||||||
// Construct address
|
|
||||||
// Try to parse dot-notation IP
|
|
||||||
addr.m_IPv4.sin_addr.s_addr=inet_addr(name);
|
|
||||||
if (addr.m_IPv4.sin_addr.s_addr==INADDR_NONE) // Not a dotted IP, try name resolution
|
|
||||||
{
|
{
|
||||||
// gethostbyname should be replaced by getaddrinfo, and all of this
|
addrinfo *ai;
|
||||||
// should be done so that IPv6 is just a manner of entering an IPv6
|
int res=getaddrinfo(name, NULL, NULL, &ai);
|
||||||
// address in the box.
|
if (res == 0)
|
||||||
he=gethostbyname(name);
|
|
||||||
if (!he)
|
|
||||||
{
|
{
|
||||||
return NO_SUCH_HOST;
|
if (ai->ai_addrlen < sizeof(addr.m_Union))
|
||||||
|
memcpy(&addr.m_Union, ai->ai_addr, ai->ai_addrlen);
|
||||||
|
switch (addr.m_Union.m_Family)
|
||||||
|
{
|
||||||
|
case IPv4:
|
||||||
|
addr.m_Union.m_IPv4.sin_port=htons(port);
|
||||||
|
break;
|
||||||
|
case IPv6:
|
||||||
|
addr.m_Union.m_IPv6.sin6_port=htons(port);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
return PS_OK;
|
||||||
}
|
}
|
||||||
addr.m_IPv4.sin_addr=*(struct in_addr *)(he->h_addr_list[0]);
|
else
|
||||||
|
return NO_SUCH_HOST;
|
||||||
}
|
}
|
||||||
addr.m_IPv4.sin_family=AF_INET;
|
else
|
||||||
addr.m_IPv4.sin_port=htons(port);
|
{
|
||||||
|
hostent *he;
|
||||||
|
|
||||||
|
addr.m_Union.m_IPv4.sin_family=AF_INET;
|
||||||
|
addr.m_Union.m_IPv4.sin_port=htons(port);
|
||||||
|
// Try to parse dot-notation IP
|
||||||
|
addr.m_Union.m_IPv4.sin_addr.s_addr=inet_addr(name);
|
||||||
|
if (addr.m_Union.m_IPv4.sin_addr.s_addr==INADDR_NONE) // Not a dotted IP, try name resolution
|
||||||
|
{
|
||||||
|
he=gethostbyname(name);
|
||||||
|
if (!he)
|
||||||
|
{
|
||||||
|
return NO_SUCH_HOST;
|
||||||
|
}
|
||||||
|
addr.m_Union.m_IPv4.sin_addr=*(struct in_addr *)(he->h_addr_list[0]);
|
||||||
|
}
|
||||||
|
return PS_OK;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return PS_OK;
|
CStr SocketAddress::GetString() const
|
||||||
|
{
|
||||||
|
char convBuf[NI_MAXHOST];
|
||||||
|
if ((getnameinfo) != NULL)
|
||||||
|
{
|
||||||
|
int res=getnameinfo((sockaddr *)&m_Union, sizeof(m_Union), convBuf, NI_MAXHOST, NULL, 0, NI_NUMERICHOST);
|
||||||
|
if (res == 0)
|
||||||
|
{
|
||||||
|
return CStr(convBuf);
|
||||||
|
}
|
||||||
|
// getnameinfo won't return a string for the IPv6 unspecified address
|
||||||
|
else if (m_Union.m_Family == IPv6 && res==EAI_NONAME)
|
||||||
|
return "::";
|
||||||
|
else
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
else if (m_Union.m_Family == IPv4)
|
||||||
|
{
|
||||||
|
sprintf(convBuf, "%d.%d.%d.%d",
|
||||||
|
m_Union.m_IPv4.sin_addr.s_addr&0xff,
|
||||||
|
(m_Union.m_IPv4.sin_addr.s_addr>>8)&0xff,
|
||||||
|
(m_Union.m_IPv4.sin_addr.s_addr>>16)&0xff,
|
||||||
|
(m_Union.m_IPv4.sin_addr.s_addr>>24)&0xff);
|
||||||
|
return CStr(convBuf);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return CStr();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SocketAddress::GetPort() const
|
||||||
|
{
|
||||||
|
switch (m_Union.m_Family)
|
||||||
|
{
|
||||||
|
case IPv4:
|
||||||
|
case IPv6:
|
||||||
|
return ntohs(m_Union.m_IPv4.sin_port);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
CSocketBase::CSocketBase()
|
CSocketBase::CSocketBase()
|
||||||
@ -345,8 +406,8 @@ PS_RESULT CSocketBase::Bind(const SocketAddress &address)
|
|||||||
|
|
||||||
PS_RESULT CSocketBase::PreAccept(SocketAddress &addr)
|
PS_RESULT CSocketBase::PreAccept(SocketAddress &addr)
|
||||||
{
|
{
|
||||||
socklen_t addrLen=sizeof(SocketAddress);
|
socklen_t addrLen=sizeof(addr.m_Union);
|
||||||
int fd=accept(m_pInternal->m_fd, (struct sockaddr *)&addr, &addrLen);
|
int fd=accept(m_pInternal->m_fd, (struct sockaddr *)&addr.m_Union, &addrLen);
|
||||||
m_pInternal->m_AcceptFd=fd;
|
m_pInternal->m_AcceptFd=fd;
|
||||||
m_pInternal->m_AcceptAddr=addr;
|
m_pInternal->m_AcceptAddr=addr;
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
@ -716,7 +777,7 @@ void CSocketBase::RunWaitLoop()
|
|||||||
printf("Commencing message loop. hWnd %p\n", g_SocketSetInternal.m_hWnd);
|
printf("Commencing message loop. hWnd %p\n", g_SocketSetInternal.m_hWnd);
|
||||||
while ((ret=GetMessage(&msg, g_SocketSetInternal.m_hWnd, 0, 0))!=0)
|
while ((ret=GetMessage(&msg, g_SocketSetInternal.m_hWnd, 0, 0))!=0)
|
||||||
{
|
{
|
||||||
printf("RunWaitLoop(): Windows message: %d:%d:%d\n", msg.message, msg.wParam, msg.lParam);
|
//printf("RunWaitLoop(): Windows message: %d:%d:%d\n", msg.message, msg.wParam, msg.lParam);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
ret=GetLastError();
|
ret=GetLastError();
|
||||||
@ -756,12 +817,12 @@ void CSocketBase::SendWaitLoopUpdate()
|
|||||||
if (m_pInternal->m_Ops & WRITE)
|
if (m_pInternal->m_Ops & WRITE)
|
||||||
wsaOps |= FD_WRITE|FD_CONNECT;
|
wsaOps |= FD_WRITE|FD_CONNECT;
|
||||||
pthread_mutex_unlock(&g_SocketSetInternal.m_Mutex);
|
pthread_mutex_unlock(&g_SocketSetInternal.m_Mutex);
|
||||||
printf("SendWaitLoopUpdate: %d: %u %x -> %p\n", m_pInternal->m_fd, m_pInternal->m_Ops, wsaOps, g_SocketSetInternal.m_hWnd);
|
//printf("SendWaitLoopUpdate: %d: %u %x -> %p\n", m_pInternal->m_fd, m_pInternal->m_Ops, wsaOps, g_SocketSetInternal.m_hWnd);
|
||||||
WSAAsyncSelect(m_pInternal->m_fd, g_SocketSetInternal.m_hWnd, MSG_SOCKET_READY, wsaOps);
|
WSAAsyncSelect(m_pInternal->m_fd, g_SocketSetInternal.m_hWnd, MSG_SOCKET_READY, wsaOps);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf("SendWaitLoopUpdate: No WaitLoop Running.\n");
|
//printf("SendWaitLoopUpdate: No WaitLoop Running.\n");
|
||||||
pthread_mutex_unlock(&g_SocketSetInternal.m_Mutex);
|
pthread_mutex_unlock(&g_SocketSetInternal.m_Mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -786,10 +847,11 @@ void CSocketBase::SetOpMask(uint ops)
|
|||||||
g_SocketSetInternal.m_HandleMap[m_pInternal->m_fd]=this;
|
g_SocketSetInternal.m_HandleMap[m_pInternal->m_fd]=this;
|
||||||
m_pInternal->m_Ops=ops;
|
m_pInternal->m_Ops=ops;
|
||||||
|
|
||||||
printf("SetOpMask(fd %d, ops %u) %u\n",
|
/*printf("SetOpMask(fd %d, ops %u) %u\n",
|
||||||
m_pInternal->m_fd,
|
m_pInternal->m_fd,
|
||||||
ops,
|
ops,
|
||||||
g_SocketSetInternal.m_HandleMap[m_pInternal->m_fd]->m_pInternal->m_Ops);
|
g_SocketSetInternal.m_HandleMap[m_pInternal->m_fd]->m_pInternal->m_Ops);*/
|
||||||
|
|
||||||
pthread_mutex_unlock(&g_SocketSetInternal.m_Mutex);
|
pthread_mutex_unlock(&g_SocketSetInternal.m_Mutex);
|
||||||
|
|
||||||
SendWaitLoopUpdate();
|
SendWaitLoopUpdate();
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "Prometheus.h"
|
#include "Prometheus.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include "CStr.h"
|
||||||
|
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
// Error Codes
|
// Error Codes
|
||||||
@ -44,9 +45,7 @@ enum SocketProtocol
|
|||||||
// you don't accidentally use an UNSPEC SocketAddress
|
// you don't accidentally use an UNSPEC SocketAddress
|
||||||
UNSPEC=((sa_family_t)-1),
|
UNSPEC=((sa_family_t)-1),
|
||||||
IPv4=PF_INET,
|
IPv4=PF_INET,
|
||||||
#ifdef USE_INET6
|
|
||||||
IPv6=PF_INET6,
|
IPv6=PF_INET6,
|
||||||
#endif
|
|
||||||
/* More protocols */
|
/* More protocols */
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -57,20 +56,24 @@ enum SocketProtocol
|
|||||||
// Modifiers Note: Each member must contain a first field, compatible with the
|
// Modifiers Note: Each member must contain a first field, compatible with the
|
||||||
// sin_family field of sockaddr_in. The field contains the SocketProtocol value
|
// sin_family field of sockaddr_in. The field contains the SocketProtocol value
|
||||||
// for the address, and it is returned by GetProtocol()
|
// for the address, and it is returned by GetProtocol()
|
||||||
union SocketAddress
|
struct SocketAddress
|
||||||
{
|
{
|
||||||
sockaddr_in m_IPv4;
|
union
|
||||||
sockaddr_in6 m_IPv6;
|
{
|
||||||
|
sa_family_t m_Family;
|
||||||
|
sockaddr_in m_IPv4;
|
||||||
|
sockaddr_in6 m_IPv6;
|
||||||
|
} m_Union;
|
||||||
|
|
||||||
inline SocketProtocol GetProtocol() const
|
inline SocketProtocol GetProtocol() const
|
||||||
{
|
{
|
||||||
return (SocketProtocol)m_IPv4.sin_family;
|
return (SocketProtocol)m_Union.m_Family;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline SocketAddress()
|
inline SocketAddress()
|
||||||
{
|
{
|
||||||
memset(this, 0, sizeof(SocketAddress));
|
memset(&m_Union, 0, sizeof(m_Union));
|
||||||
m_IPv4.sin_family=UNSPEC;
|
m_Union.m_Family=UNSPEC;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -93,16 +96,34 @@ union SocketAddress
|
|||||||
SocketAddress(u8 address[4], int port);
|
SocketAddress(u8 address[4], int port);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve the name using the systems name resolution service (i.e. DNS),
|
* Resolve the name using the system name resolution service (i.e. DNS) and
|
||||||
* and store the resulting address. When multiple addresses are found, the
|
* store the resulting address. When multiple addresses are found, the
|
||||||
* first result is returned.
|
* first result is returned.
|
||||||
*
|
*
|
||||||
|
* Note that this call will block until the name resolution attempt is
|
||||||
|
* either completed successfully or timed out.
|
||||||
|
*
|
||||||
* @param name The name to resolve
|
* @param name The name to resolve
|
||||||
* @param addr A reference to the variable to hold the address
|
* @param addr A reference to the variable to hold the address
|
||||||
*
|
*
|
||||||
* @return An error code; PS_OK for success
|
* @return The result of the operation
|
||||||
|
* @retval PS_OK The hostname was successfully retrieved
|
||||||
|
* @retval NO_SUCH_HOST The hostname was not found
|
||||||
*/
|
*/
|
||||||
static PS_RESULT Resolve(const char *name, int port, SocketAddress &addr);
|
static PS_RESULT Resolve(const char *name, int port, SocketAddress &addr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the string representation of the address, i.e. the IP (v4 or v6)
|
||||||
|
* address. Note that the port is not included in the string (mostly due to
|
||||||
|
* the fact that the port representation differs wildly between address
|
||||||
|
* families, and that Resolve does not take port as part of the hostname)
|
||||||
|
*/
|
||||||
|
CStr GetString() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the port number part of the address
|
||||||
|
*/
|
||||||
|
int GetPort() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -278,6 +299,9 @@ public:
|
|||||||
*/
|
*/
|
||||||
PS_RESULT Connect(const SocketAddress &addr);
|
PS_RESULT Connect(const SocketAddress &addr);
|
||||||
|
|
||||||
|
/** @name Functions for Server Sockets */
|
||||||
|
//@{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bind the socket to the specified address and start listening for
|
* Bind the socket to the specified address and start listening for
|
||||||
* incoming connections. You must initialize the socket for the correct
|
* incoming connections. You must initialize the socket for the correct
|
||||||
@ -314,6 +338,10 @@ public:
|
|||||||
*/
|
*/
|
||||||
void Reject();
|
void Reject();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
/** @name Status and Options */
|
||||||
|
//@{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set or reset non-blocking operation. When non-blocking, all socket
|
* Set or reset non-blocking operation. When non-blocking, all socket
|
||||||
* operations will return immediately, having done none or parts of
|
* operations will return immediately, having done none or parts of
|
||||||
@ -365,21 +393,22 @@ public:
|
|||||||
*/
|
*/
|
||||||
const SocketAddress &GetRemoteAddress();
|
const SocketAddress &GetRemoteAddress();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
/** @name Stream I/O */
|
||||||
|
//@{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to read data from the socket. Any data available without blocking
|
* Attempt to read data from the socket. Any data available without blocking
|
||||||
* will be returned. Note that a successful return does not mean that the
|
* will be returned. Note that a successful return does not mean that the
|
||||||
* whole buffer was filled.
|
* whole buffer was filled.
|
||||||
*
|
*
|
||||||
* Inputs
|
* @param buf A pointer to the buffer where the data should be written
|
||||||
* buf A pointer to the buffer where the data should be written
|
* @param len The amount of data that should be read.
|
||||||
* len The length of the buffer. The amount of data the function should
|
* @param bytesRead The number of bytes read will be stored in the variable
|
||||||
* try to read.
|
* pointed to by bytesRead
|
||||||
* bytesRead A pointer to an uint where the amount of bytes read should
|
|
||||||
* be stored
|
|
||||||
*
|
*
|
||||||
* Returns
|
* @retval PS_OK Some or all data was successfully read.
|
||||||
* PS_OK Some or all data was successfully read.
|
* @retval CONNECTION_BROKEN The socket is not connected or a server socket
|
||||||
* CONNECTION_BROKEN The socket is not connected or a server socket
|
|
||||||
*/
|
*/
|
||||||
PS_RESULT Read(void *buf, uint len, uint *bytesRead);
|
PS_RESULT Read(void *buf, uint len, uint *bytesRead);
|
||||||
|
|
||||||
@ -387,20 +416,33 @@ public:
|
|||||||
* Attempt to write data to the socket. All data that can be sent without
|
* Attempt to write data to the socket. All data that can be sent without
|
||||||
* blocking will be buffered.
|
* blocking will be buffered.
|
||||||
*
|
*
|
||||||
* Inputs
|
* @param buf A pointer to the data that should be written
|
||||||
* buf A pointer to the buffer of data to write
|
* @param len The length of the buffer.
|
||||||
* len The length of the buffer.
|
* @param bytesWritten The number of bytes written will be stored in the
|
||||||
* bytesWritten A pointer to an uint to store the bytes written
|
* variable pointed to by bytesWritten
|
||||||
*
|
*
|
||||||
* Returns
|
* @retval PS_OK Some or all data was successfully read.
|
||||||
* PS_OK Some or all data was successfully read.
|
* @retval CONNECTION_BROKEN The socket is not connected or a server socket
|
||||||
* CONNECTION_BROKEN The socket is not connected or a server socket
|
|
||||||
*/
|
*/
|
||||||
PS_RESULT Write(void *buf, uint len, uint *bytesWritten);
|
PS_RESULT Write(void *buf, uint len, uint *bytesWritten);
|
||||||
|
|
||||||
// CALLBACKS
|
//@}
|
||||||
|
/** @name Callbacks */
|
||||||
|
//@{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called by the Network Thread when data is available for reading. Use
|
||||||
|
* SetOpMask with the READ bit set to enable calling of this function.
|
||||||
|
*
|
||||||
|
* For server sockets, "data is available for reading" means "incoming
|
||||||
|
* connections are pending".
|
||||||
|
*/
|
||||||
virtual void OnRead()=0;
|
virtual void OnRead()=0;
|
||||||
|
/**
|
||||||
|
* Called by the Network Thread when data can be written to the socket.
|
||||||
|
* Will only be called when the WRITE bit is set in the Op Mask of the
|
||||||
|
* socket.
|
||||||
|
*/
|
||||||
virtual void OnWrite()=0;
|
virtual void OnWrite()=0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -408,8 +450,8 @@ public:
|
|||||||
* provides meaningful diagnostics. CONNECTION_BROKEN is the generic catch-
|
* provides meaningful diagnostics. CONNECTION_BROKEN is the generic catch-
|
||||||
* all for erroneous closures, PS_OK for clean closures.
|
* all for erroneous closures, PS_OK for clean closures.
|
||||||
*
|
*
|
||||||
* Inputs
|
* @param errorCode A result code describing the reason why the socket was
|
||||||
* errorCode The reason for closure.
|
* closed
|
||||||
*/
|
*/
|
||||||
virtual void OnClose(PS_RESULT errorCode)=0;
|
virtual void OnClose(PS_RESULT errorCode)=0;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user