cwUtility, cwDnsSd, cwEuCon : Initial commit.
This commit is contained in:
parent
23f1fbf460
commit
a6692e3365
457
cwDnsSd.cpp
Normal file
457
cwDnsSd.cpp
Normal file
@ -0,0 +1,457 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwTime.h"
|
||||||
|
|
||||||
|
#include "cwThread.h"
|
||||||
|
#include "cwTcpSocket.h"
|
||||||
|
#include "cwTcpSocketSrv.h"
|
||||||
|
|
||||||
|
#include "cwDnsSd.h"
|
||||||
|
#include "cwUtility.h"
|
||||||
|
#include "dns_sd/dns_sd.h"
|
||||||
|
#include "dns_sd/fader.h"
|
||||||
|
|
||||||
|
#define MDNS_PORT 5353
|
||||||
|
#define MDNS_IP "224.0.0.251"
|
||||||
|
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace net
|
||||||
|
{
|
||||||
|
namespace dnssd
|
||||||
|
{
|
||||||
|
typedef struct text_str
|
||||||
|
{
|
||||||
|
char* text;
|
||||||
|
struct text_str* link;
|
||||||
|
} text_t;
|
||||||
|
|
||||||
|
typedef struct dnssd_str
|
||||||
|
{
|
||||||
|
srv::handle_t udpH;
|
||||||
|
srv::handle_t tcpH;
|
||||||
|
unsigned udpRecvBufByteN;
|
||||||
|
unsigned tcpRecvBufByteN;
|
||||||
|
text_t* textL;
|
||||||
|
dns_sd* dnsSd;
|
||||||
|
fader* fdr;
|
||||||
|
|
||||||
|
char* serviceName;
|
||||||
|
char* serviceType;
|
||||||
|
char* serviceDomain;
|
||||||
|
char* hostName;
|
||||||
|
char* hostIpAddr;
|
||||||
|
uint16_t hostPort;
|
||||||
|
unsigned char hostMac[6];
|
||||||
|
|
||||||
|
unsigned cbCnt;
|
||||||
|
time::spec_t t0;
|
||||||
|
|
||||||
|
} dnssd_t;
|
||||||
|
|
||||||
|
inline dnssd_t* _handleToPtr( handle_t h )
|
||||||
|
{
|
||||||
|
return handleToPtr<handle_t,dnssd_t>(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _destroy( dnssd_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
mem::release(p->serviceName);
|
||||||
|
mem::release(p->serviceType);
|
||||||
|
mem::release(p->serviceDomain);
|
||||||
|
mem::release(p->hostName);
|
||||||
|
mem::release(p->hostIpAddr);
|
||||||
|
|
||||||
|
|
||||||
|
text_t* t0 = p->textL;
|
||||||
|
while( t0 != nullptr )
|
||||||
|
{
|
||||||
|
text_t* t1 = t0->link;
|
||||||
|
mem::release(t0->text);
|
||||||
|
mem::release(t0);
|
||||||
|
t0 = t1;
|
||||||
|
}
|
||||||
|
|
||||||
|
srv::destroy( p->tcpH );
|
||||||
|
srv::destroy( p->udpH );
|
||||||
|
|
||||||
|
if( p->fdr != nullptr )
|
||||||
|
{
|
||||||
|
delete p->fdr;
|
||||||
|
p->fdr = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p->dnsSd != nullptr )
|
||||||
|
{
|
||||||
|
delete p->dnsSd;
|
||||||
|
p->dnsSd = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p->dnsSd != nullptr )
|
||||||
|
delete p->dnsSd;
|
||||||
|
|
||||||
|
mem::release(p);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by 'dns_sd' to send UDP messages.
|
||||||
|
void udpSendCallback( void* arg, const void* buf, unsigned bufByteN )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
dnssd_t* p = (dnssd_t*)arg;
|
||||||
|
//printHex(buf,bufByteN);
|
||||||
|
if((rc = srv::send(p->udpH,buf,bufByteN,MDNS_IP,MDNS_PORT)) != kOkRC )
|
||||||
|
cwLogError(rc,"UDP send failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by 'fader' to send TCP messages.
|
||||||
|
void tcpSendCallback( void* arg, const void* buf, unsigned bufByteN )
|
||||||
|
{
|
||||||
|
rc_t rc;
|
||||||
|
dnssd_t* p = (dnssd_t*)arg;
|
||||||
|
if((rc = srv::send(p->tcpH,buf,bufByteN)) != kOkRC )
|
||||||
|
cwLogError(rc,"TCP send failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by UDP socket with incoming MDNS data.
|
||||||
|
void udpReceiveCallback( void* arg, const void* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
|
||||||
|
{
|
||||||
|
dnssd_t* p = static_cast<dnssd_t*>(arg);
|
||||||
|
p->dnsSd->receive(data,dataByteCnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by TCP socket with incoming EuCon data
|
||||||
|
void tcpReceiveCallback( void* arg, const void* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
|
||||||
|
{
|
||||||
|
dnssd_t* p = static_cast<dnssd_t*>(arg);
|
||||||
|
|
||||||
|
if( dataByteCnt > 0 )
|
||||||
|
{
|
||||||
|
p->fdr->host_receive( data, dataByteCnt );
|
||||||
|
}
|
||||||
|
|
||||||
|
time::spec_t t1;
|
||||||
|
time::get(t1);
|
||||||
|
unsigned ms = time::elapsedMs( &p->t0, &t1 );
|
||||||
|
if( ms > 50 )
|
||||||
|
{
|
||||||
|
p->cbCnt+=1;
|
||||||
|
p->fdr->tick();
|
||||||
|
p->t0 = t1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( p->cbCnt > 20 )
|
||||||
|
{
|
||||||
|
printf(".");
|
||||||
|
fflush(stdout);
|
||||||
|
p->cbCnt = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _pushTextRecdField( dnssd_t* p, const char* text )
|
||||||
|
{
|
||||||
|
text_t* t = mem::allocZ<text_t>();
|
||||||
|
t->text = mem::duplStr(text);
|
||||||
|
t->link = p->textL;
|
||||||
|
p->textL = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _setTextRecdFieldsV( dnssd_t* p, const char* text, va_list vl )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
char* s0;
|
||||||
|
|
||||||
|
if( text != nullptr )
|
||||||
|
{
|
||||||
|
_pushTextRecdField( p, text );
|
||||||
|
|
||||||
|
while( (s0 = va_arg(vl,char*)) != nullptr )
|
||||||
|
{
|
||||||
|
_pushTextRecdField( p, s0 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* _formatText( dnssd_t* p )
|
||||||
|
{
|
||||||
|
unsigned n = 0;
|
||||||
|
text_t* t = p->textL;
|
||||||
|
for(; t != nullptr; t=t->link )
|
||||||
|
n += strlen(t->text) + 1;
|
||||||
|
|
||||||
|
char* s = (char*)calloc(1,n);
|
||||||
|
char* s0 = s;
|
||||||
|
|
||||||
|
for(t=p->textL; t != nullptr; t=t->link, s++ )
|
||||||
|
{
|
||||||
|
strcpy(s,t->text);
|
||||||
|
s += strlen(t->text);
|
||||||
|
s[0] = '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
// replace the ending \n with a zero-terminator
|
||||||
|
s0[n-1] = '\0';
|
||||||
|
|
||||||
|
return s0;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _init( dnssd_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
char* formatStr = nullptr;
|
||||||
|
socket::handle_t sockH = srv::socketHandle( p->tcpH );
|
||||||
|
struct sockaddr_in hostAddr;
|
||||||
|
|
||||||
|
// get the 32bit host address
|
||||||
|
if((rc = initAddr( sockH, p->hostIpAddr, p->hostPort, &hostAddr )) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
// Get the service 'TXT' fields in the format expected by dns_sd
|
||||||
|
formatStr = _formatText(p);
|
||||||
|
|
||||||
|
if( p->dnsSd != nullptr )
|
||||||
|
delete p->dnsSd;
|
||||||
|
|
||||||
|
// create the MDNS logic object
|
||||||
|
p->dnsSd = new dns_sd(udpSendCallback,p);
|
||||||
|
|
||||||
|
// create the Surface logic object
|
||||||
|
p->fdr = new fader(p->hostMac, hostAddr.sin_addr.s_addr, tcpSendCallback, p );
|
||||||
|
|
||||||
|
// Setup the internal dnsSd object
|
||||||
|
p->dnsSd->setup( p->serviceName, p->serviceType, p->serviceDomain, p->hostName, hostAddr.sin_addr.s_addr, p->hostPort, formatStr );
|
||||||
|
|
||||||
|
free(formatStr);
|
||||||
|
|
||||||
|
p->dnsSd->gen_response();
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::net::dnssd::createV( handle_t& hRef, const char* name, const char* type, const char* domain, const char* hostName, const char* hostIpAddr, uint16_t hostPort, const unsigned char hostMac[6], const char* text, va_list vl )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned udpRecvBufByteN = 4096;
|
||||||
|
unsigned udpTimeOutMs = 50;
|
||||||
|
unsigned tcpTimeOutMs = 50;
|
||||||
|
|
||||||
|
if((rc = destroy(hRef)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
dnssd_t* p = mem::allocZ<dnssd_t>();
|
||||||
|
p->udpRecvBufByteN = udpRecvBufByteN;
|
||||||
|
|
||||||
|
// create the mDNS UDP socket server
|
||||||
|
if((rc = srv::create(
|
||||||
|
p->udpH,
|
||||||
|
MDNS_PORT,
|
||||||
|
socket::kBlockingFl | socket::kReuseAddrFl | socket::kReusePortFl | socket::kMultiCastTtlFl | socket::kMultiCastLoopFl,
|
||||||
|
srv::kUseRecvFromFl,
|
||||||
|
udpReceiveCallback,
|
||||||
|
p,
|
||||||
|
p->udpRecvBufByteN,
|
||||||
|
udpTimeOutMs,
|
||||||
|
NULL,
|
||||||
|
socket::kInvalidPortNumber )) != kOkRC )
|
||||||
|
{
|
||||||
|
return cwLogError(rc,"mDNS UDP socket create failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the mDNS socket to the multicast group
|
||||||
|
if((rc = join_multicast_group( socketHandle(p->udpH), MDNS_IP )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// set the TTL for multicast
|
||||||
|
if((rc = set_multicast_time_to_live( socketHandle(p->udpH), 255 )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// create the service TCP socket server
|
||||||
|
if((rc = srv::create(
|
||||||
|
p->tcpH,
|
||||||
|
hostPort,
|
||||||
|
socket::kTcpFl | socket::kBlockingFl | socket::kStreamFl | socket::kListenFl,
|
||||||
|
srv::kUseAcceptFl | srv::kRecvTimeOutFl,
|
||||||
|
tcpReceiveCallback,
|
||||||
|
p,
|
||||||
|
p->tcpRecvBufByteN,
|
||||||
|
tcpTimeOutMs,
|
||||||
|
NULL,
|
||||||
|
socket::kInvalidPortNumber,
|
||||||
|
hostIpAddr)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"mDNS TCP socket create failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
p->serviceName = mem::duplStr(name);
|
||||||
|
p->serviceType = mem::duplStr(type);
|
||||||
|
p->serviceDomain = mem::duplStr(domain);
|
||||||
|
p->hostName = mem::duplStr(hostName);
|
||||||
|
p->hostIpAddr = mem::duplStr(hostIpAddr);
|
||||||
|
p->hostPort = hostPort;
|
||||||
|
p->dnsSd = nullptr;
|
||||||
|
memcpy(p->hostMac,hostMac,6);
|
||||||
|
|
||||||
|
if((rc = _setTextRecdFieldsV( p, text, vl )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
hRef.set(p);
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
if( rc != kOkRC )
|
||||||
|
_destroy(p);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::net::dnssd::create( handle_t& hRef, const char* name, const char* type, const char* domain, const char* hostname, const char* hostIpAddr, uint16_t hostPort, const unsigned char hostMac[6], const char* text, ... )
|
||||||
|
{
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl,text);
|
||||||
|
rc_t rc = createV( hRef, name, type, domain, hostname, hostIpAddr, hostPort, hostMac, text, vl );
|
||||||
|
va_end(vl);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::net::dnssd::destroy( handle_t& hRef )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( !hRef.isValid() )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
dnssd_t* p = _handleToPtr(hRef);
|
||||||
|
if((rc = _destroy(p)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
hRef.clear();
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::net::srv::handle_t cw::net::dnssd::tcpHandle( handle_t h )
|
||||||
|
{
|
||||||
|
dnssd_t* p = _handleToPtr(h);
|
||||||
|
return p->tcpH;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::net::srv::handle_t cw::net::dnssd::udpHandle( handle_t h )
|
||||||
|
{
|
||||||
|
dnssd_t* p = _handleToPtr(h);
|
||||||
|
return p->udpH;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::net::dnssd::setTextRecdFields( handle_t h, const char* text, ... )
|
||||||
|
{
|
||||||
|
va_list vl;
|
||||||
|
va_start(vl,text);
|
||||||
|
dnssd_t* p = _handleToPtr(h);
|
||||||
|
rc_t rc = _setTextRecdFieldsV(p,text,vl);
|
||||||
|
va_end(vl);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::net::dnssd::start( handle_t h )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
dnssd_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
time::get(p->t0);
|
||||||
|
|
||||||
|
if((rc = _init(p)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
// start the mDNS socket server
|
||||||
|
if((rc = srv::start( p->udpH )) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
// start the TCP socket server
|
||||||
|
if((rc = srv::start( p->tcpH )) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::net::dnssd::test()
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
const char* netIFace = "wlp3s0";
|
||||||
|
const char* serviceName = "MC Mix - 1";
|
||||||
|
const char* serviceType = "_EuConProxy._tcp";
|
||||||
|
const char* serviceDomain = "local";
|
||||||
|
uint16_t hostPort = 49168;
|
||||||
|
const unsigned sbufN = 31;
|
||||||
|
handle_t h;
|
||||||
|
unsigned char hostMac[6];
|
||||||
|
char sbuf[ sbufN+1 ];
|
||||||
|
char* text0;
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
|
||||||
|
// Get the host name and address from the selected network interface
|
||||||
|
char hostname[ _POSIX_HOST_NAME_MAX+1 ];
|
||||||
|
char hostIpAddr[ INET_ADDRSTRLEN+1 ];
|
||||||
|
|
||||||
|
//memset(hostMac,0,6);
|
||||||
|
//memset(hostname,0,_POSIX_HOST_NAME_MAX+1);
|
||||||
|
//memset(&addr, 0, sizeof(struct sockaddr_in));
|
||||||
|
//memset(hostIpAddr,0,INET_ADDRSTRLEN+1);
|
||||||
|
|
||||||
|
if( socket::get_info( netIFace, hostMac, hostname, sizeof(hostname), &addr ) == kOkRC )
|
||||||
|
{
|
||||||
|
char ip[128];
|
||||||
|
memset(ip,0,128);
|
||||||
|
socket::addrToString(&addr,hostIpAddr,sizeof(hostIpAddr));
|
||||||
|
printf("%s %s 0x%x %02x:%02x:%02x:%02x:%02x:%02x\n", hostname, ip, addr.sin_addr.s_addr, hostMac[0],hostMac[1],hostMac[2],hostMac[3],hostMac[4],hostMac[5] );
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Override the host name and mac address to match the example Wireshark captures
|
||||||
|
//
|
||||||
|
strcpy(hostname,"Euphonix-MC-0090D580F4DE");
|
||||||
|
unsigned char tmp_mac[] = { 0x00, 0x90, 0xd5, 0x80, 0xf4, 0xde };
|
||||||
|
memcpy(hostMac,tmp_mac,6);
|
||||||
|
|
||||||
|
|
||||||
|
// create the DNS-SD server
|
||||||
|
if((rc = create( h, serviceName, serviceType, serviceDomain, hostname, hostIpAddr, hostPort, hostMac, nullptr, nullptr )) != kOkRC )
|
||||||
|
return cwLogError(rc,"Unable to create DNS-SD server.");
|
||||||
|
|
||||||
|
// form the 'lmac=38-C9-86-37-44-E7'
|
||||||
|
text0 = mem::printf<char>(nullptr,"lmac=%02x-%02x-%02x-%02x-%02x-%02x",hostMac[0],hostMac[1],hostMac[2],hostMac[3],hostMac[4],hostMac[5]);
|
||||||
|
|
||||||
|
// set the DNS-SD 'SRV' text fields
|
||||||
|
if((rc = setTextRecdFields( h, "dummy=0", text0, nullptr )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// start the DNS-SD server
|
||||||
|
if((rc = start( h )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
|
printf("? ");
|
||||||
|
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
||||||
|
{
|
||||||
|
|
||||||
|
if( strcmp(sbuf,"quit\n") == 0 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
mem::release(text0);
|
||||||
|
rc = destroy(h);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
32
cwDnsSd.h
Normal file
32
cwDnsSd.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef cwDnsSd_h
|
||||||
|
#define cwDnsSd_h
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace net
|
||||||
|
{
|
||||||
|
namespace dnssd
|
||||||
|
{
|
||||||
|
|
||||||
|
typedef handle<struct dnssd_str> handle_t;
|
||||||
|
|
||||||
|
rc_t createV( handle_t& hRef, const char* name, const char* type, const char* domain, const char* hostname, const char* hostIpAddr, uint16_t hostPort, const unsigned char hostMac[6], const char* text, va_list vl );
|
||||||
|
rc_t create( handle_t& hRef, const char* name, const char* type, const char* domain, const char* hostname, const char* hostIpAddr, uint16_t hostPort, const unsigned char hostMac[6], const char* text, ... );
|
||||||
|
|
||||||
|
rc_t destroy( handle_t& hRef );
|
||||||
|
|
||||||
|
srv::handle_t tcpHandle( handle_t h );
|
||||||
|
srv::handle_t udpHandle( handle_t h );
|
||||||
|
|
||||||
|
rc_t setTextRecdFieldsV( handle_t h, const char* text, va_list vl );
|
||||||
|
rc_t setTextRecdFields( handle_t h, const char* text, ... );
|
||||||
|
|
||||||
|
rc_t start( handle_t h );
|
||||||
|
|
||||||
|
rc_t test();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
345
cwEuCon.cpp
Normal file
345
cwEuCon.cpp
Normal file
@ -0,0 +1,345 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include "cwMem.h"
|
||||||
|
#include "cwTime.h"
|
||||||
|
|
||||||
|
#include "cwThread.h"
|
||||||
|
#include "cwTcpSocket.h"
|
||||||
|
#include "cwTcpSocketSrv.h"
|
||||||
|
#include "cwUtility.h"
|
||||||
|
|
||||||
|
#include "cwEuCon.h"
|
||||||
|
#include "dns_sd/dns_sd_const.h"
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace net
|
||||||
|
{
|
||||||
|
namespace eucon
|
||||||
|
{
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
kSendHandshake_0_Id,
|
||||||
|
kWaitForBeat_1_Id, //
|
||||||
|
kWaitForHandshake_2_Id,
|
||||||
|
kRunning_3_Id
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct eucon_str
|
||||||
|
{
|
||||||
|
srv::handle_t udpH;
|
||||||
|
srv::handle_t tcpH;
|
||||||
|
unsigned udpRecvBufByteN;
|
||||||
|
unsigned tcpRecvBufByteN;
|
||||||
|
socket::portNumber_t servicePort;
|
||||||
|
unsigned protoState;
|
||||||
|
unsigned cbCnt;
|
||||||
|
time::spec_t t0;
|
||||||
|
} eucon_t;
|
||||||
|
|
||||||
|
inline eucon_t* _handleToPtr( handle_t h )
|
||||||
|
{ return handleToPtr<handle_t,eucon_t>(h); }
|
||||||
|
|
||||||
|
|
||||||
|
rc_t _destroy( eucon_t* p)
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
srv::destroy(p->udpH);
|
||||||
|
srv::destroy(p->tcpH);
|
||||||
|
|
||||||
|
mem::release(p);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _init( eucon_t* p )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _sendHandshake_0( socket::handle_t sockH, const char* label )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned char buf[88];
|
||||||
|
memset(buf,0,88);
|
||||||
|
buf[0] = 0x0a;
|
||||||
|
|
||||||
|
// send the initial handshake
|
||||||
|
if((rc = socket::send( sockH, buf, 88 )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"Initial TCP '%s' request failed.",label);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc_t _sendHandshake_1( socket::handle_t sockH )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
unsigned char buf[4];
|
||||||
|
memset(buf,0,4);
|
||||||
|
buf[0] = 0x0c;
|
||||||
|
|
||||||
|
// send the initial handshake
|
||||||
|
if((rc = socket::send( sockH, buf, 4 )) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"TCP '%s' request failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _udpReceiveCallback( void* arg, const void* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
eucon_t* p = (eucon_t*)arg;
|
||||||
|
const uint16_t* u = (const uint16_t*)data;
|
||||||
|
|
||||||
|
// if this is a DNS-SD reply
|
||||||
|
if( cwIsFlag(ntohs(u[1]), kReplyHdrDnsFl ) )
|
||||||
|
{
|
||||||
|
const char* name = (const char*)(u+6);
|
||||||
|
const char* label = "MC Mix - 1";
|
||||||
|
|
||||||
|
//printf("%.*s|%li\n", name[0], name+1, strlen(label) );
|
||||||
|
|
||||||
|
// if this a 'MC Mix' DNS-SD SRV reply
|
||||||
|
if( strncmp(name+1, label, name[0]) == 0 )
|
||||||
|
{
|
||||||
|
// get the address of the advertising 'MC Mix'
|
||||||
|
char addrBuf[ INET_ADDRSTRLEN+1 ];
|
||||||
|
if(socket::addrToString( fromAddr, addrBuf, INET_ADDRSTRLEN ) == kOkRC )
|
||||||
|
{
|
||||||
|
socket::handle_t sockH = socketHandle(p->tcpH);
|
||||||
|
|
||||||
|
// if the socket is not connected
|
||||||
|
if( socket::isConnected(sockH) == false )
|
||||||
|
{
|
||||||
|
// Connect to the 'MC Mix' service
|
||||||
|
if((rc = socket::connect( sockH, addrBuf, p->servicePort )) != kOkRC )
|
||||||
|
{
|
||||||
|
cwLogError(rc,"Connection to '%s' service failed.", label );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("Connected.\n");
|
||||||
|
|
||||||
|
if( true )
|
||||||
|
{
|
||||||
|
struct sockaddr_in addr;
|
||||||
|
char aBuf[ INET_ADDRSTRLEN+1 ];
|
||||||
|
socket::peername( sockH, &addr );
|
||||||
|
socket::addrToString( &addr, aBuf, INET_ADDRSTRLEN);
|
||||||
|
printf("PEER: %i %s\n", addr.sin_port,aBuf );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the initial handshake to the Surface
|
||||||
|
_sendHandshake_0( sockH, label );
|
||||||
|
|
||||||
|
// FENCE
|
||||||
|
p->protoState = kWaitForBeat_1_Id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _tcpReceiveCallback( void* arg, const void* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
|
||||||
|
{
|
||||||
|
eucon_t* p = static_cast<eucon_t*>(arg);
|
||||||
|
|
||||||
|
if( dataByteCnt > 0)
|
||||||
|
{
|
||||||
|
if( dataByteCnt >= 4 )
|
||||||
|
{
|
||||||
|
//printHex(data,dataByteCnt);
|
||||||
|
unsigned hdr = *(const unsigned*)data;
|
||||||
|
|
||||||
|
switch( p->protoState )
|
||||||
|
{
|
||||||
|
case kWaitForBeat_1_Id:
|
||||||
|
if( hdr == 3 )
|
||||||
|
{
|
||||||
|
p->protoState = kWaitForHandshake_2_Id;
|
||||||
|
_sendHandshake_1( socketHandle(p->tcpH) );
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kWaitForHandshake_2_Id:
|
||||||
|
if( hdr == 0x0d )
|
||||||
|
{
|
||||||
|
p->protoState = kRunning_3_Id;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p->cbCnt+=1;
|
||||||
|
|
||||||
|
if( p->cbCnt % 20 == 0 )
|
||||||
|
{
|
||||||
|
time::spec_t t1;
|
||||||
|
time::get(t1);
|
||||||
|
unsigned ms = time::elapsedMs( &p->t0, &t1 );
|
||||||
|
printf("cb: %i %i\n",p->cbCnt,ms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
cw::rc_t cw::net::eucon::create( handle_t& hRef, socket::portNumber_t tcpPort, socket::portNumber_t servicePort, unsigned recvBufByteN, unsigned timeOutMs )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
uint16_t mdnsPort = 5353;
|
||||||
|
const char* mdnsIp = "224.0.0.251";
|
||||||
|
unsigned udpRecvBufByteN = recvBufByteN;
|
||||||
|
unsigned tcpRecvBufByteN = recvBufByteN;
|
||||||
|
unsigned udpTimeOutMs = timeOutMs;
|
||||||
|
unsigned tcpTimeOutMs = timeOutMs;
|
||||||
|
|
||||||
|
if((rc = destroy(hRef)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
eucon_t* p = mem::allocZ<eucon_t>();
|
||||||
|
p->udpRecvBufByteN = udpRecvBufByteN;
|
||||||
|
p->tcpRecvBufByteN = tcpRecvBufByteN;
|
||||||
|
p->servicePort = servicePort;
|
||||||
|
p->protoState = kSendHandshake_0_Id;
|
||||||
|
|
||||||
|
// create the mDNS UDP socket server
|
||||||
|
if((rc = srv::create(
|
||||||
|
p->udpH,
|
||||||
|
mdnsPort,
|
||||||
|
socket::kBlockingFl | socket::kReuseAddrFl | socket::kReusePortFl | socket::kMultiCastTtlFl | socket::kMultiCastLoopFl,
|
||||||
|
srv::kUseRecvFromFl,
|
||||||
|
_udpReceiveCallback,
|
||||||
|
p,
|
||||||
|
p->udpRecvBufByteN,
|
||||||
|
udpTimeOutMs,
|
||||||
|
NULL,
|
||||||
|
socket::kInvalidPortNumber )) != kOkRC )
|
||||||
|
{
|
||||||
|
return cwLogError(rc,"mDNS UDP socket create failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the mDNS socket to the multicast group
|
||||||
|
if((rc = join_multicast_group( socketHandle(p->udpH), mdnsIp )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// set the TTL for multicast
|
||||||
|
if((rc = set_multicast_time_to_live( socketHandle(p->udpH), 255 )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
// create the service TCP socket server
|
||||||
|
if((rc = srv::create(
|
||||||
|
p->tcpH,
|
||||||
|
tcpPort,
|
||||||
|
socket::kTcpFl | socket::kBlockingFl | socket::kStreamFl,
|
||||||
|
0,
|
||||||
|
_tcpReceiveCallback,
|
||||||
|
p,
|
||||||
|
p->tcpRecvBufByteN,
|
||||||
|
tcpTimeOutMs,
|
||||||
|
NULL,
|
||||||
|
socket::kInvalidPortNumber)) != kOkRC )
|
||||||
|
{
|
||||||
|
rc = cwLogError(rc,"mDNS TCP socket create failed.");
|
||||||
|
goto errLabel;
|
||||||
|
}
|
||||||
|
|
||||||
|
hRef.set(p);
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
if( rc != kOkRC )
|
||||||
|
_destroy(p);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::net::eucon::destroy( handle_t& hRef )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
|
if( !hRef.isValid() )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
eucon_t* p = _handleToPtr(hRef);
|
||||||
|
if((rc = _destroy(p)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
hRef.clear();
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::net::eucon::start( handle_t h )
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
eucon_t* p = _handleToPtr(h);
|
||||||
|
|
||||||
|
time::get(p->t0);
|
||||||
|
|
||||||
|
if((rc = _init(p)) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
// start the mDNS socket server
|
||||||
|
if((rc = srv::start( p->udpH )) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
// start the TCP socket server
|
||||||
|
if((rc = srv::start( p->tcpH )) != kOkRC )
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
cw::rc_t cw::net::eucon::test()
|
||||||
|
{
|
||||||
|
rc_t rc = kOkRC;
|
||||||
|
socket::portNumber_t tcpPort = 49170;
|
||||||
|
socket::portNumber_t defaultServicePort = 49168;
|
||||||
|
const unsigned sbufN = 31;
|
||||||
|
unsigned recvBufByteN = 4096;
|
||||||
|
unsigned timeOutMs = 50;
|
||||||
|
handle_t h;
|
||||||
|
char sbuf[ sbufN+1 ];
|
||||||
|
|
||||||
|
// create the EuCon server
|
||||||
|
if((rc = create( h, tcpPort, defaultServicePort, recvBufByteN, timeOutMs )) != kOkRC )
|
||||||
|
return cwLogError(rc,"Unable to create EuCon server.");
|
||||||
|
|
||||||
|
// start the EuCon server
|
||||||
|
if((rc = start( h )) != kOkRC )
|
||||||
|
goto errLabel;
|
||||||
|
|
||||||
|
while( true )
|
||||||
|
{
|
||||||
|
printf("? ");
|
||||||
|
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
||||||
|
{
|
||||||
|
|
||||||
|
if( strcmp(sbuf,"quit\n") == 0 )
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
errLabel:
|
||||||
|
rc = destroy(h);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
23
cwEuCon.h
Normal file
23
cwEuCon.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#ifndef cwEuConHost_h
|
||||||
|
#define cwEuConHost_h
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
namespace net
|
||||||
|
{
|
||||||
|
namespace eucon
|
||||||
|
{
|
||||||
|
typedef handle<struct eucon_str> handle_t;
|
||||||
|
|
||||||
|
rc_t create( handle_t& hRef, socket::portNumber_t tcpPort, socket::portNumber_t servicePort, unsigned recvBufByteN, unsigned timeOutMs );
|
||||||
|
rc_t destroy( handle_t& hRef );
|
||||||
|
rc_t start( handle_t h );
|
||||||
|
rc_t test();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
37
cwUtility.cpp
Normal file
37
cwUtility.cpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#include "cwCommon.h"
|
||||||
|
#include "cwLog.h"
|
||||||
|
#include "cwCommonImpl.h"
|
||||||
|
#include "cwUtility.h"
|
||||||
|
|
||||||
|
void cw::printHex( const void* buf, unsigned bufByteN, bool asciiFl )
|
||||||
|
{
|
||||||
|
const unsigned char* data = static_cast<const unsigned char*>(buf);
|
||||||
|
const unsigned colN = 8;
|
||||||
|
unsigned ci = 0;
|
||||||
|
|
||||||
|
for(unsigned i=0; i<bufByteN; ++i)
|
||||||
|
{
|
||||||
|
printf("%02x ", data[i] );
|
||||||
|
|
||||||
|
++ci;
|
||||||
|
if( ci == colN || i+1 == bufByteN )
|
||||||
|
{
|
||||||
|
unsigned n = ci==colN ? colN-1 : ci-1;
|
||||||
|
|
||||||
|
for(unsigned j=0; j<(colN-n)*3; ++j)
|
||||||
|
printf(" ");
|
||||||
|
|
||||||
|
if( asciiFl )
|
||||||
|
{
|
||||||
|
for(unsigned j=i-n; j<=i; ++j)
|
||||||
|
if( 32<= data[j] && data[j] < 127 )
|
||||||
|
printf("%c",data[j]);
|
||||||
|
else
|
||||||
|
printf(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
ci = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
cwUtility.h
Normal file
10
cwUtility.h
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#ifndef cwUtility_h
|
||||||
|
#define cwUtility_h
|
||||||
|
|
||||||
|
namespace cw
|
||||||
|
{
|
||||||
|
void printHex( const void* buf, unsigned bufByteN, bool asciiFl=true );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user