Initial implementation cwTcpSocket*
Standardized cwLex and cwLog namespaces.
This commit is contained in:
parent
85954c5498
commit
0ead6fa974
3
Makefile
3
Makefile
@ -20,6 +20,9 @@ SRC += cwMidi.cpp cwMidiPort.cpp cwMidiAlsa.cpp
|
||||
HDR += cwAudioBuf.h cwAudioDevice.h cwAudioDeviceAlsa.h
|
||||
SRC += cwAudioBuf.cpp cwAudioDevice.cpp cwAudioDeviceAlsa.cpp cwAudioDeviceTest.cpp
|
||||
|
||||
HDR += cwTcpSocket.h cwTcpSocketSrv.h cwTcpSocketTest.h
|
||||
SRC += cwTcpSocket.cpp cwTcpSocketSrv.cpp cwTcpSocketTest.cpp
|
||||
|
||||
|
||||
LIBS = -lpthread -lwebsockets -lasound
|
||||
|
||||
|
@ -16,4 +16,11 @@
|
||||
|
||||
- change cwMpScNbQueue so that it does not require 'new'.
|
||||
|
||||
- cwAudioBuf.cpp - the ch->fn in update() does not have the correct memory fence.
|
||||
|
||||
- change file names to match object names
|
||||
|
||||
- change all NULL's to nullptr
|
||||
|
||||
- implement kTcpFl in cwTcpSocket.cpp
|
||||
|
||||
|
@ -44,6 +44,9 @@
|
||||
|
||||
*/
|
||||
|
||||
#define atomicUIntIncr( vRef, dVal ) std::atomic_fetch_add<unsigned>(vRef,dVal)
|
||||
#define atomicUIntDecr( vRef, dVal ) std::atomic_fetch_sub<unsigned>(vRef,dVal)
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace audio
|
||||
@ -94,8 +97,8 @@ namespace cw
|
||||
unsigned devCnt;
|
||||
unsigned meterMs;
|
||||
|
||||
sample_t* zeroBuf; // buffer of zeros
|
||||
unsigned zeroBufCnt; // max of all dspFrameCnt for all devices.
|
||||
sample_t* zeroBuf; // buffer of zeros
|
||||
unsigned zeroBufCnt; // max of all dspFrameCnt for all devices.
|
||||
} cmApBuf;
|
||||
|
||||
cmApBuf _theBuf;
|
||||
@ -411,8 +414,7 @@ cw::rc_t cw::audio::buf::update(
|
||||
// advance the input channel buffer
|
||||
cp->ii = n1>0 ? n1 : cp->ii + n0;
|
||||
//cp->fn += pp->audioFramesCnt;
|
||||
//cmThUIntIncr(&cp->fn,pp->audioFramesCnt);
|
||||
std::atomic_fetch_add<unsigned>(&cp->fn,pp->audioFramesCnt);
|
||||
atomicUIntIncr(&cp->fn,pp->audioFramesCnt);
|
||||
|
||||
}
|
||||
}
|
||||
@ -424,7 +426,7 @@ cw::rc_t cw::audio::buf::update(
|
||||
for(i=0; i<outPktCnt; ++i)
|
||||
{
|
||||
device::audioPacket_t* pp = outPktArray + i;
|
||||
cmApIO* op = _theBuf.devArray[pp->devIdx].ioArray + kOutApIdx; // dest io recd
|
||||
cmApIO* op = _theBuf.devArray[pp->devIdx].ioArray + kOutApIdx; // dest io recd
|
||||
|
||||
// if the base timestamp has not yet been set then set it.
|
||||
if( op->timeStamp.tv_sec==0 && op->timeStamp.tv_nsec==0 )
|
||||
@ -433,10 +435,10 @@ cw::rc_t cw::audio::buf::update(
|
||||
// for each dest packet channel and enabled source channel
|
||||
for(j=0; j<pp->chCnt; ++j)
|
||||
{
|
||||
cmApCh* cp = op->chArray + pp->begChIdx + j; // dest ch
|
||||
unsigned n0 = op->n - cp->oi; // first src segment
|
||||
unsigned n1 = 0; // second src segment
|
||||
volatile unsigned fn = cp->fn; // store fn because it may be changed by the client thread
|
||||
cmApCh* cp = op->chArray + pp->begChIdx + j; // dest ch
|
||||
unsigned n0 = op->n - cp->oi; // first src segment
|
||||
unsigned n1 = 0; // second src segment
|
||||
volatile unsigned fn = cp->fn; // store fn because it may be changed by the client thread
|
||||
|
||||
// if the outgoing samples will underflow the buffer
|
||||
if( pp->audioFramesCnt > fn )
|
||||
@ -501,8 +503,7 @@ cw::rc_t cw::audio::buf::update(
|
||||
// advance the output channel buffer
|
||||
cp->oi = n1>0 ? n1 : cp->oi + n0;
|
||||
//cp->fn -= pp->audioFramesCnt;
|
||||
//cmThUIntDecr(&cp->fn,pp->audioFramesCnt);
|
||||
std::atomic_fetch_sub<unsigned>(&cp->fn,pp->audioFramesCnt);
|
||||
atomicUIntDecr(&cp->fn,pp->audioFramesCnt);
|
||||
|
||||
}
|
||||
}
|
||||
@ -750,7 +751,6 @@ void cw::audio::buf::getIO( unsigned iDevIdx, sample_t* iBufArray[], unsigned
|
||||
if( oBufArray[i] != NULL )
|
||||
memset( oBufArray[i], 0, byteCnt );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void cw::audio::buf::advance( unsigned devIdx, unsigned flags )
|
||||
@ -768,8 +768,7 @@ void cw::audio::buf::advance( unsigned devIdx, unsigned flags )
|
||||
{
|
||||
cmApCh* cp = ioPtr->chArray + i;
|
||||
cp->oi = (cp->oi + ioPtr->dspFrameCnt) % ioPtr->n;
|
||||
//cmThUIntDecr(&cp->fn,ioPtr->dspFrameCnt);
|
||||
std::atomic_fetch_sub<unsigned>(&cp->fn,ioPtr->dspFrameCnt);
|
||||
atomicUIntDecr(&cp->fn,ioPtr->dspFrameCnt);
|
||||
|
||||
|
||||
}
|
||||
@ -777,8 +776,7 @@ void cw::audio::buf::advance( unsigned devIdx, unsigned flags )
|
||||
// count the number of samples input from this device
|
||||
if( ioPtr->timeStamp.tv_sec!=0 && ioPtr->timeStamp.tv_nsec!=0 )
|
||||
{
|
||||
//cmThUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
||||
std::atomic_fetch_add<unsigned>(&ioPtr->ioFrameCnt, ioPtr->dspFrameCnt);
|
||||
atomicUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
||||
}
|
||||
}
|
||||
|
||||
@ -789,17 +787,14 @@ void cw::audio::buf::advance( unsigned devIdx, unsigned flags )
|
||||
{
|
||||
cmApCh* cp = ioPtr->chArray + i;
|
||||
cp->ii = (cp->ii + ioPtr->dspFrameCnt) % ioPtr->n;
|
||||
//cmThUIntIncr(&cp->fn,ioPtr->dspFrameCnt);
|
||||
std::atomic_fetch_add<unsigned>(&cp->fn,ioPtr->dspFrameCnt);
|
||||
atomicUIntIncr(&cp->fn,ioPtr->dspFrameCnt);
|
||||
|
||||
}
|
||||
|
||||
// count the number of samples output from this device
|
||||
if( ioPtr->timeStamp.tv_sec!=0 && ioPtr->timeStamp.tv_nsec!=0 )
|
||||
{
|
||||
//cmThUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
||||
std::atomic_fetch_add<unsigned>(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
||||
|
||||
atomicUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -865,17 +860,20 @@ void cw::audio::buf::report()
|
||||
unsigned ii = 0;
|
||||
unsigned oi = 0;
|
||||
unsigned fn = 0;
|
||||
sample_t m = 0;
|
||||
for(k=0; k<ip->chCnt; ++k)
|
||||
{
|
||||
cmApCh* cp = ip->chArray + i;
|
||||
ii += cp->ii;
|
||||
oi += cp->oi;
|
||||
fn += cp->fn;
|
||||
m += _cmApMeterValue(cp);
|
||||
}
|
||||
|
||||
|
||||
cwLogInfo("%i : %s - i:%7i o:%7i f:%7i n:%7i err %s:%7i ",
|
||||
cwLogInfo("%i : %s - i:%7i o:%7i f:%7i n:%7i err %s:%7i meter:%f",
|
||||
i,j==0?"IN ":"OUT",
|
||||
ii,oi,fn,ip->n, (j==0?"over":"under"), ip->faultCnt);
|
||||
ii,oi,fn,ip->n, (j==0?"over ":"under"), ip->faultCnt, m/ip->chCnt);
|
||||
|
||||
}
|
||||
}
|
||||
|
14
cwAudioBuf.h
14
cwAudioBuf.h
@ -5,26 +5,26 @@
|
||||
// samples in a thread-safe manner.
|
||||
//
|
||||
// Usage example and testing code:
|
||||
// See cmApBufTest() and cmAudioSysTest().
|
||||
// \snippet cmApBuf.c cmApBufExample
|
||||
// See audio::device::test()
|
||||
// \snippet cwAudioBuf.c cwAudioBufExample
|
||||
//
|
||||
// Notes on channel flags:
|
||||
// Disabled channels: kChFl is cleared
|
||||
// cmApBufGet()
|
||||
// get()
|
||||
// in - return NULL buffer pointers
|
||||
// out - return NULL buffer points
|
||||
//
|
||||
// cmApBufUpdate()
|
||||
// update()
|
||||
// in - incoming samples are set to 0.
|
||||
// out - outgoing samples are set to 0.
|
||||
//
|
||||
// Muted channels: kMuteFl is set
|
||||
// cmApBufUpdate()
|
||||
// update()
|
||||
// in - incoming samples are set to 0.
|
||||
// out - outgoing samples are set to 0.
|
||||
//
|
||||
// Tone channels: kToneFl is set
|
||||
// cmApBufUpdate()
|
||||
// update()
|
||||
// in - incoming samples are filled with a 1k sine tone
|
||||
// out - outgoing samples are filled with a 1k sine tone
|
||||
//)
|
||||
@ -76,7 +76,7 @@ namespace cw
|
||||
|
||||
// This function is called asynchronously by the audio device driver to transfer incoming samples to the
|
||||
// the buffer and to send outgoing samples to the DAC. This function is
|
||||
// intended to be called from the audio port callback function (\see cmApCallbackPtr_t).
|
||||
// intended to be called from the audio port callback function (\see auido::device::cbFunc_t).
|
||||
// This function is thread-safe under the condition where the audio device uses
|
||||
// different threads for input and output.
|
||||
//
|
||||
|
@ -1,3 +1,24 @@
|
||||
//( { file_desc: "Cross platform audio device interface." kw:[audio rt] }
|
||||
//
|
||||
// This interface provides data declarations for platform dependent
|
||||
// audio I/O functions. The implementation for the functions are
|
||||
// in platform specific modules. See cwAudioDeviceAlsa.cpp.
|
||||
//
|
||||
// ALSA Notes:
|
||||
// Assign capture device to line or mic input:
|
||||
// amixer -c 0 cset iface=MIXER,name='Input Source',index=0 Mic
|
||||
// amixer -c 0 cset iface=MIXER,name='Input Source',index=0 Line
|
||||
//
|
||||
// -c 0 select the first card
|
||||
// -iface=MIXER the cset is targetting the MIXER component
|
||||
// -name='Input Source',index=0 the control to set is the first 'Input Source'
|
||||
// Note that the 'Capture' control sets the input gain.
|
||||
//
|
||||
// See alsamixer for a GUI to accomplish the same thing.
|
||||
//
|
||||
//
|
||||
//)
|
||||
|
||||
#ifndef cwAudioDevice_H
|
||||
#define cwAudioDevice_H
|
||||
|
||||
@ -46,7 +67,7 @@ namespace cw
|
||||
// In general it should be assmed that this call is made from a system thread which is not
|
||||
// the same as the application thread.
|
||||
// The usual thread safety precautions should therefore be taken if this function implementation
|
||||
// interacts with data structures also handled by the application. The audio buffer class (\see cmApBuf.h)
|
||||
// interacts with data structures also handled by the application. The audio buffer class (\see cwAudioBuf.h)
|
||||
// is designed to provide a safe and efficient way to communicate between
|
||||
// the audio thread and the application.
|
||||
typedef void (*cbFunc_t)( audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt );
|
||||
@ -79,7 +100,25 @@ namespace cw
|
||||
unsigned deviceChannelCount( handle_t h, unsigned devIdx, bool inputFl );
|
||||
double deviceSampleRate( handle_t h, unsigned devIdx );
|
||||
unsigned deviceFramesPerCycle( handle_t h, unsigned devIdx, bool inputFl );
|
||||
rc_t deviceSetup( handle_t h, unsigned devIdx, double sr, unsigned frmPerCycle, cbFunc_t cb, void* cbData );
|
||||
|
||||
// Configure a device.
|
||||
// All devices must be setup before they are started.
|
||||
// framesPerCycle is the requested number of samples per audio callback. The
|
||||
// actual number of samples made from a callback may be smaller. See the note
|
||||
// regarding this in audioPacket_t.
|
||||
// If the device cannot support the requested configuration then the function
|
||||
// will return an error code.
|
||||
// If the device is started when this function is called then it will be
|
||||
// automatically stopped and then restarted following the reconfiguration.
|
||||
// If the reconfiguration fails then the device may not be restared.
|
||||
rc_t deviceSetup(
|
||||
handle_t h,
|
||||
unsigned devIdx,
|
||||
double sr,
|
||||
unsigned frmPerCycle,
|
||||
cbFunc_t cb,
|
||||
void* cbData );
|
||||
|
||||
rc_t deviceStart( handle_t h, unsigned devIdx );
|
||||
rc_t deviceStop( handle_t h, unsigned devIdx );
|
||||
bool deviceIsStarted( handle_t h, unsigned devIdx );
|
||||
|
@ -110,7 +110,7 @@ namespace cw
|
||||
|
||||
if( alsaRC == 0 )
|
||||
{
|
||||
rc = logMsg( logGlobalHandle(), kError_LogLevel, func, fn, lineNumb, 0, kOpFailRC, fmt, vl0 );
|
||||
rc = log::msg( log::globalHandle(), log::kError_LogLevel, func, fn, lineNumb, 0, kOpFailRC, fmt, vl0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -129,7 +129,7 @@ namespace cw
|
||||
char msg1[n+1];
|
||||
m = snprintf(msg1,n+1,fmt1,msg0,snd_strerror(alsaRC));
|
||||
|
||||
rc = logMsg( logGlobalHandle(), kError_LogLevel, func, fn, lineNumb, 0, kOpFailRC, "%s", msg1 );
|
||||
rc = log::msg( log::globalHandle(), log::kError_LogLevel, func, fn, lineNumb, 0, kOpFailRC, "%s", msg1 );
|
||||
}
|
||||
|
||||
va_end(vl0);
|
||||
@ -367,6 +367,7 @@ namespace cw
|
||||
int cnt = 0;
|
||||
int err;
|
||||
|
||||
|
||||
do
|
||||
{
|
||||
if((err = snd_pcm_open(pcmHPtr,devNameStr,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,0)) < 0 )
|
||||
@ -522,23 +523,48 @@ namespace cw
|
||||
}
|
||||
}
|
||||
|
||||
int NNN = 0;
|
||||
void _rms( const char* devNameStr, const device::sample_t* s0p, const int* s1p, unsigned n )
|
||||
{
|
||||
double facc = 0.0;
|
||||
int iacc = 0;
|
||||
unsigned normN = 0;
|
||||
unsigned zeroN = 0;
|
||||
|
||||
for(unsigned i=0; i<n; i+=2)
|
||||
{
|
||||
facc += s0p[i] * s0p[i];
|
||||
iacc += s1p[i] * s1p[i];
|
||||
|
||||
if( s0p[i] == 0.0 )
|
||||
zeroN += 1;
|
||||
else
|
||||
if( std::isnormal(s0p[i]) )
|
||||
normN += 1;
|
||||
}
|
||||
|
||||
printf("%i z:%i n:%i : %f %i : %s\n", n, zeroN, normN, facc/(n/2), iacc/(n/2), devNameStr);
|
||||
|
||||
}
|
||||
|
||||
// Returns count of frames written on success or < 0 on error;
|
||||
// set smpPtr to NULL to write a buffer of silence
|
||||
int _devWriteBuf( devRecd_t* drp, snd_pcm_t* pcmH, const device::sample_t* sp, unsigned chCnt, unsigned frmCnt, unsigned bits, unsigned sigBits )
|
||||
{
|
||||
int err = 0;
|
||||
unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
|
||||
unsigned smpCnt = chCnt * frmCnt;
|
||||
unsigned byteCnt = bytesPerSmp * smpCnt;
|
||||
int err = 0;
|
||||
unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
|
||||
unsigned smpCnt = chCnt * frmCnt;
|
||||
unsigned byteCnt = bytesPerSmp * smpCnt;
|
||||
const device::sample_t* ep = sp + smpCnt;
|
||||
char obuf[ byteCnt ];
|
||||
char obuf[ byteCnt ];
|
||||
|
||||
//const device::sample_t* rms = sp;
|
||||
|
||||
// if no output was given then fill the device buffer with zeros
|
||||
if( sp == NULL )
|
||||
memset(obuf,0,byteCnt);
|
||||
else
|
||||
{
|
||||
{
|
||||
// otherwise convert the floating point samples to integers
|
||||
switch( bits )
|
||||
{
|
||||
@ -575,13 +601,21 @@ namespace cw
|
||||
int* dp = (int*)obuf;
|
||||
|
||||
while( sp < ep )
|
||||
*dp++ = (int)(*sp++ * 0x7fffffff);
|
||||
*dp++ = (int)(*sp++ * 0x7fffffff);
|
||||
//*dp++ = (rand() - (RAND_MAX/2)) * 2;
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
NNN+=1;
|
||||
if( NNN % 100 == 0)
|
||||
{
|
||||
_rms(drp->nameStr,rms,(const int*)obuf,smpCnt);
|
||||
}
|
||||
*/
|
||||
|
||||
// send the bytes to the device
|
||||
err = snd_pcm_writei( pcmH, obuf, frmCnt );
|
||||
@ -734,7 +768,7 @@ namespace cw
|
||||
{
|
||||
// callback to fill the buffer
|
||||
drp->cbFunc(NULL,0,&pkt,1);
|
||||
|
||||
|
||||
// note that the application may return fewer samples than were requested
|
||||
err = _devWriteBuf(drp, pcmH, pkt.audioFramesCnt < frmCnt ? NULL : drp->oBuf,chCnt,frmCnt,drp->oBits,drp->oSigBits);
|
||||
|
||||
|
@ -26,7 +26,7 @@ namespace cw
|
||||
{
|
||||
unsigned bufCnt; // 2=double buffering 3=triple buffering
|
||||
unsigned chIdx; // first test channel
|
||||
unsigned chCnt; // count of channels to test
|
||||
//unsigned chCnt; // count of channels to test
|
||||
unsigned framesPerCycle; // DSP frames per cycle
|
||||
unsigned bufFrmCnt; // count of DSP frames used by the audio buffer (bufCnt * framesPerCycle)
|
||||
unsigned bufSmpCnt; // count of samples used by the audio buffer (chCnt * bufFrmCnt)
|
||||
@ -51,7 +51,8 @@ namespace cw
|
||||
unsigned* ilog; // ilog[logCnt]
|
||||
unsigned logIdx; // current log index
|
||||
|
||||
unsigned cbCnt; // count the callback
|
||||
unsigned iCbCnt; // count the callback
|
||||
unsigned oCbCnt;
|
||||
} cmApPortTestRecd;
|
||||
|
||||
|
||||
@ -215,7 +216,7 @@ namespace cw
|
||||
// copy the incoming audio into an internal buffer where it can be picked up by _cpApCopyOut().
|
||||
_cmApCopyIn( r, (sample_t*)inPktArray[i].audioBytesPtr, inPktArray[i].begChIdx, inPktArray[i].chCnt, inPktArray[i].audioFramesCnt );
|
||||
}
|
||||
++r->cbCnt;
|
||||
++r->iCbCnt;
|
||||
|
||||
//printf("i %4i in:%4i out:%4i\n",r->bufFullCnt,r->bufInIdx,r->bufOutIdx);
|
||||
}
|
||||
@ -252,7 +253,7 @@ namespace cw
|
||||
|
||||
//printf("o %4i in:%4i out:%4i\n",r->bufFullCnt,r->bufInIdx,r->bufOutIdx);
|
||||
// count callbacks
|
||||
++r->cbCnt;
|
||||
++r->oCbCnt;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -304,10 +305,10 @@ namespace cw
|
||||
void _cmApPortCb2( audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt )
|
||||
{
|
||||
for(unsigned i=0; i<inPktCnt; ++i)
|
||||
static_cast<cmApPortTestRecd*>(inPktArray[i].cbArg)->cbCnt++;
|
||||
static_cast<cmApPortTestRecd*>(inPktArray[i].cbArg)->iCbCnt++;
|
||||
|
||||
for(unsigned i=0; i<outPktCnt; ++i)
|
||||
static_cast<cmApPortTestRecd*>(outPktArray[i].cbArg)->cbCnt++;
|
||||
static_cast<cmApPortTestRecd*>(outPktArray[i].cbArg)->oCbCnt++;
|
||||
|
||||
buf::inputToOutput( _cmGlobalInDevIdx, _cmGlobalOutDevIdx );
|
||||
|
||||
@ -334,12 +335,12 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
||||
|
||||
runFl = _cmApGetOpt(argc,argv,"-p",0,true)?false:true;
|
||||
r.srate = _cmApGetOpt(argc,argv,"-r",44100);
|
||||
r.chIdx = _cmApGetOpt(argc,argv,"-a",0);
|
||||
r.chCnt = _cmApGetOpt(argc,argv,"-c",2);
|
||||
//r.chIdx = _cmApGetOpt(argc,argv,"-a",0);
|
||||
//r.chCnt = _cmApGetOpt(argc,argv,"-c",2);
|
||||
r.bufCnt = _cmApGetOpt(argc,argv,"-b",3);
|
||||
r.framesPerCycle = _cmApGetOpt(argc,argv,"-f",512);
|
||||
r.bufFrmCnt = (r.bufCnt*r.framesPerCycle);
|
||||
r.bufSmpCnt = (r.chCnt * r.bufFrmCnt);
|
||||
//r.bufFrmCnt = (r.bufCnt*r.framesPerCycle);
|
||||
//r.bufSmpCnt = (r.chCnt * r.bufFrmCnt);
|
||||
r.logCnt = 100;
|
||||
r.meterMs = 50;
|
||||
|
||||
@ -348,7 +349,7 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
||||
unsigned ilog[r.logCnt];
|
||||
|
||||
r.inDevIdx = _cmGlobalInDevIdx = _cmApGetOpt(argc,argv,"-i",0);
|
||||
r.outDevIdx = _cmGlobalOutDevIdx = _cmApGetOpt(argc,argv,"-o",2);
|
||||
r.outDevIdx = _cmGlobalOutDevIdx = _cmApGetOpt(argc,argv,"-o",0);
|
||||
r.phase = 0;
|
||||
r.frqHz = 2000;
|
||||
r.bufInIdx = 0;
|
||||
@ -359,9 +360,10 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
||||
r.buf = buf;
|
||||
r.log = log;
|
||||
r.ilog = ilog;
|
||||
r.cbCnt = 0;
|
||||
|
||||
cwLogInfo("Program cfg: %s in:%i out:%i chidx:%i chs:%i bufs=%i frm=%i rate=%f",runFl?"exec":"rpt",r.inDevIdx,r.outDevIdx,r.chIdx,r.chCnt,r.bufCnt,r.framesPerCycle,r.srate);
|
||||
r.iCbCnt = 0;
|
||||
r.oCbCnt = 0;
|
||||
|
||||
//cwLogInfo("Program cfg: %s in:%i out:%i chidx:%i chs:%i bufs=%i frm=%i rate=%f",runFl?"exec":"rpt",r.inDevIdx,r.outDevIdx,r.chIdx,r.chCnt,r.bufCnt,r.framesPerCycle,r.srate);
|
||||
|
||||
|
||||
// initialize the audio device interface
|
||||
@ -388,11 +390,11 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
||||
// report the current audio device configuration
|
||||
for(i=0; i<deviceCount(h); ++i)
|
||||
{
|
||||
cwLogInfo("%i [in: chs=%i frames=%i] [out: chs=%i frames=%i] srate:%f %s",i,deviceChannelCount(h,i,true),deviceFramesPerCycle(h,i,true),deviceChannelCount(h,i,false),deviceFramesPerCycle(h,i,false),deviceSampleRate(h,i),deviceLabel(h,i));
|
||||
cwLogInfo("%i [in: chs=%i frames=%i] [out: chs=%i frames=%i] srate:%8.1f %s",i,deviceChannelCount(h,i,true),deviceFramesPerCycle(h,i,true),deviceChannelCount(h,i,false),deviceFramesPerCycle(h,i,false),deviceSampleRate(h,i),deviceLabel(h,i));
|
||||
}
|
||||
|
||||
// report the current audio devices using the audio port interface function
|
||||
report(h);
|
||||
//report(h);
|
||||
|
||||
if( runFl )
|
||||
{
|
||||
@ -403,7 +405,7 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
||||
buf::setup( r.outDevIdx, r.srate, r.framesPerCycle, r.bufCnt, deviceChannelCount(h,r.outDevIdx,true), r.framesPerCycle, deviceChannelCount(h,r.outDevIdx,false), r.framesPerCycle );
|
||||
|
||||
// setup the buffer for the input device
|
||||
if( r.inDevIdx != r.outDevIdx )
|
||||
//if( r.inDevIdx != r.outDevIdx )
|
||||
buf::setup( r.inDevIdx, r.srate, r.framesPerCycle, r.bufCnt, deviceChannelCount(h,r.inDevIdx,true), r.framesPerCycle, deviceChannelCount(h,r.inDevIdx,false), r.framesPerCycle );
|
||||
|
||||
// setup an output device
|
||||
@ -425,7 +427,11 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
||||
cwLogInfo("Setup complete!");
|
||||
|
||||
|
||||
cwLogInfo("q=quit O/o output tone, I/i input tone P/p pass s=buf report");
|
||||
cwLogInfo("q=quit O/o output tone, I/i input tone, P/p pass M/m meter s=buf report");
|
||||
|
||||
//buf::enableTone( r.outDevIdx,-1,buf::kOutFl | buf::kEnableFl);
|
||||
//buf::enableMeter(r.outDevIdx,-1,buf::kOutFl | buf::kEnableFl);
|
||||
|
||||
char c;
|
||||
while((c=getchar()) != 'q')
|
||||
{
|
||||
@ -447,6 +453,12 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
||||
case 'P':
|
||||
buf::enablePass(r.outDevIdx,-1,buf::kOutFl | (c=='P'?buf::kEnableFl:0));
|
||||
break;
|
||||
|
||||
case 'M':
|
||||
case 'm':
|
||||
buf::enableMeter( r.inDevIdx, -1, buf::kInFl | (c=='M'?buf::kEnableFl:0));
|
||||
buf::enableMeter( r.outDevIdx, -1, buf::kOutFl | (c=='M'?buf::kEnableFl:0));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
buf::report();
|
||||
@ -480,7 +492,7 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
||||
//cmApFileFree();
|
||||
|
||||
// report the count of audio buffer callbacks
|
||||
cwLogInfo("cb count:%i", r.cbCnt );
|
||||
cwLogInfo("cb count: i:%i o:%i", r.iCbCnt, r.oCbCnt );
|
||||
|
||||
return rcSelect(rc,rc0,rc1,rc2);
|
||||
}
|
||||
|
@ -18,7 +18,8 @@
|
||||
|
||||
#if defined(cwLINUX) || defined(cwOSX)
|
||||
#define cwPOSIX_FILE_SYS
|
||||
#include <time.h> // linux time.h
|
||||
#include <time.h> // timespec
|
||||
#include <netinet/in.h> // struct sockaddr_in
|
||||
#define cwPathSeparatorChar '/'
|
||||
#endif
|
||||
|
||||
|
192
cwLex.h
192
cwLex.h
@ -6,131 +6,131 @@
|
||||
|
||||
namespace cw
|
||||
{
|
||||
|
||||
// Predefined Lexer Id's
|
||||
enum
|
||||
namespace lex
|
||||
{
|
||||
kErrorLexTId, // 0 the lexer was unable to identify the current token
|
||||
kUnknownLexTId, // 1 the token is of an unknown type (only used when kReturnUnknownLexFl is set)
|
||||
kEofLexTId, // 2 the lexer reached the end of input
|
||||
kSpaceLexTId, // 3 white space
|
||||
kRealLexTId, // 4 real number (contains a decimal point or is in scientific notation)
|
||||
kIntLexTId, // 5 decimal integer
|
||||
kHexLexTId, // 6 hexidecimal integer
|
||||
kIdentLexTId, // 7 identifier
|
||||
kQStrLexTId, // 8 quoted string
|
||||
kQCharLexTId, // 9 quoted char
|
||||
kBlockCmtLexTId, // 10 block comment
|
||||
kLineCmtLexTId, // 11 line comment
|
||||
kUserLexTId // 12 user registered token (See lexRegisterToken().)
|
||||
};
|
||||
|
||||
// Lexer control flags used with lexInit().
|
||||
enum
|
||||
{
|
||||
kReturnSpaceLexFl = 0x01, //< Return space tokens
|
||||
kReturnCommentsLexFl = 0x02, //< Return comment tokens
|
||||
kReturnUnknownLexFl = 0x04, //< Return unknown tokens
|
||||
kReturnQCharLexFl = 0x08, //< Return quoted characters
|
||||
kUserDefPriorityLexFl= 0x10 //< User defined tokens take priority even if a kIdentLexTId token has a longer match
|
||||
};
|
||||
// Predefined Lexer Id's
|
||||
enum
|
||||
{
|
||||
kErrorLexTId, // 0 the lexer was unable to identify the current token
|
||||
kUnknownLexTId, // 1 the token is of an unknown type (only used when kReturnUnknownLexFl is set)
|
||||
kEofLexTId, // 2 the lexer reached the end of input
|
||||
kSpaceLexTId, // 3 white space
|
||||
kRealLexTId, // 4 real number (contains a decimal point or is in scientific notation)
|
||||
kIntLexTId, // 5 decimal integer
|
||||
kHexLexTId, // 6 hexidecimal integer
|
||||
kIdentLexTId, // 7 identifier
|
||||
kQStrLexTId, // 8 quoted string
|
||||
kQCharLexTId, // 9 quoted char
|
||||
kBlockCmtLexTId, // 10 block comment
|
||||
kLineCmtLexTId, // 11 line comment
|
||||
kUserLexTId // 12 user registered token (See lexRegisterToken().)
|
||||
};
|
||||
|
||||
// Lexer control flags used with lexInit().
|
||||
enum
|
||||
{
|
||||
kReturnSpaceLexFl = 0x01, //< Return space tokens
|
||||
kReturnCommentsLexFl = 0x02, //< Return comment tokens
|
||||
kReturnUnknownLexFl = 0x04, //< Return unknown tokens
|
||||
kReturnQCharLexFl = 0x08, //< Return quoted characters
|
||||
kUserDefPriorityLexFl= 0x10 //< User defined tokens take priority even if a kIdentLexTId token has a longer match
|
||||
};
|
||||
|
||||
typedef handle<struct lex_str> lexH_t;
|
||||
extern lexH_t lexNullHandle;
|
||||
typedef handle<struct lex_str> handle_t;
|
||||
|
||||
// Iniitalize the lexer and receive a lexer handle in return.
|
||||
// Set cp to nullptr if the buffer will be later via lexSetTextBuffer();
|
||||
// See the kXXXLexFl enum's above for possible flag values.
|
||||
rc_t lexCreate( lexH_t& hRef, const char* cp, unsigned cn, unsigned flags );
|
||||
// Iniitalize the lexer and receive a lexer handle in return.
|
||||
// Set cp to nullptr if the buffer will be later via lexSetTextBuffer();
|
||||
// See the kXXXLexFl enum's above for possible flag values.
|
||||
rc_t create( handle_t& hRef, const char* cp, unsigned cn, unsigned flags );
|
||||
|
||||
// Finalize a lexer created by an earlier call to lexInit()
|
||||
rc_t lexDestroy( lexH_t& hRef );
|
||||
// Finalize a lexer created by an earlier call to lexInit()
|
||||
rc_t destroy( handle_t& hRef );
|
||||
|
||||
// Rewind the lexer to the begining of the buffer (the same as post initialize state)
|
||||
rc_t lexReset( lexH_t h );
|
||||
// Rewind the lexer to the begining of the buffer (the same as post initialize state)
|
||||
rc_t reset( handle_t h );
|
||||
|
||||
// Verify that a lexer handle is valid
|
||||
bool lexIsValid( lexH_t h );
|
||||
// Verify that a lexer handle is valid
|
||||
bool isValid( handle_t h );
|
||||
|
||||
// Set a new text buffer and reset the lexer to the post initialize state.
|
||||
rc_t lexSetTextBuffer( lexH_t h, const char* cp, unsigned cn );
|
||||
rc_t lexSetFile( lexH_t h, const char* fn );
|
||||
// Set a new text buffer and reset the lexer to the post initialize state.
|
||||
rc_t setTextBuffer( handle_t h, const char* cp, unsigned cn );
|
||||
rc_t setFile( handle_t h, const char* fn );
|
||||
|
||||
// Register a user defined token. The id of the first user defined token should be
|
||||
// kUserLexTId+1. Neither the id or token text can be used by a previously registered
|
||||
// or built-in token.
|
||||
rc_t lexRegisterToken( lexH_t h, unsigned id, const char* token );
|
||||
// Register a user defined token. The id of the first user defined token should be
|
||||
// kUserLexTId+1. Neither the id or token text can be used by a previously registered
|
||||
// or built-in token.
|
||||
rc_t registerToken( handle_t h, unsigned id, const char* token );
|
||||
|
||||
// Register a user defined token recognition function. This function should return the count
|
||||
// of initial, consecutive, characters in 'cp[cn]' which match its token pattern.
|
||||
typedef unsigned (*lexUserMatcherPtr_t)( const char* cp, unsigned cn );
|
||||
// Register a user defined token recognition function. This function should return the count
|
||||
// of initial, consecutive, characters in 'cp[cn]' which match its token pattern.
|
||||
typedef unsigned (*lexUserMatcherPtr_t)( const char* cp, unsigned cn );
|
||||
|
||||
rc_t lexRegisterMatcher( lexH_t h, unsigned id, lexUserMatcherPtr_t funcPtr );
|
||||
rc_t registerMatcher( handle_t h, unsigned id, lexUserMatcherPtr_t funcPtr );
|
||||
|
||||
// Enable or disable the specified token type.
|
||||
rc_t lexEnableToken( lexH_t h, unsigned id, bool enableFl );
|
||||
// Enable or disable the specified token type.
|
||||
rc_t enableToken( handle_t h, unsigned id, bool enableFl );
|
||||
|
||||
// Get and set the lexer filter flags kReturnXXXLexFl.
|
||||
// These flags can be safely enabled and disabled between
|
||||
// calls to lexGetNextToken().
|
||||
unsigned lexFilterFlags( lexH_t h );
|
||||
void lexSetFilterFlags( lexH_t h, unsigned flags );
|
||||
// Get and set the lexer filter flags kReturnXXXLexFl.
|
||||
// These flags can be safely enabled and disabled between
|
||||
// calls to lexGetNextToken().
|
||||
unsigned filterFlags( handle_t h );
|
||||
void setFilterFlags( handle_t h, unsigned flags );
|
||||
|
||||
// Return the type id of the current token and advances to the next token
|
||||
unsigned lexGetNextToken( lexH_t h );
|
||||
// Return the type id of the current token and advances to the next token
|
||||
unsigned getNextToken( handle_t h );
|
||||
|
||||
// Return the type id associated with the current token. This is the same value
|
||||
// returned by the previous call to lexGetNextToken().
|
||||
unsigned lexTokenId( lexH_t h );
|
||||
// Return the type id associated with the current token. This is the same value
|
||||
// returned by the previous call to lexGetNextToken().
|
||||
unsigned tokenId( handle_t h );
|
||||
|
||||
// Return a pointer to the first character of text associated with the
|
||||
// current token. The returned pointer directly references the text contained
|
||||
// in the buffer given to the lexer in the call to lexInit(). The string
|
||||
// is therefore not zero terminated. Use lexTokenCharCount() to get the
|
||||
// length of the token string.
|
||||
const char* lexTokenText( lexH_t h );
|
||||
// Return a pointer to the first character of text associated with the
|
||||
// current token. The returned pointer directly references the text contained
|
||||
// in the buffer given to the lexer in the call to lexInit(). The string
|
||||
// is therefore not zero terminated. Use lexTokenCharCount() to get the
|
||||
// length of the token string.
|
||||
const char* tokenText( handle_t h );
|
||||
|
||||
// Return the count of characters in the text associated with the current token.
|
||||
// This is the only way to get this count since the string returned by
|
||||
// lexTokenText() is not zero terminated.
|
||||
unsigned lexTokenCharCount( lexH_t h );
|
||||
// Return the count of characters in the text associated with the current token.
|
||||
// This is the only way to get this count since the string returned by
|
||||
// lexTokenText() is not zero terminated.
|
||||
unsigned tokenCharCount( handle_t h );
|
||||
|
||||
// Return the value of the current token as an integer.
|
||||
int lexTokenInt( lexH_t h );
|
||||
// Return the value of the current token as an integer.
|
||||
int tokenInt( handle_t h );
|
||||
|
||||
// Return the value of the current token as an unsigned integer.
|
||||
unsigned lexTokenUInt( lexH_t h );
|
||||
// Return the value of the current token as an unsigned integer.
|
||||
unsigned tokenUInt( handle_t h );
|
||||
|
||||
// Return the value of the current token as a float.
|
||||
float lexTokenFloat( lexH_t h );
|
||||
// Return the value of the current token as a float.
|
||||
float tokenFloat( handle_t h );
|
||||
|
||||
// Return the value of the current token as a double.
|
||||
double lexTokenDouble( lexH_t h );
|
||||
// Return the value of the current token as a double.
|
||||
double tokenDouble( handle_t h );
|
||||
|
||||
// Return true if the current token is an int and it was suffixed
|
||||
// with 'u' to indicate that it is unsigned.
|
||||
bool lexTokenIsUnsigned( lexH_t h );
|
||||
// Return true if the current token is an int and it was suffixed
|
||||
// with 'u' to indicate that it is unsigned.
|
||||
bool tokenIsUnsigned( handle_t h );
|
||||
|
||||
// Return true if the current token is a real and it was suffexed
|
||||
// with 'f' to indicate that it is a single precision float.
|
||||
bool lexTokenIsSinglePrecision( lexH_t h );
|
||||
// Return true if the current token is a real and it was suffexed
|
||||
// with 'f' to indicate that it is a single precision float.
|
||||
bool tokenIsSinglePrecision( handle_t h );
|
||||
|
||||
// Return the line number associated with the current token
|
||||
unsigned lexCurrentLineNumber( lexH_t h );
|
||||
// Return the line number associated with the current token
|
||||
unsigned currentLineNumber( handle_t h );
|
||||
|
||||
// Return the starting column of the current token
|
||||
unsigned lexCurrentColumnNumber( lexH_t h );
|
||||
// Return the starting column of the current token
|
||||
unsigned currentColumnNumber( handle_t h );
|
||||
|
||||
// Return the RC code associated with the last error
|
||||
unsigned lexErrorRC( lexH_t h );
|
||||
// Return the RC code associated with the last error
|
||||
unsigned errorRC( handle_t h );
|
||||
|
||||
// Return the label associated with a token id
|
||||
const char* lexIdToLabel( lexH_t h, unsigned typeId );
|
||||
|
||||
// Lexer testing stub.
|
||||
void lexTest( );
|
||||
// Return the label associated with a token id
|
||||
const char* idToLabel( handle_t h, unsigned typeId );
|
||||
|
||||
// Lexer testing stub.
|
||||
void test( );
|
||||
}
|
||||
}
|
||||
|
||||
//)
|
||||
|
99
cwLog.cpp
99
cwLog.cpp
@ -6,46 +6,47 @@
|
||||
|
||||
namespace cw
|
||||
{
|
||||
|
||||
typedef struct log_str
|
||||
namespace log
|
||||
{
|
||||
logOutputCbFunc_t outCbFunc;
|
||||
void* outCbArg;
|
||||
logFormatCbFunc_t fmtCbFunc;
|
||||
void* fmtCbArg;
|
||||
unsigned level;
|
||||
} log_t;
|
||||
typedef struct log_str
|
||||
{
|
||||
logOutputCbFunc_t outCbFunc;
|
||||
void* outCbArg;
|
||||
logFormatCbFunc_t fmtCbFunc;
|
||||
void* fmtCbArg;
|
||||
unsigned level;
|
||||
} log_t;
|
||||
|
||||
|
||||
logHandle_t __logGlobalHandle__;
|
||||
logHandle_t logNullHandle;
|
||||
|
||||
#define logHandleToPtr(h) handleToPtr<logHandle_t,log_t>(h)
|
||||
|
||||
idLabelPair_t logLevelLabelArray[] =
|
||||
{
|
||||
{ kDebug_LogLevel, "debug" },
|
||||
{ kInfo_LogLevel, "info" },
|
||||
{ kWarning_LogLevel, "warning" },
|
||||
{ kError_LogLevel, "error" },
|
||||
{ kFatal_LogLevel, "fatal" },
|
||||
{ kInvalid_LogLevel, "<invalid>" }
|
||||
};
|
||||
handle_t __logGlobalHandle__;
|
||||
|
||||
idLabelPair_t logLevelLabelArray[] =
|
||||
{
|
||||
{ kDebug_LogLevel, "debug" },
|
||||
{ kInfo_LogLevel, "info" },
|
||||
{ kWarning_LogLevel, "warning" },
|
||||
{ kError_LogLevel, "error" },
|
||||
{ kFatal_LogLevel, "fatal" },
|
||||
{ kInvalid_LogLevel, "<invalid>" }
|
||||
};
|
||||
|
||||
log_t* _handleToPtr( handle_t h ) { return handleToPtr<handle_t,log_t>(h); }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
cw::rc_t cw::logCreate( logHandle_t& hRef, unsigned level, logOutputCbFunc_t outCbFunc, void* outCbArg, logFormatCbFunc_t fmtCbFunc, void* fmtCbArg )
|
||||
|
||||
cw::rc_t cw::log::create( handle_t& hRef, unsigned level, logOutputCbFunc_t outCbFunc, void* outCbArg, logFormatCbFunc_t fmtCbFunc, void* fmtCbArg )
|
||||
{
|
||||
rc_t rc;
|
||||
if((rc = logDestroy(hRef)) != kOkRC)
|
||||
if((rc = destroy(hRef)) != kOkRC)
|
||||
return rc;
|
||||
|
||||
log_t* p = memAllocZ<log_t>();
|
||||
p->outCbFunc = outCbFunc == nullptr ? logDefaultOutput : outCbFunc;
|
||||
p->outCbFunc = outCbFunc == nullptr ? defaultOutput : outCbFunc;
|
||||
p->outCbArg = outCbArg;
|
||||
p->fmtCbFunc = fmtCbFunc == nullptr ? logDefaultFormatter : fmtCbFunc;
|
||||
p->fmtCbFunc = fmtCbFunc == nullptr ? defaultFormatter : fmtCbFunc;
|
||||
p->fmtCbArg = fmtCbArg;
|
||||
p->level = level;
|
||||
hRef.p = p;
|
||||
@ -53,7 +54,7 @@ cw::rc_t cw::logCreate( logHandle_t& hRef, unsigned level, logOutputCbFunc_t ou
|
||||
return rc;
|
||||
}
|
||||
|
||||
cw::rc_t cw::logDestroy( logHandle_t& hRef )
|
||||
cw::rc_t cw::log::destroy( handle_t& hRef )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
|
||||
@ -64,9 +65,9 @@ cw::rc_t cw::logDestroy( logHandle_t& hRef )
|
||||
return rc;
|
||||
}
|
||||
|
||||
cw::rc_t cw::logMsg( logHandle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* fmt, va_list vl )
|
||||
cw::rc_t cw::log::msg( handle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* fmt, va_list vl )
|
||||
{
|
||||
log_t* p = logHandleToPtr(h);
|
||||
log_t* p = _handleToPtr(h);
|
||||
|
||||
va_list vl1;
|
||||
va_copy(vl1,vl);
|
||||
@ -88,30 +89,30 @@ cw::rc_t cw::logMsg( logHandle_t h, unsigned level, const char* function, const
|
||||
return rc;
|
||||
}
|
||||
|
||||
cw::rc_t cw::logMsg( logHandle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t returnCode, const char* fmt, ... )
|
||||
cw::rc_t cw::log::msg( handle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t returnCode, const char* fmt, ... )
|
||||
{
|
||||
rc_t rc;
|
||||
va_list vl;
|
||||
va_start(vl,fmt);
|
||||
rc = logMsg( h, level, function, filename, line, systemErrorCode, returnCode, fmt, vl );
|
||||
rc = msg( h, level, function, filename, line, systemErrorCode, returnCode, fmt, vl );
|
||||
va_end(vl);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void cw::logSetLevel( logHandle_t h, unsigned level )
|
||||
void cw::log::setLevel( handle_t h, unsigned level )
|
||||
{
|
||||
log_t* p = logHandleToPtr(h);
|
||||
log_t* p = _handleToPtr(h);
|
||||
p->level = level;
|
||||
}
|
||||
|
||||
unsigned cw::logLevel( logHandle_t h )
|
||||
unsigned cw::log::level( handle_t h )
|
||||
{
|
||||
log_t* p = logHandleToPtr(h);
|
||||
log_t* p = _handleToPtr(h);
|
||||
return p->level;
|
||||
}
|
||||
|
||||
|
||||
const char* cw::logLevelToLabel( unsigned level )
|
||||
const char* cw::log::levelToLabel( unsigned level )
|
||||
{
|
||||
const char* label;
|
||||
if((label = idToLabel(logLevelLabelArray,level,kInvalid_LogLevel)) == nullptr)
|
||||
@ -122,20 +123,20 @@ const char* cw::logLevelToLabel( unsigned level )
|
||||
|
||||
|
||||
|
||||
void cw::logDefaultOutput( void* arg, unsigned level, const char* text )
|
||||
void cw::log::defaultOutput( void* arg, unsigned level, const char* text )
|
||||
{
|
||||
FILE* f = level >= kWarning_LogLevel ? stderr : stdout;
|
||||
fprintf(f,"%s",text);
|
||||
}
|
||||
|
||||
void cw::logDefaultFormatter( void* cbArg, logOutputCbFunc_t outFunc, void* outCbArg, unsigned level, const char* function, const char* filename, unsigned lineno, int sys_errno, rc_t rc, const char* msg )
|
||||
void cw::log::defaultFormatter( void* cbArg, logOutputCbFunc_t outFunc, void* outCbArg, unsigned level, const char* function, const char* filename, unsigned lineno, int sys_errno, rc_t rc, const char* msg )
|
||||
{
|
||||
// TODO: This code is avoids the use of dynamic memory allocation but relies on stack allocation. It's a security vulnerability.
|
||||
//
|
||||
|
||||
const char* systemLabel = sys_errno==0 ? "" : "System Error: ";
|
||||
const char* systemMsg = sys_errno==0 ? "" : strerror(sys_errno);
|
||||
const char* levelStr = logLevelToLabel(level);
|
||||
const char* levelStr = levelToLabel(level);
|
||||
|
||||
const char* rcFmt = "rc:%i";
|
||||
int rcn = snprintf(nullptr,0,rcFmt,rc);
|
||||
@ -175,35 +176,33 @@ void cw::logDefaultFormatter( void* cbArg, logOutputCbFunc_t outFunc, void* outC
|
||||
int m = snprintf(s,n+1,fmt,levelStr,msg,syStr,rcStr,loStr);
|
||||
cwAssert(m==n);
|
||||
|
||||
outFunc(outCbArg,level,s);
|
||||
|
||||
outFunc(outCbArg,level,s);
|
||||
}
|
||||
|
||||
|
||||
cw::rc_t cw::logCreateGlobal( unsigned level, logOutputCbFunc_t outCb, void* outCbArg, logFormatCbFunc_t fmtCb, void* fmtCbArg )
|
||||
cw::rc_t cw::log::createGlobal( unsigned level, logOutputCbFunc_t outCb, void* outCbArg, logFormatCbFunc_t fmtCb, void* fmtCbArg )
|
||||
{
|
||||
logHandle_t h;
|
||||
handle_t h;
|
||||
rc_t rc;
|
||||
|
||||
if((rc = logCreate(h, level, outCb, outCbArg, fmtCb, fmtCbArg )) == kOkRC )
|
||||
logSetGlobalHandle(h);
|
||||
if((rc = create(h, level, outCb, outCbArg, fmtCb, fmtCbArg )) == kOkRC )
|
||||
setGlobalHandle(h);
|
||||
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
cw::rc_t cw::logDestroyGlobal()
|
||||
cw::rc_t cw::log::destroyGlobal()
|
||||
{
|
||||
return logDestroy(__logGlobalHandle__);
|
||||
return destroy(__logGlobalHandle__);
|
||||
}
|
||||
|
||||
|
||||
void cw::logSetGlobalHandle( logHandle_t h )
|
||||
void cw::log::setGlobalHandle( handle_t h )
|
||||
{
|
||||
__logGlobalHandle__ = h;
|
||||
}
|
||||
|
||||
cw::logHandle_t cw::logGlobalHandle()
|
||||
cw::log::handle_t cw::log::globalHandle()
|
||||
{
|
||||
return __logGlobalHandle__;
|
||||
}
|
||||
|
109
cwLog.h
109
cwLog.h
@ -4,73 +4,74 @@
|
||||
namespace cw
|
||||
{
|
||||
|
||||
typedef enum
|
||||
namespace log
|
||||
{
|
||||
kInvalid_LogLevel,
|
||||
kDebug_LogLevel,
|
||||
kInfo_LogLevel,
|
||||
kWarning_LogLevel,
|
||||
kError_LogLevel,
|
||||
kFatal_LogLevel,
|
||||
} logLevelId_t;
|
||||
typedef enum
|
||||
{
|
||||
kInvalid_LogLevel,
|
||||
kDebug_LogLevel,
|
||||
kInfo_LogLevel,
|
||||
kWarning_LogLevel,
|
||||
kError_LogLevel,
|
||||
kFatal_LogLevel,
|
||||
} logLevelId_t;
|
||||
|
||||
typedef handle<struct log_str> logHandle_t;
|
||||
|
||||
extern logHandle_t logNullHandle;
|
||||
typedef handle<struct log_str> handle_t;
|
||||
|
||||
typedef void (*logOutputCbFunc_t)( void* cbArg, unsigned level, const char* text );
|
||||
typedef void (*logFormatCbFunc_t)( void* cbArg, logOutputCbFunc_t outFunc, void* outCbArg, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* msg );
|
||||
typedef void (*logOutputCbFunc_t)( void* cbArg, unsigned level, const char* text );
|
||||
typedef void (*logFormatCbFunc_t)( void* cbArg, logOutputCbFunc_t outFunc, void* outCbArg, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* msg );
|
||||
|
||||
rc_t logCreate( logHandle_t& hRef, unsigned level=kDebug_LogLevel, logOutputCbFunc_t outCb=nullptr, void* outCbArg=nullptr, logFormatCbFunc_t fmtCb=nullptr, void* fmtCbArg=nullptr );
|
||||
rc_t logDestroy( logHandle_t& hRef );
|
||||
rc_t create( handle_t& hRef, unsigned level=kDebug_LogLevel, logOutputCbFunc_t outCb=nullptr, void* outCbArg=nullptr, logFormatCbFunc_t fmtCb=nullptr, void* fmtCbArg=nullptr );
|
||||
rc_t destroy( handle_t& hRef );
|
||||
|
||||
rc_t logMsg( logHandle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* fmt, va_list vl );
|
||||
rc_t logMsg( logHandle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* fmt, ... );
|
||||
rc_t msg( handle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* fmt, va_list vl );
|
||||
rc_t msg( handle_t h, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* fmt, ... );
|
||||
|
||||
void logSetLevel( logHandle_t h, unsigned level );
|
||||
unsigned logLevel( logHandle_t h );
|
||||
void setLevel( handle_t h, unsigned level );
|
||||
unsigned level( handle_t h );
|
||||
|
||||
const char* logLevelToLabel( unsigned level );
|
||||
const char* levelToLabel( unsigned level );
|
||||
|
||||
void logDefaultOutput( void* arg, unsigned level, const char* text );
|
||||
void logDefaultFormatter( void* cbArg, logOutputCbFunc_t outFunc, void* outCbArg, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* msg );
|
||||
void defaultOutput( void* arg, unsigned level, const char* text );
|
||||
void defaultFormatter( void* cbArg, logOutputCbFunc_t outFunc, void* outCbArg, unsigned level, const char* function, const char* filename, unsigned line, int systemErrorCode, rc_t rc, const char* msg );
|
||||
|
||||
rc_t logCreateGlobal( unsigned level=kDebug_LogLevel, logOutputCbFunc_t outCb=nullptr, void* outCbArg=nullptr, logFormatCbFunc_t fmtCb=nullptr, void* fmtCbArg=nullptr );
|
||||
rc_t logDestroyGlobal( );
|
||||
rc_t createGlobal( unsigned level=kDebug_LogLevel, logOutputCbFunc_t outCb=nullptr, void* outCbArg=nullptr, logFormatCbFunc_t fmtCb=nullptr, void* fmtCbArg=nullptr );
|
||||
rc_t destroyGlobal( );
|
||||
|
||||
void logSetGlobalHandle( logHandle_t h );
|
||||
logHandle_t logGlobalHandle();
|
||||
void setGlobalHandle( handle_t h );
|
||||
handle_t globalHandle();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#define cwLogVDebugH(h,rc,fmt, vl) cw::logMsg( h, cw::kDebug_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
||||
#define cwLogDebugH( h,rc,fmt,...) cw::logMsg( h, cw::kDebug_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||
#define cwLogVDebugH(h,rc,fmt, vl) cw::log::msg( h, cw::log::kDebug_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
||||
#define cwLogDebugH( h,rc,fmt,...) cw::log::msg( h, cw::log::kDebug_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVInfoH(h,fmt, vl) cw::logMsg( h, cw::kInfo_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, cw::kOkRC, fmt, vl )
|
||||
#define cwLogInfoH( h,fmt,...) cw::logMsg( h, cw::kInfo_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, cw::kOkRC, fmt, ##__VA_ARGS__ )
|
||||
#define cwLogVInfoH(h,fmt, vl) cw::log::msg( h, cw::log::kInfo_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, cw::kOkRC, fmt, vl )
|
||||
#define cwLogInfoH( h,fmt,...) cw::log::msg( h, cw::log::kInfo_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, cw::kOkRC, fmt, ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVWarningH(h,rc,fmt, vl) cw::logMsg( h, cw::kWarning_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
||||
#define cwLogWarningH( h,rc,fmt,...) cw::logMsg( h, cw::kWarning_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||
#define cwLogVWarningH(h,rc,fmt, vl) cw::log::msg( h, cw::log::kWarning_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
||||
#define cwLogWarningH( h,rc,fmt,...) cw::log::msg( h, cw::log::kWarning_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVErrorH(h,rc,fmt, vl) cw::logMsg( h, cw::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
||||
#define cwLogErrorH( h,rc,fmt,...) cw::logMsg( h, cw::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||
#define cwLogVErrorH(h,rc,fmt, vl) cw::log::msg( h, cw::log::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
||||
#define cwLogErrorH( h,rc,fmt,...) cw::log::msg( h, cw::log::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVSysErrorH(h,rc,sysRc,fmt, vl) cw::logMsg( h, cw::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, sysRc, rc, fmt, vl )
|
||||
#define cwLogSysErrorH( h,rc,sysRc,fmt,...) cw::logMsg( h, cw::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, sysRc, rc, fmt, ##__VA_ARGS__ )
|
||||
#define cwLogVSysErrorH(h,rc,sysRc,fmt, vl) cw::log::msg( h, cw::log::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, sysRc, rc, fmt, vl )
|
||||
#define cwLogSysErrorH( h,rc,sysRc,fmt,...) cw::log::msg( h, cw::log::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, sysRc, rc, fmt, ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVFatalH(h,rc,fmt, vl) cw::logMsg( h, cw::kFatal_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
||||
#define cwLogFatalH( h,rc,fmt,...) cw::logMsg( h, cw::kFatal_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||
#define cwLogVFatalH(h,rc,fmt, vl) cw::log::msg( h, cw::log::kFatal_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
||||
#define cwLogFatalH( h,rc,fmt,...) cw::log::msg( h, cw::log::kFatal_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||
|
||||
#ifdef cwLOG_DEBUG
|
||||
|
||||
#define cwLogVDebugRC(rc,fmt, vl) cwLogVDebugH( cw::logGlobalHandle(), (rc), (fmt), (vl) )
|
||||
#define cwLogDebugRC( rc,fmt,...) cwLogDebugH( cw::logGlobalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||
#define cwLogVDebugRC(rc,fmt, vl) cwLogVDebugH( cw::log::globalhandle(), (rc), (fmt), (vl) )
|
||||
#define cwLogDebugRC( rc,fmt,...) cwLogDebugH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVDebug(fmt, vl) cwLogVDebugH( cw::logGlobalHandle(), cw::kOkRC, (fmt), (vl) )
|
||||
#define cwLogDebug( fmt,...) cwLogDebugH( cw::logGlobalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ )
|
||||
#define cwLogVDebug(fmt, vl) cwLogVDebugH( cw::log::globalHandle(), cw::kOkRC, (fmt), (vl) )
|
||||
#define cwLogDebug( fmt,...) cwLogDebugH( cw::log::globalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ )
|
||||
|
||||
#else
|
||||
|
||||
@ -83,23 +84,23 @@ namespace cw
|
||||
#endif
|
||||
|
||||
|
||||
#define cwLogVInfo(fmt, vl) cwLogVInfoH( cw::logGlobalHandle(), (fmt), (vl) )
|
||||
#define cwLogInfo( fmt,...) cwLogInfoH( cw::logGlobalHandle(), (fmt), ##__VA_ARGS__ )
|
||||
#define cwLogVInfo(fmt, vl) cwLogVInfoH( cw::log::globalHandle(), (fmt), (vl) )
|
||||
#define cwLogInfo( fmt,...) cwLogInfoH( cw::log::globalHandle(), (fmt), ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVWarningRC(rc,fmt, vl) cwLogVWarningH( cw::logGlobalHandle(), (rc), (fmt), (vl) )
|
||||
#define cwLogWarningRC( rc,fmt,...) cwLogWarningH( cw::logGlobalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||
#define cwLogVWarningRC(rc,fmt, vl) cwLogVWarningH( cw::log::globalHandle(), (rc), (fmt), (vl) )
|
||||
#define cwLogWarningRC( rc,fmt,...) cwLogWarningH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVWarning(fmt, vl) cwLogVWarningH( cw::logGlobalHandle(), cw::kOkRC, (fmt), (vl) )
|
||||
#define cwLogWarning( fmt,...) cwLogWarningH( cw::logGlobalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ )
|
||||
#define cwLogVWarning(fmt, vl) cwLogVWarningH( cw::log::globalHandle(), cw::kOkRC, (fmt), (vl) )
|
||||
#define cwLogWarning( fmt,...) cwLogWarningH( cw::log::globalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVSysError(rc,sysRC,fmt, vl) cwLogVSysErrorH( cw::logGlobalHandle(), (rc), (sysRC), (fmt), (vl) )
|
||||
#define cwLogSysError( rc,sysRC,fmt,...) cwLogSysErrorH( cw::logGlobalHandle(), (rc), (sysRC), (fmt), ##__VA_ARGS__ )
|
||||
#define cwLogVSysError(rc,sysRC,fmt, vl) cwLogVSysErrorH( cw::log::globalHandle(), (rc), (sysRC), (fmt), (vl) )
|
||||
#define cwLogSysError( rc,sysRC,fmt,...) cwLogSysErrorH( cw::log::globalHandle(), (rc), (sysRC), (fmt), ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVError(rc,fmt, vl) cwLogVErrorH( cw::logGlobalHandle(), (rc), (fmt), (vl) )
|
||||
#define cwLogError( rc,fmt,...) cwLogErrorH( cw::logGlobalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||
#define cwLogVError(rc,fmt, vl) cwLogVErrorH( cw::log::globalHandle(), (rc), (fmt), (vl) )
|
||||
#define cwLogError( rc,fmt,...) cwLogErrorH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||
|
||||
#define cwLogVFatal(rc,fmt, vl) cwLogVFatalH( cw::logGlobalHandle(), (rc), (fmt), (vl) )
|
||||
#define cwLogFatal( rc,fmt,...) cwLogFatalH( cw::logGlobalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||
#define cwLogVFatal(rc,fmt, vl) cwLogVFatalH( cw::log::globalHandle(), (rc), (fmt), (vl) )
|
||||
#define cwLogFatal( rc,fmt,...) cwLogFatalH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||
|
||||
|
||||
#endif
|
||||
|
59
cwObject.cpp
59
cwObject.cpp
@ -16,7 +16,7 @@ namespace cw
|
||||
{
|
||||
enum
|
||||
{
|
||||
kLCurlyLexTId = cw::kUserLexTId+1,
|
||||
kLCurlyLexTId = cw::lex::kUserLexTId+1,
|
||||
kRCurlyLexTId,
|
||||
kLHardLexTId,
|
||||
kRHardLexTId,
|
||||
@ -38,7 +38,7 @@ namespace cw
|
||||
{ kTrueLexTId, "true"},
|
||||
{ kFalseLexTId, "false"},
|
||||
{ kNullLexTId, "null" },
|
||||
{ cw::kErrorLexTId,""}
|
||||
{ lex::kErrorLexTId,""}
|
||||
|
||||
};
|
||||
|
||||
@ -98,8 +98,7 @@ namespace cw
|
||||
{
|
||||
for(unsigned i=0; i<indent; ++i)
|
||||
printf(indentStr);
|
||||
printf("%s",text);
|
||||
|
||||
printf("%s",text);
|
||||
}
|
||||
|
||||
void _objTypePrintChild( const object_t* o, print_ctx_t& c, const char* eolStr=",\n", const char* indentStr=" " )
|
||||
@ -244,19 +243,19 @@ namespace cw
|
||||
return o;
|
||||
}
|
||||
|
||||
rc_t _objSyntaxError( lexH_t lexH, const char* fmt, ... )
|
||||
rc_t _objSyntaxError( lex::handle_t lexH, const char* fmt, ... )
|
||||
{
|
||||
va_list vl;
|
||||
va_start(vl,fmt);
|
||||
|
||||
cwLogVError( kSyntaxErrorRC, fmt, vl );
|
||||
cwLogError( kSyntaxErrorRC, "Error on line: %i.", lexCurrentLineNumber(lexH));
|
||||
cwLogError( kSyntaxErrorRC, "Error on line: %i.", lex::currentLineNumber(lexH));
|
||||
va_end(vl);
|
||||
return kSyntaxErrorRC;
|
||||
}
|
||||
|
||||
|
||||
rc_t _objVerifyParentIsValueContainer( lexH_t lexH, const object_t* parent, const char* msg )
|
||||
rc_t _objVerifyParentIsValueContainer( lex::handle_t lexH, const object_t* parent, const char* msg )
|
||||
{
|
||||
if( parent == nullptr )
|
||||
return _objSyntaxError(lexH,"The parent node must always be valid.");
|
||||
@ -289,7 +288,7 @@ namespace cw
|
||||
return newNode;
|
||||
}
|
||||
|
||||
object_t* _objCreateConainerNode( lexH_t lexH, object_t* parent, objTypeId_t tid )
|
||||
object_t* _objCreateConainerNode( lex::handle_t lexH, object_t* parent, objTypeId_t tid )
|
||||
{
|
||||
if( _objVerifyParentIsValueContainer(lexH,parent,_objTypeIdToLabel(tid)) == kOkRC )
|
||||
return _objAppendLeftMostNode( parent, _objAllocate( tid, parent ));
|
||||
@ -390,28 +389,28 @@ void cw::object_t::print(const print_ctx_t* c) const
|
||||
|
||||
cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
||||
{
|
||||
lexH_t lexH;
|
||||
rc_t rc;
|
||||
unsigned lexFlags = 0;
|
||||
unsigned lexId = kErrorLexTId;
|
||||
object_t* cnp = _objAllocate(kRootTId,nullptr);
|
||||
object_t* root = cnp;
|
||||
lex::handle_t lexH;
|
||||
rc_t rc;
|
||||
unsigned lexFlags = 0;
|
||||
unsigned lexId = lex::kErrorLexTId;
|
||||
object_t* cnp = _objAllocate(kRootTId,nullptr);
|
||||
object_t* root = cnp;
|
||||
|
||||
objRef = nullptr;
|
||||
|
||||
if((rc = lexCreate(lexH,s,textLength(s), lexFlags )) != kOkRC )
|
||||
if((rc = lex::create(lexH,s,textLength(s), lexFlags )) != kOkRC )
|
||||
return rc;
|
||||
|
||||
// setup the lexer with additional tokens
|
||||
for(unsigned i=0; _objTokenArray[i].id != cw::kErrorLexTId; ++i)
|
||||
if((rc = lexRegisterToken( lexH, _objTokenArray[i].id, _objTokenArray[i].label )) != kOkRC )
|
||||
for(unsigned i=0; _objTokenArray[i].id != lex::kErrorLexTId; ++i)
|
||||
if((rc = lex::registerToken( lexH, _objTokenArray[i].id, _objTokenArray[i].label )) != kOkRC )
|
||||
{
|
||||
rc = cwLogError(rc,"Object lexer token registration failed on token id:%i : '%s'",_objTokenArray[i].id, _objTokenArray[i].label);
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// main parser loop
|
||||
while((lexId = lexGetNextToken(lexH)) != cw::kErrorLexTId && (lexId != kEofLexTId) && (rc == kOkRC))
|
||||
while((lexId = lex::getNextToken(lexH)) != lex::kErrorLexTId && (lexId != lex::kEofLexTId) && (rc == kOkRC))
|
||||
{
|
||||
|
||||
//printf("Lex:%s\n",lexIdToLabel(lexH,lexId));
|
||||
@ -450,16 +449,16 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
||||
rc = _objSyntaxError(lexH,"Unexpected comma outside of 'array' or 'object'.");
|
||||
break;
|
||||
|
||||
case kRealLexTId:
|
||||
_objCreateValueNode( cnp, lexTokenDouble(lexH), "real" );
|
||||
case lex::kRealLexTId:
|
||||
_objCreateValueNode( cnp, lex::tokenDouble(lexH), "real" );
|
||||
break;
|
||||
|
||||
case kIntLexTId:
|
||||
_objCreateValueNode( cnp, lexTokenInt(lexH), "int" );
|
||||
case lex::kIntLexTId:
|
||||
_objCreateValueNode( cnp, lex::tokenInt(lexH), "int" );
|
||||
break;
|
||||
|
||||
case kHexLexTId:
|
||||
_objCreateValueNode( cnp, lexTokenInt(lexH), "int", kHexFl );
|
||||
case lex::kHexLexTId:
|
||||
_objCreateValueNode( cnp, lex::tokenInt(lexH), "int", kHexFl );
|
||||
break;
|
||||
|
||||
case kTrueLexTId:
|
||||
@ -474,8 +473,8 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
||||
_objAppendLeftMostNode( cnp, _objAllocate( kNullTId, cnp ));
|
||||
break;
|
||||
|
||||
case kIdentLexTId:
|
||||
case kQStrLexTId:
|
||||
case lex::kIdentLexTId:
|
||||
case lex::kQStrLexTId:
|
||||
{
|
||||
|
||||
// if the parent is an object then this string must be a pair label
|
||||
@ -483,15 +482,15 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
||||
cnp = _objAppendLeftMostNode( cnp, _objAllocate( kPairTId, cnp ));
|
||||
|
||||
|
||||
char* v = memDuplStr(lexTokenText(lexH),lexTokenCharCount(lexH));
|
||||
unsigned identFl = lexId == kIdentLexTId ? kIdentFl : 0;
|
||||
char* v = memDuplStr(lex::tokenText(lexH),lex::tokenCharCount(lexH));
|
||||
unsigned identFl = lexId == lex::kIdentLexTId ? kIdentFl : 0;
|
||||
|
||||
|
||||
_objCreateValueNode<char*>( cnp, v, "string", identFl );
|
||||
}
|
||||
break;
|
||||
|
||||
case kEofLexTId:
|
||||
case lex::kEofLexTId:
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -509,7 +508,7 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
||||
objRef = root;
|
||||
|
||||
errLabel:
|
||||
rc_t rc0 = lexDestroy(lexH);
|
||||
rc_t rc0 = lex::destroy(lexH);
|
||||
|
||||
return rc != kOkRC ? rc : rc0;
|
||||
|
||||
|
@ -6,7 +6,7 @@ namespace cw
|
||||
{
|
||||
objType_t* _objIdToType( objTypeId_t tid );
|
||||
object_t* _objAllocate( objTypeId_t tid=kInvalidTId, object_t* parent=NULL );
|
||||
object_t* _objCreateConainerNode( lexH_t lexH, object_t* parent, objTypeId_t tid );
|
||||
object_t* _objCreateConainerNode( lex::handle_t lexH, object_t* parent, objTypeId_t tid );
|
||||
object_t* _objAppendLeftMostNode( object_t* parent, object_t* newNode );
|
||||
|
||||
template< typename T >
|
||||
|
389
cwTcpSocket.cpp
Normal file
389
cwTcpSocket.cpp
Normal file
@ -0,0 +1,389 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwMem.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h> // close
|
||||
|
||||
#include "cwTcpSocket.h"
|
||||
|
||||
#define cwSOCKET_SYS_ERR (-1)
|
||||
#define cwSOCKET_NULL_SOCK (-1)
|
||||
|
||||
#ifndef HOST_NAME_MAX
|
||||
#define HOST_NAME_MAX _POSIX_HOST_NAME_MAX
|
||||
#endif
|
||||
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
namespace socket
|
||||
{
|
||||
enum
|
||||
{
|
||||
kIsConnectedFl = 0x01,
|
||||
kIsBlockingFl = 0x02
|
||||
};
|
||||
|
||||
typedef struct socket_str
|
||||
{
|
||||
int sockH;
|
||||
unsigned flags;
|
||||
unsigned recvBufByteCnt;
|
||||
struct sockaddr_in sockaddr;
|
||||
char ntopBuf[ INET_ADDRSTRLEN+1 ]; // use INET6_ADDRSTRLEN for IPv6
|
||||
char hnameBuf[ HOST_NAME_MAX+1 ];
|
||||
} socket_t;
|
||||
|
||||
inline socket_t* _handleToPtr( handle_t h ) { return handleToPtr<handle_t,socket_t>(h); }
|
||||
|
||||
rc_t _destroy( socket_t* p )
|
||||
{
|
||||
// close the socket
|
||||
if( p->sockH != cwSOCKET_NULL_SOCK )
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
if( ::close(p->sockH) != 0 )
|
||||
cwLogSysError(kOpFailRC,errno,"The socket close failed." );
|
||||
|
||||
p->sockH = cwSOCKET_NULL_SOCK;
|
||||
}
|
||||
|
||||
memRelease(p);
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
|
||||
rc_t _initAddr( socket_t* p, const char* addrStr, portNumber_t portNumber, struct sockaddr_in* retAddrPtr )
|
||||
{
|
||||
memset(retAddrPtr,0,sizeof(struct sockaddr_in));
|
||||
|
||||
if( portNumber == kInvalidPortNumber )
|
||||
return cwLogError(kInvalidArgRC,"The port number %i cannot be used.",kInvalidPortNumber);
|
||||
|
||||
if( addrStr == NULL )
|
||||
retAddrPtr->sin_addr.s_addr = htonl(INADDR_ANY);
|
||||
else
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
if(inet_pton(AF_INET,addrStr,&retAddrPtr->sin_addr) == 0 )
|
||||
return cwLogSysError(kOpFailRC,errno, "The network address string '%s' could not be converted to a netword address structure.",cwStringNullGuard(addrStr) );
|
||||
}
|
||||
|
||||
//retAddrPtr->sin_len = sizeof(struct sockaddr_in);
|
||||
retAddrPtr->sin_family = AF_INET;
|
||||
retAddrPtr->sin_port = htons(portNumber);
|
||||
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
rc_t _connect( socket_t* p, const char* remoteAddr, portNumber_t remotePort )
|
||||
{
|
||||
struct sockaddr_in addr;
|
||||
rc_t rc;
|
||||
|
||||
// create the remote address
|
||||
if((rc = _initAddr(p, remoteAddr, remotePort, &addr )) != kOkRC )
|
||||
return rc;
|
||||
|
||||
errno = 0;
|
||||
|
||||
// ... and connect this socket to the remote address/port
|
||||
if( connect(p->sockH, (struct sockaddr*)&addr, sizeof(addr)) == cwSOCKET_SYS_ERR )
|
||||
return cwLogSysError(kOpFailRC, errno, "Socket connect failed." );
|
||||
|
||||
p->flags = cwSetFlag(p->flags,kIsConnectedFl);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
cw::rc_t cw::net::socket::create(
|
||||
handle_t& hRef,
|
||||
portNumber_t port,
|
||||
unsigned flags,
|
||||
unsigned timeOutMs,
|
||||
const char* remoteAddr,
|
||||
portNumber_t remotePort )
|
||||
{
|
||||
rc_t rc;
|
||||
if((rc = destroy(hRef)) != kOkRC )
|
||||
return rc;
|
||||
|
||||
socket_t* p = memAllocZ<socket_t>();
|
||||
p->sockH = cwSOCKET_NULL_SOCK;
|
||||
|
||||
// get a handle to the socket
|
||||
if(( p->sockH = ::socket( AF_INET, SOCK_DGRAM, IPPROTO_UDP ) ) == cwSOCKET_SYS_ERR )
|
||||
return cwLogSysError(kOpFailRC, errno, "Socket create failed." );
|
||||
|
||||
// create the local address
|
||||
if((rc = _initAddr(p, NULL, port, &p->sockaddr )) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
// bind the socket to a local address/port
|
||||
if( (bind( p->sockH, (struct sockaddr*)&p->sockaddr, sizeof(p->sockaddr))) == cwSOCKET_SYS_ERR )
|
||||
{
|
||||
rc = cwLogSysError(kOpFailRC,errno,"Socket bind failed." );
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
// if a remote addr was given connect this socket to it
|
||||
if( remoteAddr != NULL )
|
||||
if((rc = _connect(p,remoteAddr,remotePort)) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
// if this socket should block
|
||||
if( cwIsFlag(flags,kBlockingFl) )
|
||||
{
|
||||
struct timeval timeOut;
|
||||
|
||||
// set the socket time out
|
||||
timeOut.tv_sec = timeOutMs/1000;
|
||||
timeOut.tv_usec = (timeOutMs - (timeOut.tv_sec * 1000)) * 1000;
|
||||
|
||||
if( setsockopt( p->sockH, SOL_SOCKET, SO_RCVTIMEO, &timeOut, sizeof(timeOut) ) == cwSOCKET_SYS_ERR )
|
||||
{
|
||||
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket timeout failed." );
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
p->flags = cwSetFlag(p->flags,kIsBlockingFl);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
int opts;
|
||||
|
||||
// get the socket options flags
|
||||
if( (opts = fcntl(p->sockH,F_GETFL)) < 0 )
|
||||
{
|
||||
rc = cwLogSysError(kOpFailRC,errno, "Attempt to get the socket options flags failed." );
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
opts = (opts | O_NONBLOCK);
|
||||
|
||||
// set the socket options flags
|
||||
if(fcntl(p->sockH,F_SETFL,opts) < 0)
|
||||
{
|
||||
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket to non-blocking failed." );
|
||||
goto errLabel;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if broadcast option was requested.
|
||||
if( cwIsFlag(flags,kBroadcastFl) )
|
||||
{
|
||||
int bcastFl = 1;
|
||||
if( setsockopt( p->sockH, SOL_SOCKET, SO_BROADCAST, &bcastFl, sizeof(bcastFl) ) == cwSOCKET_SYS_ERR )
|
||||
{
|
||||
rc = cwLogSysError(kOpFailRC,errno, "Attempt to set the socket broadcast attribute failed." );
|
||||
goto errLabel;
|
||||
}
|
||||
}
|
||||
|
||||
errLabel:
|
||||
if(rc != kOkRC )
|
||||
_destroy(p);
|
||||
else
|
||||
hRef.set(p);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::socket::destroy( handle_t& hRef )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
if( !hRef.isValid() )
|
||||
return rc;
|
||||
|
||||
socket_t* p = _handleToPtr(hRef);
|
||||
|
||||
if((rc = _destroy(p)) != kOkRC )
|
||||
return rc;
|
||||
|
||||
hRef.clear();
|
||||
return rc;
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::socket::connect( handle_t h, const char* remoteAddr, portNumber_t remotePort )
|
||||
{
|
||||
socket_t* p = _handleToPtr(h);
|
||||
return _connect(p,remoteAddr,remotePort);
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::socket::send( handle_t h, const void* data, unsigned dataByteCnt )
|
||||
{
|
||||
socket_t* p = _handleToPtr(h);
|
||||
errno = 0;
|
||||
|
||||
if( cwIsFlag(p->flags,kIsConnectedFl) == false )
|
||||
return cwLogError(kInvalidOpRC,"cmUdpSend() only works with connected sockets.");
|
||||
|
||||
if( ::send( p->sockH, data, dataByteCnt, 0 ) == cwSOCKET_SYS_ERR )
|
||||
return cwLogSysError(kOpFailRC,errno,"Send failed.");
|
||||
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::socket::send( handle_t h, const void* data, unsigned dataByteCnt, const struct sockaddr_in* remoteAddr )
|
||||
{
|
||||
socket_t* p = _handleToPtr(h);
|
||||
|
||||
errno = 0;
|
||||
|
||||
if( sendto(p->sockH, data, dataByteCnt, 0, (struct sockaddr*)remoteAddr, sizeof(*remoteAddr)) == cwSOCKET_SYS_ERR )
|
||||
return cwLogSysError(kOpFailRC,errno,"Send to remote addr. failed.");
|
||||
|
||||
return kOkRC;
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::socket::send( handle_t h, const void* data, unsigned dataByteCnt, const char* remoteAddr, portNumber_t remotePort )
|
||||
{
|
||||
rc_t rc;
|
||||
socket_t* p = _handleToPtr(h);
|
||||
struct sockaddr_in addr;
|
||||
|
||||
if((rc = _initAddr(p,remoteAddr,remotePort,&addr)) != kOkRC )
|
||||
return rc;
|
||||
|
||||
return send( h, data, dataByteCnt, &addr );
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::socket::recieve( handle_t h, char* data, unsigned dataByteCnt, unsigned* recvByteCntRef, struct sockaddr_in* fromAddr )
|
||||
{
|
||||
socket_t* p = _handleToPtr(h);
|
||||
rc_t rc = kOkRC;
|
||||
ssize_t retVal = 0;
|
||||
socklen_t sizeOfRemoteAddr = fromAddr==NULL ? 0 : sizeof(struct sockaddr_in);
|
||||
|
||||
errno = 0;
|
||||
|
||||
if( recvByteCntRef != NULL )
|
||||
*recvByteCntRef = 0;
|
||||
|
||||
if((retVal = recvfrom(p->sockH, data, dataByteCnt, 0, (struct sockaddr*)fromAddr, &sizeOfRemoteAddr )) == cwSOCKET_SYS_ERR )
|
||||
return errno == EAGAIN ? kTimeOutRC : cwLogSysError(kOpFailRC,errno,"recvfrom() failed.");
|
||||
|
||||
if( recvByteCntRef != NULL )
|
||||
*recvByteCntRef = retVal;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::socket::select_recieve(handle_t h, char* buf, unsigned bufByteCnt, unsigned timeOutMs, unsigned* recvByteCntRef, struct sockaddr_in* fromAddr )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
socket_t* p = _handleToPtr(h);
|
||||
fd_set rdSet;
|
||||
struct timeval timeOut;
|
||||
|
||||
// setup the select() call
|
||||
FD_ZERO(&rdSet);
|
||||
FD_SET(p->sockH, &rdSet );
|
||||
|
||||
timeOut.tv_sec = timeOutMs/1000;
|
||||
timeOut.tv_usec = (timeOutMs - (timeOut.tv_sec * 1000)) * 1000;
|
||||
|
||||
if( recvByteCntRef != nullptr )
|
||||
*recvByteCntRef = 0;
|
||||
|
||||
// NOTE; select() takes the highest socket value plus one of all the sockets in all the sets.
|
||||
|
||||
switch( select(p->sockH+1,&rdSet,NULL,NULL,&timeOut) )
|
||||
{
|
||||
case -1: // error
|
||||
if( errno != EINTR )
|
||||
cwLogSysError(kOpFailRC,errno,"Select failed.");
|
||||
break;
|
||||
|
||||
case 0: // select() timed out
|
||||
break;
|
||||
|
||||
case 1: // (> 0) count of ready descripters
|
||||
if( FD_ISSET(p->sockH,&rdSet) )
|
||||
{
|
||||
socklen_t addrByteCnt = fromAddr==nullptr ? 0 : sizeof(*fromAddr);
|
||||
ssize_t retByteCnt;
|
||||
|
||||
errno = 0;
|
||||
|
||||
// recv the incoming msg into buf[]
|
||||
if(( retByteCnt = recvfrom( p->sockH, buf, bufByteCnt, 0, (struct sockaddr*)fromAddr, &addrByteCnt )) == cwSOCKET_SYS_ERR )
|
||||
rc = cwLogSysError(kOpFailRC,errno,"recvfrom() failed.");
|
||||
else
|
||||
{
|
||||
// check for overflow
|
||||
if( retByteCnt == bufByteCnt )
|
||||
rc = cwLogError(kBufTooSmallRC,"The receive buffer requires more than %i bytes.",bufByteCnt);
|
||||
|
||||
if( recvByteCntRef != nullptr )
|
||||
*recvByteCntRef = retByteCnt;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{ cwAssert(0); }
|
||||
} // switch
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
cw::rc_t cw::net::socket::initAddr( handle_t h, const char* addrStr, portNumber_t portNumber, struct sockaddr_in* retAddrPtr )
|
||||
{
|
||||
socket_t* p = _handleToPtr(h);
|
||||
return _initAddr(p,addrStr,portNumber,retAddrPtr);
|
||||
}
|
||||
|
||||
const char* cw::net::socket::addrToString( const struct sockaddr_in* addr, char* buf, unsigned bufN )
|
||||
{
|
||||
errno = 0;
|
||||
|
||||
if( inet_ntop(AF_INET, &(addr->sin_addr), buf, bufN) == NULL)
|
||||
{
|
||||
cwLogSysError(kOpFailRC,errno, "Network address to string conversion failed." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf[bufN-1]=0;
|
||||
return buf;
|
||||
}
|
||||
|
||||
bool cw::net::socket::addrIsEqual( const struct sockaddr_in* a0, const struct sockaddr_in* a1 )
|
||||
{
|
||||
return a0->sin_family == a1->sin_family
|
||||
&& a0->sin_port == a1->sin_port
|
||||
&& memcmp(&a0->sin_addr,&a1->sin_addr,sizeof(a0->sin_addr))==0;
|
||||
}
|
||||
|
||||
const char* cw::net::socket::hostName( handle_t h )
|
||||
{
|
||||
socket_t* p = _handleToPtr(h);
|
||||
|
||||
errno = 0;
|
||||
|
||||
if( gethostname(p->hnameBuf,HOST_NAME_MAX) != 0 )
|
||||
{
|
||||
cwLogSysError(kOpFailRC,errno, "gethostname() failed." );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
p->hnameBuf[HOST_NAME_MAX] = 0;
|
||||
return p->hnameBuf;
|
||||
}
|
85
cwTcpSocket.h
Normal file
85
cwTcpSocket.h
Normal file
@ -0,0 +1,85 @@
|
||||
#ifndef cwTcpPort_H
|
||||
#define cwTcpPort_H
|
||||
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
namespace socket
|
||||
{
|
||||
typedef handle<struct socket_str> handle_t;
|
||||
|
||||
typedef unsigned short portNumber_t;
|
||||
|
||||
enum
|
||||
{
|
||||
kNonBlockingFl = 0x00, // create a non-blocking socket
|
||||
kBlockingFl = 0x01, // create a blocking socket
|
||||
kTcpFl = 0x02, // create a TCP socket rather than a UDP socket
|
||||
kBroadcastFl = 0x04
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
// port 0 is reserved by and is therefore a convenient invalid port number
|
||||
kInvalidPortNumber = 0
|
||||
};
|
||||
|
||||
|
||||
rc_t create( handle_t& hRef,
|
||||
portNumber_t port,
|
||||
unsigned flags,
|
||||
unsigned timeOutMs = 100, // time out to use with recv() on blocking sockets
|
||||
const char* remoteAddr = NULL,
|
||||
portNumber_t remotePort = socket::kInvalidPortNumber );
|
||||
|
||||
rc_t destroy( handle_t& hRef );
|
||||
|
||||
// Set a destination address for this socket. Once a destination address is set
|
||||
// the caller may use send() to communicate with the specified remote socket
|
||||
// without having to specify a destination address on each call.
|
||||
rc_t connect( handle_t h, const char* remoteAddr, portNumber_t port );
|
||||
|
||||
// Send a message to a remote UDP socket over a previously connected socket
|
||||
rc_t send( handle_t h, const void* data, unsigned dataByteCnt );
|
||||
|
||||
// Send a message to a specific remote node over an unconnected socket.
|
||||
// Use the function initAddr() to setup the 'sockaddr_in';
|
||||
rc_t send( handle_t h, const void* data, unsigned dataByteCnt, const struct sockaddr_in* remoteAddr );
|
||||
rc_t send( handle_t h, const void* data, unsigned dataByteCnt, const char* remoteAddr, portNumber_t port );
|
||||
|
||||
// Receive incoming messages by directly checking the internal
|
||||
// socket for waiting data. This function is used to receive
|
||||
// incoming data when the internal listening thread is not used.
|
||||
// Note that if kBlockingFl was set in create() this call will
|
||||
// block for available data or for 'timeOutMs' milliseconds,
|
||||
// whichever comes first (as set in create()). If
|
||||
// kNonBlockingFl was set in create() then the function will
|
||||
// return immediately if no incoming messages are waiting. If
|
||||
// recvByteCntRef is valid (non-NULL) then it is set to the
|
||||
// length of the received message or 0 if no msg was received.
|
||||
rc_t recieve(handle_t h, char* data, unsigned dataByteCnt, unsigned* recvByteCntRef=nullptr, struct sockaddr_in* fromAddr=nullptr );
|
||||
|
||||
//
|
||||
rc_t select_recieve(handle_t h, char* buf, unsigned bufByteCnt, unsigned timeOutMs, unsigned* recvByteCntRef=nullptr, struct sockaddr_in* fromAddr=nullptr );
|
||||
|
||||
|
||||
// Prepare a struct sockadddr_in for use with send()
|
||||
rc_t initAddr( handle_t h, const char* addrStr, portNumber_t portNumber, struct sockaddr_in* retAddrPtr );
|
||||
|
||||
const char* addrToString( const struct sockaddr_in* addr, char* buf, unsigned bufN=INET_ADDRSTRLEN );
|
||||
|
||||
bool addrIsEqual( const struct sockaddr_in* addr0, const struct sockaddr_in* addr1 );
|
||||
|
||||
const char* hostName( handle_t h );
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
151
cwTcpSocketSrv.cpp
Normal file
151
cwTcpSocketSrv.cpp
Normal file
@ -0,0 +1,151 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwMem.h"
|
||||
#include "cwThread.h"
|
||||
#include "cwTcpSocket.h"
|
||||
#include "cwTcpSocketSrv.h"
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
namespace srv
|
||||
{
|
||||
typedef struct socksrv_str
|
||||
{
|
||||
socket::handle_t sockH;
|
||||
thread::handle_t threadH;
|
||||
cbFunc_t cbFunc;
|
||||
void* cbArg;
|
||||
unsigned timeOutMs;
|
||||
char* recvBuf;
|
||||
unsigned recvBufByteCnt;
|
||||
} socksrv_t;
|
||||
|
||||
inline socksrv_t* _handleToPtr( handle_t h ) { return handleToPtr<handle_t,socksrv_t>(h); }
|
||||
|
||||
rc_t _destroy( socksrv_t* p )
|
||||
{
|
||||
rc_t rc;
|
||||
|
||||
if((rc = thread::destroy(p->threadH)) != kOkRC )
|
||||
return rc;
|
||||
|
||||
if((rc = socket::destroy(p->sockH)) != kOkRC )
|
||||
return rc;
|
||||
|
||||
memRelease(p->recvBuf);
|
||||
memRelease(p);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
bool _threadFunc( void* arg )
|
||||
{
|
||||
socksrv_t* p = static_cast<socksrv_t*>(arg);
|
||||
unsigned rcvByteCnt = 0;
|
||||
struct sockaddr_in fromAddr;
|
||||
|
||||
if( select_recieve(p->sockH, p->recvBuf, p->recvBufByteCnt, p->timeOutMs, &rcvByteCnt, &fromAddr ) == kOkRC )
|
||||
if( rcvByteCnt>0 && p->cbFunc != nullptr )
|
||||
p->cbFunc( p->cbArg, p->recvBuf, rcvByteCnt, &fromAddr );
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::srv::create(
|
||||
handle_t& hRef,
|
||||
socket::portNumber_t port,
|
||||
unsigned flags,
|
||||
cbFunc_t cbFunc,
|
||||
void* cbArg,
|
||||
unsigned recvBufByteCnt,
|
||||
unsigned timeOutMs,
|
||||
const char* remoteAddr,
|
||||
socket::portNumber_t remotePort )
|
||||
{
|
||||
rc_t rc;
|
||||
if((rc = destroy(hRef)) != kOkRC )
|
||||
return rc;
|
||||
|
||||
socksrv_t* p = memAllocZ<socksrv_t>();
|
||||
|
||||
if((rc = socket::create( p->sockH, port, socket::kNonBlockingFl, 0, remoteAddr, remotePort )) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
if((rc = thread::create( p->threadH, _threadFunc, p )) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
p->recvBuf = memAllocZ<char>( recvBufByteCnt );
|
||||
p->recvBufByteCnt = recvBufByteCnt;
|
||||
p->cbFunc = cbFunc;
|
||||
p->cbArg = cbArg;
|
||||
|
||||
errLabel:
|
||||
if( rc == kOkRC )
|
||||
hRef.set(p);
|
||||
else
|
||||
_destroy(p);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::srv::destroy( handle_t& hRef )
|
||||
{
|
||||
rc_t rc = kOkRC;
|
||||
if( !hRef.isValid() )
|
||||
return rc;
|
||||
|
||||
socksrv_t* p = _handleToPtr(hRef);
|
||||
|
||||
if((rc = _destroy(p)) != kOkRC )
|
||||
return rc;
|
||||
|
||||
hRef.clear();
|
||||
return rc;
|
||||
}
|
||||
|
||||
cw::thread::handle_t cw::net::srv::threadHandle( handle_t h )
|
||||
{
|
||||
socksrv_t* p = _handleToPtr(h);
|
||||
return p->threadH;
|
||||
}
|
||||
cw::net::socket::handle_t cw::net::srv::socketHandle( handle_t h )
|
||||
{
|
||||
socksrv_t* p = _handleToPtr(h);
|
||||
return p->sockH;
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::srv::start( handle_t h )
|
||||
{
|
||||
socksrv_t* p = _handleToPtr(h);
|
||||
return thread::pause( p->threadH, thread::kWaitFl );
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::srv::pause( handle_t h )
|
||||
{
|
||||
socksrv_t* p = _handleToPtr(h);
|
||||
return thread::pause( p->threadH, thread::kWaitFl|thread::kPauseFl );
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::srv::send( handle_t h, const void* data, unsigned dataByteCnt )
|
||||
{
|
||||
socksrv_t* p = _handleToPtr(h);
|
||||
return socket::send(p->sockH,data,dataByteCnt);
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::srv::send( handle_t h, const void* data, unsigned dataByteCnt, const struct sockaddr_in* remoteAddr )
|
||||
{
|
||||
socksrv_t* p = _handleToPtr(h);
|
||||
return socket::send(p->sockH,data,dataByteCnt,remoteAddr);
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::srv::send( handle_t h, const void* data, unsigned dataByteCnt, const char* remoteAddr, socket::portNumber_t remotePort )
|
||||
{
|
||||
socksrv_t* p = _handleToPtr(h);
|
||||
return socket::send(p->sockH,data,dataByteCnt,remoteAddr,remotePort);
|
||||
}
|
44
cwTcpSocketSrv.h
Normal file
44
cwTcpSocketSrv.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef cwTcpSocketSrv_H
|
||||
#define cwTcpSocketSrv_H
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
namespace srv
|
||||
{
|
||||
typedef void (*cbFunc_t)( void* cbArg, const char* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr );
|
||||
typedef handle< struct socksrv_str > handle_t;
|
||||
|
||||
rc_t create( handle_t& hRef, //
|
||||
socket::portNumber_t port, // local port number
|
||||
unsigned flags, // see socket::flags
|
||||
cbFunc_t cbFunc, // callback for received messages
|
||||
void* cbArg, // callback arg
|
||||
unsigned recvBufByteCnt = 1024,// recieve buffer size
|
||||
unsigned timeOutMs = 100, // time out to use with recv() on thread select()
|
||||
const char* remoteAddr = NULL,
|
||||
socket::portNumber_t remotePort = socket::kInvalidPortNumber );
|
||||
|
||||
rc_t destroy( handle_t& hRef );
|
||||
|
||||
thread::handle_t threadHandle( handle_t h );
|
||||
socket::handle_t socketHandle( handle_t h );
|
||||
|
||||
rc_t start( handle_t h );
|
||||
rc_t pause( handle_t h );
|
||||
|
||||
|
||||
// Send a message to a remote UDP socket over a previously connected socket
|
||||
rc_t send( handle_t h, const void* data, unsigned dataByteCnt );
|
||||
|
||||
// Send a message to a specific remote node over an unconnected socket.
|
||||
// Use the function initAddr() to setup the 'sockaddr_in';
|
||||
rc_t send( handle_t h, const void* data, unsigned dataByteCnt, const struct sockaddr_in* remoteAddr );
|
||||
rc_t send( handle_t h, const void* data, unsigned dataByteCnt, const char* remoteAddr, socket::portNumber_t port );
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
155
cwTcpSocketTest.cpp
Normal file
155
cwTcpSocketTest.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
#include "cwCommon.h"
|
||||
#include "cwLog.h"
|
||||
#include "cwCommonImpl.h"
|
||||
#include "cwMem.h"
|
||||
|
||||
#include "cwThread.h"
|
||||
|
||||
#include "cwTcpSocket.h"
|
||||
#include "cwTcpSocketSrv.h"
|
||||
#include "cwTcpSocketTest.h"
|
||||
|
||||
|
||||
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
namespace socket
|
||||
{
|
||||
typedef struct app_str
|
||||
{
|
||||
unsigned recvBufByteN;
|
||||
handle_t sockH;
|
||||
thread::handle_t threadH;
|
||||
unsigned cbN;
|
||||
} app_t;
|
||||
|
||||
bool _threadFunc( void* arg )
|
||||
{
|
||||
rc_t rc;
|
||||
app_t* app = static_cast<app_t*>(arg);
|
||||
struct sockaddr_in fromAddr;
|
||||
char addrBuf[ INET_ADDRSTRLEN ];
|
||||
char buf[ app->recvBufByteN ];
|
||||
unsigned recvBufByteN = 0;
|
||||
|
||||
if((rc = recieve( app->sockH, buf, app->recvBufByteN, &recvBufByteN, &fromAddr )) == kOkRC )
|
||||
{
|
||||
addrToString( &fromAddr, addrBuf );
|
||||
printf("%i %s from %s\n", recvBufByteN, buf, addrBuf );
|
||||
}
|
||||
|
||||
app->cbN += 1;
|
||||
if( app->cbN % 10 == 0)
|
||||
{
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::socket::test( portNumber_t localPort, const char* remoteAddr, portNumber_t remotePort )
|
||||
{
|
||||
rc_t rc;
|
||||
unsigned timeOutMs = 100;
|
||||
const unsigned sbufN = 31;
|
||||
char sbuf[ sbufN+1 ];
|
||||
app_t app;
|
||||
|
||||
app.cbN = 0;
|
||||
app.recvBufByteN = sbufN+1;
|
||||
|
||||
if((rc = create(app.sockH,localPort, kBlockingFl,timeOutMs, NULL, kInvalidPortNumber )) != kOkRC )
|
||||
return rc;
|
||||
|
||||
if((rc = thread::create( app.threadH, _threadFunc, &app )) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
if((rc = thread::unpause( app.threadH )) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
while( true )
|
||||
{
|
||||
printf("? ");
|
||||
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
||||
{
|
||||
printf("Sending:%s",sbuf);
|
||||
send(app.sockH, sbuf, strlen(sbuf)+1, remoteAddr, remotePort );
|
||||
|
||||
if( strcmp(sbuf,"quit\n") == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errLabel:
|
||||
rc_t rc0 = thread::destroy(app.threadH);
|
||||
|
||||
rc_t rc1 = destroy(app.sockH);
|
||||
|
||||
return rcSelect(rc,rc0,rc1);
|
||||
}
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
namespace srv
|
||||
{
|
||||
typedef struct app_str
|
||||
{
|
||||
handle_t srvH;
|
||||
unsigned cbN;
|
||||
} app_t;
|
||||
|
||||
void srvRecieveCallback( void* arg, const char* data, unsigned dataByteCnt, const struct sockaddr_in* fromAddr )
|
||||
{
|
||||
app_t* p = static_cast<app_t*>(arg);
|
||||
char addrBuf[ INET_ADDRSTRLEN ];
|
||||
socket::addrToString( fromAddr, addrBuf, INET_ADDRSTRLEN );
|
||||
p->cbN += 1;
|
||||
printf("%i %s %s", p->cbN, addrBuf, data );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cw::rc_t cw::net::srv::test( socket::portNumber_t localPort, const char* remoteAddr, socket::portNumber_t remotePort )
|
||||
{
|
||||
rc_t rc;
|
||||
unsigned recvBufByteCnt = 1024;
|
||||
unsigned timeOutMs = 100;
|
||||
const unsigned sbufN = 31;
|
||||
char sbuf[ sbufN+1 ];
|
||||
app_t app;
|
||||
app.cbN = 0;
|
||||
|
||||
if((rc = srv::create(app.srvH, localPort, socket::kBlockingFl, srvRecieveCallback, &app, recvBufByteCnt, timeOutMs, NULL, socket::kInvalidPortNumber )) != kOkRC )
|
||||
return rc;
|
||||
|
||||
if((rc = srv::start( app.srvH )) != kOkRC )
|
||||
goto errLabel;
|
||||
|
||||
while( true )
|
||||
{
|
||||
printf("? ");
|
||||
if( std::fgets(sbuf,sbufN,stdin) == sbuf )
|
||||
{
|
||||
printf("Sending:%s",sbuf);
|
||||
send(app.srvH, sbuf, strlen(sbuf)+1, remoteAddr, remotePort );
|
||||
|
||||
if( strcmp(sbuf,"quit\n") == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
errLabel:
|
||||
rc_t rc0 = destroy(app.srvH);
|
||||
|
||||
return rcSelect(rc,rc0);
|
||||
}
|
21
cwTcpSocketTest.h
Normal file
21
cwTcpSocketTest.h
Normal file
@ -0,0 +1,21 @@
|
||||
#ifndef cwTcpSocketTest_H
|
||||
#define cwTcpSocketTest_H
|
||||
|
||||
namespace cw
|
||||
{
|
||||
namespace net
|
||||
{
|
||||
namespace socket
|
||||
{
|
||||
rc_t test( portNumber_t localPort, const char* remoteAddr, portNumber_t remotePort );
|
||||
}
|
||||
|
||||
namespace srv
|
||||
{
|
||||
rc_t test( socket::portNumber_t localPort, const char* remoteAddr, socket::portNumber_t remotePort );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
36
main.cpp
36
main.cpp
@ -20,6 +20,9 @@
|
||||
#include "cwAudioDeviceTest.h"
|
||||
#include "cwAudioDeviceAlsa.h"
|
||||
#include "cwAudioBuf.h"
|
||||
#include "cwTcpSocket.h"
|
||||
#include "cwTcpSocketSrv.h"
|
||||
#include "cwTcpSocketTest.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@ -131,6 +134,33 @@ void audioBufTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::
|
||||
void audioDevTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::audio::device::test( argc, argv ); }
|
||||
void audioDevAlsaTest( cw::object_t* cfg, int argc, const char* argv[] ) { cw::audio::device::alsa::report(); }
|
||||
|
||||
void socketTest( cw::object_t* cfg, int argc, const char* argv[] )
|
||||
{
|
||||
if( argc >= 3 )
|
||||
{
|
||||
unsigned short localPort = atoi(argv[1]);
|
||||
unsigned short remotePort = atoi(argv[2]);
|
||||
|
||||
printf("local:%i remote:%i\n", localPort, remotePort);
|
||||
|
||||
cw::net::socket::test( localPort, "127.0.0.1", remotePort );
|
||||
}
|
||||
}
|
||||
|
||||
void socketSrvTest( cw::object_t* cfg, int argc, const char* argv[] )
|
||||
{
|
||||
if( argc >= 3 )
|
||||
{
|
||||
unsigned short localPort = atoi(argv[1]);
|
||||
unsigned short remotePort = atoi(argv[2]);
|
||||
|
||||
printf("local:%i remote:%i\n", localPort, remotePort);
|
||||
|
||||
cw::net::srv::test( localPort, "127.0.0.1", remotePort );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void stubTest( cw::object_t* cfg, int argc, const char* argv[] )
|
||||
{
|
||||
typedef struct v_str
|
||||
@ -170,6 +200,8 @@ int main( int argc, const char* argv[] )
|
||||
{ "audioBuf", audioBufTest },
|
||||
{ "audioDev",audioDevTest },
|
||||
{ "audioDevAlsa", audioDevAlsaTest },
|
||||
{ "socket", socketTest },
|
||||
{ "socketSrv", socketSrvTest },
|
||||
{ "stub", stubTest },
|
||||
{ nullptr, nullptr }
|
||||
};
|
||||
@ -180,7 +212,7 @@ int main( int argc, const char* argv[] )
|
||||
const char* mode = argc > 2 ? argv[2] : nullptr;
|
||||
|
||||
|
||||
cw::logCreateGlobal();
|
||||
cw::log::createGlobal();
|
||||
|
||||
// if valid command line args were given and the cfg file was successfully read
|
||||
if( cfgFn != nullptr && mode != nullptr && objectFromFile( cfgFn, cfg ) == cw::kOkRC )
|
||||
@ -201,7 +233,7 @@ int main( int argc, const char* argv[] )
|
||||
cfg->free();
|
||||
}
|
||||
|
||||
cw::logDestroyGlobal();
|
||||
cw::log::destroyGlobal();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
valgrind --track-origins=yes --leak-check=yes --log-file=vg0.txt ./cw_rt $1 $2 $3
|
||||
valgrind --track-origins=yes --leak-check=yes --log-file=vg0.txt ./cw_rt $1 $2 $3 $4
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user