Updated dns_sd/ to match the Arduino build.
cwAvahiSurface.cpp : initial commit.
This commit is contained in:
parent
ef70cd9420
commit
f15e06695b
8
Makefile
8
Makefile
@ -23,11 +23,11 @@ SRC += cwAudioBuf.cpp cwAudioDevice.cpp cwAudioDeviceAlsa.cpp cwAudioDeviceTest
|
||||
HDR += cwTcpSocket.h cwTcpSocketSrv.h cwTcpSocketTest.h
|
||||
SRC += cwTcpSocket.cpp cwTcpSocketSrv.cpp cwTcpSocketTest.cpp
|
||||
|
||||
HDR += cwMdns.h cwEuCon.h cwDnsSd.h dns_sd/dns_sd.h dns_sd/dns_sd_print.h dns_sd/dns_sd_const.h dns_sd/fader.h
|
||||
SRC += cwMdns.cpp cwEuCon.cpp cwDnsSd.cpp dns_sd/dns_sd.cpp dns_sd/dns_sd_print.cpp dns_sd/fader.cpp
|
||||
HDR += cwMdns.h cwEuCon.h cwDnsSd.h dns_sd/dns_sd.h dns_sd/dns_sd_print.h dns_sd/dns_sd_const.h dns_sd/fader.h dns_sd/rpt.h
|
||||
SRC += cwMdns.cpp cwEuCon.cpp cwDnsSd.cpp dns_sd/dns_sd.cpp dns_sd/dns_sd_print.cpp dns_sd/fader.cpp dns_sd/rpt.cpp
|
||||
|
||||
# HDR += cwIo.h cwIoTest.h cwNbMem.h
|
||||
# SRC += cwIo.cpp cwIoTest.cpp cwNbMem.cpp
|
||||
HDR += cwIo.h cwIoTest.h
|
||||
SRC += cwIo.cpp cwIoTest.cpp
|
||||
|
||||
LIBS = -lpthread -lwebsockets -lasound
|
||||
|
||||
|
473
cwAvahiSurface.cpp
Normal file
473
cwAvahiSurface.cpp
Normal file
@ -0,0 +1,473 @@
|
||||
|
||||
#include <avahi-client/client.h>
|
||||
#include <avahi-client/publish.h>
|
||||
|
||||
#include <avahi-common/alternative.h>
|
||||
#include <avahi-common/thread-watch.h>
|
||||
#include <avahi-common/malloc.h>
|
||||
#include <avahi-common/error.h>
|
||||
#include <avahi-common/timeval.h>
|
||||
#include <avahi-common/strlst.h>
|
||||
|
||||
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwTime.h"
|
||||
#include "cwThread.h"
|
||||
#include "cwTcpSocket.h"
|
||||
|
||||
using namespace cw;
|
||||
using namespace cw::net;
|
||||
|
||||
#define INSTANCE_NAME "MC Mix"
|
||||
#define SERVICE_NAME "_EuConProxy._tcp"
|
||||
#define SERVICE_PORT 49168
|
||||
#define SERVICE_HOST nullptr //"Euphonix-MC-38C9863744E7.local"
|
||||
#define ENET_INTERFACE "ens9"
|
||||
#define SERVICE_TXT_0 "lmac=38-C9-86-37-44-E7"
|
||||
#define SERVICE_TXT_1 "dummy=0"
|
||||
#define HOST_MAC "hmac=00-E0-4C-A9-A4-8D" // mbp19 enet MAC
|
||||
|
||||
typedef struct app_str
|
||||
{
|
||||
AvahiEntryGroup *group = nullptr;
|
||||
AvahiThreadedPoll *poll = nullptr;
|
||||
char *name = nullptr;
|
||||
unsigned instanceId = 0;
|
||||
socket::handle_t tcpH;
|
||||
thread::handle_t tcpThreadH;
|
||||
unsigned recvBufByteN = 4096;
|
||||
unsigned protocolState = 0;
|
||||
unsigned txtXmtN = 0;
|
||||
time::spec_t t0;
|
||||
|
||||
|
||||
} app_t;
|
||||
|
||||
static void create_services(app_t* app, AvahiClient *c);
|
||||
|
||||
void errorv( app_t* app, const char* fmt, va_list vl )
|
||||
{
|
||||
vprintf(fmt,vl);
|
||||
}
|
||||
|
||||
void logv( app_t* app, const char* fmt, va_list vl )
|
||||
{
|
||||
vprintf(fmt,vl);
|
||||
}
|
||||
|
||||
void error( app_t* app, const char* fmt, ... )
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl,fmt);
|
||||
errorv( app, fmt, vl );
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
void rpt( app_t* app, const char* fmt, ... )
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl,fmt);
|
||||
logv( app, fmt, vl );
|
||||
va_end(vl);
|
||||
}
|
||||
|
||||
void choose_new_service_name( app_t* app )
|
||||
{
|
||||
char buf[255];
|
||||
app->instanceId += 1;
|
||||
snprintf(buf,sizeof(buf),"%s - %i", INSTANCE_NAME, app->instanceId);
|
||||
|
||||
char* n = avahi_strdup(buf);
|
||||
avahi_free(app->name);
|
||||
app->name = n;
|
||||
|
||||
rpt(app,"Service name collision, renaming service to '%s'\n", app->name);
|
||||
}
|
||||
|
||||
static void entry_group_callback(AvahiEntryGroup *g, AvahiEntryGroupState state, void *userdata)
|
||||
{
|
||||
app_t* app = (app_t*)userdata;
|
||||
|
||||
assert(g == app->group || app->group == nullptr);
|
||||
app->group = g;
|
||||
|
||||
// Called whenever the entry group state changes
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case AVAHI_ENTRY_GROUP_ESTABLISHED :
|
||||
// The entry group has been established successfully
|
||||
rpt( app, "Service '%s' successfully established.\n", app->name);
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_COLLISION :
|
||||
{
|
||||
|
||||
// A service name collision with a remote service happened. Let's pick a new name.
|
||||
choose_new_service_name(app);
|
||||
|
||||
// And recreate the services
|
||||
create_services(app,avahi_entry_group_get_client(g));
|
||||
break;
|
||||
}
|
||||
|
||||
case AVAHI_ENTRY_GROUP_FAILURE :
|
||||
|
||||
error(app,"Entry group failure: %s\n", avahi_strerror(avahi_client_errno(avahi_entry_group_get_client(g))));
|
||||
|
||||
/* Some kind of failure happened while we were registering our services */
|
||||
avahi_threaded_poll_quit(app->poll);
|
||||
break;
|
||||
|
||||
case AVAHI_ENTRY_GROUP_UNCOMMITED:
|
||||
case AVAHI_ENTRY_GROUP_REGISTERING:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
static void create_services(app_t* app, AvahiClient *c)
|
||||
{
|
||||
int ret;
|
||||
AvahiPublishFlags flags = (AvahiPublishFlags)0;
|
||||
|
||||
assert(c);
|
||||
|
||||
// If this is the first time we're called, create a new entry group
|
||||
if (!app->group)
|
||||
{
|
||||
if (!(app->group = avahi_entry_group_new(c, entry_group_callback, app)))
|
||||
{
|
||||
error(app,"avahi_entry_group_new() failed: %s\n", avahi_strerror(avahi_client_errno(c)));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
// If the group is empty (either because it was just created, or because it was reset previously, add our entries.
|
||||
if (avahi_entry_group_is_empty(app->group))
|
||||
{
|
||||
rpt(app,"Adding service '%s'\n", app->name);
|
||||
|
||||
// Add the service to the group
|
||||
if ((ret = avahi_entry_group_add_service(app->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, flags, app->name, SERVICE_NAME, nullptr, SERVICE_HOST, SERVICE_PORT, SERVICE_TXT_0, SERVICE_TXT_1, nullptr)) < 0)
|
||||
{
|
||||
if (ret == AVAHI_ERR_COLLISION)
|
||||
goto collision;
|
||||
|
||||
error(app, "Failed to add _ipp._tcp service: %s\n", avahi_strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
// Tell the server to register the service
|
||||
if ((ret = avahi_entry_group_commit(app->group)) < 0)
|
||||
{
|
||||
error(app,"Failed to commit entry group: %s\n", avahi_strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
collision:
|
||||
|
||||
// A service name collision with a local service happened. Pick a new name.
|
||||
choose_new_service_name(app);
|
||||
|
||||
avahi_entry_group_reset(app->group);
|
||||
|
||||
create_services(app,c);
|
||||
return;
|
||||
|
||||
fail:
|
||||
avahi_threaded_poll_quit(app->poll);
|
||||
}
|
||||
|
||||
|
||||
static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata)
|
||||
{
|
||||
assert(c);
|
||||
|
||||
app_t* app = (app_t*)userdata;
|
||||
|
||||
// Called whenever the client or server state changes
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case AVAHI_CLIENT_S_RUNNING:
|
||||
// The server has startup successfully and registered its host
|
||||
// name on the network, so it's time to create our services
|
||||
create_services(app,c);
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_FAILURE:
|
||||
error(app,"Client failure: %s\n", avahi_strerror(avahi_client_errno(c)));
|
||||
avahi_threaded_poll_quit(app->poll);
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_S_COLLISION:
|
||||
// Let's drop our registered services. When the server is back
|
||||
// in AVAHI_SERVER_RUNNING state we will register them
|
||||
// again with the new host name.
|
||||
rpt(app,"S Collision\n");
|
||||
|
||||
case AVAHI_CLIENT_S_REGISTERING:
|
||||
|
||||
rpt(app,"S Registering\n");
|
||||
|
||||
// The server records are now being established. This
|
||||
// might be caused by a host name change. We need to wait
|
||||
// for our own records to register until the host name is
|
||||
// properly esatblished.
|
||||
if (app->group)
|
||||
avahi_entry_group_reset(app->group);
|
||||
|
||||
break;
|
||||
|
||||
case AVAHI_CLIENT_CONNECTING:
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
rc_t _send_response( app_t* app, const unsigned char* buf, unsigned bufByteN )
|
||||
{
|
||||
rc_t rc;
|
||||
|
||||
if((rc = socket::send( app->tcpH, buf, bufByteN )) != kOkRC )
|
||||
{
|
||||
error(app,"Send failed.");
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
rc_t send_response1( app_t* app )
|
||||
{
|
||||
// wifi: 98 5A EB 89 BA AA
|
||||
// enet: 38 C9 86 37 44 E7
|
||||
|
||||
unsigned char buf[] =
|
||||
{ 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x02,0x03,0xfc,0x01,0x05,
|
||||
0x06,0x00,
|
||||
0x38,0xc9,0x86,0x37,0x44,0xe7,
|
||||
0x01,0x00,
|
||||
0xc0,0xa8,0x00,0x44,
|
||||
0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x03,0xff,0x00,0x30,0x08,0x00,0x00,0x80,0x00,0x40,0x01,0x01,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00
|
||||
};
|
||||
|
||||
return _send_response(app,buf,sizeof(buf));
|
||||
}
|
||||
|
||||
rc_t send_response2( app_t* app )
|
||||
{
|
||||
unsigned char buf[] = { 0x0d,0x00,0x00,0x00,0x00,0x00,0x00,0x08 };
|
||||
|
||||
return _send_response(app,buf,sizeof(buf));
|
||||
}
|
||||
|
||||
rc_t send_heart_beat( app_t* app )
|
||||
{
|
||||
unsigned char buf[] = { 0x03,0x00,0x00,0x00 };
|
||||
return _send_response(app,buf,sizeof(buf));
|
||||
}
|
||||
|
||||
rc_t send_txt( app_t* app, bool updateFl=true )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
int ret;
|
||||
|
||||
const char* array[] =
|
||||
{
|
||||
"lmac=38-C9-86-37-44-E7",
|
||||
"host=mbp19",
|
||||
"hmac=BE-BD-EA-31-F9-88",
|
||||
"dummy=1"
|
||||
};
|
||||
|
||||
AvahiStringList* list = avahi_string_list_new_from_array(array,4);
|
||||
if( updateFl )
|
||||
ret = avahi_entry_group_update_service_txt_strlst(app->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, app->name, SERVICE_NAME, nullptr, list);
|
||||
else
|
||||
ret = avahi_entry_group_add_service_strlst(app->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, (AvahiPublishFlags)0, app->name, SERVICE_NAME, nullptr, nullptr, SERVICE_PORT, list);
|
||||
|
||||
if(ret < 0)
|
||||
{
|
||||
error(app,"Failed to %s entry group text: %s\n", updateFl ? "update" : "add", avahi_strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
avahi_string_list_free(list);
|
||||
|
||||
fail:
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool tcpReceiveCallback( void* arg )
|
||||
{
|
||||
app_t* app = static_cast<app_t*>(arg);
|
||||
socket::handle_t sockH = app->tcpH;
|
||||
char buf[ app->recvBufByteN ];
|
||||
unsigned readByteN = 0;
|
||||
rc_t rc = kOkRC;
|
||||
time::spec_t t1;
|
||||
|
||||
if( !socket::isConnected(sockH) )
|
||||
{
|
||||
if((rc = socket::accept( sockH )) == kOkRC )
|
||||
{
|
||||
rpt(app,"TCP connected.\n");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if((rc = socket::receive( sockH, buf, app->recvBufByteN, &readByteN, nullptr )) == kOkRC || rc == kTimeOutRC )
|
||||
{
|
||||
if( rc == kTimeOutRC )
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
if( readByteN > 0 )
|
||||
{
|
||||
unsigned* h = (unsigned*)buf;
|
||||
unsigned id = h[0];
|
||||
switch( app->protocolState )
|
||||
{
|
||||
case 0:
|
||||
if( id == 10 )
|
||||
{
|
||||
send_response1(app);
|
||||
sleepMs(20);
|
||||
send_heart_beat(app);
|
||||
app->protocolState+=1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
{
|
||||
if( buf[0] == 0x0c )
|
||||
{
|
||||
send_response2(app);
|
||||
app->protocolState+=1;
|
||||
time::get(app->t0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
{
|
||||
time::get(t1);
|
||||
if( time::elapsedMs( &app->t0, &t1 ) >= 4000 )
|
||||
{
|
||||
send_heart_beat(app);
|
||||
app->t0 = t1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, const char* argv[] )
|
||||
{
|
||||
|
||||
AvahiClient *client = nullptr;
|
||||
int err_code;
|
||||
int ret = 1;
|
||||
const unsigned sbufN = 31;
|
||||
char sbuf[ sbufN+1 ];
|
||||
app_t app;
|
||||
rc_t rc;
|
||||
unsigned tcpTimeOutMs = 50;
|
||||
|
||||
cw::log::createGlobal();
|
||||
|
||||
// create the TCP socket
|
||||
if((rc = socket::create(
|
||||
app.tcpH,
|
||||
SERVICE_PORT,
|
||||
socket::kTcpFl | socket::kBlockingFl | socket::kStreamFl | socket::kListenFl,
|
||||
tcpTimeOutMs,
|
||||
NULL,
|
||||
socket::kInvalidPortNumber )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"mDNS TCP socket create failed.");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
unsigned char mac[6];
|
||||
socket::get_mac( app.tcpH, mac, nullptr, ENET_INTERFACE );
|
||||
for(int i=0; i<6; ++i)
|
||||
printf("%02x:",mac[i]);
|
||||
|
||||
|
||||
// create the TCP listening thread
|
||||
if((rc = thread::create( app.tcpThreadH, tcpReceiveCallback, &app )) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
// Allocate Avahi thread
|
||||
if (!(app.poll = avahi_threaded_poll_new()))
|
||||
{
|
||||
error(&app,"Failed to create simple poll object.\n");
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// Assign the service name
|
||||
app.name = avahi_strdup(INSTANCE_NAME);
|
||||
|
||||
// Allocate a new client
|
||||
if((client = avahi_client_new(avahi_threaded_poll_get(app.poll), (AvahiClientFlags)0, client_callback, &app, &err_code)) == nullptr )
|
||||
{
|
||||
error(&app,"Failed to create client: %s\n", avahi_strerror(err_code));
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// start the tcp thread
|
||||
if((rc = thread::unpause( app.tcpThreadH )) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
// start the avahi thread
|
||||
avahi_threaded_poll_start(app.poll);
|
||||
|
||||
while( true )
|
||||
{
|
||||
printf("? ");
|
||||
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
||||
{
|
||||
if( strcmp(sbuf,"quit\n") == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
avahi_threaded_poll_stop(app.poll);
|
||||
|
||||
ret = 0;
|
||||
|
||||
errLabel:
|
||||
|
||||
//if (client)
|
||||
// avahi_client_free(client);
|
||||
|
||||
thread::destroy(app.tcpThreadH);
|
||||
socket::destroy(app.tcpH);
|
||||
|
||||
if (app.poll)
|
||||
avahi_threaded_poll_free(app.poll);
|
||||
|
||||
avahi_free(app.name);
|
||||
|
||||
|
||||
cw::log::destroyGlobal();
|
||||
|
||||
return ret;
|
||||
}
|
19
cwDnsSd.cpp
19
cwDnsSd.cpp
@ -10,6 +10,8 @@
|
||||
|
||||
#include "cwDnsSd.h"
|
||||
#include "cwUtility.h"
|
||||
|
||||
#include "dns_sd/rpt.h"
|
||||
#include "dns_sd/dns_sd.h"
|
||||
#include "dns_sd/fader.h"
|
||||
|
||||
@ -46,17 +48,25 @@ namespace cw
|
||||
char* hostIpAddr;
|
||||
uint16_t hostPort;
|
||||
unsigned char hostMac[6];
|
||||
unsigned ticksPerHeartBeat;
|
||||
|
||||
unsigned cbCnt;
|
||||
time::spec_t t0;
|
||||
|
||||
} dnssd_t;
|
||||
|
||||
void print_callback( const char* text )
|
||||
{
|
||||
printf("%s",text);
|
||||
}
|
||||
|
||||
inline dnssd_t* _handleToPtr( handle_t h )
|
||||
{
|
||||
return handleToPtr<handle_t,dnssd_t>(h);
|
||||
}
|
||||
|
||||
|
||||
|
||||
rc_t _destroy( dnssd_t* p )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
@ -132,7 +142,7 @@ namespace cw
|
||||
|
||||
if( dataByteCnt > 0 )
|
||||
{
|
||||
p->fdr->host_receive( data, dataByteCnt );
|
||||
p->fdr->receive( data, dataByteCnt );
|
||||
}
|
||||
|
||||
time::spec_t t1;
|
||||
@ -219,17 +229,17 @@ namespace cw
|
||||
delete p->dnsSd;
|
||||
|
||||
// create the MDNS logic object
|
||||
p->dnsSd = new dns_sd(udpSendCallback,p);
|
||||
p->dnsSd = new dns_sd(udpSendCallback,p,print_callback);
|
||||
|
||||
// create the Surface logic object
|
||||
p->fdr = new fader(p->hostMac, hostAddr.sin_addr.s_addr, tcpSendCallback, p );
|
||||
p->fdr = new fader(print_callback, p->hostMac, hostAddr.sin_addr.s_addr, tcpSendCallback, p, p->ticksPerHeartBeat );
|
||||
|
||||
// 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();
|
||||
p->dnsSd->gen_question();
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -299,6 +309,7 @@ cw::rc_t cw::net::dnssd::createV( handle_t& hRef, const char* name, const char*
|
||||
p->hostIpAddr = mem::duplStr(hostIpAddr);
|
||||
p->hostPort = hostPort;
|
||||
p->dnsSd = nullptr;
|
||||
p->ticksPerHeartBeat = 50;
|
||||
memcpy(p->hostMac,hostMac,6);
|
||||
|
||||
if((rc = _setTextRecdFieldsV( p, text, vl )) != kOkRC )
|
||||
|
@ -159,7 +159,8 @@ namespace cw
|
||||
{
|
||||
if( dataByteCnt >= 4 )
|
||||
{
|
||||
//printHex(data,dataByteCnt);
|
||||
printHex(data,dataByteCnt);
|
||||
|
||||
unsigned hdr = *(const unsigned*)data;
|
||||
|
||||
switch( p->protoState )
|
||||
|
@ -1,20 +1,29 @@
|
||||
#include "dns_sd.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef cwLINUX
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include <utility/util.h>
|
||||
#endif
|
||||
|
||||
#include "rpt.h"
|
||||
#include "dns_sd.h"
|
||||
#include "dns_sd_const.h"
|
||||
#include "dns_sd_print.h"
|
||||
|
||||
|
||||
#define DNS_SD_SERVICE_TYPE_STRING "_services._dns-sd._udp"
|
||||
|
||||
dns_sd::dns_sd(sendCallback_t sendCbFunc, void* sendCbArg )
|
||||
: _sendCbFunc(sendCbFunc),_sendCbArg(sendCbArg),_serviceName(nullptr),_serviceType(nullptr),_serviceDomain(nullptr),_hostName(nullptr),_hostPort(0),_text(nullptr)
|
||||
dns_sd::dns_sd(sendCallback_t sendCbFunc, void* sendCbArg, printCallback_t printCbFunc )
|
||||
: _sendCbFunc(sendCbFunc),_sendCbArg(sendCbArg),_printCbFunc(printCbFunc),_serviceName(nullptr),_serviceType(nullptr),_serviceDomain(nullptr),_hostName(nullptr),_hostPort(0),_text(nullptr)
|
||||
{}
|
||||
|
||||
dns_sd::dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text )
|
||||
: _sendCbFunc(sendCbFunc),_sendCbArg(sendCbArg),_serviceName(nullptr),_serviceType(nullptr),_serviceDomain(nullptr),_hostName(nullptr),_hostPort(0),_text(nullptr)
|
||||
dns_sd::dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, printCallback_t printCbFunc, const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text )
|
||||
: _sendCbFunc(sendCbFunc),_sendCbArg(sendCbArg),_printCbFunc(printCbFunc),_serviceName(nullptr),_serviceType(nullptr),_serviceDomain(nullptr),_hostName(nullptr),_hostPort(0),_text(nullptr)
|
||||
{
|
||||
setup( serviceName, serviceType, serviceDomain, hostName, hostAddr, hostPort, text );
|
||||
}
|
||||
@ -52,7 +61,6 @@ void dns_sd::gen_question()
|
||||
_format_question(b, n);
|
||||
_send(b,n);
|
||||
free(b);
|
||||
|
||||
}
|
||||
|
||||
void dns_sd::gen_response()
|
||||
@ -76,9 +84,14 @@ void dns_sd::_free()
|
||||
unsigned dns_sd::_calc_question_byte_count()
|
||||
{
|
||||
unsigned n = kHdrBodyByteN;
|
||||
// Question
|
||||
n += 1 + strlen(_serviceName) + 1 + strlen(_serviceType) + 1 + strlen(_serviceDomain) + 1 + kQuestionBodyByteN;
|
||||
|
||||
// SRV
|
||||
n += 2 + kRsrcBodyByteN + kSrvBodyByteN + 1 + strlen(_hostName) + 2;
|
||||
//n += 2 + kRsrcBodyByteN + strlen(_text) + 1;
|
||||
|
||||
// TXT
|
||||
n += 2 + kRsrcBodyByteN + strlen(_text) + 1;
|
||||
return n;
|
||||
}
|
||||
|
||||
@ -92,7 +105,7 @@ void dns_sd::_format_question( unsigned char* buf, unsigned bufByteN )
|
||||
u[1] = htons(0); // flags
|
||||
u[2] = htons(1); // question
|
||||
u[3] = htons(0); // answer
|
||||
u[4] = htons(1); // name server
|
||||
u[4] = htons(2); // name server
|
||||
u[5] = htons(0); // other
|
||||
|
||||
unsigned char* b = (unsigned char*)(u + 6);
|
||||
@ -111,7 +124,7 @@ void dns_sd::_format_question( unsigned char* buf, unsigned bufByteN )
|
||||
b = _write_uint16( b, bend, kInClassDnsFl );
|
||||
|
||||
// Format SRV name server
|
||||
b = _write_ptr( namePtr, b, bend ); // name
|
||||
b = _write_ptr( b, bend, namePtr ); // name
|
||||
b = _write_uint16( b, bend, kSRV_DnsTId ); // type
|
||||
b = _write_uint16( b, bend, kInClassDnsFl ); // class
|
||||
b = _write_uint32( b, bend, 120 ); // TTL
|
||||
@ -121,16 +134,19 @@ void dns_sd::_format_question( unsigned char* buf, unsigned bufByteN )
|
||||
b = _write_uint16( b, bend, _hostPort ); // port
|
||||
b = _write_text( b, bend, _hostName ); // host
|
||||
b = _write_ptr( b, bend, domainPtr ); // host suffix (.local)
|
||||
/*
|
||||
|
||||
// Format TXT name server
|
||||
b = _write_ptr( namePtr, b, bend ); // name
|
||||
b = _write_uint16( kTXT_DnsTId, b, bend ); // type
|
||||
b = _write_uint16( kInClassDnsFl, b, bend ); // class
|
||||
b = _write_uint32( 4500, b, bend ); // TTL
|
||||
b = _write_uint16( strlen(_text),b, bend ); // dlen
|
||||
b = _write_text( _text, b, bend ); // text
|
||||
*/
|
||||
assert( b == bend );
|
||||
b = _write_ptr( b, bend, namePtr ); // name
|
||||
b = _write_uint16( b, bend, kTXT_DnsTId ); // type
|
||||
b = _write_uint16( b, bend, kInClassDnsFl ); // class
|
||||
b = _write_uint32( b, bend, 4500 ); // TTL
|
||||
b = _write_uint16( b, bend, strlen(_text)+1 ); // dlen
|
||||
b = _write_text( b, bend, _text ); // text
|
||||
|
||||
//assert( b == bend );
|
||||
|
||||
//rpt(_printCbFunc,"%i %i : %s\n", b - buf, bend - buf, _text );
|
||||
|
||||
}
|
||||
|
||||
unsigned char* dns_sd::_write_uint16( unsigned char* b, unsigned char* bend, uint16_t value )
|
||||
@ -152,6 +168,8 @@ unsigned char* dns_sd::_write_uint32( unsigned char* b, unsigned char* bend, uin
|
||||
unsigned char* dns_sd::_write_ptr( unsigned char* b, unsigned char* bend, const unsigned char ptr[2] )
|
||||
{
|
||||
assert( (ptr[0] & 0xc0) == 0xc0 );
|
||||
assert( bend - b >= 2 );
|
||||
|
||||
b[0] = ptr[0];
|
||||
b[1] = ptr[1];
|
||||
return b+2;
|
||||
@ -291,13 +309,15 @@ void dns_sd::_format_response( unsigned char* buf, unsigned bufByteN )
|
||||
b = _write_ptr( b, bend, typePtr );
|
||||
|
||||
|
||||
printf("%li %li : %s\n", b - buf, bend - buf, _text );
|
||||
//rpt(_printCbFunc,"%i %i : %s\n", b - buf, bend - buf, _text );
|
||||
}
|
||||
|
||||
|
||||
void dns_sd::_parse( const char* buf, unsigned bufByteN )
|
||||
{
|
||||
dns_sd_print(buf,bufByteN);
|
||||
//(void)buf;
|
||||
//(void)bufByteN;
|
||||
dns_sd_print(_printCbFunc,buf,bufByteN);
|
||||
}
|
||||
|
||||
void dns_sd::_send( const void* buf, unsigned bufByteN )
|
||||
|
@ -14,8 +14,8 @@ public:
|
||||
|
||||
typedef void (*sendCallback_t)( void* arg, const void* buf, unsigned bufByteN );
|
||||
|
||||
dns_sd( sendCallback_t sendCbFunc, void* sendCbArg );
|
||||
dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text );
|
||||
dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, printCallback_t printCbFunc );
|
||||
dns_sd( sendCallback_t sendCbFunc, void* sendCbArg, printCallback_t printCbFunc, const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text );
|
||||
virtual ~dns_sd();
|
||||
|
||||
result_t setup( const char* serviceName, const char* serviceType, const char* serviceDomain, const char* hostName, uint32_t hostAddr, uint16_t hostPort, const char* text );
|
||||
@ -40,6 +40,7 @@ private:
|
||||
|
||||
sendCallback_t _sendCbFunc;
|
||||
void* _sendCbArg;
|
||||
printCallback_t _printCbFunc;
|
||||
char* _serviceName;
|
||||
char* _serviceType;
|
||||
char* _serviceDomain;
|
||||
|
@ -1,13 +1,24 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef cwLINUX
|
||||
#include <arpa/inet.h>
|
||||
#endif
|
||||
|
||||
#ifdef ARDUINO
|
||||
#include <utility/util.h>
|
||||
#endif
|
||||
|
||||
#include "rpt.h"
|
||||
#include "dns_sd.h"
|
||||
#include "dns_sd_print.h"
|
||||
#include "dns_sd_const.h"
|
||||
|
||||
|
||||
unsigned _print_name( const char* s, const char* buf )
|
||||
int _print_name( printCallback_t printCbFunc, const unsigned char* s, const unsigned char* buf )
|
||||
{
|
||||
unsigned n = 0; // track allocated length of the name in this record
|
||||
int n = 0; // track allocated length of the name in this record
|
||||
bool incrFl = true; // do not incrmement 'n' if the name switches to a ptr segment
|
||||
|
||||
while( *s )
|
||||
@ -23,10 +34,12 @@ unsigned _print_name( const char* s, const char* buf )
|
||||
{
|
||||
for(char i=0; i<s[0]; ++i)
|
||||
{
|
||||
printf("%c",s[i+1]);
|
||||
char x[2];
|
||||
x[0] = s[i+1];
|
||||
x[1] = 0;
|
||||
rpt(printCbFunc,"%s",x);
|
||||
if( incrFl )
|
||||
++n;
|
||||
|
||||
}
|
||||
|
||||
s += s[0]+1;
|
||||
@ -34,54 +47,56 @@ unsigned _print_name( const char* s, const char* buf )
|
||||
|
||||
if(*s)
|
||||
{
|
||||
printf(".");
|
||||
rpt(printCbFunc,".");
|
||||
}
|
||||
}
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
void dns_sd_print( const void* buf, unsigned bufByteN )
|
||||
void dns_sd_print( printCallback_t printCbFunc, const void* buf, unsigned bufByteN )
|
||||
{
|
||||
(void)bufByteN;
|
||||
|
||||
const uint16_t* u = (uint16_t*)buf;
|
||||
const char* b = (const char*)(u+6);
|
||||
const unsigned char* b = (const unsigned char*)(u+6);
|
||||
|
||||
printf("%s ", ntohs(u[1]) & 0x8000 ? "Response " : "Question ");
|
||||
rpt(printCbFunc,"%s ", ntohs(u[1]) & 0x8000 ? "Response:" : "Question:");
|
||||
|
||||
unsigned n = _print_name(b,(const char*)buf);
|
||||
int n = _print_name(printCbFunc,b,(const unsigned char*)buf);
|
||||
|
||||
printf(" slen:%i ",n);
|
||||
rpt(printCbFunc," slen:%i ", n);
|
||||
|
||||
u = (uint16_t*)(b + n + 1); // advance past name
|
||||
|
||||
switch( ntohs(u[0]) )
|
||||
{
|
||||
case kA_DnsTId: printf("A ");
|
||||
case kA_DnsTId: rpt(printCbFunc,"A ");
|
||||
break;
|
||||
|
||||
case kPTR_DnsTId: printf("PTR ");
|
||||
case kPTR_DnsTId: rpt(printCbFunc,"PTR ");
|
||||
break;
|
||||
|
||||
case kTXT_DnsTId: printf("TXT ");
|
||||
case kTXT_DnsTId: rpt(printCbFunc,"TXT ");
|
||||
break;
|
||||
|
||||
case kSRV_DnsTId: printf("SRV ");
|
||||
case kSRV_DnsTId: rpt(printCbFunc,"SRV ");
|
||||
break;
|
||||
|
||||
case kAAAA_DnsTId:printf("AAAA ");
|
||||
case kAAAA_DnsTId:rpt(printCbFunc,"AAAA ");
|
||||
break;
|
||||
case kOPT_DnsTId: printf("OPT ");
|
||||
case kOPT_DnsTId: rpt(printCbFunc,"OPT ");
|
||||
break;
|
||||
case kNSEC_DnsTId:printf("NSEC "); break;
|
||||
case kANY_DnsTId: printf("ANY "); break;
|
||||
case kNSEC_DnsTId:rpt(printCbFunc,"NSEC "); break;
|
||||
case kANY_DnsTId: rpt(printCbFunc,"ANY "); break;
|
||||
default:
|
||||
printf("<unk> 0x%2x",ntohs(u[0])); break;
|
||||
rpt(printCbFunc,"<unk> 0x%2x",ntohs(u[0])); break;
|
||||
}
|
||||
|
||||
if( ntohs(u[1]) & 0x80 )
|
||||
printf("flush ");
|
||||
rpt(printCbFunc,"flush ");
|
||||
|
||||
printf("\n");
|
||||
rpt(printCbFunc,"\n");
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#ifndef print_dns_sd_h
|
||||
#define print_dns_sd_h
|
||||
|
||||
void dns_sd_print( const void* buf, unsigned bufByteN );
|
||||
void dns_sd_print( printCallback_t printCbFunc, const void* buf, unsigned bufByteN );
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -2,11 +2,14 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include "rpt.h"
|
||||
#include "fader.h"
|
||||
|
||||
|
||||
fader::fader( const unsigned char faderMac[6], uint32_t faderInetAddr, hostCallback_t hostCbFunc, void* hostCbArg, unsigned chN )
|
||||
: _inetAddr(faderInetAddr),_lastTickSeconds(0),_chArray(nullptr),_hostCbFunc(hostCbFunc),_hostCbArg(hostCbArg),_protoState(kWaitForHandshake_0_Id)
|
||||
|
||||
fader::fader( printCallback_t printCbFunc, const unsigned char faderMac[6], uint32_t faderInetAddr, hostCallback_t hostCbFunc, void* hostCbArg, unsigned ticksPerHeartBeat, unsigned chN )
|
||||
: _printCbFunc(printCbFunc), _inetAddr(faderInetAddr),_tickN(0),_chArray(nullptr),_hostCbFunc(hostCbFunc),_hostCbArg(hostCbArg),_protoState(kWaitForHandshake_0_Id),_ticksPerHeartBeat(ticksPerHeartBeat)
|
||||
{
|
||||
memcpy(_mac,faderMac,6);
|
||||
|
||||
@ -24,18 +27,19 @@ fader::~fader()
|
||||
delete[] _chArray;
|
||||
}
|
||||
|
||||
fader::rc_t fader::host_receive( const void* buf, unsigned bufByteN )
|
||||
fader::rc_t fader::receive( const void* buf, unsigned bufByteN )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
const uint8_t* b = (const uint8_t*)buf;
|
||||
|
||||
printf("FDR:%i\n",bufByteN);
|
||||
_printCbFunc("FDR ");
|
||||
|
||||
switch( _protoState )
|
||||
{
|
||||
case kWaitForHandshake_0_Id:
|
||||
if( bufByteN>0 && ((uint8_t*)buf)[0] == 10 )
|
||||
if( bufByteN>0 && b[0] == 10 )
|
||||
{
|
||||
printf("HS 0\n");
|
||||
_printCbFunc("HS 0 ");
|
||||
_send_response_0();
|
||||
_protoState = kWaitForHandshake_Tick_Id;
|
||||
}
|
||||
@ -45,7 +49,8 @@ fader::rc_t fader::host_receive( const void* buf, unsigned bufByteN )
|
||||
break;
|
||||
|
||||
case kWaitForHandshake_1_Id:
|
||||
printf("HS 1: %i",bufByteN);
|
||||
_printCbFunc("HS 1 ");
|
||||
_send_response_1();
|
||||
_protoState = kWaitForHeartBeat_Id;
|
||||
break;
|
||||
|
||||
@ -64,31 +69,45 @@ fader::rc_t fader::tick()
|
||||
break;
|
||||
|
||||
case kWaitForHandshake_Tick_Id:
|
||||
printf("HS Tick");
|
||||
_printCbFunc("HS Tick ");
|
||||
_send_heartbeat();
|
||||
_protoState = kWaitForHandshake_1_Id;
|
||||
break;
|
||||
|
||||
case kWaitForHandshake_1_Id:
|
||||
break;
|
||||
|
||||
case kWaitForHeartBeat_Id:
|
||||
break;
|
||||
}
|
||||
|
||||
_tickN += 1;
|
||||
if( _tickN == _ticksPerHeartBeat )
|
||||
{
|
||||
_tickN = 0;
|
||||
_send_heartbeat();
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
fader::rc_t fader::physical_fader_touched( uint16_t chanIdx )
|
||||
{
|
||||
(void)chanIdx;
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
fader::rc_t fader::physical_fader_moved( uint16_t chanIdx, uint16_t value )
|
||||
{
|
||||
(void)chanIdx;
|
||||
(void)value;
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
fader::rc_t fader::physical_mute_switched( uint16_t chanIdx, bool value )
|
||||
{
|
||||
(void)chanIdx;
|
||||
(void)value;
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
@ -97,9 +116,9 @@ void fader::_send_response_0()
|
||||
unsigned char buf[] =
|
||||
{ 0x0b,0x00,0x00,0x00,0x00,0x00,0x00,0x50,0x00,0x02,0x03,0xfc,0x01,0x05,
|
||||
0x06,0x00,
|
||||
0x38,0xc9,0x86,0x37,0x44,0xe7, // mac: 16
|
||||
0x38,0xc9,0x86,0x37,0x44,0xe7, // mac: offset 16
|
||||
0x01,0x00,
|
||||
0xc0,0xa8,0x00,0x44, // ip: 24
|
||||
0xc0,0xa8,0x00,0x44, // ip: offset 24
|
||||
0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
|
||||
@ -113,6 +132,14 @@ void fader::_send_response_0()
|
||||
_send(buf,sizeof(buf));
|
||||
}
|
||||
|
||||
void fader::_send_response_1()
|
||||
{
|
||||
unsigned char buf[] = { 0x0d,0x00,0x00,0x00, 0x00,0x00,0x00,0x08 };
|
||||
|
||||
_send(buf,sizeof(buf));
|
||||
}
|
||||
|
||||
|
||||
void fader::_send_heartbeat()
|
||||
{
|
||||
const unsigned char buf[] = { 0x03, 0x00, 0x00, 0x00 };
|
||||
@ -126,9 +153,13 @@ void fader::_send( const void* buf, unsigned bufByteN )
|
||||
|
||||
void fader::_on_fader_receive( uint16_t chanIdx, uint16_t value )
|
||||
{
|
||||
(void)chanIdx;
|
||||
(void)value;
|
||||
}
|
||||
|
||||
void fader::_on_mute_receive( uint16_t chanIdx, bool value )
|
||||
{
|
||||
(void)chanIdx;
|
||||
(void)value;
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,17 @@
|
||||
#define fader_h
|
||||
|
||||
|
||||
/*
|
||||
1. wait for 0x0a packet
|
||||
send_response_0()
|
||||
wait 50 ms
|
||||
send_heart_beat()
|
||||
2. wait for next host packet
|
||||
send_response_1()
|
||||
|
||||
*/
|
||||
|
||||
|
||||
class fader
|
||||
{
|
||||
public:
|
||||
@ -15,13 +26,13 @@ public:
|
||||
// Function to send TCP messages to the host.
|
||||
typedef void (*hostCallback_t)( void* arg, const void* buf, unsigned bufByteN );
|
||||
|
||||
fader( const unsigned char faderMac[6], uint32_t faderInetAddr, hostCallback_t hostCbFunc, void* cbArg, unsigned chN = 8 );
|
||||
fader( printCallback_t printCbFunc, const unsigned char faderMac[6], uint32_t faderInetAddr, hostCallback_t hostCbFunc, void* cbArg, unsigned ticksPerHeartBeat, unsigned chN = 8 );
|
||||
virtual ~fader();
|
||||
|
||||
// Called by the TCP receive function to update the faders state
|
||||
// based on host state changes.
|
||||
// Return kUnknownMsgRC if the received msg is not recognized.
|
||||
rc_t host_receive( const void* buf, unsigned bufByteN );
|
||||
rc_t receive( const void* buf, unsigned bufByteN );
|
||||
|
||||
// Called by the application to drive time dependent functions.
|
||||
// Return kTimeOut if the protocol state machine has timed out.
|
||||
@ -48,16 +59,19 @@ private:
|
||||
bool muteFl;
|
||||
} ch_t;
|
||||
|
||||
printCallback_t _printCbFunc;
|
||||
uint32_t _inetAddr;
|
||||
unsigned _lastTickSeconds;
|
||||
unsigned _tickN;
|
||||
ch_t* _chArray;
|
||||
unsigned _chN;
|
||||
hostCallback_t _hostCbFunc;
|
||||
void* _hostCbArg;
|
||||
protoState_t _protoState;
|
||||
unsigned char _mac[6];
|
||||
unsigned _ticksPerHeartBeat;
|
||||
|
||||
void _send_response_0();
|
||||
void _send_response_1();
|
||||
void _send_heartbeat();
|
||||
void _send( const void* buf, unsigned bufByteN );
|
||||
void _on_fader_receive( uint16_t chanIdx, uint16_t position );
|
||||
|
Loading…
Reference in New Issue
Block a user