added examples/chant.cpp for simple command-line NORM chat app

pull/82/head
bebopagogo 2023-05-31 19:30:36 -04:00
parent 61b6e31f6f
commit 17dc41ab72
8 changed files with 1545 additions and 88 deletions

View File

@ -212,6 +212,7 @@ if(NORM_BUILD_EXAMPLES)
normMsgr normMsgr
normStreamer normStreamer
normCast normCast
chant
normClient normClient
normServer normServer
#wintest #wintest

1419
examples/chant.cpp Executable file

File diff suppressed because it is too large Load Diff

View File

@ -17,7 +17,7 @@
#include <sys/timerfd.h> #include <sys/timerfd.h>
#endif // LINUX #endif // LINUX
const unsigned int LOOP_MAX = 100; const unsigned int LOOP_MAX = 1;
// Setting SHOOT_FIRST to non-zero means that an ACK request // Setting SHOOT_FIRST to non-zero means that an ACK request
// will be used to advance the acking "watermark" point // will be used to advance the acking "watermark" point
@ -577,7 +577,7 @@ bool NormStreamer::OpenNormSession(NormInstanceHandle instance, const char* addr
NormSetLoopback(norm_session, loopback); NormSetLoopback(norm_session, loopback);
// Set some default parameters (maybe we should put parameter setting in Start()) // Set some default parameters (maybe we should put parameter setting in Start())
NormSetDefaultSyncPolicy(norm_session, NORM_SYNC_STREAM); NormSetDefaultSyncPolicy(norm_session, NORM_SYNC_CURRENT);
if (!is_multicast) if (!is_multicast)
NormSetDefaultUnicastNack(norm_session, true); NormSetDefaultUnicastNack(norm_session, true);
@ -711,7 +711,7 @@ bool NormStreamer::Start(bool sender, bool receiver)
void NormStreamer::ReadInputSocket() void NormStreamer::ReadInputSocket()
{ {
unsigned int loopCount = 0; unsigned int loopCount = 0;
NormSuspendInstance(NormGetInstance(norm_session)); //NormSuspendInstance(NormGetInstance(norm_session));
while (input_needed && input_ready && (loopCount < LOOP_MAX)) while (input_needed && input_ready && (loopCount < LOOP_MAX))
{ {
loopCount++; loopCount++;
@ -739,7 +739,7 @@ void NormStreamer::ReadInputSocket()
input_ready = false; input_ready = false;
} }
} }
NormResumeInstance(NormGetInstance(norm_session)); //NormResumeInstance(NormGetInstance(norm_session));
} // end NormStreamer::ReadInputSocket() } // end NormStreamer::ReadInputSocket()
void NormStreamer::ReadInput() void NormStreamer::ReadInput()
@ -748,7 +748,7 @@ void NormStreamer::ReadInput()
// The loop count makes sure we don't spend too much time here // The loop count makes sure we don't spend too much time here
// before going back to the main loop to handle NORM events, etc // before going back to the main loop to handle NORM events, etc
unsigned int loopCount = 0; unsigned int loopCount = 0;
NormSuspendInstance(NormGetInstance(norm_session)); //NormSuspendInstance(NormGetInstance(norm_session));
while (input_needed && input_ready && (loopCount < LOOP_MAX)) while (input_needed && input_ready && (loopCount < LOOP_MAX))
{ {
loopCount++; loopCount++;
@ -766,7 +766,9 @@ void NormStreamer::ReadInput()
assert(input_index < input_msg_length); assert(input_index < input_msg_length);
numBytes = input_msg_length - input_index; numBytes = input_msg_length - input_index;
} }
TRACE("reading STDIN ...\n");
ssize_t result = read(input_fd, input_buffer + input_index, numBytes); ssize_t result = read(input_fd, input_buffer + input_index, numBytes);
TRACE(" result: %d\n", (int)result);
if (result > 0) if (result > 0)
{ {
input_index += result; input_index += result;
@ -833,7 +835,7 @@ void NormStreamer::ReadInput()
break; break;
} }
} // end while (input_needed && input_ready) } // end while (input_needed && input_ready)
NormResumeInstance(NormGetInstance(norm_session)); //NormResumeInstance(NormGetInstance(norm_session));
} // end NormStreamer::ReadInput() } // end NormStreamer::ReadInput()
void NormStreamer::SendData() void NormStreamer::SendData()
@ -1000,7 +1002,7 @@ void NormStreamer::RecvData()
// before going back to the main loop to handle NORM events, etc // before going back to the main loop to handle NORM events, etc
unsigned int loopCount = 0; unsigned int loopCount = 0;
// Reads data from rx_stream to available output_buffer // Reads data from rx_stream to available output_buffer
NormSuspendInstance(NormGetInstance(norm_session)); //NormSuspendInstance(NormGetInstance(norm_session));
while (rx_needed && rx_ready && (loopCount < LOOP_MAX)) while (rx_needed && rx_ready && (loopCount < LOOP_MAX))
{ {
loopCount++; loopCount++;
@ -1065,7 +1067,7 @@ void NormStreamer::RecvData()
WriteOutput(); WriteOutput();
} }
} }
NormResumeInstance(NormGetInstance(norm_session)); //NormResumeInstance(NormGetInstance(norm_session));
} // end NormStreamer::RecvData() } // end NormStreamer::RecvData()
@ -1120,8 +1122,8 @@ void NormStreamer::WriteOutput()
if (0 != output_bucket_depth) if (0 != output_bucket_depth)
{ {
// Debit output token bucket since it's active // Debit output token bucket since it's active
if (result > output_bucket_count) //if (result > output_bucket_count)
TRACE("result:%d output_bucket_count:%u\n", (int)result, output_bucket_count); // TRACE("result:%d output_bucket_count:%u\n", (int)result, output_bucket_count);
ASSERT(output_bucket_count >= result); ASSERT(output_bucket_count >= result);
output_bucket_count -= result; output_bucket_count -= result;
} }
@ -1174,7 +1176,7 @@ void NormStreamer::HandleNormEvent(const NormEvent& event)
break; break;
case NORM_GRTT_UPDATED: case NORM_GRTT_UPDATED:
//fprintf(stderr, "new GRTT = %lf\n", NormGetGrttEstimate(norm_session)); fprintf(stderr, "new GRTT = %lf\n", NormGetGrttEstimate(norm_session));
break; break;
case NORM_ACKING_NODE_NEW: case NORM_ACKING_NODE_NEW:
@ -1453,7 +1455,7 @@ int main(int argc, char* argv[])
unsigned long outputSocketBufferSize = 0; // 6*1024*1024; unsigned long outputSocketBufferSize = 0; // 6*1024*1024;
unsigned long txSocketBufferSize = 0; // 6*1024*1024; unsigned long txSocketBufferSize = 0; // 6*1024*1024;
unsigned long rxSocketBufferSize = 0; // 6*1024*1024; unsigned long rxSocketBufferSize = 0; // 6*1024*1024;
unsigned long streamBufferSize = 1*1024*1024; unsigned long streamBufferSize = 10*1024*1024;
// Instantiate a NormStreamer and set default params // Instantiate a NormStreamer and set default params
NormStreamer normStreamer; NormStreamer normStreamer;
@ -2136,6 +2138,7 @@ int main(int argc, char* argv[])
int maxfd = -1; int maxfd = -1;
int fdMask = 0; int fdMask = 0;
bool waitOnNorm = false; bool waitOnNorm = false;
bool waitOnInput = false;
double timeoutInterval = -1.0; double timeoutInterval = -1.0;
if (send) if (send)
{ {
@ -2151,6 +2154,7 @@ int main(int argc, char* argv[])
FD_SET(inputfd, &fdsetInput); FD_SET(inputfd, &fdsetInput);
if (inputfd > maxfd) maxfd = inputfd; if (inputfd > maxfd) maxfd = inputfd;
fdMask |= 0x01; fdMask |= 0x01;
waitOnInput = true;
} }
} }
else else
@ -2268,6 +2272,7 @@ int main(int argc, char* argv[])
timeout.tv_sec = timeout.tv_usec = 0; timeout.tv_sec = timeout.tv_usec = 0;
} }
#endif // if/else LINUX #endif // if/else LINUX
//ßTRACE("waitOnNorm:%d waitOnInput:%d\n", waitOnNorm, waitOnInput);
int result = select(maxfd+1, &fdsetInput, &fdsetOutput, NULL, timeoutPtr); int result = select(maxfd+1, &fdsetInput, &fdsetOutput, NULL, timeoutPtr);
switch (result) switch (result)
{ {
@ -2304,9 +2309,14 @@ int main(int argc, char* argv[])
} }
// We always clear out/handle pending NORM API events // We always clear out/handle pending NORM API events
// (to keep event queue from building up) // (to keep event queue from building up)
unsigned int eventCount = 0;
const unsigned int maxBurstCount = 50;
NormEvent event; NormEvent event;
while (NormGetNextEvent(normInstance, &event, false)) while ((eventCount < maxBurstCount) && (NormGetNextEvent(normInstance, &event, false)))
{
normStreamer.HandleNormEvent(event); normStreamer.HandleNormEvent(event);
eventCount += 1;
}
struct timeval thisTime; struct timeval thisTime;
gettimeofday(&thisTime, NULL); gettimeofday(&thisTime, NULL);

View File

@ -207,6 +207,16 @@ normCastApp: $(CASTAPP_OBJ) libnorm.a $(LIBPROTO)
mkdir -p ../bin mkdir -p ../bin
cp $@ ../bin/$@ cp $@ ../bin/$@
# (chant) NORM command-line chat sender/receiver
CHANT_SRC = $(EXAMPLE)/chant.cpp
CHANT_OBJ = $(CHANT_SRC:.cpp=.o)
chant: $(CHANT_OBJ) libnorm.a $(LIBPROTO)
$(CC) $(CFLAGS) -o $@ $(CHANT_OBJ) $(LDFLAGS) libnorm.a $(LIBPROTO) $(LIBS)
mkdir -p ../bin
cp $@ ../bin/$@
# These are the new "NormSocket" API extension examples # These are the new "NormSocket" API extension examples
SERVER_SRC = $(EXAMPLE)/normServer.cpp $(EXAMPLE)/normSocket.cpp SERVER_SRC = $(EXAMPLE)/normServer.cpp $(EXAMPLE)/normSocket.cpp
SERVER_OBJ = $(SERVER_SRC:.cpp=.o) SERVER_OBJ = $(SERVER_SRC:.cpp=.o)

View File

@ -1637,12 +1637,15 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
bool presetStream = false; bool presetStream = false;
NormObject* obj = NULL; NormObject* obj = NULL;
bool doInsert = true; bool doInsert = true;
bool seen = false;
switch (status) switch (status)
{ {
case OBJ_PENDING: case OBJ_PENDING:
{ {
if (NULL != (obj = rx_table.Find(objectId))) if (NULL != (obj = rx_table.Find(objectId)))
{ {
// This checks for an object that's been "seen" but did not
// include Object FTI information previously.
if (0 == obj->GetSize().GetOffset()) if (0 == obj->GetSize().GetOffset())
{ {
// It's a seen object for which are awaiting FTI // It's a seen object for which are awaiting FTI
@ -1651,6 +1654,7 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
gotFTI = true; gotFTI = true;
obj->SetNackingMode(default_nacking_mode); obj->SetNackingMode(default_nacking_mode);
doInsert = false; doInsert = false;
seen = true;
// Intentionally pass through to case OBJ_NEW // Intentionally pass through to case OBJ_NEW
} }
else else
@ -1759,7 +1763,7 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
if (GetFtiData(msg, ftiData) || session.GetPresetFtiData(ftiData)) if (GetFtiData(msg, ftiData) || session.GetPresetFtiData(ftiData))
gotFTI = true; gotFTI = true;
} }
if (gotFTI) if (gotFTI || presetStream) // this assumes presetStream matches if !gotFTI (if we get conflicting info, an abort/resync will be forced)
{ {
if (presetStream || if (presetStream ||
obj->RxOpen(ftiData.GetObjectSize(), obj->RxOpen(ftiData.GetObjectSize(),
@ -1791,7 +1795,7 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
NormBlockId syncId = blockId; NormBlockId syncId = blockId;
stream->Decrement(syncId, stream->GetPendingMaskSize() - 1); stream->Decrement(syncId, stream->GetPendingMaskSize() - 1);
if ((stream->Compare(blockId, NormBlockId(0)) >= 0) && if ((stream->Compare(blockId, NormBlockId(0)) >= 0) &&
(stream->Compare(syncId, NormBlockId(0)) <= 0)) (stream->Compare(syncId, NormBlockId(0)) <= 0) && !seen)
{ {
// Assume we are "in-range" of sender initial stream startup // Assume we are "in-range" of sender initial stream startup
syncId = NormBlockId(0); syncId = NormBlockId(0);
@ -1835,8 +1839,8 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
(unsigned long)GetId(), (UINT16)objectId); (unsigned long)GetId(), (UINT16)objectId);
if (!presetStream) DeleteObject(obj); if (!presetStream) DeleteObject(obj);
obj = NULL; obj = NULL;
} } // end if/else (gotFTI : ((NormMsg::INFO != msgType) && msg.FlagIsSet(NormObjectMsg::FLAG_INFO)))
} } // end if (NULL != obj)
break; break;
} }
case OBJ_COMPLETE: case OBJ_COMPLETE:
@ -1875,7 +1879,7 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
completion_count++; completion_count++;
} }
} }
} } // end (if (NULL != obj)
switch (repair_boundary) switch (repair_boundary)
{ {
case BLOCK_BOUNDARY: case BLOCK_BOUNDARY:

View File

@ -3073,22 +3073,23 @@ bool NormStreamObject::StreamUpdateStatus(NormBlockId blockId)
//stream_next_id = blockId + pending_mask.GetSize(); //stream_next_id = blockId + pending_mask.GetSize();
stream_next_id = blockId; stream_next_id = blockId;
Increment(stream_next_id, pending_mask.GetSize()); Increment(stream_next_id, pending_mask.GetSize());
if (NULL != sender) if ((NULL != sender) && read_init)
{
if (read_init && (NormSenderNode::SYNC_CURRENT != sender->GetSyncPolicy()))
{ {
// This is a fresh rx stream, so init the read indices // This is a fresh rx stream, so init the read indices
read_init = false;
PLOG(PL_DEBUG, "NormStreamObject::StreamUpdateStatus() syncing stream to blockId: %lu\n", PLOG(PL_DEBUG, "NormStreamObject::StreamUpdateStatus() syncing stream to blockId: %lu\n",
(unsigned long)blockId.GetValue()); (unsigned long)blockId.GetValue());
read_init = false;
read_index.block = blockId; read_index.block = blockId;
if (0 != blockId.GetValue()) stream_broken = true;
read_index.segment = 0; read_index.segment = 0;
read_index.offset = 0; read_index.offset = 0;
read_offset = 0; read_offset = 0;
sender->DecrementResyncCount(); // correction since stream sync here will falsely increment sender->DecrementResyncCount(); // correction since stream sync here will falsely increment
if ((NormSenderNode::SYNC_CURRENT != sender->GetSyncPolicy()) &&
(0 != blockId.GetValue()))
{
stream_broken = true;
} }
} } // end if ((NULL != sender) && read_init)
// Since we're doing a resync including "read_init", dump any buffered data // Since we're doing a resync including "read_init", dump any buffered data
// (TBD) this may not be necessary??? and is thus currently commented-out code // (TBD) this may not be necessary??? and is thus currently commented-out code
@ -3230,16 +3231,8 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
NormSegmentId segmentId, NormSegmentId segmentId,
const char* segment) const char* segment)
{ {
UINT32 segmentOffset = NormDataMsg::ReadStreamPayloadOffset(segment); //UINT32 segmentOffset = NormDataMsg::ReadStreamPayloadOffset(segment);
if (read_init) ASSERT(!read_init);
{
read_init = false;
read_index.block = blockId;
read_index.segment = segmentId;
read_index.offset = 0;
read_offset = segmentOffset;
read_ready = true;
}
//if ((blockId < read_index.block) || //if ((blockId < read_index.block) ||
if ((Compare(blockId, read_index.block) < 0) || if ((Compare(blockId, read_index.block) < 0) ||

View File

@ -2275,7 +2275,6 @@ void NormSession::TxSocketRecvHandler(ProtoSocket &theSocket,
unsigned int msgLength = NormMsg::MAX_SIZE; unsigned int msgLength = NormMsg::MAX_SIZE;
while (true) while (true)
{ {
if (theSocket.RecvFrom(msg.AccessBuffer(), if (theSocket.RecvFrom(msg.AccessBuffer(),
msgLength, msgLength,
msg.AccessAddress())) msg.AccessAddress()))
@ -2631,6 +2630,7 @@ void NormTrace(const struct timeval &currentTime,
time_t secs = (time_t)currentTime.tv_sec; time_t secs = (time_t)currentTime.tv_sec;
struct tm *ct = gmtime(&secs); struct tm *ct = gmtime(&secs);
#endif // if/else _WIN32_WCE #endif // if/else _WIN32_WCE
PLOG(PL_ALWAYS, "trace>%02d:%02d:%02d.%06lu ", PLOG(PL_ALWAYS, "trace>%02d:%02d:%02d.%06lu ",
(int)ct->tm_hour, (int)ct->tm_min, (int)ct->tm_sec, (unsigned int)currentTime.tv_usec); (int)ct->tm_hour, (int)ct->tm_min, (int)ct->tm_sec, (unsigned int)currentTime.tv_usec);
PLOG(PL_ALWAYS, "node>%lu %s>%s/%hu ", (unsigned long)localId, status, addr.GetHostString(), addr.GetPort()); PLOG(PL_ALWAYS, "node>%lu %s>%s/%hu ", (unsigned long)localId, status, addr.GetHostString(), addr.GetPort());
@ -2741,12 +2741,13 @@ void NormTrace(const struct timeval &currentTime,
{ {
PLOG(PL_ALWAYS, "inst>%hu ", instId); PLOG(PL_ALWAYS, "inst>%hu ", instId);
// look for NormCCFeedback extension // look for NormCCFeedback extension
bool ccExt = false;
NormHeaderExtension ext; NormHeaderExtension ext;
while (msg.GetNextExtension(ext)) while (msg.GetNextExtension(ext))
{ {
if (NormHeaderExtension::CC_FEEDBACK == ext.GetType()) if (NormHeaderExtension::CC_FEEDBACK == ext.GetType())
{ {
clrFlag = ((NormCCFeedbackExtension &)ext).CCFlagIsSet(NormCC::CLR); ccExt = true;
break; break;
} }
} }
@ -2775,6 +2776,23 @@ void NormTrace(const struct timeval &currentTime,
PLOG(PL_ALWAYS, "NACK "); PLOG(PL_ALWAYS, "NACK ");
// TBD - provide deeper NACK inspection? // TBD - provide deeper NACK inspection?
} }
if (ccExt)
{
clrFlag = ((NormCCFeedbackExtension &)ext).CCFlagIsSet(NormCC::CLR);
// Print ccRtt (only valid if pcap file is from sender node)
double ccRtt = NormUnquantizeRtt(((NormCCFeedbackExtension &)ext).GetCCRtt());
double ccLoss = NormUnquantizeLoss32(((NormCCFeedbackExtension &)ext).GetCCLoss32());
PLOG(PL_ALWAYS, "ccRtt:%lf ccLoss:%lf ", ccRtt, ccLoss);
// Print locally measured rtt (only valid if pcap file is from sender node)
struct timeval grttResponse;
if (NormMsg::NACK == msgType)
static_cast<const NormNackMsg &>(msg).GetGrttResponse(grttResponse);
else
static_cast<const NormAckMsg &>(msg).GetGrttResponse(grttResponse);
double rtt = ProtoTime::Delta(ProtoTime(currentTime), ProtoTime(grttResponse));
PLOG(PL_ALWAYS, "rtt:%lf ", rtt);
}
break; break;
} }

View File

@ -231,6 +231,8 @@ def build(ctx):
'normStreamSend', 'normStreamSend',
'normMsgr', 'normMsgr',
'normStreamer', 'normStreamer',
'normCast',
'chant',
'normClient', 'normClient',
'normServer', 'normServer',
#'wintest' # Windows only (can uncomment on Windows) #'wintest' # Windows only (can uncomment on Windows)