added examples/chant.cpp for simple command-line NORM chat app
parent
61b6e31f6f
commit
17dc41ab72
|
|
@ -212,6 +212,7 @@ if(NORM_BUILD_EXAMPLES)
|
|||
normMsgr
|
||||
normStreamer
|
||||
normCast
|
||||
chant
|
||||
normClient
|
||||
normServer
|
||||
#wintest
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -17,7 +17,7 @@
|
|||
#include <sys/timerfd.h>
|
||||
#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
|
||||
// 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);
|
||||
|
||||
// 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)
|
||||
NormSetDefaultUnicastNack(norm_session, true);
|
||||
|
|
@ -711,7 +711,7 @@ bool NormStreamer::Start(bool sender, bool receiver)
|
|||
void NormStreamer::ReadInputSocket()
|
||||
{
|
||||
unsigned int loopCount = 0;
|
||||
NormSuspendInstance(NormGetInstance(norm_session));
|
||||
//NormSuspendInstance(NormGetInstance(norm_session));
|
||||
while (input_needed && input_ready && (loopCount < LOOP_MAX))
|
||||
{
|
||||
loopCount++;
|
||||
|
|
@ -739,7 +739,7 @@ void NormStreamer::ReadInputSocket()
|
|||
input_ready = false;
|
||||
}
|
||||
}
|
||||
NormResumeInstance(NormGetInstance(norm_session));
|
||||
//NormResumeInstance(NormGetInstance(norm_session));
|
||||
} // end NormStreamer::ReadInputSocket()
|
||||
|
||||
void NormStreamer::ReadInput()
|
||||
|
|
@ -748,7 +748,7 @@ void NormStreamer::ReadInput()
|
|||
// 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
|
||||
unsigned int loopCount = 0;
|
||||
NormSuspendInstance(NormGetInstance(norm_session));
|
||||
//NormSuspendInstance(NormGetInstance(norm_session));
|
||||
while (input_needed && input_ready && (loopCount < LOOP_MAX))
|
||||
{
|
||||
loopCount++;
|
||||
|
|
@ -766,7 +766,9 @@ void NormStreamer::ReadInput()
|
|||
assert(input_index < input_msg_length);
|
||||
numBytes = input_msg_length - input_index;
|
||||
}
|
||||
TRACE("reading STDIN ...\n");
|
||||
ssize_t result = read(input_fd, input_buffer + input_index, numBytes);
|
||||
TRACE(" result: %d\n", (int)result);
|
||||
if (result > 0)
|
||||
{
|
||||
input_index += result;
|
||||
|
|
@ -833,7 +835,7 @@ void NormStreamer::ReadInput()
|
|||
break;
|
||||
}
|
||||
} // end while (input_needed && input_ready)
|
||||
NormResumeInstance(NormGetInstance(norm_session));
|
||||
//NormResumeInstance(NormGetInstance(norm_session));
|
||||
} // end NormStreamer::ReadInput()
|
||||
|
||||
void NormStreamer::SendData()
|
||||
|
|
@ -1000,7 +1002,7 @@ void NormStreamer::RecvData()
|
|||
// before going back to the main loop to handle NORM events, etc
|
||||
unsigned int loopCount = 0;
|
||||
// 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))
|
||||
{
|
||||
loopCount++;
|
||||
|
|
@ -1065,7 +1067,7 @@ void NormStreamer::RecvData()
|
|||
WriteOutput();
|
||||
}
|
||||
}
|
||||
NormResumeInstance(NormGetInstance(norm_session));
|
||||
//NormResumeInstance(NormGetInstance(norm_session));
|
||||
|
||||
} // end NormStreamer::RecvData()
|
||||
|
||||
|
|
@ -1120,8 +1122,8 @@ void NormStreamer::WriteOutput()
|
|||
if (0 != output_bucket_depth)
|
||||
{
|
||||
// Debit output token bucket since it's active
|
||||
if (result > output_bucket_count)
|
||||
TRACE("result:%d output_bucket_count:%u\n", (int)result, output_bucket_count);
|
||||
//if (result > output_bucket_count)
|
||||
// TRACE("result:%d output_bucket_count:%u\n", (int)result, output_bucket_count);
|
||||
ASSERT(output_bucket_count >= result);
|
||||
output_bucket_count -= result;
|
||||
}
|
||||
|
|
@ -1174,7 +1176,7 @@ void NormStreamer::HandleNormEvent(const NormEvent& event)
|
|||
break;
|
||||
|
||||
case NORM_GRTT_UPDATED:
|
||||
//fprintf(stderr, "new GRTT = %lf\n", NormGetGrttEstimate(norm_session));
|
||||
fprintf(stderr, "new GRTT = %lf\n", NormGetGrttEstimate(norm_session));
|
||||
break;
|
||||
|
||||
case NORM_ACKING_NODE_NEW:
|
||||
|
|
@ -1453,7 +1455,7 @@ int main(int argc, char* argv[])
|
|||
unsigned long outputSocketBufferSize = 0; // 6*1024*1024;
|
||||
unsigned long txSocketBufferSize = 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
|
||||
NormStreamer normStreamer;
|
||||
|
|
@ -2136,6 +2138,7 @@ int main(int argc, char* argv[])
|
|||
int maxfd = -1;
|
||||
int fdMask = 0;
|
||||
bool waitOnNorm = false;
|
||||
bool waitOnInput = false;
|
||||
double timeoutInterval = -1.0;
|
||||
if (send)
|
||||
{
|
||||
|
|
@ -2151,6 +2154,7 @@ int main(int argc, char* argv[])
|
|||
FD_SET(inputfd, &fdsetInput);
|
||||
if (inputfd > maxfd) maxfd = inputfd;
|
||||
fdMask |= 0x01;
|
||||
waitOnInput = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -2268,6 +2272,7 @@ int main(int argc, char* argv[])
|
|||
timeout.tv_sec = timeout.tv_usec = 0;
|
||||
}
|
||||
#endif // if/else LINUX
|
||||
//ßTRACE("waitOnNorm:%d waitOnInput:%d\n", waitOnNorm, waitOnInput);
|
||||
int result = select(maxfd+1, &fdsetInput, &fdsetOutput, NULL, timeoutPtr);
|
||||
switch (result)
|
||||
{
|
||||
|
|
@ -2304,9 +2309,14 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
// We always clear out/handle pending NORM API events
|
||||
// (to keep event queue from building up)
|
||||
unsigned int eventCount = 0;
|
||||
const unsigned int maxBurstCount = 50;
|
||||
NormEvent event;
|
||||
while (NormGetNextEvent(normInstance, &event, false))
|
||||
while ((eventCount < maxBurstCount) && (NormGetNextEvent(normInstance, &event, false)))
|
||||
{
|
||||
normStreamer.HandleNormEvent(event);
|
||||
eventCount += 1;
|
||||
}
|
||||
|
||||
struct timeval thisTime;
|
||||
gettimeofday(&thisTime, NULL);
|
||||
|
|
|
|||
|
|
@ -207,6 +207,16 @@ normCastApp: $(CASTAPP_OBJ) libnorm.a $(LIBPROTO)
|
|||
mkdir -p ../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
|
||||
SERVER_SRC = $(EXAMPLE)/normServer.cpp $(EXAMPLE)/normSocket.cpp
|
||||
SERVER_OBJ = $(SERVER_SRC:.cpp=.o)
|
||||
|
|
|
|||
|
|
@ -1637,12 +1637,15 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
bool presetStream = false;
|
||||
NormObject* obj = NULL;
|
||||
bool doInsert = true;
|
||||
bool seen = false;
|
||||
switch (status)
|
||||
{
|
||||
case OBJ_PENDING:
|
||||
{
|
||||
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())
|
||||
{
|
||||
// It's a seen object for which are awaiting FTI
|
||||
|
|
@ -1651,6 +1654,7 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
gotFTI = true;
|
||||
obj->SetNackingMode(default_nacking_mode);
|
||||
doInsert = false;
|
||||
seen = true;
|
||||
// Intentionally pass through to case OBJ_NEW
|
||||
}
|
||||
else
|
||||
|
|
@ -1759,7 +1763,7 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
if (GetFtiData(msg, ftiData) || session.GetPresetFtiData(ftiData))
|
||||
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 ||
|
||||
obj->RxOpen(ftiData.GetObjectSize(),
|
||||
|
|
@ -1791,7 +1795,7 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
NormBlockId syncId = blockId;
|
||||
stream->Decrement(syncId, stream->GetPendingMaskSize() - 1);
|
||||
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
|
||||
syncId = NormBlockId(0);
|
||||
|
|
@ -1835,8 +1839,8 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
(unsigned long)GetId(), (UINT16)objectId);
|
||||
if (!presetStream) DeleteObject(obj);
|
||||
obj = NULL;
|
||||
}
|
||||
}
|
||||
} // end if/else (gotFTI : ((NormMsg::INFO != msgType) && msg.FlagIsSet(NormObjectMsg::FLAG_INFO)))
|
||||
} // end if (NULL != obj)
|
||||
break;
|
||||
}
|
||||
case OBJ_COMPLETE:
|
||||
|
|
@ -1875,7 +1879,7 @@ void NormSenderNode::HandleObjectMessage(const NormObjectMsg& msg)
|
|||
completion_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // end (if (NULL != obj)
|
||||
switch (repair_boundary)
|
||||
{
|
||||
case BLOCK_BOUNDARY:
|
||||
|
|
|
|||
|
|
@ -3073,22 +3073,23 @@ bool NormStreamObject::StreamUpdateStatus(NormBlockId blockId)
|
|||
//stream_next_id = blockId + pending_mask.GetSize();
|
||||
stream_next_id = blockId;
|
||||
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
|
||||
PLOG(PL_DEBUG, "NormStreamObject::StreamUpdateStatus() syncing stream to blockId: %lu\n",
|
||||
(unsigned long)blockId.GetValue());
|
||||
read_init = false;
|
||||
read_index.block = blockId;
|
||||
read_index.segment = 0;
|
||||
read_index.offset = 0;
|
||||
read_offset = 0;
|
||||
sender->DecrementResyncCount(); // correction since stream sync here will falsely increment
|
||||
if ((NormSenderNode::SYNC_CURRENT != sender->GetSyncPolicy()) &&
|
||||
(0 != blockId.GetValue()))
|
||||
{
|
||||
// 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",
|
||||
(unsigned long)blockId.GetValue());
|
||||
read_index.block = blockId;
|
||||
if (0 != blockId.GetValue()) stream_broken = true;
|
||||
read_index.segment = 0;
|
||||
read_index.offset = 0;
|
||||
read_offset = 0;
|
||||
sender->DecrementResyncCount(); // correction since stream sync here will falsely increment
|
||||
stream_broken = true;
|
||||
}
|
||||
}
|
||||
} // end if ((NULL != sender) && read_init)
|
||||
|
||||
// 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
|
||||
|
|
@ -3230,16 +3231,8 @@ bool NormStreamObject::WriteSegment(NormBlockId blockId,
|
|||
NormSegmentId segmentId,
|
||||
const char* segment)
|
||||
{
|
||||
UINT32 segmentOffset = NormDataMsg::ReadStreamPayloadOffset(segment);
|
||||
if (read_init)
|
||||
{
|
||||
read_init = false;
|
||||
read_index.block = blockId;
|
||||
read_index.segment = segmentId;
|
||||
read_index.offset = 0;
|
||||
read_offset = segmentOffset;
|
||||
read_ready = true;
|
||||
}
|
||||
//UINT32 segmentOffset = NormDataMsg::ReadStreamPayloadOffset(segment);
|
||||
ASSERT(!read_init);
|
||||
|
||||
//if ((blockId < read_index.block) ||
|
||||
if ((Compare(blockId, read_index.block) < 0) ||
|
||||
|
|
|
|||
|
|
@ -2275,7 +2275,6 @@ void NormSession::TxSocketRecvHandler(ProtoSocket &theSocket,
|
|||
unsigned int msgLength = NormMsg::MAX_SIZE;
|
||||
while (true)
|
||||
{
|
||||
|
||||
if (theSocket.RecvFrom(msg.AccessBuffer(),
|
||||
msgLength,
|
||||
msg.AccessAddress()))
|
||||
|
|
@ -2631,6 +2630,7 @@ void NormTrace(const struct timeval ¤tTime,
|
|||
time_t secs = (time_t)currentTime.tv_sec;
|
||||
struct tm *ct = gmtime(&secs);
|
||||
#endif // if/else _WIN32_WCE
|
||||
|
||||
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);
|
||||
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 ¤tTime,
|
|||
{
|
||||
PLOG(PL_ALWAYS, "inst>%hu ", instId);
|
||||
// look for NormCCFeedback extension
|
||||
bool ccExt = false;
|
||||
NormHeaderExtension ext;
|
||||
while (msg.GetNextExtension(ext))
|
||||
{
|
||||
if (NormHeaderExtension::CC_FEEDBACK == ext.GetType())
|
||||
{
|
||||
clrFlag = ((NormCCFeedbackExtension &)ext).CCFlagIsSet(NormCC::CLR);
|
||||
ccExt = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -2775,6 +2776,23 @@ void NormTrace(const struct timeval ¤tTime,
|
|||
PLOG(PL_ALWAYS, "NACK ");
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
@ -4811,46 +4829,46 @@ bool NormSession::OnTxTimeout(ProtoTimer & /*theTimer*/)
|
|||
|
||||
switch (SendMessage(*msg))
|
||||
{
|
||||
case MSG_SEND_OK:
|
||||
if (tx_rate > 0.0)
|
||||
tx_timer.SetInterval(GetTxInterval(msgLength, tx_rate));
|
||||
if (advertise_repairs)
|
||||
{
|
||||
advertise_repairs = false;
|
||||
suppress_rate = -1.0; // reset cc feedback suppression rate
|
||||
}
|
||||
else
|
||||
{
|
||||
ReturnMessageToPool(msg);
|
||||
}
|
||||
// Pre-serve to allow pre-prompt for empty tx queue
|
||||
// (TBD) do this in a better way ??? There is a slight chance
|
||||
// that with this approach some new data may get pre-queued
|
||||
// when an interim repair request should be serviced first
|
||||
// instead ???
|
||||
//if (message_queue.IsEmpty() && IsSender()) Serve();
|
||||
return true; // reinstall tx_timer
|
||||
case MSG_SEND_OK:
|
||||
if (tx_rate > 0.0)
|
||||
tx_timer.SetInterval(GetTxInterval(msgLength, tx_rate));
|
||||
if (advertise_repairs)
|
||||
{
|
||||
advertise_repairs = false;
|
||||
suppress_rate = -1.0; // reset cc feedback suppression rate
|
||||
}
|
||||
else
|
||||
{
|
||||
ReturnMessageToPool(msg);
|
||||
}
|
||||
// Pre-serve to allow pre-prompt for empty tx queue
|
||||
// (TBD) do this in a better way ??? There is a slight chance
|
||||
// that with this approach some new data may get pre-queued
|
||||
// when an interim repair request should be serviced first
|
||||
// instead ???
|
||||
//if (message_queue.IsEmpty() && IsSender()) Serve();
|
||||
return true; // reinstall tx_timer
|
||||
|
||||
case MSG_SEND_BLOCKED:
|
||||
// Message was not sent due to to EWOULDBLOCK, so we invoke async i/o output notification
|
||||
if (!advertise_repairs)
|
||||
message_queue.Prepend(msg);
|
||||
if (tx_timer.IsActive())
|
||||
tx_timer.Deactivate();
|
||||
tx_socket->StartOutputNotification();
|
||||
return false; // since timer was deactivated
|
||||
case MSG_SEND_BLOCKED:
|
||||
// Message was not sent due to to EWOULDBLOCK, so we invoke async i/o output notification
|
||||
if (!advertise_repairs)
|
||||
message_queue.Prepend(msg);
|
||||
if (tx_timer.IsActive())
|
||||
tx_timer.Deactivate();
|
||||
tx_socket->StartOutputNotification();
|
||||
return false; // since timer was deactivated
|
||||
|
||||
case MSG_SEND_FAILED:
|
||||
// Message was not sent due to socket error (no route, etc), so so just timeout and try again
|
||||
// (TBD - is there something smarter we should do)
|
||||
if (!advertise_repairs)
|
||||
message_queue.Prepend(msg);
|
||||
if (tx_rate > 0.0)
|
||||
tx_timer.SetInterval(GetTxInterval(msgLength, tx_rate));
|
||||
else if (0.0 == tx_timer.GetInterval())
|
||||
tx_timer.SetInterval(0.001);
|
||||
return true; // timer will be reactivated
|
||||
}
|
||||
case MSG_SEND_FAILED:
|
||||
// Message was not sent due to socket error (no route, etc), so so just timeout and try again
|
||||
// (TBD - is there something smarter we should do)
|
||||
if (!advertise_repairs)
|
||||
message_queue.Prepend(msg);
|
||||
if (tx_rate > 0.0)
|
||||
tx_timer.SetInterval(GetTxInterval(msgLength, tx_rate));
|
||||
else if (0.0 == tx_timer.GetInterval())
|
||||
tx_timer.SetInterval(0.001);
|
||||
return true; // timer will be reactivated
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue