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
|
HDR += cwAudioBuf.h cwAudioDevice.h cwAudioDeviceAlsa.h
|
||||||
SRC += cwAudioBuf.cpp cwAudioDevice.cpp cwAudioDeviceAlsa.cpp cwAudioDeviceTest.cpp
|
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
|
LIBS = -lpthread -lwebsockets -lasound
|
||||||
|
|
||||||
|
@ -16,4 +16,11 @@
|
|||||||
|
|
||||||
- change cwMpScNbQueue so that it does not require 'new'.
|
- 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 cw
|
||||||
{
|
{
|
||||||
namespace audio
|
namespace audio
|
||||||
@ -94,8 +97,8 @@ namespace cw
|
|||||||
unsigned devCnt;
|
unsigned devCnt;
|
||||||
unsigned meterMs;
|
unsigned meterMs;
|
||||||
|
|
||||||
sample_t* zeroBuf; // buffer of zeros
|
sample_t* zeroBuf; // buffer of zeros
|
||||||
unsigned zeroBufCnt; // max of all dspFrameCnt for all devices.
|
unsigned zeroBufCnt; // max of all dspFrameCnt for all devices.
|
||||||
} cmApBuf;
|
} cmApBuf;
|
||||||
|
|
||||||
cmApBuf _theBuf;
|
cmApBuf _theBuf;
|
||||||
@ -411,8 +414,7 @@ cw::rc_t cw::audio::buf::update(
|
|||||||
// advance the input channel buffer
|
// advance the input channel buffer
|
||||||
cp->ii = n1>0 ? n1 : cp->ii + n0;
|
cp->ii = n1>0 ? n1 : cp->ii + n0;
|
||||||
//cp->fn += pp->audioFramesCnt;
|
//cp->fn += pp->audioFramesCnt;
|
||||||
//cmThUIntIncr(&cp->fn,pp->audioFramesCnt);
|
atomicUIntIncr(&cp->fn,pp->audioFramesCnt);
|
||||||
std::atomic_fetch_add<unsigned>(&cp->fn,pp->audioFramesCnt);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -424,7 +426,7 @@ cw::rc_t cw::audio::buf::update(
|
|||||||
for(i=0; i<outPktCnt; ++i)
|
for(i=0; i<outPktCnt; ++i)
|
||||||
{
|
{
|
||||||
device::audioPacket_t* pp = outPktArray + 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 the base timestamp has not yet been set then set it.
|
||||||
if( op->timeStamp.tv_sec==0 && op->timeStamp.tv_nsec==0 )
|
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 each dest packet channel and enabled source channel
|
||||||
for(j=0; j<pp->chCnt; ++j)
|
for(j=0; j<pp->chCnt; ++j)
|
||||||
{
|
{
|
||||||
cmApCh* cp = op->chArray + pp->begChIdx + j; // dest ch
|
cmApCh* cp = op->chArray + pp->begChIdx + j; // dest ch
|
||||||
unsigned n0 = op->n - cp->oi; // first src segment
|
unsigned n0 = op->n - cp->oi; // first src segment
|
||||||
unsigned n1 = 0; // second src segment
|
unsigned n1 = 0; // second src segment
|
||||||
volatile unsigned fn = cp->fn; // store fn because it may be changed by the client thread
|
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 the outgoing samples will underflow the buffer
|
||||||
if( pp->audioFramesCnt > fn )
|
if( pp->audioFramesCnt > fn )
|
||||||
@ -501,8 +503,7 @@ cw::rc_t cw::audio::buf::update(
|
|||||||
// advance the output channel buffer
|
// advance the output channel buffer
|
||||||
cp->oi = n1>0 ? n1 : cp->oi + n0;
|
cp->oi = n1>0 ? n1 : cp->oi + n0;
|
||||||
//cp->fn -= pp->audioFramesCnt;
|
//cp->fn -= pp->audioFramesCnt;
|
||||||
//cmThUIntDecr(&cp->fn,pp->audioFramesCnt);
|
atomicUIntDecr(&cp->fn,pp->audioFramesCnt);
|
||||||
std::atomic_fetch_sub<unsigned>(&cp->fn,pp->audioFramesCnt);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -750,7 +751,6 @@ void cw::audio::buf::getIO( unsigned iDevIdx, sample_t* iBufArray[], unsigned
|
|||||||
if( oBufArray[i] != NULL )
|
if( oBufArray[i] != NULL )
|
||||||
memset( oBufArray[i], 0, byteCnt );
|
memset( oBufArray[i], 0, byteCnt );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cw::audio::buf::advance( unsigned devIdx, unsigned flags )
|
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;
|
cmApCh* cp = ioPtr->chArray + i;
|
||||||
cp->oi = (cp->oi + ioPtr->dspFrameCnt) % ioPtr->n;
|
cp->oi = (cp->oi + ioPtr->dspFrameCnt) % ioPtr->n;
|
||||||
//cmThUIntDecr(&cp->fn,ioPtr->dspFrameCnt);
|
atomicUIntDecr(&cp->fn,ioPtr->dspFrameCnt);
|
||||||
std::atomic_fetch_sub<unsigned>(&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
|
// count the number of samples input from this device
|
||||||
if( ioPtr->timeStamp.tv_sec!=0 && ioPtr->timeStamp.tv_nsec!=0 )
|
if( ioPtr->timeStamp.tv_sec!=0 && ioPtr->timeStamp.tv_nsec!=0 )
|
||||||
{
|
{
|
||||||
//cmThUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
atomicUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
||||||
std::atomic_fetch_add<unsigned>(&ioPtr->ioFrameCnt, ioPtr->dspFrameCnt);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -789,17 +787,14 @@ void cw::audio::buf::advance( unsigned devIdx, unsigned flags )
|
|||||||
{
|
{
|
||||||
cmApCh* cp = ioPtr->chArray + i;
|
cmApCh* cp = ioPtr->chArray + i;
|
||||||
cp->ii = (cp->ii + ioPtr->dspFrameCnt) % ioPtr->n;
|
cp->ii = (cp->ii + ioPtr->dspFrameCnt) % ioPtr->n;
|
||||||
//cmThUIntIncr(&cp->fn,ioPtr->dspFrameCnt);
|
atomicUIntIncr(&cp->fn,ioPtr->dspFrameCnt);
|
||||||
std::atomic_fetch_add<unsigned>(&cp->fn,ioPtr->dspFrameCnt);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// count the number of samples output from this device
|
// count the number of samples output from this device
|
||||||
if( ioPtr->timeStamp.tv_sec!=0 && ioPtr->timeStamp.tv_nsec!=0 )
|
if( ioPtr->timeStamp.tv_sec!=0 && ioPtr->timeStamp.tv_nsec!=0 )
|
||||||
{
|
{
|
||||||
//cmThUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
atomicUIntIncr(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
||||||
std::atomic_fetch_add<unsigned>(&ioPtr->ioFrameCnt,ioPtr->dspFrameCnt);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -865,17 +860,20 @@ void cw::audio::buf::report()
|
|||||||
unsigned ii = 0;
|
unsigned ii = 0;
|
||||||
unsigned oi = 0;
|
unsigned oi = 0;
|
||||||
unsigned fn = 0;
|
unsigned fn = 0;
|
||||||
|
sample_t m = 0;
|
||||||
for(k=0; k<ip->chCnt; ++k)
|
for(k=0; k<ip->chCnt; ++k)
|
||||||
{
|
{
|
||||||
cmApCh* cp = ip->chArray + i;
|
cmApCh* cp = ip->chArray + i;
|
||||||
ii += cp->ii;
|
ii += cp->ii;
|
||||||
oi += cp->oi;
|
oi += cp->oi;
|
||||||
fn += cp->fn;
|
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",
|
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.
|
// samples in a thread-safe manner.
|
||||||
//
|
//
|
||||||
// Usage example and testing code:
|
// Usage example and testing code:
|
||||||
// See cmApBufTest() and cmAudioSysTest().
|
// See audio::device::test()
|
||||||
// \snippet cmApBuf.c cmApBufExample
|
// \snippet cwAudioBuf.c cwAudioBufExample
|
||||||
//
|
//
|
||||||
// Notes on channel flags:
|
// Notes on channel flags:
|
||||||
// Disabled channels: kChFl is cleared
|
// Disabled channels: kChFl is cleared
|
||||||
// cmApBufGet()
|
// get()
|
||||||
// in - return NULL buffer pointers
|
// in - return NULL buffer pointers
|
||||||
// out - return NULL buffer points
|
// out - return NULL buffer points
|
||||||
//
|
//
|
||||||
// cmApBufUpdate()
|
// update()
|
||||||
// in - incoming samples are set to 0.
|
// in - incoming samples are set to 0.
|
||||||
// out - outgoing samples are set to 0.
|
// out - outgoing samples are set to 0.
|
||||||
//
|
//
|
||||||
// Muted channels: kMuteFl is set
|
// Muted channels: kMuteFl is set
|
||||||
// cmApBufUpdate()
|
// update()
|
||||||
// in - incoming samples are set to 0.
|
// in - incoming samples are set to 0.
|
||||||
// out - outgoing samples are set to 0.
|
// out - outgoing samples are set to 0.
|
||||||
//
|
//
|
||||||
// Tone channels: kToneFl is set
|
// Tone channels: kToneFl is set
|
||||||
// cmApBufUpdate()
|
// update()
|
||||||
// in - incoming samples are filled with a 1k sine tone
|
// in - incoming samples are filled with a 1k sine tone
|
||||||
// out - outgoing 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
|
// 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
|
// 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
|
// This function is thread-safe under the condition where the audio device uses
|
||||||
// different threads for input and output.
|
// 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
|
#ifndef cwAudioDevice_H
|
||||||
#define 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
|
// 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 same as the application thread.
|
||||||
// The usual thread safety precautions should therefore be taken if this function implementation
|
// 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
|
// is designed to provide a safe and efficient way to communicate between
|
||||||
// the audio thread and the application.
|
// the audio thread and the application.
|
||||||
typedef void (*cbFunc_t)( audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt );
|
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 );
|
unsigned deviceChannelCount( handle_t h, unsigned devIdx, bool inputFl );
|
||||||
double deviceSampleRate( handle_t h, unsigned devIdx );
|
double deviceSampleRate( handle_t h, unsigned devIdx );
|
||||||
unsigned deviceFramesPerCycle( handle_t h, unsigned devIdx, bool inputFl );
|
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 deviceStart( handle_t h, unsigned devIdx );
|
||||||
rc_t deviceStop( handle_t h, unsigned devIdx );
|
rc_t deviceStop( handle_t h, unsigned devIdx );
|
||||||
bool deviceIsStarted( handle_t h, unsigned devIdx );
|
bool deviceIsStarted( handle_t h, unsigned devIdx );
|
||||||
|
@ -110,7 +110,7 @@ namespace cw
|
|||||||
|
|
||||||
if( alsaRC == 0 )
|
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
|
else
|
||||||
{
|
{
|
||||||
@ -129,7 +129,7 @@ namespace cw
|
|||||||
char msg1[n+1];
|
char msg1[n+1];
|
||||||
m = snprintf(msg1,n+1,fmt1,msg0,snd_strerror(alsaRC));
|
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);
|
va_end(vl0);
|
||||||
@ -367,6 +367,7 @@ namespace cw
|
|||||||
int cnt = 0;
|
int cnt = 0;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if((err = snd_pcm_open(pcmHPtr,devNameStr,inputFl ? SND_PCM_STREAM_CAPTURE : SND_PCM_STREAM_PLAYBACK,0)) < 0 )
|
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;
|
// Returns count of frames written on success or < 0 on error;
|
||||||
// set smpPtr to NULL to write a buffer of silence
|
// 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 _devWriteBuf( devRecd_t* drp, snd_pcm_t* pcmH, const device::sample_t* sp, unsigned chCnt, unsigned frmCnt, unsigned bits, unsigned sigBits )
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
|
unsigned bytesPerSmp = (bits==24 ? 32 : bits)/8;
|
||||||
unsigned smpCnt = chCnt * frmCnt;
|
unsigned smpCnt = chCnt * frmCnt;
|
||||||
unsigned byteCnt = bytesPerSmp * smpCnt;
|
unsigned byteCnt = bytesPerSmp * smpCnt;
|
||||||
const device::sample_t* ep = sp + 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 no output was given then fill the device buffer with zeros
|
||||||
if( sp == NULL )
|
if( sp == NULL )
|
||||||
memset(obuf,0,byteCnt);
|
memset(obuf,0,byteCnt);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// otherwise convert the floating point samples to integers
|
// otherwise convert the floating point samples to integers
|
||||||
switch( bits )
|
switch( bits )
|
||||||
{
|
{
|
||||||
@ -575,13 +601,21 @@ namespace cw
|
|||||||
int* dp = (int*)obuf;
|
int* dp = (int*)obuf;
|
||||||
|
|
||||||
while( sp < ep )
|
while( sp < ep )
|
||||||
*dp++ = (int)(*sp++ * 0x7fffffff);
|
*dp++ = (int)(*sp++ * 0x7fffffff);
|
||||||
|
//*dp++ = (rand() - (RAND_MAX/2)) * 2;
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NNN+=1;
|
||||||
|
if( NNN % 100 == 0)
|
||||||
|
{
|
||||||
|
_rms(drp->nameStr,rms,(const int*)obuf,smpCnt);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
// send the bytes to the device
|
// send the bytes to the device
|
||||||
err = snd_pcm_writei( pcmH, obuf, frmCnt );
|
err = snd_pcm_writei( pcmH, obuf, frmCnt );
|
||||||
@ -734,7 +768,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
// callback to fill the buffer
|
// callback to fill the buffer
|
||||||
drp->cbFunc(NULL,0,&pkt,1);
|
drp->cbFunc(NULL,0,&pkt,1);
|
||||||
|
|
||||||
// note that the application may return fewer samples than were requested
|
// 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);
|
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 bufCnt; // 2=double buffering 3=triple buffering
|
||||||
unsigned chIdx; // first test channel
|
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 framesPerCycle; // DSP frames per cycle
|
||||||
unsigned bufFrmCnt; // count of DSP frames used by the audio buffer (bufCnt * framesPerCycle)
|
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)
|
unsigned bufSmpCnt; // count of samples used by the audio buffer (chCnt * bufFrmCnt)
|
||||||
@ -51,7 +51,8 @@ namespace cw
|
|||||||
unsigned* ilog; // ilog[logCnt]
|
unsigned* ilog; // ilog[logCnt]
|
||||||
unsigned logIdx; // current log index
|
unsigned logIdx; // current log index
|
||||||
|
|
||||||
unsigned cbCnt; // count the callback
|
unsigned iCbCnt; // count the callback
|
||||||
|
unsigned oCbCnt;
|
||||||
} cmApPortTestRecd;
|
} cmApPortTestRecd;
|
||||||
|
|
||||||
|
|
||||||
@ -215,7 +216,7 @@ namespace cw
|
|||||||
// copy the incoming audio into an internal buffer where it can be picked up by _cpApCopyOut().
|
// 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 );
|
_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);
|
//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);
|
//printf("o %4i in:%4i out:%4i\n",r->bufFullCnt,r->bufInIdx,r->bufOutIdx);
|
||||||
// count callbacks
|
// count callbacks
|
||||||
++r->cbCnt;
|
++r->oCbCnt;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -304,10 +305,10 @@ namespace cw
|
|||||||
void _cmApPortCb2( audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt )
|
void _cmApPortCb2( audioPacket_t* inPktArray, unsigned inPktCnt, audioPacket_t* outPktArray, unsigned outPktCnt )
|
||||||
{
|
{
|
||||||
for(unsigned i=0; i<inPktCnt; ++i)
|
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)
|
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 );
|
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;
|
runFl = _cmApGetOpt(argc,argv,"-p",0,true)?false:true;
|
||||||
r.srate = _cmApGetOpt(argc,argv,"-r",44100);
|
r.srate = _cmApGetOpt(argc,argv,"-r",44100);
|
||||||
r.chIdx = _cmApGetOpt(argc,argv,"-a",0);
|
//r.chIdx = _cmApGetOpt(argc,argv,"-a",0);
|
||||||
r.chCnt = _cmApGetOpt(argc,argv,"-c",2);
|
//r.chCnt = _cmApGetOpt(argc,argv,"-c",2);
|
||||||
r.bufCnt = _cmApGetOpt(argc,argv,"-b",3);
|
r.bufCnt = _cmApGetOpt(argc,argv,"-b",3);
|
||||||
r.framesPerCycle = _cmApGetOpt(argc,argv,"-f",512);
|
r.framesPerCycle = _cmApGetOpt(argc,argv,"-f",512);
|
||||||
r.bufFrmCnt = (r.bufCnt*r.framesPerCycle);
|
//r.bufFrmCnt = (r.bufCnt*r.framesPerCycle);
|
||||||
r.bufSmpCnt = (r.chCnt * r.bufFrmCnt);
|
//r.bufSmpCnt = (r.chCnt * r.bufFrmCnt);
|
||||||
r.logCnt = 100;
|
r.logCnt = 100;
|
||||||
r.meterMs = 50;
|
r.meterMs = 50;
|
||||||
|
|
||||||
@ -348,7 +349,7 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
|||||||
unsigned ilog[r.logCnt];
|
unsigned ilog[r.logCnt];
|
||||||
|
|
||||||
r.inDevIdx = _cmGlobalInDevIdx = _cmApGetOpt(argc,argv,"-i",0);
|
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.phase = 0;
|
||||||
r.frqHz = 2000;
|
r.frqHz = 2000;
|
||||||
r.bufInIdx = 0;
|
r.bufInIdx = 0;
|
||||||
@ -359,9 +360,10 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
|||||||
r.buf = buf;
|
r.buf = buf;
|
||||||
r.log = log;
|
r.log = log;
|
||||||
r.ilog = ilog;
|
r.ilog = ilog;
|
||||||
r.cbCnt = 0;
|
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);
|
|
||||||
|
//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
|
// 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
|
// report the current audio device configuration
|
||||||
for(i=0; i<deviceCount(h); ++i)
|
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 the current audio devices using the audio port interface function
|
||||||
report(h);
|
//report(h);
|
||||||
|
|
||||||
if( runFl )
|
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 );
|
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
|
// 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 );
|
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
|
// setup an output device
|
||||||
@ -425,7 +427,11 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
|||||||
cwLogInfo("Setup complete!");
|
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;
|
char c;
|
||||||
while((c=getchar()) != 'q')
|
while((c=getchar()) != 'q')
|
||||||
{
|
{
|
||||||
@ -447,6 +453,12 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
|||||||
case 'P':
|
case 'P':
|
||||||
buf::enablePass(r.outDevIdx,-1,buf::kOutFl | (c=='P'?buf::kEnableFl:0));
|
buf::enablePass(r.outDevIdx,-1,buf::kOutFl | (c=='P'?buf::kEnableFl:0));
|
||||||
break;
|
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':
|
case 's':
|
||||||
buf::report();
|
buf::report();
|
||||||
@ -480,7 +492,7 @@ cw::rc_t cw::audio::device::test( int argc, const char** argv )
|
|||||||
//cmApFileFree();
|
//cmApFileFree();
|
||||||
|
|
||||||
// report the count of audio buffer callbacks
|
// 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);
|
return rcSelect(rc,rc0,rc1,rc2);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
|
|
||||||
#if defined(cwLINUX) || defined(cwOSX)
|
#if defined(cwLINUX) || defined(cwOSX)
|
||||||
#define cwPOSIX_FILE_SYS
|
#define cwPOSIX_FILE_SYS
|
||||||
#include <time.h> // linux time.h
|
#include <time.h> // timespec
|
||||||
|
#include <netinet/in.h> // struct sockaddr_in
|
||||||
#define cwPathSeparatorChar '/'
|
#define cwPathSeparatorChar '/'
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
192
cwLex.h
192
cwLex.h
@ -6,131 +6,131 @@
|
|||||||
|
|
||||||
namespace cw
|
namespace cw
|
||||||
{
|
{
|
||||||
|
namespace lex
|
||||||
// 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().
|
// Predefined Lexer Id's
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kReturnSpaceLexFl = 0x01, //< Return space tokens
|
kErrorLexTId, // 0 the lexer was unable to identify the current token
|
||||||
kReturnCommentsLexFl = 0x02, //< Return comment tokens
|
kUnknownLexTId, // 1 the token is of an unknown type (only used when kReturnUnknownLexFl is set)
|
||||||
kReturnUnknownLexFl = 0x04, //< Return unknown tokens
|
kEofLexTId, // 2 the lexer reached the end of input
|
||||||
kReturnQCharLexFl = 0x08, //< Return quoted characters
|
kSpaceLexTId, // 3 white space
|
||||||
kUserDefPriorityLexFl= 0x10 //< User defined tokens take priority even if a kIdentLexTId token has a longer match
|
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;
|
typedef handle<struct lex_str> handle_t;
|
||||||
extern lexH_t lexNullHandle;
|
|
||||||
|
|
||||||
// Iniitalize the lexer and receive a lexer handle in return.
|
// Iniitalize the lexer and receive a lexer handle in return.
|
||||||
// Set cp to nullptr if the buffer will be later via lexSetTextBuffer();
|
// Set cp to nullptr if the buffer will be later via lexSetTextBuffer();
|
||||||
// See the kXXXLexFl enum's above for possible flag values.
|
// See the kXXXLexFl enum's above for possible flag values.
|
||||||
rc_t lexCreate( lexH_t& hRef, const char* cp, unsigned cn, unsigned flags );
|
rc_t create( handle_t& hRef, const char* cp, unsigned cn, unsigned flags );
|
||||||
|
|
||||||
// Finalize a lexer created by an earlier call to lexInit()
|
// Finalize a lexer created by an earlier call to lexInit()
|
||||||
rc_t lexDestroy( lexH_t& hRef );
|
rc_t destroy( handle_t& hRef );
|
||||||
|
|
||||||
// Rewind the lexer to the begining of the buffer (the same as post initialize state)
|
// Rewind the lexer to the begining of the buffer (the same as post initialize state)
|
||||||
rc_t lexReset( lexH_t h );
|
rc_t reset( handle_t h );
|
||||||
|
|
||||||
// Verify that a lexer handle is valid
|
// Verify that a lexer handle is valid
|
||||||
bool lexIsValid( lexH_t h );
|
bool isValid( handle_t h );
|
||||||
|
|
||||||
// Set a new text buffer and reset the lexer to the post initialize state.
|
// 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 setTextBuffer( handle_t h, const char* cp, unsigned cn );
|
||||||
rc_t lexSetFile( lexH_t h, const char* fn );
|
rc_t setFile( handle_t h, const char* fn );
|
||||||
|
|
||||||
// Register a user defined token. The id of the first user defined token should be
|
// 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
|
// kUserLexTId+1. Neither the id or token text can be used by a previously registered
|
||||||
// or built-in token.
|
// or built-in token.
|
||||||
rc_t lexRegisterToken( lexH_t h, unsigned id, const char* 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
|
// 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.
|
// of initial, consecutive, characters in 'cp[cn]' which match its token pattern.
|
||||||
typedef unsigned (*lexUserMatcherPtr_t)( const char* cp, unsigned cn );
|
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.
|
// Enable or disable the specified token type.
|
||||||
rc_t lexEnableToken( lexH_t h, unsigned id, bool enableFl );
|
rc_t enableToken( handle_t h, unsigned id, bool enableFl );
|
||||||
|
|
||||||
// Get and set the lexer filter flags kReturnXXXLexFl.
|
// Get and set the lexer filter flags kReturnXXXLexFl.
|
||||||
// These flags can be safely enabled and disabled between
|
// These flags can be safely enabled and disabled between
|
||||||
// calls to lexGetNextToken().
|
// calls to lexGetNextToken().
|
||||||
unsigned lexFilterFlags( lexH_t h );
|
unsigned filterFlags( handle_t h );
|
||||||
void lexSetFilterFlags( lexH_t h, unsigned flags );
|
void setFilterFlags( handle_t h, unsigned flags );
|
||||||
|
|
||||||
// Return the type id of the current token and advances to the next token
|
// Return the type id of the current token and advances to the next token
|
||||||
unsigned lexGetNextToken( lexH_t h );
|
unsigned getNextToken( handle_t h );
|
||||||
|
|
||||||
// Return the type id associated with the current token. This is the same value
|
// Return the type id associated with the current token. This is the same value
|
||||||
// returned by the previous call to lexGetNextToken().
|
// returned by the previous call to lexGetNextToken().
|
||||||
unsigned lexTokenId( lexH_t h );
|
unsigned tokenId( handle_t h );
|
||||||
|
|
||||||
// Return a pointer to the first character of text associated with the
|
// Return a pointer to the first character of text associated with the
|
||||||
// current token. The returned pointer directly references the text contained
|
// current token. The returned pointer directly references the text contained
|
||||||
// in the buffer given to the lexer in the call to lexInit(). The string
|
// in the buffer given to the lexer in the call to lexInit(). The string
|
||||||
// is therefore not zero terminated. Use lexTokenCharCount() to get the
|
// is therefore not zero terminated. Use lexTokenCharCount() to get the
|
||||||
// length of the token string.
|
// length of the token string.
|
||||||
const char* lexTokenText( lexH_t h );
|
const char* tokenText( handle_t h );
|
||||||
|
|
||||||
// Return the count of characters in the text associated with the current token.
|
// 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
|
// This is the only way to get this count since the string returned by
|
||||||
// lexTokenText() is not zero terminated.
|
// lexTokenText() is not zero terminated.
|
||||||
unsigned lexTokenCharCount( lexH_t h );
|
unsigned tokenCharCount( handle_t h );
|
||||||
|
|
||||||
// Return the value of the current token as an integer.
|
// Return the value of the current token as an integer.
|
||||||
int lexTokenInt( lexH_t h );
|
int tokenInt( handle_t h );
|
||||||
|
|
||||||
// Return the value of the current token as an unsigned integer.
|
// Return the value of the current token as an unsigned integer.
|
||||||
unsigned lexTokenUInt( lexH_t h );
|
unsigned tokenUInt( handle_t h );
|
||||||
|
|
||||||
// Return the value of the current token as a float.
|
// Return the value of the current token as a float.
|
||||||
float lexTokenFloat( lexH_t h );
|
float tokenFloat( handle_t h );
|
||||||
|
|
||||||
// Return the value of the current token as a double.
|
// Return the value of the current token as a double.
|
||||||
double lexTokenDouble( lexH_t h );
|
double tokenDouble( handle_t h );
|
||||||
|
|
||||||
// Return true if the current token is an int and it was suffixed
|
// Return true if the current token is an int and it was suffixed
|
||||||
// with 'u' to indicate that it is unsigned.
|
// with 'u' to indicate that it is unsigned.
|
||||||
bool lexTokenIsUnsigned( lexH_t h );
|
bool tokenIsUnsigned( handle_t h );
|
||||||
|
|
||||||
// Return true if the current token is a real and it was suffexed
|
// Return true if the current token is a real and it was suffexed
|
||||||
// with 'f' to indicate that it is a single precision float.
|
// with 'f' to indicate that it is a single precision float.
|
||||||
bool lexTokenIsSinglePrecision( lexH_t h );
|
bool tokenIsSinglePrecision( handle_t h );
|
||||||
|
|
||||||
// Return the line number associated with the current token
|
// Return the line number associated with the current token
|
||||||
unsigned lexCurrentLineNumber( lexH_t h );
|
unsigned currentLineNumber( handle_t h );
|
||||||
|
|
||||||
// Return the starting column of the current token
|
// Return the starting column of the current token
|
||||||
unsigned lexCurrentColumnNumber( lexH_t h );
|
unsigned currentColumnNumber( handle_t h );
|
||||||
|
|
||||||
// Return the RC code associated with the last error
|
// Return the RC code associated with the last error
|
||||||
unsigned lexErrorRC( lexH_t h );
|
unsigned errorRC( handle_t h );
|
||||||
|
|
||||||
// Return the label associated with a token id
|
// Return the label associated with a token id
|
||||||
const char* lexIdToLabel( lexH_t h, unsigned typeId );
|
const char* idToLabel( handle_t h, unsigned typeId );
|
||||||
|
|
||||||
// Lexer testing stub.
|
|
||||||
void lexTest( );
|
|
||||||
|
|
||||||
|
// Lexer testing stub.
|
||||||
|
void test( );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//)
|
//)
|
||||||
|
99
cwLog.cpp
99
cwLog.cpp
@ -6,46 +6,47 @@
|
|||||||
|
|
||||||
namespace cw
|
namespace cw
|
||||||
{
|
{
|
||||||
|
namespace log
|
||||||
typedef struct log_str
|
|
||||||
{
|
{
|
||||||
logOutputCbFunc_t outCbFunc;
|
typedef struct log_str
|
||||||
void* outCbArg;
|
{
|
||||||
logFormatCbFunc_t fmtCbFunc;
|
logOutputCbFunc_t outCbFunc;
|
||||||
void* fmtCbArg;
|
void* outCbArg;
|
||||||
unsigned level;
|
logFormatCbFunc_t fmtCbFunc;
|
||||||
} log_t;
|
void* fmtCbArg;
|
||||||
|
unsigned level;
|
||||||
|
} log_t;
|
||||||
|
|
||||||
|
|
||||||
logHandle_t __logGlobalHandle__;
|
handle_t __logGlobalHandle__;
|
||||||
logHandle_t logNullHandle;
|
|
||||||
|
idLabelPair_t logLevelLabelArray[] =
|
||||||
#define logHandleToPtr(h) handleToPtr<logHandle_t,log_t>(h)
|
{
|
||||||
|
{ kDebug_LogLevel, "debug" },
|
||||||
idLabelPair_t logLevelLabelArray[] =
|
{ kInfo_LogLevel, "info" },
|
||||||
{
|
{ kWarning_LogLevel, "warning" },
|
||||||
{ kDebug_LogLevel, "debug" },
|
{ kError_LogLevel, "error" },
|
||||||
{ kInfo_LogLevel, "info" },
|
{ kFatal_LogLevel, "fatal" },
|
||||||
{ kWarning_LogLevel, "warning" },
|
{ kInvalid_LogLevel, "<invalid>" }
|
||||||
{ 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;
|
rc_t rc;
|
||||||
if((rc = logDestroy(hRef)) != kOkRC)
|
if((rc = destroy(hRef)) != kOkRC)
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
log_t* p = memAllocZ<log_t>();
|
log_t* p = memAllocZ<log_t>();
|
||||||
p->outCbFunc = outCbFunc == nullptr ? logDefaultOutput : outCbFunc;
|
p->outCbFunc = outCbFunc == nullptr ? defaultOutput : outCbFunc;
|
||||||
p->outCbArg = outCbArg;
|
p->outCbArg = outCbArg;
|
||||||
p->fmtCbFunc = fmtCbFunc == nullptr ? logDefaultFormatter : fmtCbFunc;
|
p->fmtCbFunc = fmtCbFunc == nullptr ? defaultFormatter : fmtCbFunc;
|
||||||
p->fmtCbArg = fmtCbArg;
|
p->fmtCbArg = fmtCbArg;
|
||||||
p->level = level;
|
p->level = level;
|
||||||
hRef.p = p;
|
hRef.p = p;
|
||||||
@ -53,7 +54,7 @@ cw::rc_t cw::logCreate( logHandle_t& hRef, unsigned level, logOutputCbFunc_t ou
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::rc_t cw::logDestroy( logHandle_t& hRef )
|
cw::rc_t cw::log::destroy( handle_t& hRef )
|
||||||
{
|
{
|
||||||
rc_t rc = kOkRC;
|
rc_t rc = kOkRC;
|
||||||
|
|
||||||
@ -64,9 +65,9 @@ cw::rc_t cw::logDestroy( logHandle_t& hRef )
|
|||||||
return rc;
|
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_list vl1;
|
||||||
va_copy(vl1,vl);
|
va_copy(vl1,vl);
|
||||||
@ -88,30 +89,30 @@ cw::rc_t cw::logMsg( logHandle_t h, unsigned level, const char* function, const
|
|||||||
return rc;
|
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;
|
rc_t rc;
|
||||||
va_list vl;
|
va_list vl;
|
||||||
va_start(vl,fmt);
|
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);
|
va_end(vl);
|
||||||
return rc;
|
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;
|
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;
|
return p->level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const char* cw::logLevelToLabel( unsigned level )
|
const char* cw::log::levelToLabel( unsigned level )
|
||||||
{
|
{
|
||||||
const char* label;
|
const char* label;
|
||||||
if((label = idToLabel(logLevelLabelArray,level,kInvalid_LogLevel)) == nullptr)
|
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;
|
FILE* f = level >= kWarning_LogLevel ? stderr : stdout;
|
||||||
fprintf(f,"%s",text);
|
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.
|
// 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* systemLabel = sys_errno==0 ? "" : "System Error: ";
|
||||||
const char* systemMsg = sys_errno==0 ? "" : strerror(sys_errno);
|
const char* systemMsg = sys_errno==0 ? "" : strerror(sys_errno);
|
||||||
const char* levelStr = logLevelToLabel(level);
|
const char* levelStr = levelToLabel(level);
|
||||||
|
|
||||||
const char* rcFmt = "rc:%i";
|
const char* rcFmt = "rc:%i";
|
||||||
int rcn = snprintf(nullptr,0,rcFmt,rc);
|
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);
|
int m = snprintf(s,n+1,fmt,levelStr,msg,syStr,rcStr,loStr);
|
||||||
cwAssert(m==n);
|
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;
|
rc_t rc;
|
||||||
|
|
||||||
if((rc = logCreate(h, level, outCb, outCbArg, fmtCb, fmtCbArg )) == kOkRC )
|
if((rc = create(h, level, outCb, outCbArg, fmtCb, fmtCbArg )) == kOkRC )
|
||||||
logSetGlobalHandle(h);
|
setGlobalHandle(h);
|
||||||
|
|
||||||
return rc;
|
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;
|
__logGlobalHandle__ = h;
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::logHandle_t cw::logGlobalHandle()
|
cw::log::handle_t cw::log::globalHandle()
|
||||||
{
|
{
|
||||||
return __logGlobalHandle__;
|
return __logGlobalHandle__;
|
||||||
}
|
}
|
||||||
|
109
cwLog.h
109
cwLog.h
@ -4,73 +4,74 @@
|
|||||||
namespace cw
|
namespace cw
|
||||||
{
|
{
|
||||||
|
|
||||||
typedef enum
|
namespace log
|
||||||
{
|
{
|
||||||
kInvalid_LogLevel,
|
typedef enum
|
||||||
kDebug_LogLevel,
|
{
|
||||||
kInfo_LogLevel,
|
kInvalid_LogLevel,
|
||||||
kWarning_LogLevel,
|
kDebug_LogLevel,
|
||||||
kError_LogLevel,
|
kInfo_LogLevel,
|
||||||
kFatal_LogLevel,
|
kWarning_LogLevel,
|
||||||
} logLevelId_t;
|
kError_LogLevel,
|
||||||
|
kFatal_LogLevel,
|
||||||
|
} logLevelId_t;
|
||||||
|
|
||||||
typedef handle<struct log_str> logHandle_t;
|
typedef handle<struct log_str> handle_t;
|
||||||
|
|
||||||
extern logHandle_t logNullHandle;
|
|
||||||
|
|
||||||
typedef void (*logOutputCbFunc_t)( void* cbArg, unsigned level, const char* text );
|
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 (*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 create( handle_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 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 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 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, ... );
|
||||||
|
|
||||||
void logSetLevel( logHandle_t h, unsigned level );
|
void setLevel( handle_t h, unsigned level );
|
||||||
unsigned logLevel( logHandle_t h );
|
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 defaultOutput( 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 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 createGlobal( unsigned level=kDebug_LogLevel, logOutputCbFunc_t outCb=nullptr, void* outCbArg=nullptr, logFormatCbFunc_t fmtCb=nullptr, void* fmtCbArg=nullptr );
|
||||||
rc_t logDestroyGlobal( );
|
rc_t destroyGlobal( );
|
||||||
|
|
||||||
void logSetGlobalHandle( logHandle_t h );
|
void setGlobalHandle( handle_t h );
|
||||||
logHandle_t logGlobalHandle();
|
handle_t globalHandle();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define cwLogVDebugH(h,rc,fmt, vl) cw::logMsg( h, cw::kDebug_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, vl )
|
#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::logMsg( h, cw::kDebug_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
#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 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::logMsg( h, cw::kInfo_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, cw::kOkRC, fmt, ##__VA_ARGS__ )
|
#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 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::logMsg( h, cw::kWarning_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
#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 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::logMsg( h, cw::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
#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 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::logMsg( h, cw::kError_LogLevel, __FUNCTION__, __FILE__, __LINE__, sysRc, rc, fmt, ##__VA_ARGS__ )
|
#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 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::logMsg( h, cw::kFatal_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
#define cwLogFatalH( h,rc,fmt,...) cw::log::msg( h, cw::log::kFatal_LogLevel, __FUNCTION__, __FILE__, __LINE__, 0, rc, fmt, ##__VA_ARGS__ )
|
||||||
|
|
||||||
#ifdef cwLOG_DEBUG
|
#ifdef cwLOG_DEBUG
|
||||||
|
|
||||||
#define cwLogVDebugRC(rc,fmt, vl) cwLogVDebugH( cw::logGlobalHandle(), (rc), (fmt), (vl) )
|
#define cwLogVDebugRC(rc,fmt, vl) cwLogVDebugH( cw::log::globalhandle(), (rc), (fmt), (vl) )
|
||||||
#define cwLogDebugRC( rc,fmt,...) cwLogDebugH( cw::logGlobalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
#define cwLogDebugRC( rc,fmt,...) cwLogDebugH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||||
|
|
||||||
#define cwLogVDebug(fmt, vl) cwLogVDebugH( cw::logGlobalHandle(), cw::kOkRC, (fmt), (vl) )
|
#define cwLogVDebug(fmt, vl) cwLogVDebugH( cw::log::globalHandle(), cw::kOkRC, (fmt), (vl) )
|
||||||
#define cwLogDebug( fmt,...) cwLogDebugH( cw::logGlobalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ )
|
#define cwLogDebug( fmt,...) cwLogDebugH( cw::log::globalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ )
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
@ -83,23 +84,23 @@ namespace cw
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#define cwLogVInfo(fmt, vl) cwLogVInfoH( cw::logGlobalHandle(), (fmt), (vl) )
|
#define cwLogVInfo(fmt, vl) cwLogVInfoH( cw::log::globalHandle(), (fmt), (vl) )
|
||||||
#define cwLogInfo( fmt,...) cwLogInfoH( cw::logGlobalHandle(), (fmt), ##__VA_ARGS__ )
|
#define cwLogInfo( fmt,...) cwLogInfoH( cw::log::globalHandle(), (fmt), ##__VA_ARGS__ )
|
||||||
|
|
||||||
#define cwLogVWarningRC(rc,fmt, vl) cwLogVWarningH( cw::logGlobalHandle(), (rc), (fmt), (vl) )
|
#define cwLogVWarningRC(rc,fmt, vl) cwLogVWarningH( cw::log::globalHandle(), (rc), (fmt), (vl) )
|
||||||
#define cwLogWarningRC( rc,fmt,...) cwLogWarningH( cw::logGlobalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
#define cwLogWarningRC( rc,fmt,...) cwLogWarningH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||||
|
|
||||||
#define cwLogVWarning(fmt, vl) cwLogVWarningH( cw::logGlobalHandle(), cw::kOkRC, (fmt), (vl) )
|
#define cwLogVWarning(fmt, vl) cwLogVWarningH( cw::log::globalHandle(), cw::kOkRC, (fmt), (vl) )
|
||||||
#define cwLogWarning( fmt,...) cwLogWarningH( cw::logGlobalHandle(), cw::kOkRC, (fmt), ##__VA_ARGS__ )
|
#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 cwLogVSysError(rc,sysRC,fmt, vl) cwLogVSysErrorH( cw::log::globalHandle(), (rc), (sysRC), (fmt), (vl) )
|
||||||
#define cwLogSysError( rc,sysRC,fmt,...) cwLogSysErrorH( cw::logGlobalHandle(), (rc), (sysRC), (fmt), ##__VA_ARGS__ )
|
#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 cwLogVError(rc,fmt, vl) cwLogVErrorH( cw::log::globalHandle(), (rc), (fmt), (vl) )
|
||||||
#define cwLogError( rc,fmt,...) cwLogErrorH( cw::logGlobalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
#define cwLogError( rc,fmt,...) cwLogErrorH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||||
|
|
||||||
#define cwLogVFatal(rc,fmt, vl) cwLogVFatalH( cw::logGlobalHandle(), (rc), (fmt), (vl) )
|
#define cwLogVFatal(rc,fmt, vl) cwLogVFatalH( cw::log::globalHandle(), (rc), (fmt), (vl) )
|
||||||
#define cwLogFatal( rc,fmt,...) cwLogFatalH( cw::logGlobalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
#define cwLogFatal( rc,fmt,...) cwLogFatalH( cw::log::globalHandle(), (rc), (fmt), ##__VA_ARGS__ )
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
59
cwObject.cpp
59
cwObject.cpp
@ -16,7 +16,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
kLCurlyLexTId = cw::kUserLexTId+1,
|
kLCurlyLexTId = cw::lex::kUserLexTId+1,
|
||||||
kRCurlyLexTId,
|
kRCurlyLexTId,
|
||||||
kLHardLexTId,
|
kLHardLexTId,
|
||||||
kRHardLexTId,
|
kRHardLexTId,
|
||||||
@ -38,7 +38,7 @@ namespace cw
|
|||||||
{ kTrueLexTId, "true"},
|
{ kTrueLexTId, "true"},
|
||||||
{ kFalseLexTId, "false"},
|
{ kFalseLexTId, "false"},
|
||||||
{ kNullLexTId, "null" },
|
{ kNullLexTId, "null" },
|
||||||
{ cw::kErrorLexTId,""}
|
{ lex::kErrorLexTId,""}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -98,8 +98,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
for(unsigned i=0; i<indent; ++i)
|
for(unsigned i=0; i<indent; ++i)
|
||||||
printf(indentStr);
|
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=" " )
|
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;
|
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_list vl;
|
||||||
va_start(vl,fmt);
|
va_start(vl,fmt);
|
||||||
|
|
||||||
cwLogVError( kSyntaxErrorRC, fmt, vl );
|
cwLogVError( kSyntaxErrorRC, fmt, vl );
|
||||||
cwLogError( kSyntaxErrorRC, "Error on line: %i.", lexCurrentLineNumber(lexH));
|
cwLogError( kSyntaxErrorRC, "Error on line: %i.", lex::currentLineNumber(lexH));
|
||||||
va_end(vl);
|
va_end(vl);
|
||||||
return kSyntaxErrorRC;
|
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 )
|
if( parent == nullptr )
|
||||||
return _objSyntaxError(lexH,"The parent node must always be valid.");
|
return _objSyntaxError(lexH,"The parent node must always be valid.");
|
||||||
@ -289,7 +288,7 @@ namespace cw
|
|||||||
return newNode;
|
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 )
|
if( _objVerifyParentIsValueContainer(lexH,parent,_objTypeIdToLabel(tid)) == kOkRC )
|
||||||
return _objAppendLeftMostNode( parent, _objAllocate( tid, parent ));
|
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 )
|
cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
||||||
{
|
{
|
||||||
lexH_t lexH;
|
lex::handle_t lexH;
|
||||||
rc_t rc;
|
rc_t rc;
|
||||||
unsigned lexFlags = 0;
|
unsigned lexFlags = 0;
|
||||||
unsigned lexId = kErrorLexTId;
|
unsigned lexId = lex::kErrorLexTId;
|
||||||
object_t* cnp = _objAllocate(kRootTId,nullptr);
|
object_t* cnp = _objAllocate(kRootTId,nullptr);
|
||||||
object_t* root = cnp;
|
object_t* root = cnp;
|
||||||
|
|
||||||
objRef = nullptr;
|
objRef = nullptr;
|
||||||
|
|
||||||
if((rc = lexCreate(lexH,s,textLength(s), lexFlags )) != kOkRC )
|
if((rc = lex::create(lexH,s,textLength(s), lexFlags )) != kOkRC )
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
// setup the lexer with additional tokens
|
// setup the lexer with additional tokens
|
||||||
for(unsigned i=0; _objTokenArray[i].id != cw::kErrorLexTId; ++i)
|
for(unsigned i=0; _objTokenArray[i].id != lex::kErrorLexTId; ++i)
|
||||||
if((rc = lexRegisterToken( lexH, _objTokenArray[i].id, _objTokenArray[i].label )) != kOkRC )
|
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);
|
rc = cwLogError(rc,"Object lexer token registration failed on token id:%i : '%s'",_objTokenArray[i].id, _objTokenArray[i].label);
|
||||||
goto errLabel;
|
goto errLabel;
|
||||||
}
|
}
|
||||||
|
|
||||||
// main parser loop
|
// 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));
|
//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'.");
|
rc = _objSyntaxError(lexH,"Unexpected comma outside of 'array' or 'object'.");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kRealLexTId:
|
case lex::kRealLexTId:
|
||||||
_objCreateValueNode( cnp, lexTokenDouble(lexH), "real" );
|
_objCreateValueNode( cnp, lex::tokenDouble(lexH), "real" );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kIntLexTId:
|
case lex::kIntLexTId:
|
||||||
_objCreateValueNode( cnp, lexTokenInt(lexH), "int" );
|
_objCreateValueNode( cnp, lex::tokenInt(lexH), "int" );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kHexLexTId:
|
case lex::kHexLexTId:
|
||||||
_objCreateValueNode( cnp, lexTokenInt(lexH), "int", kHexFl );
|
_objCreateValueNode( cnp, lex::tokenInt(lexH), "int", kHexFl );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kTrueLexTId:
|
case kTrueLexTId:
|
||||||
@ -474,8 +473,8 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
|||||||
_objAppendLeftMostNode( cnp, _objAllocate( kNullTId, cnp ));
|
_objAppendLeftMostNode( cnp, _objAllocate( kNullTId, cnp ));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kIdentLexTId:
|
case lex::kIdentLexTId:
|
||||||
case kQStrLexTId:
|
case lex::kQStrLexTId:
|
||||||
{
|
{
|
||||||
|
|
||||||
// if the parent is an object then this string must be a pair label
|
// 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 ));
|
cnp = _objAppendLeftMostNode( cnp, _objAllocate( kPairTId, cnp ));
|
||||||
|
|
||||||
|
|
||||||
char* v = memDuplStr(lexTokenText(lexH),lexTokenCharCount(lexH));
|
char* v = memDuplStr(lex::tokenText(lexH),lex::tokenCharCount(lexH));
|
||||||
unsigned identFl = lexId == kIdentLexTId ? kIdentFl : 0;
|
unsigned identFl = lexId == lex::kIdentLexTId ? kIdentFl : 0;
|
||||||
|
|
||||||
|
|
||||||
_objCreateValueNode<char*>( cnp, v, "string", identFl );
|
_objCreateValueNode<char*>( cnp, v, "string", identFl );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case kEofLexTId:
|
case lex::kEofLexTId:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -509,7 +508,7 @@ cw::rc_t cw::objectFromString( const char* s, object_t*& objRef )
|
|||||||
objRef = root;
|
objRef = root;
|
||||||
|
|
||||||
errLabel:
|
errLabel:
|
||||||
rc_t rc0 = lexDestroy(lexH);
|
rc_t rc0 = lex::destroy(lexH);
|
||||||
|
|
||||||
return rc != kOkRC ? rc : rc0;
|
return rc != kOkRC ? rc : rc0;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ namespace cw
|
|||||||
{
|
{
|
||||||
objType_t* _objIdToType( objTypeId_t tid );
|
objType_t* _objIdToType( objTypeId_t tid );
|
||||||
object_t* _objAllocate( objTypeId_t tid=kInvalidTId, object_t* parent=NULL );
|
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 );
|
object_t* _objAppendLeftMostNode( object_t* parent, object_t* newNode );
|
||||||
|
|
||||||
template< typename T >
|
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 "cwAudioDeviceTest.h"
|
||||||
#include "cwAudioDeviceAlsa.h"
|
#include "cwAudioDeviceAlsa.h"
|
||||||
#include "cwAudioBuf.h"
|
#include "cwAudioBuf.h"
|
||||||
|
#include "cwTcpSocket.h"
|
||||||
|
#include "cwTcpSocketSrv.h"
|
||||||
|
#include "cwTcpSocketTest.h"
|
||||||
|
|
||||||
#include <iostream>
|
#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 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 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[] )
|
void stubTest( cw::object_t* cfg, int argc, const char* argv[] )
|
||||||
{
|
{
|
||||||
typedef struct v_str
|
typedef struct v_str
|
||||||
@ -170,6 +200,8 @@ int main( int argc, const char* argv[] )
|
|||||||
{ "audioBuf", audioBufTest },
|
{ "audioBuf", audioBufTest },
|
||||||
{ "audioDev",audioDevTest },
|
{ "audioDev",audioDevTest },
|
||||||
{ "audioDevAlsa", audioDevAlsaTest },
|
{ "audioDevAlsa", audioDevAlsaTest },
|
||||||
|
{ "socket", socketTest },
|
||||||
|
{ "socketSrv", socketSrvTest },
|
||||||
{ "stub", stubTest },
|
{ "stub", stubTest },
|
||||||
{ nullptr, nullptr }
|
{ nullptr, nullptr }
|
||||||
};
|
};
|
||||||
@ -180,7 +212,7 @@ int main( int argc, const char* argv[] )
|
|||||||
const char* mode = argc > 2 ? argv[2] : nullptr;
|
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 valid command line args were given and the cfg file was successfully read
|
||||||
if( cfgFn != nullptr && mode != nullptr && objectFromFile( cfgFn, cfg ) == cw::kOkRC )
|
if( cfgFn != nullptr && mode != nullptr && objectFromFile( cfgFn, cfg ) == cw::kOkRC )
|
||||||
@ -201,7 +233,7 @@ int main( int argc, const char* argv[] )
|
|||||||
cfg->free();
|
cfg->free();
|
||||||
}
|
}
|
||||||
|
|
||||||
cw::logDestroyGlobal();
|
cw::log::destroyGlobal();
|
||||||
|
|
||||||
return 0;
|
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