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 "misc.h"
|
||||
#include "CStr.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
@ -41,46 +42,106 @@ PS_RESULT GetPS_RESULT(int error)
|
||||
|
||||
SocketAddress::SocketAddress(int port, SocketProtocol proto)
|
||||
{
|
||||
memset(&m_Union, 0, sizeof(m_Union));
|
||||
switch (proto)
|
||||
{
|
||||
case IPv4:
|
||||
memset(&m_IPv4, 0, sizeof(m_IPv4));
|
||||
m_IPv4.sin_family=PF_INET;
|
||||
m_IPv4.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
m_IPv4.sin_port=htons(port);
|
||||
m_Union.m_IPv4.sin_family=PF_INET;
|
||||
m_Union.m_IPv4.sin_addr.s_addr=htonl(INADDR_ANY);
|
||||
m_Union.m_IPv4.sin_port=htons(port);
|
||||
break;
|
||||
#ifdef USE_INET6
|
||||
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;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
PS_RESULT SocketAddress::Resolve(const char *name, int port, SocketAddress &addr)
|
||||
{
|
||||
hostent *he;
|
||||
|
||||
//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
|
||||
if ((getaddrinfo) != NULL)
|
||||
{
|
||||
// gethostbyname should be replaced by getaddrinfo, and all of this
|
||||
// should be done so that IPv6 is just a manner of entering an IPv6
|
||||
// address in the box.
|
||||
he=gethostbyname(name);
|
||||
if (!he)
|
||||
addrinfo *ai;
|
||||
int res=getaddrinfo(name, NULL, NULL, &ai);
|
||||
if (res == 0)
|
||||
{
|
||||
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;
|
||||
addr.m_IPv4.sin_port=htons(port);
|
||||
else
|
||||
{
|
||||
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()
|
||||
@ -345,8 +406,8 @@ PS_RESULT CSocketBase::Bind(const SocketAddress &address)
|
||||
|
||||
PS_RESULT CSocketBase::PreAccept(SocketAddress &addr)
|
||||
{
|
||||
socklen_t addrLen=sizeof(SocketAddress);
|
||||
int fd=accept(m_pInternal->m_fd, (struct sockaddr *)&addr, &addrLen);
|
||||
socklen_t addrLen=sizeof(addr.m_Union);
|
||||
int fd=accept(m_pInternal->m_fd, (struct sockaddr *)&addr.m_Union, &addrLen);
|
||||
m_pInternal->m_AcceptFd=fd;
|
||||
m_pInternal->m_AcceptAddr=addr;
|
||||
if (fd != -1)
|
||||
@ -716,7 +777,7 @@ void CSocketBase::RunWaitLoop()
|
||||
printf("Commencing message loop. hWnd %p\n", g_SocketSetInternal.m_hWnd);
|
||||
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)
|
||||
{
|
||||
ret=GetLastError();
|
||||
@ -756,12 +817,12 @@ void CSocketBase::SendWaitLoopUpdate()
|
||||
if (m_pInternal->m_Ops & WRITE)
|
||||
wsaOps |= FD_WRITE|FD_CONNECT;
|
||||
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);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("SendWaitLoopUpdate: No WaitLoop Running.\n");
|
||||
//printf("SendWaitLoopUpdate: No WaitLoop Running.\n");
|
||||
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;
|
||||
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,
|
||||
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);
|
||||
|
||||
SendWaitLoopUpdate();
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "types.h"
|
||||
#include "Prometheus.h"
|
||||
#include <string.h>
|
||||
#include "CStr.h"
|
||||
|
||||
//-------------------------------------------------
|
||||
// Error Codes
|
||||
@ -44,9 +45,7 @@ enum SocketProtocol
|
||||
// you don't accidentally use an UNSPEC SocketAddress
|
||||
UNSPEC=((sa_family_t)-1),
|
||||
IPv4=PF_INET,
|
||||
#ifdef USE_INET6
|
||||
IPv6=PF_INET6,
|
||||
#endif
|
||||
/* More protocols */
|
||||
};
|
||||
|
||||
@ -57,20 +56,24 @@ enum SocketProtocol
|
||||
// Modifiers Note: Each member must contain a first field, compatible with the
|
||||
// sin_family field of sockaddr_in. The field contains the SocketProtocol value
|
||||
// for the address, and it is returned by GetProtocol()
|
||||
union SocketAddress
|
||||
struct SocketAddress
|
||||
{
|
||||
sockaddr_in m_IPv4;
|
||||
sockaddr_in6 m_IPv6;
|
||||
union
|
||||
{
|
||||
sa_family_t m_Family;
|
||||
sockaddr_in m_IPv4;
|
||||
sockaddr_in6 m_IPv6;
|
||||
} m_Union;
|
||||
|
||||
inline SocketProtocol GetProtocol() const
|
||||
{
|
||||
return (SocketProtocol)m_IPv4.sin_family;
|
||||
return (SocketProtocol)m_Union.m_Family;
|
||||
}
|
||||
|
||||
inline SocketAddress()
|
||||
{
|
||||
memset(this, 0, sizeof(SocketAddress));
|
||||
m_IPv4.sin_family=UNSPEC;
|
||||
memset(&m_Union, 0, sizeof(m_Union));
|
||||
m_Union.m_Family=UNSPEC;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -93,16 +96,34 @@ union SocketAddress
|
||||
SocketAddress(u8 address[4], int port);
|
||||
|
||||
/**
|
||||
* Resolve the name using the systems name resolution service (i.e. DNS),
|
||||
* and store the resulting address. When multiple addresses are found, the
|
||||
* Resolve the name using the system name resolution service (i.e. DNS) and
|
||||
* store the resulting address. When multiple addresses are found, the
|
||||
* 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 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);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/** @name Functions for Server Sockets */
|
||||
//@{
|
||||
|
||||
/**
|
||||
* Bind the socket to the specified address and start listening for
|
||||
* incoming connections. You must initialize the socket for the correct
|
||||
@ -314,6 +338,10 @@ public:
|
||||
*/
|
||||
void Reject();
|
||||
|
||||
//@}
|
||||
/** @name Status and Options */
|
||||
//@{
|
||||
|
||||
/**
|
||||
* Set or reset non-blocking operation. When non-blocking, all socket
|
||||
* operations will return immediately, having done none or parts of
|
||||
@ -365,21 +393,22 @@ public:
|
||||
*/
|
||||
const SocketAddress &GetRemoteAddress();
|
||||
|
||||
//@}
|
||||
/** @name Stream I/O */
|
||||
//@{
|
||||
|
||||
/**
|
||||
* 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
|
||||
* whole buffer was filled.
|
||||
*
|
||||
* Inputs
|
||||
* buf A pointer to the buffer where the data should be written
|
||||
* len The length of the buffer. The amount of data the function should
|
||||
* try to read.
|
||||
* bytesRead A pointer to an uint where the amount of bytes read should
|
||||
* be stored
|
||||
* @param buf A pointer to the buffer where the data should be written
|
||||
* @param len The amount of data that should be read.
|
||||
* @param bytesRead The number of bytes read will be stored in the variable
|
||||
* pointed to by bytesRead
|
||||
*
|
||||
* Returns
|
||||
* PS_OK Some or all data was successfully read.
|
||||
* CONNECTION_BROKEN The socket is not connected or a server socket
|
||||
* @retval PS_OK Some or all data was successfully read.
|
||||
* @retval CONNECTION_BROKEN The socket is not connected or a server socket
|
||||
*/
|
||||
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
|
||||
* blocking will be buffered.
|
||||
*
|
||||
* Inputs
|
||||
* buf A pointer to the buffer of data to write
|
||||
* len The length of the buffer.
|
||||
* bytesWritten A pointer to an uint to store the bytes written
|
||||
* @param buf A pointer to the data that should be written
|
||||
* @param len The length of the buffer.
|
||||
* @param bytesWritten The number of bytes written will be stored in the
|
||||
* variable pointed to by bytesWritten
|
||||
*
|
||||
* Returns
|
||||
* PS_OK Some or all data was successfully read.
|
||||
* CONNECTION_BROKEN The socket is not connected or a server socket
|
||||
* @retval PS_OK Some or all data was successfully read.
|
||||
* @retval CONNECTION_BROKEN The socket is not connected or a server socket
|
||||
*/
|
||||
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;
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/**
|
||||
@ -408,8 +450,8 @@ public:
|
||||
* provides meaningful diagnostics. CONNECTION_BROKEN is the generic catch-
|
||||
* all for erroneous closures, PS_OK for clean closures.
|
||||
*
|
||||
* Inputs
|
||||
* errorCode The reason for closure.
|
||||
* @param errorCode A result code describing the reason why the socket was
|
||||
* closed
|
||||
*/
|
||||
virtual void OnClose(PS_RESULT errorCode)=0;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user