// WinSockIPv6Internel.h.h
// IPV6 通讯建立的基本实现
// author: panchao 2012
#pragma once
#include <memory>
#include <tchar.h>
#include <string>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment( lib, "Ws2_32.lib")
#define WM_WINSOCKIPV6EVENTS 3040
template < class T>
class CWinSockIPv6Internel : public CMessageMap
{
private:
typedef CWinSockIPv6Internel<T> thisClass;
static const int kRECV_BUFFER_SIZE = 8096;
private:
SOCKET socket_;
std::string local_ipaddr_;
std::string remote_ipaddr_;
std::string local_port_;
std::string remote_port_;
public:
char recv_buffer_[kRECV_BUFFER_SIZE];
int recv_length_;
public:
CWinSockIPv6Internel();
virtual ~CWinSockIPv6Internel();
private: //
CWinSockIPv6Internel( const CWinSockIPv6Internel& );
CWinSockIPv6Internel& operator=( const CWinSockIPv6Internel& );
public:
// local bind parameter
const std::string& local_ipaddr() { return local_ipaddr_; }
void set_local_ipaddr( const std::string& local_ipaddr ) { local_ipaddr_ = local_ipaddr; }
const std::string& local_port() { return local_port_; }
void set_local_port( const std::string& local_port ) { local_port_ = local_port; }
// remote bind parameter
const std::string& remote_ipaddr() { return remote_ipaddr_; }
void set_remote_ipaddr( const std::string& remote_ipaddr ) { remote_ipaddr_ = remote_ipaddr; }
const std::string& remote_port() { return remote_port_; }
void set_remote_port( const std::string& remote_port ) { remote_port_ = remote_port; }
public:
int bind();
int close();
int sendto( const char * buf, int len );
protected:
BEGIN_MSG_MAP( thisClass )
MESSAGE_HANDLER( WM_WINSOCKIPV6EVENTS, OnWinsockIPv6Events)
END_MSG_MAP()
LRESULT OnWinsockIPv6Events(UINT, WPARAM, LPARAM, BOOL&);
};
template < class T>
CWinSockIPv6Internel<T>::
CWinSockIPv6Internel() :
socket_(INVALID_SOCKET),
local_ipaddr_(),
remote_ipaddr_(),
local_port_(),
remote_port_(),
recv_length_(0)
{
}
template < class T>
CWinSockIPv6Internel<T>::
~CWinSockIPv6Internel()
{
close();
}
template < class T>
int
CWinSockIPv6Internel<T>::
bind()
{
if ( socket_ != INVALID_SOCKET)
return 1;
WSADATA wsaData;
if ( ::WSAStartup(MAKEWORD(2, 2), &wsaData) != 0 )
{
::WSACleanup();
return 9;
}
int ret;
addrinfo hints;
addrinfo* p_source;
memset( &hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_NUMERICHOST; // Nodename must be a numeric address string
ret = ::getaddrinfo( local_ipaddr_.c_str(), local_port_.c_str(), &hints, &p_source);
if ( ret != 0 ) {
ATLASSERT( p_source == NULL );
return 2;
}
ATLASSERT( p_source != NULL );
socket_ = ::socket( p_source->ai_family, p_source->ai_socktype, p_source->ai_protocol);
if ( socket_ == INVALID_SOCKET) {
::freeaddrinfo( p_source);
return 3;
}
ret = ::bind ( socket_, p_source->ai_addr, p_source->ai_addrlen);
::freeaddrinfo( p_source); // no longer need it.
//getsockname
if ( ret == SOCKET_ERROR) {
::closesocket( socket_);
socket_ = INVALID_SOCKET;
return 4;
}
BOOL broadcast = TRUE;
::setsockopt( socket_, SOL_SOCKET, SO_BROADCAST, (const char*)&broadcast, sizeof(BOOL));
ATLASSERT( ::IsWindow(static_cast<T*>(this)->m_hWnd) );
ret = ::WSAAsyncSelect( socket_, static_cast<T*>(this)->m_hWnd, WM_WINSOCKIPV6EVENTS, FD_READ);
if ( ret == SOCKET_ERROR ) {
::closesocket( socket_);
socket_ = INVALID_SOCKET;
return 5;
}
return 0;
}
template < class T>
int
CWinSockIPv6Internel<T>::
close()
{
if ( socket_ == INVALID_SOCKET)
return 0;
::closesocket( socket_);
socket_ = INVALID_SOCKET;
::WSACleanup();
return 0;
}
template < class T>
int
CWinSockIPv6Internel<T>::
sendto( const char * buf, int len )
{
if ( socket_ == INVALID_SOCKET)
return 0;
int ret;
addrinfo hints;
addrinfo* p_destination;
memset( &hints, 0, sizeof(hints));
hints.ai_family = AF_INET6;
hints.ai_socktype = SOCK_DGRAM;
hints.ai_protocol = IPPROTO_UDP;
hints.ai_flags = AI_NUMERICHOST; // Nodename must be a numeric address string
ret = ::getaddrinfo( remote_ipaddr_.c_str(), remote_port_.c_str(), &hints, &p_destination);
if ( ret != 0 ) {
ATLASSERT( p_destination == NULL );
return 2;
}
ATLASSERT( p_destination != NULL );
ret = ::sendto( socket_, buf, len, 0,
p_destination->ai_addr, p_destination->ai_addrlen);
::freeaddrinfo( p_destination); // no longer need it.
return ret;
}
template < class T>
LRESULT
CWinSockIPv6Internel<T>::
OnWinsockIPv6Events(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if ( socket_ == INVALID_SOCKET)
return 0;
int ret;
sockaddr_in6 recvAddr;
memset( &recvAddr, 0, sizeof(recvAddr));
int len = sizeof(recvAddr);
ret = ::recvfrom( socket_, recv_buffer_, kRECV_BUFFER_SIZE, 0, (SOCKADDR*)&recvAddr, &len);
if ( ret > 0 )
{
recv_length_ = ret;
static_cast<T*>(this)->Fire_DataArrival( recv_length_ );
recv_length_ = 0;
}
return S_OK;
}