IPv6 Compatability (DLL-detection aware), added GetString() and GetPort() to SocketAddress, Documentation

This was SVN commit r138.
This commit is contained in:
Simon Brenner 2003-12-10 19:39:22 +00:00
parent 50ad3a0e42
commit 73771118b7
2 changed files with 165 additions and 61 deletions

View File

@ -2,6 +2,7 @@
#include "NetworkInternal.h"
#include "misc.h"
#include "CStr.h"
#include <errno.h>
@ -41,47 +42,107 @@ 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)
{
if ((getaddrinfo) != NULL)
{
addrinfo *ai;
int res=getaddrinfo(name, NULL, NULL, &ai);
if (res == 0)
{
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;
}
else
return NO_SUCH_HOST;
}
else
{
hostent *he;
//FIXME IPv6 compatibilitise
// Construct address
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_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
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
{
// 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)
{
return NO_SUCH_HOST;
}
addr.m_IPv4.sin_addr=*(struct in_addr *)(he->h_addr_list[0]);
addr.m_Union.m_IPv4.sin_addr=*(struct in_addr *)(he->h_addr_list[0]);
}
addr.m_IPv4.sin_family=AF_INET;
addr.m_IPv4.sin_port=htons(port);
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();

View File

@ -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
{
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;
};