diff --git a/common/normApp.cpp b/common/normApp.cpp index 55be57b..5c5bdf2 100644 --- a/common/normApp.cpp +++ b/common/normApp.cpp @@ -1,31 +1,32 @@ -// norm.cpp - Command-line NORM application +// normApp.cpp - Command-line NORM application -#include "protoLib.h" +#include "protokit.h" #include "normSession.h" #include "normPostProcess.h" #include // for stdout/stderr printouts #include // for SIGTERM/SIGINT handling #include +#include // Command-line application using Protolib EventDispatcher -class NormApp : public NormController +class NormApp : public NormController, public ProtoApp { public: NormApp(); virtual ~NormApp(); - bool OnStartup(); - int MainLoop() {return dispatcher.Run();} - void Stop(int exitCode) {dispatcher.Stop(exitCode);} + + // Overrides from ProtoApp or NsProtoSimAgent base + bool OnStartup(int argc, const char*const* argv); + bool ProcessCommands(int argc, const char*const* argv); void OnShutdown(); bool ProcessCommand(const char* cmd, const char* val); - bool ParseCommandLine(int argc, char* argv[]); - static void DoInputReady(EventDispatcher::Descriptor descriptor, - EventDispatcher::EventType theEvent, - const void* userData); + static void DoInputReady(ProtoDispatcher::Descriptor descriptor, + ProtoDispatcher::Event theEvent, + const void* userData); private: void OnInputReady(); @@ -39,17 +40,14 @@ class NormApp : public NormController class NormServerNode* server, class NormObject* object); - void InstallTimer(ProtocolTimer* timer) - {dispatcher.InstallTimer(timer);} - bool OnIntervalTimeout(); + bool OnIntervalTimeout(ProtoTimer& theTimer); static const char* const cmd_list[]; - + +#ifdef UNIX static void SignalHandler(int sigNum); - bool IsPostProcessing() {return post_processor.IsActive();} - void HandleSIGCHLD() {post_processor.HandleSIGCHLD();} - - EventDispatcher dispatcher; +#endif // UNIX + NormSessionMgr session_mgr; NormSession* session; NormStreamObject* tx_stream; @@ -91,13 +89,13 @@ class NormApp : public NormController double tx_object_interval; int tx_repeat_count; double tx_repeat_interval; - ProtocolTimer interval_timer; + ProtoTimer interval_timer; // NormSession client-only parameters unsigned long rx_buffer_size; // bytes NormFileList rx_file_cache; char* rx_cache_path; - NormPostProcessor post_processor; + NormPostProcessor* post_processor; bool unicast_nacks; bool silent_client; @@ -109,7 +107,8 @@ class NormApp : public NormController }; // end class NormApp NormApp::NormApp() - : session(NULL), tx_stream(NULL), rx_stream(NULL), input(NULL), output(NULL), + : session_mgr(GetTimerMgr(), GetSocketNotifier()), + session(NULL), tx_stream(NULL), rx_stream(NULL), input(NULL), output(NULL), input_index(0), input_length(0), input_active(false), push_stream(false), input_messaging(false), input_msg_length(0), input_msg_index(0), output_index(0), output_messaging(false), output_msg_length(0), output_msg_sync(false), @@ -122,14 +121,14 @@ NormApp::NormApp() tracing(false), tx_loss(0.0), rx_loss(0.0) { // Init tx_timer for 1.0 second interval, infinite repeats - session_mgr.Init(EventDispatcher::TimerInstaller, &dispatcher, - EventDispatcher::SocketInstaller, &dispatcher, - this); - interval_timer.Init(0.0, 0, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormApp::OnIntervalTimeout); + session_mgr.SetController(this); + + interval_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormApp::OnIntervalTimeout); + interval_timer.SetInterval(0.0); + interval_timer.SetRepeat(0); struct timeval currentTime; - GetSystemTime(¤tTime); + ProtoSystemTime(currentTime); srand(currentTime.tv_usec); } @@ -137,6 +136,7 @@ NormApp::~NormApp() { if (address) delete address; if (rx_cache_path) delete rx_cache_path; + if (post_processor) delete post_processor; } @@ -299,9 +299,9 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val) else if (!strncmp("input", cmd, len)) { if (!strcmp(val, "STDIN")) - { + { input = stdin; - } + } else if (!(input = fopen(val, "rb"))) { DMSG(0, "NormApp::ProcessCommand(input) fopen() error: %s\n", @@ -310,16 +310,18 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val) } input_index = input_length = 0; input_messaging = false; +#ifdef UNIX // Set input non-blocking if(-1 == fcntl(fileno(input), F_SETFL, fcntl(fileno(input), F_GETFL, 0) | O_NONBLOCK)) perror("NormApp::ProcessCommand(input) fcntl(F_SETFL(O_NONBLOCK)) error"); +#endif // UNIX } else if (!strncmp("output", cmd, len)) { if (!strcmp(val, "STDOUT")) - { + { output = stdout; - } + } else if (!(output = fopen(val, "wb"))) { DMSG(0, "NormApp::ProcessCommand(output) fopen() error: %s\n", @@ -333,9 +335,9 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val) else if (!strncmp("minput", cmd, len)) { if (!strcmp(val, "STDIN")) - { + { input = stdin; - } + } else if (!(input = fopen(val, "rb"))) { DMSG(0, "NormApp::ProcessCommand(input) fopen() error: %s\n", @@ -344,16 +346,18 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val) } input_index = input_length = 0; input_messaging = true; +#ifdef UNIX // Set input non-blocking if(-1 == fcntl(fileno(input), F_SETFL, fcntl(fileno(input), F_GETFL, 0) | O_NONBLOCK)) perror("NormApp::ProcessCommand(input) fcntl(F_SETFL(O_NONBLOCK)) error"); +#endif // UNIX } else if (!strncmp("moutput", cmd, len)) { if (!strcmp(val, "STDOUT")) - { + { output = stdout; - } + } else if (!(output = fopen(val, "wb"))) { DMSG(0, "NormApp::ProcessCommand(output) fopen() error: %s\n", @@ -404,8 +408,8 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val) else if (!strncmp("rxcachedir", cmd, len)) { unsigned int length = strlen(val); - // Make sure there is a trailing DIR_DELIMITER - if (DIR_DELIMITER != val[length-1]) + // Make sure there is a trailing PROTO_PATH_DELIMITER + if (PROTO_PATH_DELIMITER != val[length-1]) length += 2; else length += 1; @@ -416,7 +420,7 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val) return false; } strcpy(rx_cache_path, val); - rx_cache_path[length-2] = DIR_DELIMITER; + rx_cache_path[length-2] = PROTO_PATH_DELIMITER; rx_cache_path[length-1] = '\0'; } else if (!strncmp("segment", cmd, len)) @@ -514,7 +518,7 @@ bool NormApp::ProcessCommand(const char* cmd, const char* val) } else if (!strncmp("processor", cmd, len)) { - if (!post_processor.SetCommand(val)) + if (!post_processor->SetCommand(val)) { DMSG(0, "NormApp::ProcessCommand(processor) error!\n"); return false; @@ -555,7 +559,7 @@ NormApp::CmdType NormApp::CommandType(const char* cmd) } // end NormApp::CommandType() -bool NormApp::ParseCommandLine(int argc, char* argv[]) +bool NormApp::ProcessCommands(int argc, const char*const* argv) { int i = 1; while ( i < argc) @@ -564,13 +568,13 @@ bool NormApp::ParseCommandLine(int argc, char* argv[]) switch (cmdType) { case CMD_INVALID: - DMSG(0, "NormApp::ParseCommandLine() Invalid command:%s\n", + DMSG(0, "NormApp::ProcessCommands() Invalid command:%s\n", argv[i]); return false; case CMD_NOARG: if (!ProcessCommand(argv[i], NULL)) { - DMSG(0, "NormApp::ParseCommandLine() ProcessCommand(%s) error\n", + DMSG(0, "NormApp::ProcessCommands() ProcessCommand(%s) error\n", argv[i]); return false; } @@ -579,7 +583,7 @@ bool NormApp::ParseCommandLine(int argc, char* argv[]) case CMD_ARG: if (!ProcessCommand(argv[i], argv[i+1])) { - DMSG(0, "NormApp::ParseCommandLine() ProcessCommand(%s, %s) error\n", + DMSG(0, "NormApp::ProcessCommands() ProcessCommand(%s, %s) error\n", argv[i], argv[i+1]); return false; } @@ -588,10 +592,10 @@ bool NormApp::ParseCommandLine(int argc, char* argv[]) } } return true; -} // end NormApp::ParseCommandLine() +} // end NormApp::ProcessCommands() -void NormApp::DoInputReady(EventDispatcher::Descriptor /*descriptor*/, - EventDispatcher::EventType /*theEvent*/, +void NormApp::DoInputReady(ProtoDispatcher::Descriptor /*descriptor*/, + ProtoDispatcher::Event /*theEvent*/, const void* userData) { ((NormApp*)userData)->OnInputReady(); @@ -607,6 +611,8 @@ void NormApp::OnInputReady() // the stream has buffer space for input while (input) { + bool inputStarved = false; + if (0 == input_length) { // We need input ... @@ -667,7 +673,11 @@ void NormApp::OnInputReady() DMSG(0, "norm: input end-of-file.\n"); if (input_active) { +#ifdef WIN32 + ASSERT(0); // no Win32 support for stream i/o yet +#else dispatcher.RemoveGenericInput(fileno(input)); +#endif // if/else WIN32/UNIX input_active = false; } if (stdin != input) fclose(input); @@ -679,8 +689,10 @@ void NormApp::OnInputReady() switch (errno) { case EINTR: + continue; case EAGAIN: // Input not ready, will get notification when ready + inputStarved = true; break; default: DMSG(0, "norm: input error:%s\n", strerror(errno)); @@ -716,30 +728,37 @@ void NormApp::OnInputReady() { // Stream buffer full, temporarily deactive "input" and // wait for next TX_QUEUE_EMPTY notification - //TRACE("stream buffer full ...\n"); if (input_active) { - dispatcher.RemoveGenericInput(fileno(input)); +#ifdef WIN32 + ASSERT(0); // no Win32 support for stream i/o yet +#else + dispatcher.RemoveGenericInput(fileno(input)); +#endif // if/else WIN32/UNIX input_active = false; } break; } } - else + else if (inputStarved) { // Input not ready, wait for "input" to be ready // (Activate/reactivate "input" as necessary - //TRACE("input starved ...\n"); if (!input_active) { - if (dispatcher.AddGenericInput(fileno(input), NormApp::DoInputReady, this)) +#ifdef WIN32 + ASSERT(0); // no Win32 support for stream i/o yet + if (false) +#else + if (dispatcher.InstallGenericInput(fileno(input), NormApp::DoInputReady, this)) +#endif // if/else WIN32/UNIX input_active = true; else DMSG(0, "NormApp::Notify(TX_QUEUE_EMPTY) error adding input notification!\n"); } break; } - } // end while (1) + } // end while (input) } // NormApp::OnInputReady() @@ -762,14 +781,10 @@ void NormApp::Notify(NormController::Event event, { // Can queue a new object for transmission if (interval_timer.IsActive()) interval_timer.Deactivate(); - if (interval_timer.Interval() > 0.0) - { - InstallTimer(&interval_timer); - } + if (interval_timer.GetInterval() > 0.0) + ActivateTimer(interval_timer); else - { - OnIntervalTimeout(); - } + OnIntervalTimeout(interval_timer); } break; @@ -789,7 +804,7 @@ void NormApp::Notify(NormController::Event event, // object Size() has recommended buffering size NormObjectSize size; if (silent_client) - size = NormObjectSize(rx_buffer_size); + size = NormObjectSize((UINT32)rx_buffer_size); else size = object->Size(); @@ -863,7 +878,7 @@ void NormApp::Notify(NormController::Event event, for (UINT16 i = pathLen; i < (pathLen+len); i++) { if ('/' == fileName[i]) - fileName[i] = DIR_DELIMITER; + fileName[i] = PROTO_PATH_DELIMITER; } pathLen += len; if (pathLen < PATH_MAX) fileName[pathLen] = '\0'; @@ -947,7 +962,8 @@ void NormApp::Notify(NormController::Event event, } else { - output_msg_sync = true; + if (readLength > 0) + output_msg_sync = true; } if (readLength) @@ -1015,15 +1031,16 @@ void NormApp::Notify(NormController::Event event, case RX_OBJECT_COMPLETE: { + //TRACE("NormApp::Notify(RX_OBJECT_COMPLETE) ...\n"); switch(object->GetType()) { case NormObject::FILE: { const char* filePath = ((NormFileObject*)object)->Path(); //DMSG(0, "norm: Completed rx file: %s\n", filePath); - if (post_processor.IsEnabled()) + if (post_processor->IsEnabled()) { - if (!post_processor.ProcessFile(filePath)) + if (!post_processor->ProcessFile(filePath)) { DMSG(0, "norm: post processing error\n"); } @@ -1044,7 +1061,7 @@ void NormApp::Notify(NormController::Event event, } // end NormApp::Notify() -bool NormApp::OnIntervalTimeout() +bool NormApp::OnIntervalTimeout(ProtoTimer& /*theTimer*/) { char fileName[PATH_MAX]; if (tx_file_list.GetNextFile(fileName)) @@ -1063,7 +1080,7 @@ bool NormApp::OnIntervalTimeout() // Normalize directory delimiters in file name info for (unsigned int i = 0; i < len; i++) { - if (DIR_DELIMITER == fileNameInfo[i]) + if (PROTO_PATH_DELIMITER == fileNameInfo[i]) fileNameInfo[i] = '/'; } char temp[PATH_MAX]; @@ -1076,7 +1093,7 @@ bool NormApp::OnIntervalTimeout() // Wait a second, then try the next file in the list if (interval_timer.IsActive()) interval_timer.Deactivate(); interval_timer.SetInterval(1.0); - InstallTimer(&interval_timer); + ActivateTimer(interval_timer); return false; } //DMSG(0, "norm: File \"%s\" queued for transmission.\n", fileName); @@ -1091,12 +1108,12 @@ bool NormApp::OnIntervalTimeout() { if (interval_timer.IsActive()) interval_timer.Deactivate(); interval_timer.SetInterval(tx_repeat_interval = tx_object_interval); - InstallTimer(&interval_timer); + ActivateTimer(interval_timer); return false; } else { - return OnIntervalTimeout(); + return OnIntervalTimeout(interval_timer); } } else @@ -1106,20 +1123,25 @@ bool NormApp::OnIntervalTimeout() return true; } // end NormApp::OnIntervalTimeout() -bool NormApp::OnStartup() +bool NormApp::OnStartup(int argc, const char*const* argv) { -#ifdef WIN32 - if (!dispatcher.Win32Init()) - { - fprintf(stderr, "norm:: Win32Init() error!\n"); - return false; - } -#endif // WIN32 - - signal(SIGTERM, SignalHandler); - signal(SIGINT, SignalHandler); - signal(SIGCHLD, SignalHandler); + if (!(post_processor = NormPostProcessor::Create())) + { + DMSG(0, "NormApp::OnStartup() error creating post processor\n"); + return false; + } + + if (!ProcessCommands(argc, argv)) + { + DMSG(0, "NormApp::OnStartup() error processing command-line commands\n"); + return false; + } + +#ifdef UNIX + signal(SIGCHLD, SignalHandler); +#endif // UNIX + // Validate our application settings if (!address) { @@ -1200,7 +1222,11 @@ void NormApp::OnShutdown() { if (input_active) { +#ifdef WIN32 + ASSERT(0); // no Win32 support for stream i/o yet +#else dispatcher.RemoveGenericInput(fileno(input)); +#endif // if/else WIN32/UNIX input_active = false; } if (stdin != input) fclose(input); @@ -1211,97 +1237,32 @@ void NormApp::OnShutdown() if (stdout != output) fclose(output); output = NULL; } + if (post_processor) + { + delete post_processor; + post_processor = NULL; + } } // end NormApp::OnShutdown() +// Out application instance +PROTO_INSTANTIATE_APP(NormApp); -// Out application instance (global for SignalHandler) -NormApp theApp; - -// Use "main()" for UNIX and WIN32 console apps, -// "WinMain()" for non-console WIN32 -// (VC++ uses the "_CONSOLE_" macro to indicate build type) - -#if defined(WIN32) && !defined(_CONSOLE_) -int PASCAL WinMain(HINSTANCE instance, HINSTANCE prevInst, LPSTR cmdline, int cmdshow) -{ - // (TBD) transform WinMain "cmdLine" to (argc, argv[]) values - int argc = 0; - char* argv[] = NULL; -#else -int main(int argc, char* argv[]) -{ -#endif -#ifdef WIN32 - // Hack to determine if Win32 console application was launched - // independently or from a pre-existing console window - bool pauseForUser = false; - HANDLE hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE); - if (INVALID_HANDLE_VALUE != hConsoleOutput) - { - CONSOLE_SCREEN_BUFFER_INFO csbi; - GetConsoleScreenBufferInfo(hConsoleOutput, &csbi); - pauseForUser = ((csbi.dwCursorPosition.X==0) && (csbi.dwCursorPosition.Y==0)); - if ((csbi.dwSize.X<=0) || (csbi.dwSize.Y <= 0)) pauseForUser = false; - } - else - { - // We're not a "console" application, so create one - // This could be commented out or made a command-line option - OpenDebugWindow(); - pauseForUser = true; - } -#endif // WIN32 - - int exitCode = 0; - if (theApp.ParseCommandLine(argc, argv)) - { - if (theApp.OnStartup()) - { - exitCode = theApp.MainLoop(); - theApp.OnShutdown(); - fprintf(stderr, "norm: Done.\n"); - } - else - { - fprintf(stderr, "norm: Error initializing application!\n"); - exitCode = -1; - } - } - else - { - fprintf(stderr, "norm: Error parsing command line!\n"); - exitCode = -1; - } - -#ifdef WIN32 - // If Win32 console is going to disappear, pause for user before exiting - if (pauseForUser) - { - printf ("Program Finished - Hit to exit"); - getchar(); - } -#endif // WIN32 - return exitCode; // exitCode contains "signum" causing exit -} // end main(); - - - +#ifdef UNIX void NormApp::SignalHandler(int sigNum) { switch(sigNum) { - case SIGTERM: - case SIGINT: - theApp.Stop(sigNum); // causes theApp's main loop to exit - break; - case SIGCHLD: - if (theApp.IsPostProcessing()) theApp.HandleSIGCHLD(); + { + NormApp* app = static_cast(ProtoApp::GetApp()); + if (app->post_processor) app->post_processor->OnDeath(); signal(SIGCHLD, SignalHandler); break; + } default: fprintf(stderr, "norm: Unexpected signal: %d\n", sigNum); break; } } // end NormApp::SignalHandler() +#endif // UNIX diff --git a/common/normBitmask.h b/common/normBitmask.h index 55fa646..a280d3e 100644 --- a/common/normBitmask.h +++ b/common/normBitmask.h @@ -1,7 +1,8 @@ #ifndef _NORM_BITMASK_ #define _NORM_BITMASK_ -#include "debug.h" // for PROTO_DEBUG stuff +#include "protokit.h" // for PROTO_DEBUG stuff + #include // for memset() #include // for fprintf() @@ -183,7 +184,6 @@ class NormSlidingMask long start; long end; unsigned long offset; - unsigned char* mask2; }; // end class NormSlidingMask #endif // _NORM_BITMASK_ diff --git a/common/normEncoder.cpp b/common/normEncoder.cpp index 46ab715..2053698 100644 --- a/common/normEncoder.cpp +++ b/common/normEncoder.cpp @@ -146,13 +146,14 @@ bool NormEncoder::CreateGeneratorPolynomial() for (int i = 0; i < degree; i++) { memset(&tp2[degree], 0, degree*sizeof(unsigned char)); + int j; // Scale tp2 by p1[i] - for(int j=0; j= i; j--) tp2[j] = tp2[j-i]; + for (j = (degree*2)-1; j >= i; j--) tp2[j] = tp2[j-i]; memset(tp2, 0, i*sizeof(unsigned char)); // Add into partial product - for(int j=0; j < (npar+1); j++) genPoly[j] ^= tp2[j]; + for(j=0; j < (npar+1); j++) genPoly[j] ^= tp2[j]; } memcpy(tp1, genPoly, (npar+1)*sizeof(unsigned char)); memset(&tp1[npar+1], 0, (2*degree)-(npar+1)); @@ -343,7 +344,8 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era int vecSize = vector_size; #endif // if/else SIMUATE - for (int i = 0; i < npar; i++) + int i; + for (i = 0; i < npar; i++) { int X = gexp(i+1); unsigned char* synVec = sVec[i]; @@ -365,7 +367,7 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era int nvecsMinusOne = nvecs - 1; memset(Lambda, 0, degree*sizeof(char)); Lambda[0] = 1; - for (int i = 0; i < erasureCount; i++) + for (i = 0; i < erasureCount; i++) { int X = gexp(nvecsMinusOne - erasureLocs[i]); for(int j = (degree-1); j > 0; j--) @@ -373,7 +375,7 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era } // (C) Compute modified Omega using Lambda - for(int i = 0; i < npar; i++) + for(i = 0; i < npar; i++) { int k = i; memset(oVec[i], 0, vecSize*sizeof(char)); @@ -389,7 +391,7 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era } // (D) Finally, fill in the erasures - for (int i = 0; i < erasureCount; i++) + for (i = 0; i < erasureCount; i++) { // Only fill _data_ erasures if (erasureLocs[i] >= ndata) break;//return erasureCount; @@ -398,14 +400,15 @@ int NormDecoder::Decode(char** dVec, int ndata, UINT16 erasureCount, UINT16* era // ( all odd powers disappear) int k = nvecsMinusOne - erasureLocs[i]; int denom = 0; - for (int j = 1; j < degree; j += 2) + int j; + for (j = 1; j < degree; j += 2) denom ^= gmult(Lambda[j], gexp(((255-k)*(j-1)) % 255)); // Invert for use computing errror value below denom = ginv(denom); // Now evaluate Omega at alpha^(-i) (numerator) unsigned char* eVec = (unsigned char*)dVec[erasureLocs[i]]; - for (int j = 0; j < npar; j++) + for (j = 0; j < npar; j++) { unsigned char* data = eVec; unsigned char* Omega = oVec[j]; diff --git a/common/normEncoder.h b/common/normEncoder.h index fb5c4f0..adc0a28 100644 --- a/common/normEncoder.h +++ b/common/normEncoder.h @@ -33,7 +33,7 @@ #ifndef _NORM_ENCODER #define _NORM_ENCODER -#include "sysdefs.h" // protolib stuff +#include "protokit.h" // protolib stuff class NormEncoder { diff --git a/common/normFile.cpp b/common/normFile.cpp index e9911ad..45942ac 100644 --- a/common/normFile.cpp +++ b/common/normFile.cpp @@ -3,7 +3,7 @@ #include // for strerror() #include // for errno - +#include // for rename() #ifdef WIN32 #include #include @@ -34,14 +34,14 @@ bool NormFile::Open(const char* thePath, int theFlags) // Create sub-directories as needed. char tempPath[PATH_MAX]; strncpy(tempPath, thePath, PATH_MAX); - char* ptr = strrchr(tempPath, DIR_DELIMITER); + char* ptr = strrchr(tempPath, PROTO_PATH_DELIMITER); if (ptr) *ptr = '\0'; ptr = NULL; while (!NormFile::Exists(tempPath)) { char* ptr2 = ptr; - ptr = strrchr(tempPath, DIR_DELIMITER); - if (ptr2) *ptr2 = DIR_DELIMITER; + ptr = strrchr(tempPath, PROTO_PATH_DELIMITER); + if (ptr2) *ptr2 = PROTO_PATH_DELIMITER; if (ptr) { *ptr = '\0'; @@ -52,18 +52,22 @@ bool NormFile::Open(const char* thePath, int theFlags) break; } } - if (ptr && ('\0' == *ptr)) *ptr++ = DIR_DELIMITER; + if (ptr && ('\0' == *ptr)) *ptr++ = PROTO_PATH_DELIMITER; while (ptr) { - ptr = strchr(ptr, DIR_DELIMITER); + ptr = strchr(ptr, PROTO_PATH_DELIMITER); if (ptr) *ptr = '\0'; +#ifdef WIN32 + if (mkdir(tempPath)) +#else if (mkdir(tempPath, 0755)) +#endif // if/else WIN32/UNIX { DMSG(0, "NormFile::Rename() mkdir(%s) error: %s\n", tempPath, strerror(errno)); return false; } - if (ptr) *ptr++ = DIR_DELIMITER; + if (ptr) *ptr++ = PROTO_PATH_DELIMITER; } } #ifdef WIN32 @@ -82,8 +86,7 @@ bool NormFile::Open(const char* thePath, int theFlags) } else { - DMSG(0, "Error opening file \"%s\": %s\n", path, - strerror(errno)); + DMSG(0, "Error opening file \"%s\": %s\n", thePath, strerror(errno)); flags = 0; return false; } @@ -159,7 +162,7 @@ bool NormFile::Rename(const char* oldName, const char* newName) if (NormFile::IsLocked(newName)) return false; #ifdef WIN32 // In Win32, the new file can't already exist - if (NormFile::Exists(newName) _unlink(newName); + if (NormFile::Exists(newName)) _unlink(newName); // In Win32, the old file can't be open int oldFlags = 0; if (IsOpen()) @@ -172,14 +175,14 @@ bool NormFile::Rename(const char* oldName, const char* newName) // Create sub-directories as needed. char tempPath[PATH_MAX]; strncpy(tempPath, newName, PATH_MAX); - char* ptr = strrchr(tempPath, DIR_DELIMITER); + char* ptr = strrchr(tempPath, PROTO_PATH_DELIMITER); if (ptr) *ptr = '\0'; ptr = NULL; while (!NormFile::Exists(tempPath)) { char* ptr2 = ptr; - ptr = strrchr(tempPath, DIR_DELIMITER); - if (ptr2) *ptr2 = DIR_DELIMITER; + ptr = strrchr(tempPath, PROTO_PATH_DELIMITER); + if (ptr2) *ptr2 = PROTO_PATH_DELIMITER; if (ptr) { *ptr = '\0'; @@ -190,10 +193,10 @@ bool NormFile::Rename(const char* oldName, const char* newName) break; } } - if (ptr && ('\0' == *ptr)) *ptr++ = DIR_DELIMITER; + if (ptr && ('\0' == *ptr)) *ptr++ = PROTO_PATH_DELIMITER; while (ptr) { - ptr = strchr(ptr, DIR_DELIMITER); + ptr = strchr(ptr, PROTO_PATH_DELIMITER); if (ptr) *ptr = '\0'; if (mkdir(tempPath, 0755)) { @@ -201,7 +204,7 @@ bool NormFile::Rename(const char* oldName, const char* newName) tempPath, strerror(errno)); return false; } - if (ptr) *ptr++ = DIR_DELIMITER; + if (ptr) *ptr++ = PROTO_PATH_DELIMITER; } #endif // if/else WIN32 if (rename(oldName, newName)) @@ -367,7 +370,7 @@ bool NormDirectoryIterator::GetNextFile(char* fileName) bool success = true; while(success) { - WIN32_findData findData; + WIN32_FIND_DATA findData; if (current->hSearch == (HANDLE)-1) { // Construct search string @@ -387,7 +390,7 @@ bool NormDirectoryIterator::GetNextFile(char* fileName) // Do we have a candidate file? if (success) { - char* ptr = strrchr(findData.cFileName, DIR_DELIMITER); + char* ptr = strrchr(findData.cFileName, PROTO_PATH_DELIMITER); if (ptr) ptr += 1; else @@ -535,9 +538,9 @@ NormDirectoryIterator::NormDirectory::NormDirectory(const char* thePath, { strncpy(path, thePath, PATH_MAX); int len = MIN(PATH_MAX, strlen(path)); - if ((len < PATH_MAX) && (DIR_DELIMITER != path[len-1])) + if ((len < PATH_MAX) && (PROTO_PATH_DELIMITER != path[len-1])) { - path[len++] = DIR_DELIMITER; + path[len++] = PROTO_PATH_DELIMITER; if (len < PATH_MAX) path[len] = '\0'; } } @@ -551,10 +554,10 @@ bool NormDirectoryIterator::NormDirectory::Open() { Close(); // in case it's already open char fullName[PATH_MAX]; - GetFullName(fullName); - // Get rid of trailing DIR_DELIMITER + GetFullName(fullName); + // Get rid of trailing PROTO_PATH_DELIMITER int len = MIN(PATH_MAX, strlen(fullName)); - if (DIR_DELIMITER == fullName[len-1]) fullName[len-1] = '\0'; + if (PROTO_PATH_DELIMITER == fullName[len-1]) fullName[len-1] = '\0'; #ifdef WIN32 DWORD attr = GetFileAttributes(fullName); if (0xFFFFFFFF == attr) @@ -581,8 +584,11 @@ void NormDirectoryIterator::NormDirectory::Close() hSearch = (HANDLE)-1; } #else - closedir(dptr); - dptr = NULL; + if (dptr) + { + closedir(dptr); + dptr = NULL; + } #endif // if/else WIN32 } // end NormDirectoryIterator::NormDirectory::Close() @@ -856,15 +862,15 @@ void NormFileList::GetCurrentBasePath(char* pathBuffer) strncpy(pathBuffer, next->Path(), PATH_MAX); unsigned int len = strlen(pathBuffer); len = MIN(len, PATH_MAX); - if (DIR_DELIMITER != pathBuffer[len-1]) + if (PROTO_PATH_DELIMITER != pathBuffer[len-1]) { - if (len < PATH_MAX) pathBuffer[len++] = DIR_DELIMITER; + if (len < PATH_MAX) pathBuffer[len++] = PROTO_PATH_DELIMITER; if (len < PATH_MAX) pathBuffer[len] = '\0'; } } else // NormFile::NORMAL { - const char* ptr = strrchr(next->Path(), DIR_DELIMITER); + const char* ptr = strrchr(next->Path(), PROTO_PATH_DELIMITER); if (ptr++) { unsigned int len = ptr - next->Path(); @@ -925,6 +931,7 @@ bool NormFileList::FileItem::GetNextFile(char* thePath, NormFileList::DirectoryItem::DirectoryItem(const char* thePath) : NormFileList::FileItem(thePath) { + } NormFileList::DirectoryItem::~DirectoryItem() @@ -963,9 +970,9 @@ bool NormFileList::DirectoryItem::GetNextFile(char* thePath, strncpy(thePath, path, PATH_MAX); unsigned int len = strlen(thePath); len = MIN(len, PATH_MAX); - if ((DIR_DELIMITER != thePath[len-1]) && (len < PATH_MAX)) + if ((PROTO_PATH_DELIMITER != thePath[len-1]) && (len < PATH_MAX)) { - thePath[len++] = DIR_DELIMITER; + thePath[len++] = PROTO_PATH_DELIMITER; if (len < PATH_MAX) thePath[len] = '\0'; } char tempPath[PATH_MAX]; diff --git a/common/normFile.h b/common/normFile.h index 63cf272..81d5f3c 100644 --- a/common/normFile.h +++ b/common/normFile.h @@ -18,8 +18,7 @@ #include // From PROTOLIB -#include "sysdefs.h" // for bool definition, DIR_DELIMITER, PATH_MAX, etc -#include "debug.h" // for DEBUG stuff +#include "protokit.h" // for Protolib stuff class NormFile { @@ -61,11 +60,11 @@ class NormFile #ifdef WIN32 DWORD attr = GetFileAttributes(path); return ((0xFFFFFFFF == attr) ? - false : (0 == (attr & FILE_ATTRIBUTE_READONLY))); + false : (0 == (attr & FILE_ATTRIBUTE_READONLY))); #else return (0 == access(path, W_OK)); - } #endif // if/else WIN32 + } // Members @@ -73,7 +72,9 @@ class NormFile int fd; int flags; off_t offset; -}; +}; // end class NormFile + + /****************************************** * The NormDirectory and NormDirectoryIterator classes @@ -98,11 +99,11 @@ class NormDirectoryIterator private: char path[PATH_MAX]; NormDirectory* parent; - #ifdef WIN32 +#ifdef WIN32 HANDLE hSearch; - #else +#else DIR* dptr; - #endif // if/else WIN32 +#endif // if/else WIN32 NormDirectory(const char *thePath, NormDirectory* theParent = NULL); ~NormDirectory(); void GetFullName(char* namePtr); diff --git a/common/normMessage.cpp b/common/normMessage.cpp index 877ce04..5176e50 100644 --- a/common/normMessage.cpp +++ b/common/normMessage.cpp @@ -150,7 +150,7 @@ bool NormRepairRequest::AppendRepairItem(const NormObjectId& objectId, if (buffer_len >= (length+ITEM_LIST_OFFSET+RepairItemLength())) { char* ptr = buffer + length + ITEM_LIST_OFFSET; - ptr[FEC_ID_OFFSET] = 129; + ptr[FEC_ID_OFFSET] = (char)129; ptr[RESERVED_OFFSET] = 0; *((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)objectId); *((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)blockId); @@ -181,7 +181,7 @@ bool NormRepairRequest::AppendRepairRange(const NormObjectId& startObjectId, { // range start char* ptr = buffer + length + ITEM_LIST_OFFSET; - ptr[FEC_ID_OFFSET] = 129; + ptr[FEC_ID_OFFSET] = (char)129; ptr[RESERVED_OFFSET] = 0; *((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)startObjectId); *((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)startBlockId); @@ -189,7 +189,7 @@ bool NormRepairRequest::AppendRepairRange(const NormObjectId& startObjectId, *((UINT16*)(ptr+SYMBOL_ID_OFFSET)) = htons((UINT16)startSymbolId); ptr += RepairItemLength(); // range end - ptr[FEC_ID_OFFSET] = 129; + ptr[FEC_ID_OFFSET] = (char)129; ptr[RESERVED_OFFSET] = 0; *((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)endObjectId); *((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)endBlockId); @@ -212,7 +212,7 @@ bool NormRepairRequest::AppendErasureCount(const NormObjectId& objectId, if (buffer_len >= (ITEM_LIST_OFFSET+length+ErasureItemLength())) { char* ptr = buffer + length + ITEM_LIST_OFFSET; - ptr[FEC_ID_OFFSET] = 129; + ptr[FEC_ID_OFFSET] = (char)129; ptr[RESERVED_OFFSET] = 0; *((UINT16*)(ptr+OBJ_ID_OFFSET)) = htons((UINT16)objectId); *((UINT32*)(ptr+BLOCK_ID_OFFSET)) = htonl((UINT32)blockId); @@ -425,8 +425,6 @@ unsigned char NormQuantizeRtt(double rtt) return ((unsigned char)(ceil(255.0 - (13.0*log(NORM_RTT_MAX/rtt))))); } // end NormQuantizeRtt() - - bool NormObjectSize::operator<(const NormObjectSize& size) const { UINT16 diff = msb - size.msb; diff --git a/common/normMessage.h b/common/normMessage.h index 698dafd..1846d72 100644 --- a/common/normMessage.h +++ b/common/normMessage.h @@ -2,14 +2,12 @@ #define _NORM_MESSAGE // PROTOLIB includes -#include "networkAddress.h" // for NetworkAddress class -#include "sysdefs.h" // for UINT typedefs -#include "debug.h" +#include "protokit.h" // standard includes #include // for memcpy(), etc #include - +#include // for rand(), etc #ifdef SIMULATE #define SIM_PAYLOAD_MAX 36 // MGEN message size @@ -22,6 +20,22 @@ const UINT8 NORM_PROTOCOL_VERSION = 1; const int NORM_ROBUST_FACTOR = 20; // default robust factor + +// Pick a random number from 0..max +inline double UniformRand(double max) +{ + return (max * ((double)rand() / (double)RAND_MAX)); +} + +// Pick a random number from 0..max +// (truncated exponential dist. lambda = log(groupSize) + 1) +inline double ExponentialRand(double max, double groupSize) +{ + double lambda = log(groupSize) + 1; + double x = UniformRand(lambda/max)+lambda/(max*(exp(lambda)-1)); + return ((max/lambda)*log(x*(exp(lambda)-1)*(max/lambda))); +} + // These are the GRTT estimation bounds set for the current // NORM protocol. (Note that our Grtt quantization routines // are good for the range of 1.0e-06 <= 1000.0) @@ -39,13 +53,20 @@ unsigned char NormQuantizeRtt(double rtt); inline double NormUnquantizeGroupSize(unsigned char gsize) { - return ((double)(gsize >> 4) * pow(10.0, (double)(gsize & 0x0f))); + double exponent = (double)((gsize & 0x07) + 1); + double mantissa = (0 != (gsize & 0x08)) ? 5.0 : 1.0; + return (mantissa * pow(10.0, exponent)); } inline unsigned char NormQuantizeGroupSize(double gsize) { - unsigned char exponent = (unsigned char)log10(gsize); - exponent = MIN(exponent, 0x0f); - return ((((unsigned char)(gsize / pow(10.0, (double)exponent) + 0.5)) << 4) | exponent); + unsigned char ebits = (unsigned char)log10(gsize); + int mantissa = (int)((gsize/pow(10.0, (double)ebits)) + 0.5); + // round up quantized group size + unsigned char mbit = (mantissa > 1) ? ((mantissa > 5) ? 0x00 : 0x08) : 0x00; + ebits = (mantissa > 5) ? ebits : ebits+1; + mbit = (ebits > 0x07) ? 0x08 : mbit; + ebits = (ebits > 0x07) ? 0x07 : ebits; + return (mbit | ebits); } inline unsigned short NormQuantizeLoss(double lossFraction) @@ -62,8 +83,7 @@ inline double NormUnquantizeLoss(unsigned short lossQuantized) inline unsigned short NormQuantizeRate(double rate) { - unsigned char exponent = (unsigned short)log10(rate); - exponent = MIN(exponent, 0xff); + unsigned char exponent = (unsigned char)log10(rate); unsigned short mantissa = (unsigned short)((256.0/10.0) * rate / pow(10.0, (double)exponent)); return ((mantissa << 8) | exponent); } @@ -88,7 +108,11 @@ class NormObjectSize UINT32 LSB() const {return lsb;} bool operator<(const NormObjectSize& size) const; + bool operator<=(const NormObjectSize& size) const + {return ((*this == size) || (*this(const NormObjectSize& size) const; + bool operator>=(const NormObjectSize& size) const + {return ((*this == size) || (*this>size));} bool operator==(const NormObjectSize& size) const {return ((msb == size.msb) && (lsb == size.lsb));} bool operator!=(const NormObjectSize& size) const @@ -135,7 +159,11 @@ class NormObjectId NormObjectId(const NormObjectId& id) {value = id.value;} operator UINT16() const {return value;} bool operator<(const NormObjectId& id) const; + bool operator<=(const NormObjectId& id) const + {return ((value == id.value) || (*this(const NormObjectId& id) const; + bool operator>=(const NormObjectId& id) const + {return ((value == id.value) || (*this>id));} bool operator==(const NormObjectId& id) const {return (value == id.value);} bool operator!=(const NormObjectId& id) const @@ -251,7 +279,7 @@ class NormMsg { *((UINT32*)(buffer+SOURCE_ID_OFFSET)) = htonl(sourceId); } - void SetDestination(const NetworkAddress& dst) {addr = dst;} + void SetDestination(const ProtoAddress& dst) {addr = dst;} void AttachExtension(NormHeaderExtension& extension) { @@ -272,8 +300,8 @@ class NormMsg { return (ntohl(*((UINT32*)(buffer+SOURCE_ID_OFFSET)))); } - const NetworkAddress& GetDestination() const {return addr;} - const NetworkAddress& GetSource() const {return addr;} + const ProtoAddress& GetDestination() const {return addr;} + const ProtoAddress& GetSource() const {return addr;} const char* GetBuffer() {return buffer;} UINT16 GetLength() const {return length;} @@ -286,12 +314,11 @@ class NormMsg bool result = (nextOffset < header_length); ext.AttachBuffer(result ? (buffer+nextOffset) : NULL); return result; - } - + } // For message reception and misc. char* AccessBuffer() {return buffer;} - NetworkAddress* AccessAddress() {return &addr;} + ProtoAddress& AccessAddress() {return addr;} protected: // Common message header offsets @@ -321,7 +348,7 @@ class NormMsg UINT16 length; UINT16 header_length; UINT16 header_length_base; - NetworkAddress addr; // src or dst address + ProtoAddress addr; // src or dst address NormMsg* prev; NormMsg* next; @@ -349,7 +376,8 @@ class NormObjectMsg : public NormMsg return (ntohs(*((UINT16*)(buffer+SESSION_ID_OFFSET)))); } UINT8 GetGrtt() const {return buffer[GRTT_OFFSET];} - UINT8 GetGroupSize() const {return buffer[GSIZE_OFFSET];} + UINT8 GetBackoffFactor() const {return ((buffer[GSIZE_OFFSET] >> 4) & 0x0f);} + UINT8 GetGroupSize() const {return (buffer[GSIZE_OFFSET] & 0x0f);} bool FlagIsSet(NormObjectMsg::Flag flag) const {return (0 != (flag & buffer[FLAGS_OFFSET]));} UINT8 GetFecId() const {return buffer[FEC_ID_OFFSET];} @@ -364,7 +392,14 @@ class NormObjectMsg : public NormMsg *((UINT16*)(buffer+SESSION_ID_OFFSET)) = htons(sessionId); } void SetGrtt(UINT8 grtt) {buffer[GRTT_OFFSET] = grtt;} - void SetGroupSize(UINT8 gsize) {buffer[GSIZE_OFFSET] = gsize;} + void SetBackoffFactor(UINT8 backoff) + { + buffer[BACKOFF_OFFSET] = (buffer[GSIZE_OFFSET] & 0x0f) | (backoff << 4); + } + void SetGroupSize(UINT8 gsize) + { + buffer[GSIZE_OFFSET] = (buffer[GSIZE_OFFSET] & 0xf0) | gsize; + } void ResetFlags() {buffer[FLAGS_OFFSET] = 0;} void SetFlag(NormObjectMsg::Flag flag) {buffer[FLAGS_OFFSET] |= flag;} void SetFecId(UINT8 fecId) {buffer[FEC_ID_OFFSET] = fecId;} @@ -378,7 +413,8 @@ class NormObjectMsg : public NormMsg { SESSION_ID_OFFSET = MSG_OFFSET, GRTT_OFFSET = SESSION_ID_OFFSET + 2, - GSIZE_OFFSET = GRTT_OFFSET + 1, + BACKOFF_OFFSET = GRTT_OFFSET + 1, + GSIZE_OFFSET = BACKOFF_OFFSET, FLAGS_OFFSET = GSIZE_OFFSET + 1, FEC_ID_OFFSET = FLAGS_OFFSET + 1, OBJ_ID_OFFSET = FEC_ID_OFFSET + 1, @@ -448,11 +484,11 @@ class NormFtiExtension : public NormHeaderExtension private: enum { - FEC_INSTANCE_OFFSET = LENGTH_OFFSET + 1, - FEC_NDATA_OFFSET = FEC_INSTANCE_OFFSET +2, - FEC_NPARITY_OFFSET = FEC_NDATA_OFFSET + 2, - SEG_SIZE_OFFSET = FEC_NPARITY_OFFSET+2, - OBJ_SIZE_OFFSET = SEG_SIZE_OFFSET + 2 + OBJ_SIZE_OFFSET = LENGTH_OFFSET + 1, + FEC_INSTANCE_OFFSET = OBJ_SIZE_OFFSET + 6, + SEG_SIZE_OFFSET = FEC_INSTANCE_OFFSET +2, + FEC_NDATA_OFFSET = SEG_SIZE_OFFSET + 2, + FEC_NPARITY_OFFSET = FEC_NDATA_OFFSET + 2 }; }; // end class NormFtiExtension @@ -617,23 +653,32 @@ class NormCmdMsg : public NormMsg } void SetGrtt(UINT8 quantizedGrtt) {buffer[GRTT_OFFSET] = quantizedGrtt;} - void SetGroupSize(UINT8 quantizedGroupSize) - {buffer[GSIZE_OFFSET] = quantizedGroupSize;} + void SetBackoffFactor(UINT8 backoff) + { + buffer[BACKOFF_OFFSET] = (buffer[GSIZE_OFFSET] & 0x0f) | (backoff << 4); + } + void SetGroupSize(UINT8 gsize) + { + buffer[GSIZE_OFFSET] = (buffer[GSIZE_OFFSET] & 0xf0) | gsize; + } void SetFlavor(NormCmdMsg::Flavor flavor) {buffer[FLAVOR_OFFSET] = flavor;} // Message processing UINT16 GetSessionId() const {return (ntohs(*((UINT16*)(buffer+SESSION_ID_OFFSET))));} UINT8 GetGrtt() const {return buffer[GRTT_OFFSET];} - UINT8 GetGroupSize() const {return buffer[GSIZE_OFFSET];} + UINT8 GetBackoffFactor() const {return ((buffer[GSIZE_OFFSET] >> 4) & 0x0f);} + UINT8 GetGroupSize() const {return (buffer[GSIZE_OFFSET] & 0x0f);} NormCmdMsg::Flavor GetFlavor() const {return (Flavor)buffer[FLAVOR_OFFSET];} protected: + friend class NormMsg; enum { SESSION_ID_OFFSET = MSG_OFFSET, GRTT_OFFSET = SESSION_ID_OFFSET + 2, - GSIZE_OFFSET = GRTT_OFFSET + 1, + BACKOFF_OFFSET = GRTT_OFFSET + 1, + GSIZE_OFFSET = BACKOFF_OFFSET, FLAVOR_OFFSET = GSIZE_OFFSET + 1 }; }; // end class NormCmdMsg diff --git a/common/normNode.cpp b/common/normNode.cpp index d100159..349fee3 100644 --- a/common/normNode.cpp +++ b/common/normNode.cpp @@ -37,12 +37,18 @@ NormServerNode::NormServerNode(class NormSession* theSession, NormNodeId nodeId) recv_total(0), recv_goodput(0), resync_count(0), nack_count(0), suppress_count(0), completion_count(0), failure_count(0) { - repair_timer.Init(0.0, 1, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormServerNode::OnRepairTimeout); - activity_timer.Init(0.0, -1, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormServerNode::OnActivityTimeout); - cc_timer.Init(0.0, 1, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormServerNode::OnCCTimeout); + repair_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormServerNode::OnRepairTimeout); + repair_timer.SetInterval(0.0); + repair_timer.SetRepeat(1); + + activity_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormServerNode::OnActivityTimeout); + activity_timer.SetInterval(NormSession::DEFAULT_GRTT_ESTIMATE*NORM_ROBUST_FACTOR); + activity_timer.SetRepeat(NORM_ROBUST_FACTOR); + + cc_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormServerNode::OnCCTimeout); + cc_timer.SetInterval(0.0); + cc_timer.SetRepeat(1); + grtt_send_time.tv_sec = 0; grtt_send_time.tv_usec = 0; grtt_quantized = NormQuantizeRtt(NormSession::DEFAULT_GRTT_ESTIMATE); @@ -50,6 +56,8 @@ NormServerNode::NormServerNode(class NormSession* theSession, NormNodeId nodeId) gsize_quantized = NormQuantizeGroupSize(NormSession::DEFAULT_GSIZE_ESTIMATE); gsize_estimate = NormUnquantizeGroupSize(gsize_quantized); + backoff_factor = NormSession::DEFAULT_BACKOFF_FACTOR; + rtt_quantized = NormQuantizeRtt(NormSession::DEFAULT_GRTT_ESTIMATE); rtt_estimate = NormUnquantizeRtt(rtt_quantized); @@ -142,6 +150,7 @@ bool NormServerNode::Open(UINT16 sessionId, UINT16 segmentSize, UINT16 numData, void NormServerNode::Close() { + if (activity_timer.IsActive()) activity_timer.Deactivate(); decoder.Destroy(); if (erasure_loc) { @@ -169,9 +178,9 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime, grtt_quantized = grttQuantized; grtt_estimate = NormUnquantizeRtt(grttQuantized); DMSG(4, "NormServerNode::HandleCommand() node>%lu server>%lu new grtt: %lf sec\n", - LocalNodeId(), Id(), grtt_estimate); - activity_timer.SetInterval(grtt_estimate); - activity_timer.Reset(); + LocalNodeId(), GetId(), grtt_estimate); + activity_timer.SetInterval(grtt_estimate*NORM_ROBUST_FACTOR); + if (activity_timer.IsActive()) activity_timer.Reschedule(); } UINT8 gsizeQuantized = cmd.GetGroupSize(); if (gsizeQuantized != gsize_quantized) @@ -179,8 +188,9 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime, gsize_quantized = gsizeQuantized; gsize_estimate = NormUnquantizeGroupSize(gsizeQuantized); DMSG(4, "NormServerNode::HandleCommand() node>%lu server>%lu new group size:%lf\n", - LocalNodeId(), Id(), gsize_estimate); + LocalNodeId(), GetId(), gsize_estimate); } + backoff_factor = (double)cmd.GetBackoffFactor(); NormCmdMsg::Flavor flavor = cmd.GetFlavor(); switch (flavor) @@ -255,8 +265,8 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime, { // Respond immediately if (cc_timer.IsActive()) cc_timer.Deactivate(); - cc_timer.ResetRepeats(); - OnCCTimeout(); + cc_timer.ResetRepeat(); + OnCCTimeout(cc_timer); } else if (!cc_timer.IsActive()) { @@ -292,7 +302,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime, cc_timer.SetInterval(backoffTime); DMSG(4, "NormServerNode::HandleCommand() node>%lu begin CC back-off: %lf sec)...\n", LocalNodeId(), backoffTime); - session->InstallTimer(&cc_timer); + session->ActivateTimer(cc_timer); } } // end if (CC_RATE == ext.GetType()) } // end while (GetNextExtension()) @@ -316,7 +326,8 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime, { const NormCmdRepairAdvMsg& repairAdv = (const NormCmdRepairAdvMsg&)cmd; // Does the CC feedback of this ACK suppress our CC feedback - if (!is_clr && !is_plr && cc_timer.IsActive() && cc_timer.RepeatCount()) + if (!is_clr && !is_plr && cc_timer.IsActive() && + cc_timer.GetRepeatCount()) { NormCCFeedbackExtension ext; while (repairAdv.GetNextExtension(ext)) @@ -328,7 +339,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime, } } } - if (repair_timer.IsActive() && repair_timer.RepeatCount()) + if (repair_timer.IsActive() && repair_timer.GetRepeatCount()) { HandleRepairContent(repairAdv.GetRepairContent(), repairAdv.GetRepairContentLength()); @@ -345,7 +356,7 @@ void NormServerNode::HandleCommand(const struct timeval& currentTime, void NormServerNode::HandleCCFeedback(UINT8 ccFlags, double ccRate) { - ASSERT(cc_timer.IsActive() && cc_timer.RepeatCount()); + ASSERT(cc_timer.IsActive() && cc_timer.GetRepeatCount()); if (0 == (ccFlags & NormCC::CLR)) { // We're suppressed by non-CLR receivers with no RTT confirmed @@ -386,7 +397,7 @@ void NormServerNode::HandleCCFeedback(UINT8 ccFlags, double ccRate) { if (cc_timer.IsActive()) cc_timer.Deactivate(); cc_timer.SetInterval(grtt_estimate*session->BackoffFactor()); - session->InstallTimer(&cc_timer); + session->ActivateTimer(cc_timer); cc_timer.DecrementRepeatCount(); } } @@ -395,7 +406,7 @@ void NormServerNode::HandleCCFeedback(UINT8 ccFlags, double ccRate) void NormServerNode::HandleAckMessage(const NormAckMsg& ack) { // Does the CC feedback of this ACK suppress our CC feedback - if (!is_clr && !is_plr && cc_timer.IsActive() && cc_timer.RepeatCount()) + if (!is_clr && !is_plr && cc_timer.IsActive() && cc_timer.GetRepeatCount()) { NormCCFeedbackExtension ext; while (ack.GetNextExtension(ext)) @@ -412,7 +423,7 @@ void NormServerNode::HandleAckMessage(const NormAckMsg& ack) void NormServerNode::HandleNackMessage(const NormNackMsg& nack) { // Does the CC feedback of this NACK suppress our CC feedback - if (!is_clr && !is_plr && cc_timer.IsActive() && cc_timer.RepeatCount()) + if (!is_clr && !is_plr && cc_timer.IsActive() && cc_timer.GetRepeatCount()) { NormCCFeedbackExtension ext; while (nack.GetNextExtension(ext)) @@ -425,7 +436,7 @@ void NormServerNode::HandleNackMessage(const NormNackMsg& nack) } } // Clients also care about recvd NACKS for NACK suppression - if (repair_timer.IsActive() && repair_timer.RepeatCount()) + if (repair_timer.IsActive() && repair_timer.GetRepeatCount()) HandleRepairContent(nack.GetRepairContent(), nack.GetRepairContentLength()); } // end NormServerNode::HandleNackMessage() @@ -441,7 +452,7 @@ void NormServerNode::HandleRepairContent(const char* buffer, UINT16 bufferLen) NormObjectId prevObjectId; NormObject* object = NULL; bool freshBlock = true; - NormBlockId prevBlockId; + NormBlockId prevBlockId = 0; NormBlock* block = NULL; while ((requestLength = req.Unpack(buffer, bufferLen))) { @@ -670,9 +681,9 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) grtt_quantized = grttQuantized; grtt_estimate = NormUnquantizeRtt(grttQuantized); DMSG(4, "NormServerNode::HandleObjectMessage() node>%lu server>%lu new grtt: %lf sec\n", - LocalNodeId(), Id(), grtt_estimate); - activity_timer.SetInterval(grtt_estimate); - activity_timer.Reset(); + LocalNodeId(), GetId(), grtt_estimate); + activity_timer.SetInterval(grtt_estimate*NORM_ROBUST_FACTOR); + if (activity_timer.IsActive()) activity_timer.Reschedule(); } UINT8 gsizeQuantized = msg.GetGroupSize(); if (gsizeQuantized != gsize_quantized) @@ -680,8 +691,9 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) gsize_quantized = gsizeQuantized; gsize_estimate = NormUnquantizeGroupSize(gsizeQuantized); DMSG(4, "NormServerNode::HandleObjectMessage() node>%lu server>%lu new group size: %lf\n", - LocalNodeId(), Id(), gsize_estimate); + LocalNodeId(), GetId(), gsize_estimate); } + backoff_factor = (double)msg.GetBackoffFactor(); if (IsOpen()) @@ -689,7 +701,7 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) if (msg.GetSessionId() != session_id) { DMSG(2, "NormServerNode::HandleObjectMessage() node>%lu server>%lu sessionId change - resyncing.\n", - LocalNodeId(), Id()); + LocalNodeId(), GetId()); Close(); resync_count++; } @@ -711,7 +723,7 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) fti.GetFecNumParity())) { DMSG(0, "NormServerNode::HandleObjectMessage() node>%lu server>%lu open error\n", - LocalNodeId(), Id()); + LocalNodeId(), GetId()); // (TBD) notify app of error ?? return; } @@ -721,7 +733,7 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) if (!IsOpen()) { DMSG(0, "NormServerNode::HandleObjectMessage() node>%lu server>%lu - no FTI provided!\n", - LocalNodeId(), Id()); + LocalNodeId(), GetId()); // (TBD) notify app of error ?? return; } @@ -770,7 +782,8 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) switch (status) { case OBJ_PENDING: - if ((obj = rx_table.Find(objectId))) break; + if ((obj = rx_table.Find(objectId))) + break; case OBJ_NEW: { if (msg.FlagIsSet(NormObjectMsg::FLAG_STREAM)) @@ -816,7 +829,7 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) ((NormStreamObject*)obj)->StreamUpdateStatus(blockId); rx_table.Insert(obj); DMSG(8, "NormServerNode::HandleObjectMessage() node>%lu server>%lu new obj>%hu\n", - LocalNodeId(), Id(), (UINT16)objectId); + LocalNodeId(), GetId(), (UINT16)objectId); } else { @@ -835,7 +848,7 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) if (obj && !obj->IsOpen()) { DMSG(0, "NormServerNode::HandleObjectMessage() node>%lu server>%lu " - "new obj>%hu - no FTI provided!\n", LocalNodeId(), Id(), (UINT16)objectId); + "new obj>%hu - no FTI provided!\n", LocalNodeId(), GetId(), (UINT16)objectId); DeleteObject(obj); obj = NULL; } @@ -855,7 +868,7 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) obj->HandleObjectMessage(msg, msgType, blockId, segmentId); if (!obj->IsPending()) { - + // Reliable reception of this object has completed if (NormObject::FILE == obj->GetType()) #ifdef SIMULATE ((NormSimObject*)obj)->Close(); @@ -870,8 +883,7 @@ void NormServerNode::HandleObjectMessage(const NormObjectMsg& msg) completion_count++; } } - } - + } RepairCheck(NormObject::TO_BLOCK, objectId, blockId, segmentId); } // end NormServerNode::HandleObjectMessage() @@ -897,8 +909,8 @@ void NormServerNode::Sync(NormObjectId objectId) { if (rx_pending_mask.IsSet()) { - NormObjectId firstSet = NormObjectId(rx_pending_mask.FirstSet()); - if ((objectId > NormObjectId(rx_pending_mask.LastSet())) || + NormObjectId firstSet = NormObjectId((UINT16)rx_pending_mask.FirstSet()); + if ((objectId > NormObjectId((UINT16)rx_pending_mask.LastSet())) || ((next_id - objectId) > 256)) { NormObject* obj; @@ -949,7 +961,7 @@ NormServerNode::ObjectStatus NormServerNode::UpdateSyncStatus(const NormObjectId // or revert to fresh sync if sync is totally lost, // otherwise SQUELCH process will get things in order DMSG(2, "NormServerNode::HandleObjectMessage() node>%lu re-syncing to server>%lu...\n", - LocalNodeId(), Id()); + LocalNodeId(), GetId()); Sync(objectId); resync_count++; status = OBJ_NEW; @@ -975,7 +987,7 @@ void NormServerNode::SetPending(NormObjectId objectId) rx_pending_mask.SetBits(next_id, objectId - next_id + 1); next_id = objectId + 1; // This prevents the "sync_id" from getting stale - sync_id = rx_pending_mask.FirstSet(); + sync_id = (UINT16)rx_pending_mask.FirstSet(); } } // end NormServerNode::SetPending() @@ -1024,7 +1036,7 @@ NormServerNode::ObjectStatus NormServerNode::GetObjectStatus(const NormObjectId& else { NormObjectId delta = objectId - next_id + 1; - if (delta > NormObjectId(rx_pending_mask.Size())) + if (delta > NormObjectId((UINT16)rx_pending_mask.Size())) { return OBJ_INVALID; } @@ -1056,8 +1068,8 @@ void NormServerNode::RepairCheck(NormObject::CheckLevel checkLevel, if (rx_pending_mask.IsSet()) { if (rx_repair_mask.IsSet()) rx_repair_mask.Clear(); - NormObjectId nextId = rx_pending_mask.FirstSet(); - NormObjectId lastId = rx_pending_mask.LastSet(); + NormObjectId nextId = (UINT16)rx_pending_mask.FirstSet(); + NormObjectId lastId = (UINT16)rx_pending_mask.LastSet(); if (objectId < lastId) lastId = objectId; while (nextId <= lastId) { @@ -1077,7 +1089,7 @@ void NormServerNode::RepairCheck(NormObject::CheckLevel checkLevel, startTimer = true; } nextId++; - nextId = rx_pending_mask.NextSet(nextId); + nextId = (UINT16)rx_pending_mask.NextSet(nextId); } current_object_id = objectId; if (startTimer) @@ -1090,11 +1102,11 @@ void NormServerNode::RepairCheck(NormObject::CheckLevel checkLevel, repair_timer.SetInterval(backoffInterval); DMSG(3, "NormServerNode::RepairCheck() node>%lu begin NACK back-off: %lf sec)...\n", LocalNodeId(), backoffInterval); - session->InstallTimer(&repair_timer); + session->ActivateTimer(repair_timer); } } } - else if (repair_timer.RepeatCount()) + else if (repair_timer.GetRepeatCount()) { // Repair timer in backoff phase // Trim server current transmit position reference @@ -1115,7 +1127,7 @@ void NormServerNode::RepairCheck(NormObject::CheckLevel checkLevel, if (rewindDetected) { repair_timer.Deactivate(); - DMSG(0, "NormServerNode::RepairCheck() node>%lu server rewind detected, ending NACK hold-off ...\n", + DMSG(4, "NormServerNode::RepairCheck() node>%lu server rewind detected, ending NACK hold-off ...\n", LocalNodeId()); RepairCheck(checkLevel, objectId, blockId, segmentId); @@ -1125,10 +1137,10 @@ void NormServerNode::RepairCheck(NormObject::CheckLevel checkLevel, // When repair timer fires, possibly build a NACK // and queue for transmission to this server node -bool NormServerNode::OnRepairTimeout() +bool NormServerNode::OnRepairTimeout(ProtoTimer& /*theTimer*/) { - switch(repair_timer.RepeatCount()) + switch(repair_timer.GetRepeatCount()) { case 0: // hold-off time complete DMSG(4, "NormServerNode::OnRepairTimeout() node>%lu end NACK hold-off ...\n", @@ -1143,8 +1155,8 @@ bool NormServerNode::OnRepairTimeout() if (rx_pending_mask.IsSet()) { bool repairPending = false; - NormObjectId nextId = rx_pending_mask.FirstSet(); - NormObjectId lastId = rx_pending_mask.LastSet(); + NormObjectId nextId = (UINT16)rx_pending_mask.FirstSet(); + NormObjectId lastId = (UINT16)rx_pending_mask.LastSet(); if (current_object_id < lastId) lastId = current_object_id; while (nextId <= lastId) { @@ -1158,7 +1170,7 @@ bool NormServerNode::OnRepairTimeout() } } nextId++; - nextId = rx_pending_mask.NextSet(nextId); + nextId = (UINT16)rx_pending_mask.NextSet(nextId); } // end while (nextId <= current_block_id) if (repairPending) { @@ -1208,7 +1220,7 @@ bool NormServerNode::OnRepairTimeout() { cc_timer.Deactivate(); cc_timer.SetInterval(grtt_estimate*session->BackoffFactor()); - session->InstallTimer(&cc_timer); + session->ActivateTimer(cc_timer); cc_timer.DecrementRepeatCount(); } } @@ -1217,8 +1229,8 @@ bool NormServerNode::OnRepairTimeout() NormObjectId prevId; UINT16 reqCount = 0; NormRepairRequest::Form prevForm = NormRepairRequest::INVALID; - nextId = rx_pending_mask.FirstSet(); - lastId = rx_pending_mask.LastSet(); + nextId = (UINT16)rx_pending_mask.FirstSet(); + lastId = (UINT16)rx_pending_mask.LastSet(); if (max_pending_object < lastId) lastId = max_pending_object; lastId++; // force loop to fully flush nack building. while ((nextId <= lastId) || (reqCount > 0)) @@ -1298,12 +1310,12 @@ bool NormServerNode::OnRepairTimeout() } nextId++; if (nextId <= lastId) - nextId = rx_pending_mask.NextSet(nextId); + nextId = (UINT16)rx_pending_mask.NextSet(nextId); } // end while(nextId <= lastId) if (NormRepairRequest::INVALID != prevForm) nack->PackRepairRequest(req); // (TBD) error check // Queue NACK for transmission - nack->SetServerId(Id()); + nack->SetServerId(GetId()); nack->SetSessionId(session_id); // GRTT response is deferred until transmit time @@ -1382,29 +1394,30 @@ void NormServerNode::Activate() { if (activity_timer.IsActive()) { - activity_timer.ResetRepeats(); + activity_timer.ResetRepeat(); } else { - activity_timer.SetInterval(grtt_estimate); - session->InstallTimer(&activity_timer); + activity_timer.SetInterval(grtt_estimate*NORM_ROBUST_FACTOR); + session->ActivateTimer(activity_timer); } } // end NormServerNode::Activate() -bool NormServerNode::OnActivityTimeout() +bool NormServerNode::OnActivityTimeout(ProtoTimer& /*theTimer*/) { - if ((activity_timer.Repeats() - activity_timer.RepeatCount()) > 1) + if ((activity_timer.GetRepeat() - activity_timer.GetRepeatCount()) > 1) { DMSG(4, "NormServerNode::OnActivityTimeout() node>%lu for server>%lu\n", - LocalNodeId(), Id()); + LocalNodeId(), GetId()); struct timeval currentTime; - ::GetSystemTime(¤tTime); + ::ProtoSystemTime(currentTime); UpdateRecvRate(currentTime, 0); } - if (!activity_timer.RepeatCount()) + if (0 == activity_timer.GetRepeatCount()) { DMSG(0, "NormServerNode::OnActivityTimeout() node>%lu server>%lu gone inactive?\n", - LocalNodeId(), Id()); + LocalNodeId(), GetId()); + Close(); } return true; } // end NormServerNode::OnActivityTimeout() @@ -1427,10 +1440,10 @@ bool NormServerNode::UpdateLossEstimate(const struct timeval& currentTime, return result; } -bool NormServerNode::OnCCTimeout() +bool NormServerNode::OnCCTimeout(ProtoTimer& /*theTimer*/) { // Build and queue ACK() - switch (cc_timer.RepeatCount()) + switch (cc_timer.GetRepeatCount()) { case 0: // "hold-off" time has ended @@ -1448,7 +1461,7 @@ bool NormServerNode::OnCCTimeout() return false; } ack->Init(); - ack->SetServerId(Id()); + ack->SetServerId(GetId()); ack->SetSessionId(session_id); ack->SetAckType(NormAck::CC); ack->SetAckId(0); @@ -1522,7 +1535,7 @@ NormNodeTree::~NormNodeTree() } -NormNode *NormNodeTree::FindNodeById(unsigned long nodeId) const +NormNode *NormNodeTree::FindNodeById(NormNodeId nodeId) const { NormNode* x = root; while(x && (x->id != nodeId)) @@ -1854,7 +1867,8 @@ double NormLossEstimator::LossFraction() double s0 = 0.0; const double* wptr = weight; const unsigned int* h = history; - for (unsigned int i = 0; i < DEPTH; i++) + unsigned int i; + for (i = 0; i < DEPTH; i++) { if (0 == *h) break; s0 += *wptr * *h++; @@ -1866,7 +1880,7 @@ double NormLossEstimator::LossFraction() double s1 = 0.0; wptr = weight; h = history + 1; - for (unsigned int i = 0; i < DEPTH; i++) + for (i = 0; i < DEPTH; i++) { if (0 == *h) break; s1 += *wptr * *h++; // ave loss interval w/out current interval diff --git a/common/normNode.h b/common/normNode.h index 6c9904e..0f0d48d 100644 --- a/common/normNode.h +++ b/common/normNode.h @@ -4,7 +4,8 @@ #include "normMessage.h" #include "normObject.h" #include "normEncoder.h" -#include "protocolTimer.h" +#include "protokit.h" + class NormNode { friend class NormNodeTree; @@ -16,28 +17,22 @@ class NormNode NormNode(class NormSession* theSession, NormNodeId nodeId); virtual ~NormNode(); - void SetAddress(const NetworkAddress& address) {addr = address;} - const NetworkAddress& GetAddress() const {return addr;} - - const NormNodeId& Id() const {return id;} - inline const NormNodeId& LocalNodeId() const; - + const ProtoAddress& GetAddress() const {return addr;} + void SetAddress(const ProtoAddress& address) {addr = address;} + const NormNodeId& GetId() const {return id;} void SetId(const NormNodeId& nodeId) {id = nodeId;} + inline const NormNodeId& LocalNodeId() const; protected: - class NormSession* session; + class NormSession* session; private: - NormNodeId id; - NetworkAddress addr; - - NormNode* parent; - NormNode* right; - NormNode* left; - - //NormNode* prev; - //NormNode* next; - + NormNodeId id; + ProtoAddress addr; + // We keep NormNodes in a binary tree + NormNode* parent; + NormNode* right; + NormNode* left; }; // end class NormNode // Weighted-history loss event estimator @@ -156,7 +151,7 @@ class NormCCNode : public NormNode double GetRtt() const {return rtt;} double GetLoss() const {return loss;} double GetRate() const {return rate;} - UINT8 GetCCSequence() const {return cc_sequence;} + UINT16 GetCCSequence() const {return cc_sequence;} void SetActive(bool state) {is_active = state;} void SetClrStatus(bool state) {is_clr = state;} @@ -169,7 +164,7 @@ class NormCCNode : public NormNode } void SetLoss(double value) {loss = value;} void SetRate(double value) {rate = value;} - void SetCCSequence(UINT8 value) {cc_sequence = value;} + void SetCCSequence(UINT16 value) {cc_sequence = value;} private: bool is_clr; // true if worst path representative @@ -179,7 +174,7 @@ class NormCCNode : public NormNode double rtt; // in seconds double loss; // loss fraction double rate; // in bytes per second - UINT8 cc_sequence; + UINT16 cc_sequence; }; // end class NormCCNode class NormServerNode : public NormNode @@ -275,9 +270,9 @@ class NormServerNode : public NormNode NormBlockId blockId, NormSegmentId segmentId); - bool OnActivityTimeout(); - bool OnRepairTimeout(); - bool OnCCTimeout(); + bool OnActivityTimeout(ProtoTimer& theTimer); + bool OnRepairTimeout(ProtoTimer& theTimer); + bool OnCCTimeout(ProtoTimer& theTimer); void HandleRepairContent(const char* buffer, UINT16 bufferLen); UINT16 session_id; @@ -298,25 +293,26 @@ class NormServerNode : public NormNode NormDecoder decoder; UINT16* erasure_loc; - ProtocolTimer activity_timer; - ProtocolTimer repair_timer; + ProtoTimer activity_timer; + ProtoTimer repair_timer; NormObjectId current_object_id; // index for suppression NormObjectId max_pending_object; // index for NACK construction - + + // Remote server grtt measurement state double grtt_estimate; UINT8 grtt_quantized; struct timeval grtt_send_time; struct timeval grtt_recv_time; double gsize_estimate; UINT8 gsize_quantized; + double backoff_factor; - // Congestion control state + // Remote server congestion control state NormLossEstimator2 loss_estimator; - //NormLossEstimator loss_estimator; - UINT8 cc_sequence; + UINT16 cc_sequence; bool cc_enable; - double cc_rate; // ccRate at start of cc_timer - ProtocolTimer cc_timer; + double cc_rate; // ccRate at start of cc_timer + ProtoTimer cc_timer; double rtt_estimate; UINT8 rtt_quantized; bool rtt_confirmed; @@ -330,13 +326,13 @@ class NormServerNode : public NormNode double nominal_packet_size; // For statistics tracking - unsigned long recv_total; // total recvd accumulator - unsigned long recv_goodput; // goodput recvd accumulator + unsigned long recv_total; // total recvd accumulator + unsigned long recv_goodput; // goodput recvd accumulator unsigned long resync_count; unsigned long nack_count; unsigned long suppress_count; unsigned long completion_count; - unsigned long failure_count; // due to re-syncs + unsigned long failure_count; // usually due to re-syncs }; // end class NormServerNode diff --git a/common/normObject.cpp b/common/normObject.cpp index 797399f..b0283ae 100644 --- a/common/normObject.cpp +++ b/common/normObject.cpp @@ -49,8 +49,8 @@ bool NormObject::Open(const NormObjectSize& objectSize, if (server) { segmentSize = server->SegmentSize(); - numData = server->BlockSize(); - numParity = server->NumParity(); + numData = server->BlockSize(); // max source symbols per FEC block + numParity = server->NumParity(); // max parity symbols per FEC block if (infoLen > 0) { pending_info = true; @@ -65,8 +65,8 @@ bool NormObject::Open(const NormObjectSize& objectSize, else { segmentSize = session->ServerSegmentSize(); - numData = session->ServerBlockSize(); - numParity = session->ServerNumParity(); + numData = session->ServerBlockSize(); // max source symbols per FEC block + numParity = session->ServerNumParity(); // max parity symbols per FEC block if (infoPtr) { if (info) delete []info; @@ -88,11 +88,16 @@ bool NormObject::Open(const NormObjectSize& objectSize, } } - // Make sure object size and block/segment sizes are compatible - NormObjectSize blockSize((UINT32)segmentSize * (UINT32)numData); - NormObjectSize numBlocks = objectSize / blockSize; + // Compute number of segments and coding blocks for the object + // (Note NormObjectSize divide operator always rounds _up_) + NormObjectSize numSegments = objectSize / NormObjectSize(segmentSize); + NormObjectSize numBlocks = numSegments / NormObjectSize(numData); ASSERT(0 == numBlocks.MSB()); + + + + if (!block_buffer.Init(numBlocks.LSB())) { DMSG(0, "NormObject::Open() init block_buffer error\n"); @@ -119,28 +124,44 @@ bool NormObject::Open(const NormObjectSize& objectSize, } repair_mask.Clear(); + if (STREAM == type) { - last_block_id = 0; // not applicable for STREAM - last_block_size = numData; // assumed for STREAM + small_block_size = large_block_size = numData; + small_block_count = large_block_count = numBlocks.LSB(); + final_segment_size = segmentSize; NormStreamObject* stream = static_cast(this); stream->StreamResync(numBlocks.LSB()); } else { - last_block_id = numBlocks.LSB() - 1; - NormObjectSize lastBlockBytes = NormObjectSize(last_block_id) * blockSize; - lastBlockBytes = objectSize - lastBlockBytes; - NormObjectSize lastBlockSize = lastBlockBytes / NormObjectSize(segmentSize); - ASSERT(!lastBlockSize.MSB()); - ASSERT(lastBlockSize.LSB() <= numData); - last_block_size = lastBlockSize.LSB(); - NormObjectSize lastSegmentSize = - NormObjectSize(0,last_block_size-1) * NormObjectSize(segmentSize); - lastSegmentSize = lastBlockBytes - lastSegmentSize; - ASSERT(!lastSegmentSize.MSB()); - ASSERT(lastSegmentSize.LSB() <= segmentSize); - last_segment_size = lastSegmentSize.LSB(); + // Compute FEC block structure per NORM Protocol Spec Section 5.1.1 + // (Note NormObjectSize divide operator always rounds _up_) + NormObjectSize largeBlockSize = numSegments / numBlocks; + ASSERT(0 == largeBlockSize.MSB()); + large_block_size = largeBlockSize.LSB(); + if (numSegments == (numBlocks*largeBlockSize)) + { + small_block_size = large_block_size; + small_block_count = numBlocks.LSB(); + large_block_count = 0; + } + else + { + small_block_size = large_block_size - 1; + NormObjectSize largeBlockCount = numSegments - numBlocks*small_block_size; + ASSERT(0 == largeBlockCount.MSB()); + large_block_count = largeBlockCount.LSB(); + NormObjectSize smallBlockCount = numBlocks - largeBlockCount; + ASSERT(0 == smallBlockCount.MSB()); + small_block_count = smallBlockCount.LSB(); + } + + final_block_id = large_block_count + small_block_count - 1; // not used for STREAM objects + NormObjectSize finalSegmentSize = + objectSize - (numSegments - NormObjectSize((UINT32)1))*segmentSize; + ASSERT(0 == finalSegmentSize.MSB()); + final_segment_size = finalSegmentSize.LSB(); } object_size = objectSize; @@ -233,7 +254,7 @@ bool NormObject::TxReset(NormBlockId firstBlock) NormBlockId blockId = block->Id(); if (blockId >= firstBlock) { - increasedRepair |= block->TxReset(BlockSize(blockId), + increasedRepair |= block->TxReset(GetBlockSize(blockId), nparity, session->ServerAutoParity(), segment_size); @@ -255,7 +276,7 @@ bool NormObject::TxResetBlocks(NormBlockId nextId, NormBlockId lastId) } NormBlock* block = block_buffer.Find(nextId); if (block) - increasedRepair |= block->TxReset(BlockSize(block->Id()), nparity, autoParity, segment_size); + increasedRepair |= block->TxReset(GetBlockSize(block->Id()), nparity, autoParity, segment_size); nextId++; } return increasedRepair; @@ -286,7 +307,7 @@ bool NormObject::ActivateRepairs() while (nextId <= lastId) { NormBlock* block = block_buffer.Find(nextId); - if (block) block->TxReset(BlockSize(nextId), nparity, autoParity, segment_size); + if (block) block->TxReset(GetBlockSize(nextId), nparity, autoParity, segment_size); // (TBD) This check can be eventually eliminated if everything else is done right if (!pending_mask.Set(nextId)) DMSG(0, "NormObject::ActivateRepairs() pending_mask.Set(%lu) error!\n", @@ -526,12 +547,15 @@ bool NormObject::ClientRepairCheck(CheckLevel level, if (blockId > max_pending_block) { max_pending_block = blockId; - max_pending_segment = BlockSize(blockId); + max_pending_segment = GetBlockSize(blockId); } break; case THRU_OBJECT: - if (!IsStream()) max_pending_block = last_block_id; - max_pending_segment = BlockSize(max_pending_block); + if (!IsStream()) + max_pending_block = final_block_id; + else if (blockId > max_pending_block) + max_pending_block = blockId; + max_pending_segment = GetBlockSize(max_pending_block); default: break; } // end switch (level) @@ -568,7 +592,7 @@ bool NormObject::ClientRepairCheck(CheckLevel level, if (blockId < current_block_id) { current_block_id = blockId; - next_segment_id = BlockSize(blockId); + next_segment_id = GetBlockSize(blockId); } break; default: @@ -633,14 +657,14 @@ bool NormObject::ClientRepairCheck(CheckLevel level, break; case THRU_BLOCK: current_block_id = blockId; - next_segment_id = BlockSize(blockId); + next_segment_id = GetBlockSize(blockId); break; case THRU_OBJECT: if (IsStream()) current_block_id = max_pending_block; else - current_block_id = last_block_id; - next_segment_id = BlockSize(current_block_id); + current_block_id = final_block_id; + next_segment_id = GetBlockSize(current_block_id); default: break; } @@ -665,7 +689,7 @@ bool NormObject::IsRepairPending(bool flush) if (block) { bool isPending; - UINT16 numData = BlockSize(nextId); + UINT16 numData = GetBlockSize(nextId); if (flush || (nextId < lastId)) { isPending = block->IsRepairPending(numData, nparity); @@ -788,7 +812,7 @@ bool NormObject::AppendRepairRequest(NormNackMsg& nack, } // end if/else (!blockPending && reqCount && (reqCount == (nextId - prevId))) if (blockPending) { - UINT16 numData = BlockSize(nextId); + UINT16 numData = GetBlockSize(nextId); if (NormRepairRequest::INVALID != prevForm) nack.PackRepairRequest(req); // (TBD) error check reqCount = 0; @@ -846,7 +870,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, { info_len = segment_size; DMSG(0, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu " - "Warning! info too long.\n", LocalNodeId(), server->Id(), (UINT16)id); + "Warning! info too long.\n", LocalNodeId(), server->GetId(), (UINT16)id); } memcpy(info, infoMsg.GetInfo(), info_len); pending_info = false; @@ -857,7 +881,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, // (TBD) Verify info hasn't changed? DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu " "received duplicate info ...\n", LocalNodeId(), - server->Id(), (UINT16)id); + server->GetId(), (UINT16)id); } } else // NORM_MSG_DATA @@ -870,7 +894,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, if (!stream->StreamUpdateStatus(blockId)) { DMSG(4, "NormObject::HandleObjectMessage() node:%lu server:%lu obj>%hu blk>%lu " - "broken stream ...\n", LocalNodeId(), server->Id(), (UINT16)id, (UINT32)blockId); + "broken stream ...\n", LocalNodeId(), server->GetId(), (UINT16)id, (UINT32)blockId); //ASSERT(0); // ??? Ignore this new packet and try to fix stream ??? @@ -898,7 +922,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, } } } - UINT16 numData = BlockSize(blockId); + UINT16 numData = GetBlockSize(blockId); if (pending_mask.Test(blockId)) { NormBlock* block = block_buffer.Find(blockId); @@ -907,7 +931,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, if (!(block = server->GetFreeBlock(id, blockId))) { DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu " - "Warning! no free blocks ...\n", LocalNodeId(), server->Id(), + "Warning! no free blocks ...\n", LocalNodeId(), server->GetId(), (UINT16)id); return; } @@ -921,7 +945,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, if (!segment) { DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu " - "Warning! no free segments ...\n", LocalNodeId(), server->Id(), + "Warning! no free segments ...\n", LocalNodeId(), server->GetId(), (UINT16)id); return; } @@ -929,7 +953,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, if (segmentLen > segment_size) { DMSG(0, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu " - "Error! segment too large ...\n", LocalNodeId(), server->Id(), + "Error! segment too large ...\n", LocalNodeId(), server->GetId(), (UINT16)id); server->PutFreeSegment(segment); return; @@ -975,7 +999,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, // Decode (if pending_mask.FirstSet() < numData) // and write any decoded data segments to object DMSG(8, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu blk>%lu " - "completed block ...\n", LocalNodeId(), server->Id(), + "completed block ...\n", LocalNodeId(), server->GetId(), (UINT16)id, (UINT32)block->Id()); UINT16 nextErasure = block->FirstPending(); UINT16 erasureCount = 0; @@ -990,7 +1014,7 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, if (!(segment = server->GetFreeSegment(id, blockId))) { DMSG(2, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu " - "Warning! no free segments ...\n", LocalNodeId(), server->Id(), + "Warning! no free segments ...\n", LocalNodeId(), server->GetId(), (UINT16)id); // (TBD) Dump the block ...??? return; @@ -1040,14 +1064,14 @@ void NormObject::HandleObjectMessage(const NormObjectMsg& msg, { DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu " "received duplicate segment ...\n", LocalNodeId(), - server->Id(), (UINT16)id); + server->GetId(), (UINT16)id); } } else { DMSG(6, "NormObject::HandleObjectMessage() node>%lu server>%lu obj>%hu " "received duplicate block message ...\n", LocalNodeId(), - server->Id(), (UINT16)id); + server->GetId(), (UINT16)id); } // end if/else pending_mask.Test(blockId) } // end if/else (NORM_MSG_INFO) } // end NormObject::HandleObjectMessage() @@ -1183,7 +1207,7 @@ bool NormObject::NextServerMsg(NormObjectMsg* msg) NormDataMsg* data = (NormDataMsg*)msg; NormBlockId blockId = pending_mask.FirstSet(); - UINT16 numData = BlockSize(blockId); + UINT16 numData = GetBlockSize(blockId); NormBlock* block = block_buffer.Find(blockId); if (!block) { @@ -1345,7 +1369,7 @@ void NormStreamObject::StreamAdvance() bool NormObject::CalculateBlockParity(NormBlock* block) { char buffer[NormMsg::MAX_SIZE]; - UINT16 numData = BlockSize(block->Id()); + UINT16 numData = GetBlockSize(block->Id()); for (UINT16 i = 0; i < numData; i++) { if (ReadSegment(block->Id(), i, buffer)) @@ -1369,7 +1393,7 @@ NormBlock* NormObject::ServerRecoverBlock(NormBlockId blockId) NormBlock* block = session->ServerGetFreeBlock(id, blockId); if (block) { - UINT16 numData = BlockSize(blockId); + UINT16 numData = GetBlockSize(blockId); // Init block parameters block->TxRecover(blockId, numData, nparity); // Fill block with zero initialized parity segments @@ -1427,7 +1451,8 @@ NormBlock* NormObject::ServerRecoverBlock(NormBlockId blockId) NormFileObject::NormFileObject(class NormSession* theSession, class NormServerNode* theServer, const NormObjectId& objectId) - : NormObject(FILE, theSession, theServer, objectId), block_size(0,0) + : NormObject(FILE, theSession, theServer, objectId), + large_block_length(0,0), small_block_length(0,0) { path[0] = '\0'; } @@ -1462,15 +1487,15 @@ bool NormFileObject::Open(const char* thePath, return false; } } - block_size = NormObjectSize(server->BlockSize()) * - NormObjectSize(server->SegmentSize()); + //block_size = NormObjectSize(server->BlockSize()) * + // NormObjectSize(server->SegmentSize()); } else { // We're sending this file if (file.Open(thePath, O_RDONLY)) { - unsigned long size = file.GetSize(); + UINT32 size = file.GetSize(); if (size) { if (!NormObject::Open(size, infoPtr, infoLen)) @@ -1486,8 +1511,8 @@ bool NormFileObject::Open(const char* thePath, file.Close(); return false; } - block_size = NormObjectSize(session->ServerBlockSize()) * - NormObjectSize(session->ServerSegmentSize()); + large_block_length = NormObjectSize(large_block_size) * segment_size; + small_block_length = NormObjectSize(small_block_size) * segment_size; } else { @@ -1526,13 +1551,20 @@ bool NormFileObject::WriteSegment(NormBlockId blockId, const char* buffer) { UINT16 len; - if ((blockId == last_block_id) && - (segmentId == (last_block_size-1))) - len = last_segment_size; + if (blockId == final_block_id) + { + if (segmentId == (GetBlockSize(blockId)-1)) + len = final_segment_size; + else + len = segment_size; + } else + { len = segment_size; + } NormObjectSize segmentOffset = NormDataMsg::ReadPayloadOffset(buffer); - off_t offset = segmentOffset.LSB() + (segmentOffset.MSB() * 0x100000000LL); + off_t offsetScaleMSB = 0xffffffff + 1; + off_t offset = (off_t)segmentOffset.LSB() + ((off_t)segmentOffset.MSB() * offsetScaleMSB); if (offset != file.GetOffset()) { if (!file.Seek(offset)) return false; @@ -1548,20 +1580,39 @@ bool NormFileObject::ReadSegment(NormBlockId blockId, { // Determine segment length UINT16 len; - if ((blockId == last_block_id) && - (segmentId == (last_block_size - 1))) - len = last_segment_size; + if (blockId == final_block_id) + { + if (segmentId == (GetBlockSize(blockId)-1)) + len = final_segment_size; + else + len = segment_size; + } else + { len = segment_size; + } // Determine segment offset from blockId::segmentId - NormObjectSize segmentOffset = NormObjectSize(blockId) * block_size; - segmentOffset = segmentOffset + (NormObjectSize(segmentId) * NormObjectSize(segment_size)); + NormObjectSize segmentOffset; + NormObjectSize segmentSize = NormObjectSize(segment_size); + if ((UINT32)blockId < large_block_count) + { + segmentOffset = large_block_length*(UINT32)blockId + segmentSize*segmentId; + } + else + { + segmentOffset = large_block_length*large_block_count; + UINT32 smallBlockIndex = (UINT32)blockId - large_block_count; + segmentOffset = segmentOffset + small_block_length*smallBlockIndex + + segmentSize *segmentId; + } NormDataMsg::WritePayloadLength(buffer, len); NormDataMsg::WritePayloadOffset(buffer, segmentOffset); - off_t offset = segmentOffset.LSB() + (segmentOffset.MSB() * 0x100000000LL); + off_t offsetScaleMSB = 0xffffffff + 1; + off_t offset = (off_t)segmentOffset.LSB() + ((off_t)segmentOffset.MSB() * offsetScaleMSB); if (offset != file.GetOffset()) { - if (!file.Seek(offset)) return false; + if (!file.Seek(offset)) + return false; } UINT16 nbytes = file.Read(buffer+NormDataMsg::PayloadHeaderLength(), len); return (len == nbytes); @@ -1609,7 +1660,7 @@ bool NormStreamObject::Open(unsigned long bufferSize, } NormObjectSize blockSize((UINT32)segmentSize * (UINT32)numData); - NormObjectSize numBlocks = NormObjectSize(bufferSize) / blockSize; + NormObjectSize numBlocks = NormObjectSize((UINT32)bufferSize) / blockSize; ASSERT(0 == numBlocks.MSB()); // Buffering requires at least 2 blocks numBlocks = MAX(2, numBlocks.LSB()); @@ -1642,7 +1693,7 @@ bool NormStreamObject::Open(unsigned long bufferSize, write_offset = read_offset = NormObjectSize((UINT32)0); if (!server) { - if (!NormObject::Open(NormObjectSize(bufferSize), infoPtr, infoLen)) + if (!NormObject::Open(NormObjectSize((UINT32)bufferSize), infoPtr, infoLen)) { DMSG(0, "NormStreamObject::Open() object open error\n"); Close(); @@ -1970,8 +2021,8 @@ void NormStreamObject::Prune(NormBlockId blockId) // Sequential (in order) read/write routines (TBD) Add a "Seek()" method bool NormStreamObject::Read(char* buffer, unsigned int* buflen, bool findMsgStart) { - unsigned long bytesRead = 0; - unsigned long bytesToRead = *buflen; + unsigned int bytesRead = 0; + unsigned int bytesToRead = *buflen; while (bytesToRead > 0) { NormBlock* block = stream_buffer.Find(read_index.block); @@ -2178,7 +2229,7 @@ unsigned long NormStreamObject::Write(const char* buffer, unsigned long len, boo #endif // if/else SIMULATE } - UINT16 count = len - nBytes; + UINT16 count = (UINT16)(len - nBytes); UINT16 space = segment_size - index; count = MIN(count, space); #ifdef SIMULATE diff --git a/common/normObject.h b/common/normObject.h index f1d62ce..d1a574f 100644 --- a/common/normObject.h +++ b/common/normObject.h @@ -28,9 +28,9 @@ class NormObject THRU_OBJECT }; - void Verify() const; - virtual ~NormObject(); + + // Object information NormObject::Type GetType() const {return type;} const NormObjectId& Id() const {return id;} const NormObjectSize& Size() const {return object_size;} @@ -60,10 +60,12 @@ class NormObject char* buffer) = 0; // These are only valid after object is open - NormBlockId LastBlockId() const {return last_block_id;} - NormSegmentId LastBlockSize() const {return last_block_size;} - NormSegmentId BlockSize(NormBlockId blockId) - {return ((blockId == last_block_id) ? last_block_size : ndata);} + NormBlockId GetFinalBlockId() const {return final_block_id;} + UINT32 GetBlockSize(NormBlockId blockId) + { + return (((UINT32)blockId < large_block_count) ? large_block_size : + small_block_size); + } bool IsPending(bool flush = true) const; bool IsRepairPending() const; @@ -84,12 +86,12 @@ class NormObject { NormBlockId blockId = theBlock->Id(); bool result = theBlock->TxUpdate(firstSegmentId, lastSegmentId, - BlockSize(blockId), nparity, + GetBlockSize(blockId), nparity, numErasures); ASSERT(result ? pending_mask.Set(blockId) : true); result = result ? pending_mask.Set(blockId) : false; return result; - } // end NormObject::TxUpdateBlock() + } bool HandleInfoRequest(); bool HandleBlockRequest(NormBlockId nextId, NormBlockId lastId); bool SetPending(NormBlockId blockId) {return pending_mask.Set(blockId);} @@ -98,7 +100,7 @@ class NormObject bool IsRepairSet(NormBlockId blockId) {return repair_mask.Test(blockId);} bool AppendRepairAdv(NormCmdRepairAdvMsg& cmd); - // Used by session server for resource management scheme + // Used by sender for resource management scheme NormBlock* StealNonPendingBlock(bool excludeBlock, NormBlockId excludeId = 0); @@ -110,7 +112,7 @@ class NormObject NormSegmentId segmentId); - // Used by remote server node for resource management scheme + // Used by receiver for resource management scheme NormBlock* StealNewestBlock(bool excludeBlock, NormBlockId excludeId = 0); NormBlock* StealOldestBlock(bool excludeBlock, NormBlockId excludeId = 0); @@ -129,7 +131,7 @@ class NormObject } protected: - NormObject(NormObject::Type theType, + NormObject(Type theType, class NormSession* theSession, class NormServerNode* theServer, const NormObjectId& objectId); @@ -154,17 +156,18 @@ class NormObject NormSegmentId next_segment_id; // for suppression NormBlockId max_pending_block; // for NACK construction NormSegmentId max_pending_segment; // for NACK construction - NormBlockId last_block_id; - NormSegmentId last_block_size; - UINT16 last_segment_size; + UINT32 large_block_count; + UINT32 large_block_size; + UINT32 small_block_count; + UINT32 small_block_size; + NormBlockId final_block_id; + UINT16 final_segment_size; char* info; UINT16 info_len; bool accepted; - - NormObject* next; }; // end class NormObject @@ -201,7 +204,8 @@ class NormFileObject : public NormObject private: char path[PATH_MAX]; NormFile file; - NormObjectSize block_size; + NormObjectSize large_block_length; + NormObjectSize small_block_length; }; // end class NormFileObject @@ -345,14 +349,14 @@ class NormObjectTable private: NormObject* Next(NormObject* o) const {return o->next;} - NormObject** table; - unsigned long hash_mask; - unsigned long range_max; // max range of objects that can be kept - unsigned long range; // zero if "object table" is empty - NormObjectId range_lo; - NormObjectId range_hi; - unsigned long count; - NormObjectSize size; + NormObject** table; + UINT16 hash_mask; + UINT16 range_max; // max range of objects that can be kept + UINT16 range; // zero if "object table" is empty + NormObjectId range_lo; + NormObjectId range_hi; + UINT16 count; + NormObjectSize size; }; // end class NormObjectTable #endif // _NORM_OBJECT diff --git a/common/normPostProcess.cpp b/common/normPostProcess.cpp index 8ef3094..b0b1166 100644 --- a/common/normPostProcess.cpp +++ b/common/normPostProcess.cpp @@ -1,39 +1,66 @@ #include "normPostProcess.h" -#include "protoLib.h" +#include "protoDebug.h" -#include -#include #include -#ifdef UNIX -#include -#include -#include -#endif // UNIX - -typedef void (*sighandler_t)(int); +#include +#include NormPostProcessor::NormPostProcessor() - : process_argv(NULL) -#ifdef UNIX - ,process_id(0) -#endif // UNIX + : process_argv(NULL), process_argc(0) { } NormPostProcessor::~NormPostProcessor() { - if (IsActive()) Kill(); SetCommand(NULL); } +void NormPostProcessor::GetCommand(char* buffer, unsigned int buflen) +{ + if (process_argv && buffer) + { + + unsigned int i = 0; + while (buflen && (i < process_argc)) + { + strncpy(buffer, process_argv[i], buflen); + unsigned int len = strlen(process_argv[i]); + if (len < buflen) + { + buflen -= len; + buffer += len; + } + else + { + buflen = 0; + break; + } + i++; + if (i < process_argc) + { + *buffer++= ' '; + buflen--; + } + } + } + else if (buflen && buffer) + { + if (buflen < 4) + buffer[0] = '\0'; + else + strncpy(buffer, "none", 4); + if (buflen > 4) buffer[4] = '\0'; + } +} // end NormPostProcessor::GetCommand() + bool NormPostProcessor::SetCommand(const char* cmd) { // 1) Delete old command resources if (process_argv) { - const char** arg = process_argv; + char** arg = process_argv; while (*arg) { delete *arg; @@ -60,7 +87,7 @@ bool NormPostProcessor::SetCommand(const char* cmd) // 3) Allocate new process_argv array (2 extra slots, one for "target", // and one for terminating NULL pointer. - if (!(process_argv = new const char*[argCount+2])) + if (!(process_argv = new char*[argCount+2])) { DMSG(0, "NormPostProcessor::SetCommand new(process_argv) error: %s\n", strerror(errno)); @@ -92,74 +119,3 @@ bool NormPostProcessor::SetCommand(const char* cmd) } return true; } // end NormPostProcessor::SetCommand() - -bool NormPostProcessor::ProcessFile(const char* path) -{ - - if (IsActive()) Kill(); - -#ifdef UNIX - // 1) temporarily disable signal handling - sighandler_t sigtermHandler = signal(SIGTERM, SIG_DFL); - sighandler_t sigintHandler = signal(SIGINT, SIG_DFL); - sighandler_t sigchldHandler = signal(SIGCHLD, SIG_DFL); - - process_argv[process_argc] = path; - - switch((process_id = fork())) - { - case -1: // error - DMSG(0, "NormPostProcessor::ProcessFile fork() error: %s\n", strerror(errno)); - process_id = 0; - process_argv[process_argc] = NULL; - return false; - - case 0: // child - if (execvp((char*)process_argv[0], (char**)process_argv) < 0) - { - DMSG(0, "NormPostProcessor::ProcessFile execvp() error: %s\n", strerror(errno)); - exit(-1); - } - break; - - default: // parent - process_argv[process_argc] = NULL; - // Restore signal handlers for parent - signal(SIGTERM, sigtermHandler); - signal(SIGINT, sigintHandler); - signal(SIGCHLD, sigchldHandler); - break; - } -#endif // UNIX - return true; -} // end NormPostProcessor::ProcessFile() - -void NormPostProcessor::Kill() -{ - if (!IsActive()) return; -#ifdef UNIX - int count = 0; - while((kill(process_id, SIGTERM) != 0) && count < 10) - { - if (errno == ESRCH) break; - count++; - DMSG(0, "NormPostProcessor::Kill kill() error: %s\n", strerror(errno)); - } - count = 0; - int status; - while((waitpid(process_id, &status, 0) != process_id) && count < 10) - { - if (errno == ECHILD) break; - count++; - DMSG(0, "NormPostProcessor::Kill waitpid() error: %s\n", strerror(errno)); - } - process_id = 0; -#endif // UNIX -} // end NormPostProcessor::Kill() - -void NormPostProcessor::HandleSIGCHLD() -{ - // See if processor exited itself - int status; - if (wait(&status) == process_id) process_id = 0; -} // end NormPostProcessor::HandleSIGCHLD() diff --git a/common/normPostProcess.h b/common/normPostProcess.h index 35d06c7..65712d3 100644 --- a/common/normPostProcess.h +++ b/common/normPostProcess.h @@ -1,35 +1,29 @@ + #ifndef _NORM_POST_PROCESS #define _NORM_POST_PROCESS - +#include "protoDefs.h" // for NULL + class NormPostProcessor { public: NormPostProcessor(); - ~NormPostProcessor(); + virtual ~NormPostProcessor(); + // Implement this per derivation + static NormPostProcessor* Create(); - bool IsEnabled() {return (0 != process_argv);} + bool IsEnabled() {return (NULL != process_argv);} bool SetCommand(const char* cmd); - bool ProcessFile(const char* path); - void Kill(); - bool IsActive() - { -#ifdef UNIX - return (0 != process_id); -#endif // UNIX - } + void GetCommand(char* buffer, unsigned int buflen); - void HandleSIGCHLD(); + virtual bool ProcessFile(const char* path) = 0; + virtual void Kill() = 0; + virtual bool IsActive() = 0; + virtual void OnDeath() {}; - private: - const char** process_argv; + protected: + char** process_argv; unsigned int process_argc; -#ifdef UNIX - int process_id; -#endif -#ifdef WIN32 - HANDLE process_handle; -#endif }; // end class NormPostProcessor #endif // _NORM_POST_PROCESS diff --git a/common/normSegment.cpp b/common/normSegment.cpp index 5531bc1..c16fa49 100644 --- a/common/normSegment.cpp +++ b/common/normSegment.cpp @@ -184,14 +184,14 @@ bool NormBlock::IsRepairPending(UINT16 ndata, UINT16 nparity) if (nparity) { UINT16 i = nparity; - NormSegmentId nextId = pending_mask.FirstSet(); + NormSegmentId nextId = (UINT16)pending_mask.FirstSet(); while (i--) { // (TBD) for more NACK suppression, we could skip ahead // if this bit is already set in repair_mask? repair_mask.Set(nextId); // set bit a parity can fill nextId++; - nextId = pending_mask.NextSet(nextId); + nextId = (UINT16)pending_mask.NextSet(nextId); } } else if (size > ndata) @@ -390,7 +390,7 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd, NormRepairRequest req; req.SetFlag(NormRepairRequest::SEGMENT); if (repairInfo) req.SetFlag(NormRepairRequest::INFO); - UINT16 nextId = repair_mask.FirstSet(); + UINT16 nextId = (UINT16)repair_mask.FirstSet(); UINT16 blockSize = size; NormRepairRequest::Form prevForm = NormRepairRequest::INVALID; UINT16 segmentCount = 0; @@ -398,7 +398,7 @@ bool NormBlock::AppendRepairAdv(NormCmdRepairAdvMsg& cmd, while (nextId < blockSize) { UINT16 currentId = nextId; - nextId = repair_mask.NextSet(++nextId); + nextId = (UINT16)repair_mask.NextSet(++nextId); if (!segmentCount) firstId = currentId; segmentCount++; @@ -467,19 +467,19 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack, if (erasure_count > nparity) { // Request explicit repair - nextId = pending_mask.FirstSet(); + nextId = (UINT16)pending_mask.FirstSet(); UINT16 i = nparity; // Skip nparity missing data segments while (i--) { nextId++; - endId = pending_mask.NextSet(nextId); + endId = (UINT16)pending_mask.NextSet(nextId); } endId = ndata + nparity; } else { - nextId = pending_mask.NextSet(ndata); + nextId = (UINT16)pending_mask.NextSet(ndata); endId = ndata + erasure_count; } NormRepairRequest req; @@ -492,7 +492,7 @@ bool NormBlock::AppendRepairRequest(NormNackMsg& nack, while (nextId < endId) { UINT16 currentId = nextId; - nextId = pending_mask.NextSet(++nextId); + nextId = (UINT16)pending_mask.NextSet(++nextId); if (0 == segmentCount) firstId = currentId; segmentCount++; // Check for break in consecutive series or end diff --git a/common/normSegment.h b/common/normSegment.h index 1e227c2..158dbc0 100644 --- a/common/normSegment.h +++ b/common/normSegment.h @@ -157,9 +157,9 @@ class NormBlock UINT16 ParityCount() const {return parity_count;} NormSymbolId FirstPending() const - {return pending_mask.FirstSet();} + {return (NormSymbolId)pending_mask.FirstSet();} NormSymbolId FirstRepair() const - {return repair_mask.FirstSet();} + {return (NormSymbolId)repair_mask.FirstSet();} bool SetPending(NormSymbolId s) {return pending_mask.Set(s);} bool SetPending(NormSymbolId firstId, UINT16 count) @@ -192,7 +192,7 @@ class NormBlock NormSymbolId NextPending(NormSymbolId index) const - {return pending_mask.NextSet(index);} + {return ((NormSymbolId)pending_mask.NextSet(index));} bool AppendRepairRequest(NormNackMsg& nack, diff --git a/common/normSession.cpp b/common/normSession.cpp index 4f5e6e4..28e0f2b 100644 --- a/common/normSession.cpp +++ b/common/normSession.cpp @@ -15,12 +15,14 @@ const UINT16 NormSession::DEFAULT_NDATA = 64; const UINT16 NormSession::DEFAULT_NPARITY = 32; NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId) - : session_mgr(sessionMgr), notify_pending(false), local_node_id(localNodeId), + : session_mgr(sessionMgr), notify_pending(false), + tx_socket(ProtoSocket::UDP), rx_socket(ProtoSocket::UDP), + local_node_id(localNodeId), ttl(DEFAULT_TTL), tx_rate(DEFAULT_TRANSMIT_RATE/8.0), backoff_factor(DEFAULT_BACKOFF_FACTOR), is_server(false), session_id(0), ndata(DEFAULT_NDATA), nparity(DEFAULT_NPARITY), auto_parity(0), extra_parity(0), next_tx_object_id(0), tx_cache_count_min(1), tx_cache_count_max(256), - tx_cache_size_max((unsigned long)20*1024*1024), + tx_cache_size_max((UINT32)20*1024*1024), flush_count(NORM_ROBUST_FACTOR+1), posted_tx_queue_empty(false), advertise_repairs(false), suppress_nonconfirmed(false), suppress_rate(-1.0), suppress_rtt(-1.0), @@ -35,24 +37,27 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId) trace(false), tx_loss_rate(0.0), rx_loss_rate(0.0), next(NULL) { - tx_socket.Init((UdpSocketOwner*) this, - (UdpSocketRecvHandler)&NormSession::TxSocketRecvHandler, - sessionMgr.SocketInstaller(), - sessionMgr.SocketInstallData()); - rx_socket.Init((UdpSocketOwner*) this, - (UdpSocketRecvHandler)&NormSession::RxSocketRecvHandler, - sessionMgr.SocketInstaller(), - sessionMgr.SocketInstallData()); + tx_socket.SetNotifier(&sessionMgr.GetSocketNotifier()); + tx_socket.SetListener(this, (ProtoSocket::EventHandler)&NormSession::TxSocketRecvHandler); - tx_timer.Init(0.0, -1, - (ProtocolTimerOwner *)this, - (ProtocolTimeoutFunc)&NormSession::OnTxTimeout); - repair_timer.Init(0.0, 1, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormSession::OnRepairTimeout); - flush_timer.Init(0.0, 0, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormSession::OnFlushTimeout); - probe_timer.Init(0.0, -1, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormSession::OnProbeTimeout); + rx_socket.SetNotifier(&sessionMgr.GetSocketNotifier()); + rx_socket.SetListener(this, (ProtoSocket::EventHandler)&NormSession::RxSocketRecvHandler); + + tx_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormSession::OnTxTimeout); + tx_timer.SetInterval(0.0); + tx_timer.SetRepeat(-1); + + repair_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormSession::OnRepairTimeout); + repair_timer.SetInterval(0.0); + repair_timer.SetRepeat(1); + + flush_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormSession::OnFlushTimeout); + flush_timer.SetInterval(0.0); + flush_timer.SetRepeat(0); + + probe_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormSession::OnProbeTimeout); + probe_timer.SetInterval(0.0); + probe_timer.SetRepeat(-1); grtt_quantized = NormQuantizeRtt(DEFAULT_GRTT_ESTIMATE); grtt_measured = grtt_advertised = NormUnquantizeRtt(grtt_quantized); @@ -65,8 +70,9 @@ NormSession::NormSession(NormSessionMgr& sessionMgr, NormNodeId localNodeId) // This timer is for printing out occasional status reports // (It may be used to trigger transmission of report messages // in the future for debugging, etc - report_timer.Init(30.0, -1, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormSession::OnReportTimeout); + report_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormSession::OnReportTimeout); + report_timer.SetInterval(10.0); + report_timer.SetRepeat(-1); } NormSession::~NormSession() @@ -75,13 +81,12 @@ NormSession::~NormSession() } - bool NormSession::Open() { ASSERT(address.IsValid()); if (!tx_socket.IsOpen()) { - if (UDP_SOCKET_ERROR_NONE != tx_socket.Open()) + if (!tx_socket.Open()) { DMSG(0, "NormSession::Open() tx_socket open error\n"); return false; @@ -89,7 +94,7 @@ bool NormSession::Open() } if (!rx_socket.IsOpen()) { - if (UDP_SOCKET_ERROR_NONE != rx_socket.Open(address.Port())) + if (!rx_socket.Open(address.GetPort())) { DMSG(0, "NormSession::Open() rx_socket open error\n"); Close(); @@ -99,13 +104,13 @@ bool NormSession::Open() if (address.IsMulticast()) { - if (UDP_SOCKET_ERROR_NONE != rx_socket.JoinGroup(&address)) + if (!rx_socket.JoinGroup(address)) { DMSG(0, "NormSession::Open() rx_socket join group error\n"); Close(); return false; } - if (UDP_SOCKET_ERROR_NONE != tx_socket.SetTTL(ttl)) + if (!tx_socket.SetTTL(ttl)) { DMSG(0, "NormSession::Open() tx_socket set ttl error\n"); Close(); @@ -126,7 +131,7 @@ bool NormSession::Open() return false; } } - InstallTimer(&report_timer); + ActivateTimer(report_timer); return true; } // end NormSession::Open() @@ -142,7 +147,7 @@ void NormSession::Close() if (tx_socket.IsOpen()) tx_socket.Close(); if (rx_socket.IsOpen()) { - if (address.IsMulticast()) rx_socket.LeaveGroup(&address); + if (address.IsMulticast()) rx_socket.LeaveGroup(address); rx_socket.Close(); } } // end NormSession::Close() @@ -226,8 +231,8 @@ bool NormSession::StartServer(unsigned long bufferSpace, is_server = true; flush_count = NORM_ROBUST_FACTOR+1; // (TBD) parameterize robust_factor //probe_timer.SetInterval(0.0); - OnProbeTimeout(); - InstallTimer(&probe_timer); + OnProbeTimeout(probe_timer); + ActivateTimer(probe_timer); return true; } // end NormSession::StartServer() @@ -274,7 +279,7 @@ void NormSession::Serve() // Queue next server message if (tx_pending_mask.IsSet()) { - NormObjectId objectId(tx_pending_mask.FirstSet()); + NormObjectId objectId((unsigned short)tx_pending_mask.FirstSet()); obj = tx_table.Find(objectId); ASSERT(obj); } @@ -293,6 +298,7 @@ void NormSession::Serve() if (obj) { + NormObjectMsg* msg = (NormObjectMsg*)GetMessageFromPool(); if (msg) { @@ -300,6 +306,7 @@ void NormSession::Serve() { msg->SetDestination(address); msg->SetGrtt(grtt_quantized); + msg->SetBackoffFactor((unsigned char)backoff_factor); msg->SetGroupSize(gsize_quantized); QueueMessage(msg); flush_count = 0; @@ -378,8 +385,8 @@ void NormSession::ServerQueueFlush() else { objectId = obj->Id(); - blockId = obj->LastBlockId(); - segmentId = obj->LastBlockSize() - 1; + blockId = obj->GetFinalBlockId(); + segmentId = obj->GetBlockSize(blockId) - 1; } } else @@ -389,7 +396,7 @@ void NormSession::ServerQueueFlush() { flush_count++; flush_timer.SetInterval(2*grtt_advertised); - InstallTimer(&flush_timer); + ActivateTimer(flush_timer); } DMSG(8, "NormSession::ServerQueueFlush() node>%lu squelch queued (flush_count:%u)...\n", LocalNodeId(), flush_count); @@ -401,6 +408,7 @@ void NormSession::ServerQueueFlush() flush->Init(); flush->SetDestination(address); flush->SetGrtt(grtt_quantized); + flush->SetBackoffFactor((unsigned char)backoff_factor); flush->SetGroupSize(gsize_quantized); flush->SetObjectId(objectId); flush->SetFecBlockId(blockId); @@ -408,7 +416,7 @@ void NormSession::ServerQueueFlush() QueueMessage(flush); flush_count++; flush_timer.SetInterval(2*grtt_advertised); - InstallTimer(&flush_timer); + ActivateTimer(flush_timer); DMSG(8, "NormSession::ServerQueueFlush() node>%lu, flush queued (flush_count:%u)...\n", LocalNodeId(), flush_count); } @@ -419,7 +427,7 @@ void NormSession::ServerQueueFlush() } } // end NormSession::ServerQueueFlush() -bool NormSession::OnFlushTimeout() +bool NormSession::OnFlushTimeout(ProtoTimer& /*theTimer*/) { flush_timer.Deactivate(); Serve(); // (TBD) Change this to PromptServer() ?? @@ -432,7 +440,7 @@ void NormSession::QueueMessage(NormMsg* msg) /* A little test jig static struct timeval lastTime = {0,0}; struct timeval currentTime; - GetSystemTime(¤tTime); + ProtoSystemTime(currentTime); if (0 != lastTime.tv_sec) { double delta = currentTime.tv_sec - lastTime.tv_sec; @@ -445,7 +453,7 @@ void NormSession::QueueMessage(NormMsg* msg) if (!tx_timer.IsActive()) { tx_timer.SetInterval(0.0); - InstallTimer(&tx_timer); + ActivateTimer(tx_timer); } message_queue.Append(msg); } // end NormSesssion::QueueMessage(NormMsg& msg) @@ -682,40 +690,34 @@ char* NormSession::ServerGetFreeSegment(NormObjectId objectId, return segment_pool.Get(); } // end NormSession::ServerGetFreeSegment() -bool NormSession::TxSocketRecvHandler(UdpSocket* /*theSocket*/) +void NormSession::TxSocketRecvHandler(ProtoSocket& /*theSocket*/, + ProtoSocket::Event /*theEvent*/) { NormMsg msg; unsigned int msgLength = NormMsg::MAX_SIZE; - if (UDP_SOCKET_ERROR_NONE == tx_socket.RecvFrom(msg.AccessBuffer(), - &msgLength, - msg.AccessAddress())) + while (tx_socket.RecvFrom(msg.AccessBuffer(), + msgLength, + msg.AccessAddress())) { msg.InitFromBuffer(msgLength); HandleReceiveMessage(msg, true); + msgLength = NormMsg::MAX_SIZE; } - else - { - DMSG(0, "NormSession::TxSocketRecvHandler() recvfrom error"); - } - return true; } // end NormSession::TxSocketRecvHandler() -bool NormSession::RxSocketRecvHandler(UdpSocket* /*theSocket*/) +void NormSession::RxSocketRecvHandler(ProtoSocket& /*theSocket*/, + ProtoSocket::Event /*theEvent*/) { NormMsg msg; unsigned int msgLength = NormMsg::MAX_SIZE; - if (UDP_SOCKET_ERROR_NONE == rx_socket.RecvFrom(msg.AccessBuffer(), - &msgLength, - msg.AccessAddress())) + while (rx_socket.RecvFrom(msg.AccessBuffer(), + msgLength, + msg.AccessAddress())) { msg.InitFromBuffer(msgLength); HandleReceiveMessage(msg, false); + msgLength = NormMsg::MAX_SIZE; } - else - { - DMSG(0, "NormSession::RxSocketRecvHandler() recvfrom error"); - } - return true; } // end NormSession::RxSocketRecvHandler() void NormTrace(const struct timeval& currentTime, @@ -759,12 +761,12 @@ void NormTrace(const struct timeval& currentTime, NormMsg::Type msgType = msg.GetType(); UINT16 length = msg.GetLength(); const char* status = sent ? "dst" : "src"; - const NetworkAddress& addr = sent ? msg.GetDestination() : msg.GetSource(); + const ProtoAddress& addr = sent ? msg.GetDestination() : msg.GetSource(); struct tm* ct = gmtime((time_t*)¤tTime.tv_sec); DMSG(0, "trace>%02d:%02d:%02d.%06lu node>%lu %s>%s ", ct->tm_hour, ct->tm_min, ct->tm_sec, currentTime.tv_usec, - (UINT32)localId, status, addr.HostAddressString()); + (UINT32)localId, status, addr.GetHostString()); bool clrFlag = false; switch (msgType) { @@ -881,9 +883,8 @@ void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast) return; } - struct timeval currentTime; - ::GetSystemTime(¤tTime); + ::ProtoSystemTime(currentTime); if (trace) NormTrace(currentTime, LocalNodeId(), msg, false); @@ -894,10 +895,10 @@ void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast) { // (TBD) combine these as needed for efficiency // (i.e. fewer function calls per message) + if (theServer->IsOpen()) theServer->Activate(); theServer->UpdateRecvRate(currentTime, msg.GetLength()); theServer->UpdateLossEstimate(currentTime, msg.GetSequence()); theServer->SetAddress(msg.GetSource()); - // for statistics only (TBD) #ifdef NORM_DEBUG theServer->IncrementRecvTotal(msg.GetLength()); } @@ -929,7 +930,7 @@ void NormSession::HandleReceiveMessage(NormMsg& msg, bool wasUnicast) if (!tx_timer.IsActive()) { tx_timer.SetInterval(0.0); - InstallTimer(&tx_timer); + ActivateTimer(tx_timer); } } } @@ -1083,7 +1084,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId, double ccRtt, double ccLoss, double ccRate, - UINT8 ccSequence) + UINT16 ccSequence) { // Keep track of current suppressing feedback // (non-CLR, lowest rate, unconfirmed RTT) @@ -1123,14 +1124,14 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId, // 1) Does this response replace the active CLR? if (next && next->IsActive()) { - if (ccRate < next->GetRate() || (nodeId == next->Id())) + if (ccRate < next->GetRate() || (nodeId == next->GetId())) { - NormNodeId savedId = next->Id(); + NormNodeId savedId = next->GetId(); bool savedRttStatus = next->HasRtt(); double savedRtt = next->GetRtt(); double savedLoss = next->GetLoss(); double savedRate = next->GetRate(); - UINT8 savedSequence = next->GetCCSequence(); + UINT16 savedSequence = next->GetCCSequence(); next->SetId(nodeId); next->SetClrStatus(true); @@ -1139,7 +1140,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId, next->SetRate(ccRate); next->SetCCSequence(ccSequence); next->SetActive(true); - if (next->Id() == nodeId) + if (next->GetId() == nodeId) { // This was feedback from the current CLR AdjustRate(true); @@ -1206,7 +1207,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId, { while ((next = (NormCCNode*)iterator.GetNextNode())) { - if (next->Id() == nodeId) + if (next->GetId() == nodeId) { candidate = next; break; @@ -1238,7 +1239,7 @@ void NormSession::ServerHandleCCFeedback(NormNodeId nodeId, { bool haveRtt = (0 != (ccFlags && NormCC::RTT)); bool replace; - if (candidate->Id() == nodeId) + if (candidate->GetId() == nodeId) replace = true; else if (!candidate->IsActive()) replace = true; @@ -1297,7 +1298,7 @@ void NormSession::ServerHandleAckMessage(const struct timeval& currentTime, cons if (!tx_timer.IsActive()) { tx_timer.SetInterval(0.0); - InstallTimer(&tx_timer); + ActivateTimer(tx_timer); } } @@ -1346,10 +1347,10 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor NormRepairRequest req; NormObject* object = NULL; bool freshObject = true; - NormObjectId prevObjectId; + NormObjectId prevObjectId = 0; NormBlock* block = NULL; bool freshBlock = true; - NormBlockId prevBlockId; + NormBlockId prevBlockId = 0; bool startTimer = false; UINT16 numErasures = extra_parity; @@ -1360,7 +1361,7 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor NormBlockId txBlockIndex; if (tx_pending_mask.IsSet()) { - txObjectIndex = tx_pending_mask.FirstSet(); + txObjectIndex = NormObjectId((unsigned short)tx_pending_mask.FirstSet()); NormObject* obj = tx_table.Find(txObjectIndex); ASSERT(obj); if (obj->IsPending()) @@ -1382,7 +1383,7 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor txBlockIndex = 0; } - bool holdoff = (repair_timer.IsActive() && !repair_timer.RepeatCount()); + bool holdoff = (repair_timer.IsActive() && !repair_timer.GetRepeatCount()); enum NormRequestLevel {SEGMENT, BLOCK, INFO, OBJECT}; while ((requestLength = nack.UnpackRepairRequest(req, requestOffset))) { @@ -1728,14 +1729,14 @@ void NormSession::ServerHandleNackMessage(const struct timeval& currentTime, Nor if (tx_timer.IsActive()) { - double txTimeout = tx_timer.TimeRemaining() - 1.0e-06; + double txTimeout = tx_timer.GetTimeRemaining() - 1.0e-06; aggregateInterval = MAX(txTimeout, aggregateInterval); } repair_timer.SetInterval(aggregateInterval); DMSG(4, "NormSession::ServerHandleNackMessage() node>%lu starting server " "NACK aggregation timer (%lf sec)...\n", LocalNodeId(), aggregateInterval); - InstallTimer(&repair_timer); + ActivateTimer(repair_timer); } } // end NormSession::ServerHandleNackMessage() @@ -1778,6 +1779,7 @@ bool NormSession::ServerQueueSquelch(NormObjectId objectId) squelch->Init(); squelch->SetDestination(address); squelch->SetGrtt(grtt_quantized); + squelch->SetBackoffFactor((unsigned char)backoff_factor); squelch->SetGroupSize(gsize_quantized); NormObject* obj = tx_table.Find(objectId); NormObjectTable::Iterator iterator(tx_table); @@ -1933,9 +1935,9 @@ bool NormSession::ServerBuildRepairAdv(NormCmdRepairAdvMsg& cmd) return true; } // end NormSession::ServerBuildRepairAdv() -bool NormSession::OnRepairTimeout() +bool NormSession::OnRepairTimeout(ProtoTimer& /*theTimer*/) { - if (repair_timer.RepeatCount()) + if (repair_timer.GetRepeatCount()) { // NACK aggregation period has ended. (incorporate accumulated repair requests) DMSG(4, "NormSession::OnRepairTimeout() node>%lu server NACK aggregation time ended.\n", @@ -1994,9 +1996,9 @@ bool NormSession::OnRepairTimeout() } // end NormSession::OnRepairTimeout() -// (TBD) Should pass current system time to ProtocolTimer timeout handlers +// (TBD) Should pass current system time to ProtoTimer timeout handlers // for more efficiency ... -bool NormSession::OnTxTimeout() +bool NormSession::OnTxTimeout(ProtoTimer& /*theTimer*/) { NormMsg* msg; @@ -2004,12 +2006,13 @@ bool NormSession::OnTxTimeout() NormCmdRepairAdvMsg adv; if (advertise_repairs && (probe_proactive || (repair_timer.IsActive() && - repair_timer.RepeatCount()))) + repair_timer.GetRepeatCount()))) { // Build a NORM_CMD(NACK_ADV) in response to // receipt of unicast NACK or CC update adv.Init(); adv.SetGrtt(grtt_quantized); + adv.SetBackoffFactor((unsigned char)backoff_factor); adv.SetGroupSize(gsize_quantized); adv.SetDestination(address); @@ -2044,11 +2047,19 @@ bool NormSession::OnTxTimeout() if (msg) { - SendMessage(*msg); - if (advertise_repairs) - advertise_repairs = false; + if (SendMessage(*msg)) + { + if (advertise_repairs) + advertise_repairs = false; + else + ReturnMessageToPool(msg); + } else - ReturnMessageToPool(msg); + { + // Requeue the message for another try + if (!advertise_repairs) + message_queue.Prepend(msg); + } return true; // reinstall tx_timer } else @@ -2068,16 +2079,15 @@ bool NormSession::OnTxTimeout() else { // We have a new message as a result of serving, so send it immediately - OnTxTimeout(); - return true; + return OnTxTimeout(tx_timer); } } } // end NormSession::OnTxTimeout() -void NormSession::SendMessage(NormMsg& msg) +bool NormSession::SendMessage(NormMsg& msg) { struct timeval currentTime; - GetSystemTime(¤tTime); + ProtoSystemTime(currentTime); bool clientMsg = false; @@ -2134,61 +2144,65 @@ void NormSession::SendMessage(NormMsg& msg) msg.SetSequence(tx_sequence++); msg.SetSourceId(local_node_id); UINT16 msgSize = msg.GetLength(); + bool result = true; // Drop some tx messages for testing purposes bool drop = (UniformRand(100.0) < tx_loss_rate); - if (drop || (clientMsg && client_silent)) { //TRACE("TX MESSAGE DROPPED! (tx_loss_rate:%lf\n", tx_loss_rate); } else { - if (UDP_SOCKET_ERROR_NONE != tx_socket.SendTo(&msg.GetDestination(), - msg.GetBuffer(), - msgSize)) - { - DMSG(0, "NormSession::SendMessage() sendto() error\n"); - } - else + if (tx_socket.SendTo(msg.GetBuffer(), + msgSize, + msg.GetDestination())) { // Separate send/recv tracing - if (trace) NormTrace(currentTime, LocalNodeId(), msg, true); - } - // Keep track of _actual_ sent rate - double interval; - if (prev_update_time.tv_sec || prev_update_time.tv_usec) - { - interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec); - if (currentTime.tv_usec > prev_update_time.tv_sec) - interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec); + if (trace) NormTrace(currentTime, LocalNodeId(), msg, true); + + // Keep track of _actual_ sent rate + double interval; + if (prev_update_time.tv_sec || prev_update_time.tv_usec) + { + interval = (double)(currentTime.tv_sec - prev_update_time.tv_sec); + if (currentTime.tv_usec > prev_update_time.tv_sec) + interval += 1.0e-06*(double)(currentTime.tv_usec - prev_update_time.tv_usec); + else + interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec); + } else - interval -= 1.0e-06*(double)(prev_update_time.tv_usec - currentTime.tv_usec); + { + sent_rate = ((double)msgSize) / grtt_advertised; + interval = -1.0; + prev_update_time = currentTime; + } + if (interval < grtt_advertised) + { + sent_accumulator += msgSize; + } + else + { + sent_rate = ((double)(sent_accumulator+msgSize)) / interval; + prev_update_time = currentTime; + sent_accumulator = 0; + } + // Update nominal packet size + nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size); } else { - sent_rate = ((double)msgSize) / grtt_advertised; - interval = -1.0; - prev_update_time = currentTime; - } - if (interval < grtt_advertised) - { - sent_accumulator += msgSize; - } - else - { - sent_rate = ((double)(sent_accumulator+msgSize)) / interval; - prev_update_time = currentTime; - sent_accumulator = 0; + DMSG(8, "NormSession::SendMessage() sendto() error\n"); + result = false; } } - nominal_packet_size += 0.05 * (((double)msgSize) - nominal_packet_size); tx_timer.SetInterval(((double)msgSize) / tx_rate); + return result; } // end NormSession::SendMessage() -bool NormSession::OnProbeTimeout() +bool NormSession::OnProbeTimeout(ProtoTimer& /*theTimer*/) { // 1) Update grtt_estimate _if_ sufficient time elapsed. - grtt_age += probe_timer.Interval(); + grtt_age += probe_timer.GetInterval(); if (grtt_age >= grtt_interval) { if (grtt_response) @@ -2247,6 +2261,7 @@ bool NormSession::OnProbeTimeout() cmd->Init(); cmd->SetDestination(address); cmd->SetGrtt(grtt_quantized); + cmd->SetBackoffFactor((unsigned char)backoff_factor); cmd->SetGroupSize(gsize_quantized); // SetSendTime() when message is being sent (in OnTxTimeout()) cmd->SetCCSequence(cc_sequence++); @@ -2276,7 +2291,7 @@ bool NormSession::OnProbeTimeout() UINT16 rateQuantized = NormQuantizeRate(next->GetRate()); // (TBD) check result cmd->AppendCCNode(segment_size, - next->Id(), + next->GetId(), ccFlags, rttQuantized, rateQuantized); @@ -2368,16 +2383,16 @@ void NormSession::AdjustRate(bool onResponse) tx_rate = MAX(tx_rate, minRate); struct timeval currentTime; - ::GetSystemTime(¤tTime); + ::ProtoSystemTime(currentTime); double theTime = (double)currentTime.tv_sec + 1.0e-06 * ((double)currentTime.tv_usec); DMSG(6, "ServerRateTracking time>%lf rate>%lf rtt>%lf loss>%lf\n", theTime, tx_rate * (8.0/1000.0), ccRtt, ccLoss); } // end NormSession::AdjustRate() -bool NormSession::OnReportTimeout() +bool NormSession::OnReportTimeout(ProtoTimer& /*theTimer*/) { // Client reporting (just print out for now) struct timeval currentTime; - GetSystemTime(¤tTime); + ProtoSystemTime(currentTime); struct tm* ct = gmtime((time_t*)¤tTime.tv_sec); DMSG(2, "Report time>%02d:%02d:%02d.%06lu node>%lu ***************************************\n", ct->tm_hour, ct->tm_min, ct->tm_sec, currentTime.tv_usec, LocalNodeId()); @@ -2387,9 +2402,9 @@ bool NormSession::OnReportTimeout() NormServerNode* next; while ((next = (NormServerNode*)iterator.GetNextNode())) { - DMSG(2, "Remote server:%lu\n", next->Id()); - double rxRate = 8.0e-03*((double)next->RecvTotal()) / report_timer.Interval(); // kbps - double rxGoodput = 8.0e-03*((double)next->RecvGoodput()) / report_timer.Interval(); // kbps + DMSG(2, "Remote server:%lu\n", next->GetId()); + double rxRate = 8.0e-03*((double)next->RecvTotal()) / report_timer.GetInterval(); // kbps + double rxGoodput = 8.0e-03*((double)next->RecvGoodput()) / report_timer.GetInterval(); // kbps next->ResetRecvStats(); DMSG(2, " rx_rate>%9.3lf kbps rx_goodput>%9.3lf kbps\n", rxRate, rxGoodput); DMSG(2, " objects completed>%lu pending>%lu failed:%lu\n", @@ -2406,8 +2421,9 @@ bool NormSession::OnReportTimeout() return true; } // end NormSession::OnReportTimeout() -NormSessionMgr::NormSessionMgr() - : socket_installer(NULL), socket_install_data(NULL), +NormSessionMgr::NormSessionMgr(ProtoTimerMgr& timerMgr, + ProtoSocket::Notifier& socketNotifier) + : timer_mgr(timerMgr), socket_notifier(socketNotifier), controller(NULL), top_session(NULL) { } @@ -2434,8 +2450,8 @@ NormSession* NormSessionMgr::NewSession(const char* sessionAddress, if (NORM_NODE_ANY == localNodeId) { // Use local ip address to assign default localNodeId - NetworkAddress localAddr; - if (!localAddr.LookupLocalHostAddress()) + ProtoAddress localAddr; + if (!localAddr.ResolveLocalAddress()) { DMSG(0, "NormSessionMgr::NewSession() local address lookup error\n"); return ((NormSession*)NULL); @@ -2443,8 +2459,8 @@ NormSession* NormSessionMgr::NewSession(const char* sessionAddress, // (TBD) test IPv6 "EndIdentifier" ??? localNodeId = localAddr.EndIdentifier(); } - NetworkAddress theAddress; - if (!theAddress.LookupHostAddress(sessionAddress)) + ProtoAddress theAddress; + if (!theAddress.ResolveFromString(sessionAddress)) { DMSG(0, "NormSessionMgr::NewSession() session address lookup error!\n"); return ((NormSession*)NULL); diff --git a/common/normSession.h b/common/normSession.h index 067862d..c35e150 100644 --- a/common/normSession.h +++ b/common/normSession.h @@ -6,9 +6,7 @@ #include "normNode.h" #include "normEncoder.h" -#include "protocolTimer.h" -#include "udpSocket.h" - +#include "protokit.h" class NormController { @@ -34,19 +32,11 @@ class NormSessionMgr { friend class NormSession; public: - NormSessionMgr(); + NormSessionMgr(ProtoTimerMgr& timerMgr, + ProtoSocket::Notifier& socketNotifier); ~NormSessionMgr(); - void Init(ProtocolTimerInstallFunc* timerInstaller, - const void* timerInstallData, - UdpSocketInstallFunc* socketInstaller, - void* socketInstallData, - NormController* theController) - { - timer_mgr.SetInstaller(timerInstaller, timerInstallData); - socket_installer = socketInstaller; - socket_install_data = socketInstallData; - controller = theController; - } + void SetController(NormController* theController) + {controller = theController;} void Destroy(); class NormSession* NewSession(const char* sessionAddress, @@ -55,10 +45,6 @@ class NormSessionMgr NORM_NODE_ANY); void DeleteSession(class NormSession* theSession); - - UdpSocketInstallFunc* SocketInstaller() {return socket_installer;} - const void* SocketInstallData() {return socket_install_data;} - void Notify(NormController::Event event, class NormSession* session, class NormServerNode* server, @@ -68,12 +54,13 @@ class NormSessionMgr controller->Notify(event, this, session, server, object); } - void InstallTimer(ProtocolTimer* timer) {timer_mgr.InstallTimer(timer);} + void ActivateTimer(ProtoTimer& timer) {timer_mgr.ActivateTimer(timer);} + ProtoTimerMgr& GetTimerMgr() {return timer_mgr;} + ProtoSocket::Notifier& GetSocketNotifier() {return socket_notifier;} private: - ProtocolTimerMgr timer_mgr; - UdpSocketInstallFunc* socket_installer; - const void* socket_install_data; + ProtoTimerMgr& timer_mgr; + ProtoSocket::Notifier& socket_notifier; NormController* controller; class NormSession* top_session; // top of NormSession list @@ -104,8 +91,8 @@ class NormSession bool Open(); void Close(); bool IsOpen() {return (rx_socket.IsOpen() || tx_socket.IsOpen());} - const NetworkAddress& Address() {return address;} - void SetAddress(const NetworkAddress& addr) {address = addr;} + const ProtoAddress& Address() {return address;} + void SetAddress(const ProtoAddress& addr) {address = addr;} static double CalculateRate(double size, double rtt, double loss); @@ -135,9 +122,8 @@ class NormSession NormMsg* GetMessageFromPool() {return message_pool.RemoveHead();} void ReturnMessageToPool(NormMsg* msg) {message_pool.Append(msg);} void QueueMessage(NormMsg* msg); - void SendMessage(NormMsg& msg); - void InstallTimer(ProtocolTimer* timer) - {session_mgr.InstallTimer(timer);} + bool SendMessage(NormMsg& msg); + void ActivateTimer(ProtoTimer& timer) {session_mgr.ActivateTimer(timer);} // Server methods void ServerSetBaseObjectId(NormObjectId baseId) @@ -195,7 +181,7 @@ class NormSession if (!tx_timer.IsActive()) { tx_timer.SetInterval(0.0); - InstallTimer(&tx_timer); + ActivateTimer(tx_timer); } } @@ -227,7 +213,7 @@ class NormSession // Simulation specific methods NormSimObject* QueueTxSim(unsigned long objectSize); bool SimSocketRecvHandler(char* buffer, unsigned short buflen, - const NetworkAddress& src, bool unicast); + const ProtoAddress& src, bool unicast); #endif // SIMULATE private: @@ -239,15 +225,15 @@ class NormSession bool QueueTxObject(NormObject* obj, bool touchServer = true); void DeleteTxObject(NormObject* obj); - bool OnTxTimeout(); - bool OnRepairTimeout(); - bool OnFlushTimeout(); - bool OnWatermarkTimeout(); - bool OnProbeTimeout(); - bool OnReportTimeout(); + bool OnTxTimeout(ProtoTimer& theTimer); + bool OnRepairTimeout(ProtoTimer& theTimer); + bool OnFlushTimeout(ProtoTimer& theTimer); + bool OnWatermarkTimeout(ProtoTimer& theTimer); + bool OnProbeTimeout(ProtoTimer& theTimer); + bool OnReportTimeout(ProtoTimer& theTimer); - bool TxSocketRecvHandler(UdpSocket* theSocket); - bool RxSocketRecvHandler(UdpSocket* theSocket); + void TxSocketRecvHandler(ProtoSocket& theSocket, ProtoSocket::Event theEvent); + void RxSocketRecvHandler(ProtoSocket& theSocket, ProtoSocket::Event theEve); void HandleReceiveMessage(NormMsg& msg, bool wasUnicast); // Server message handling routines @@ -264,7 +250,7 @@ class NormSession double ccRtt, double ccLoss, double ccRate, - UINT8 ccSequence); + UINT16 ccSequence); void AdjustRate(bool onResponse); bool ServerQueueSquelch(NormObjectId objectId); void ServerQueueFlush(); @@ -283,17 +269,17 @@ class NormSession NormSessionMgr& session_mgr; bool notify_pending; - ProtocolTimer tx_timer; - UdpSocket tx_socket; - UdpSocket rx_socket; + ProtoTimer tx_timer; + ProtoSocket tx_socket; + ProtoSocket rx_socket; NormMessageQueue message_queue; NormMessageQueue message_pool; - ProtocolTimer report_timer; + ProtoTimer report_timer; UINT16 tx_sequence; // General session parameters NormNodeId local_node_id; - NetworkAddress address; // session destination address + ProtoAddress address; // session destination address UINT8 ttl; // session multicast ttl double tx_rate; // bytes per second double backoff_factor; @@ -310,7 +296,7 @@ class NormSession NormObjectTable tx_table; NormSlidingMask tx_pending_mask; NormSlidingMask tx_repair_mask; - ProtocolTimer repair_timer; + ProtoTimer repair_timer; NormBlockPool block_pool; NormSegmentPool segment_pool; NormEncoder encoder; @@ -319,10 +305,10 @@ class NormSession unsigned int tx_cache_count_min; unsigned int tx_cache_count_max; NormObjectSize tx_cache_size_max; - ProtocolTimer flush_timer; + ProtoTimer flush_timer; int flush_count; bool posted_tx_queue_empty; - ProtocolTimer watermark_timer; + ProtoTimer watermark_timer; int watermark_count; // (TBD) watermark_object_id, watermark_block_id, watermark_symbol_id @@ -332,7 +318,7 @@ class NormSession double suppress_rate; double suppress_rtt; - ProtocolTimer probe_timer; // GRTT/congestion control probes + ProtoTimer probe_timer; // GRTT/congestion control probes bool probe_proactive; double grtt_interval; // current GRTT update interval diff --git a/common/normSimAgent.cpp b/common/normSimAgent.cpp index c87b463..7f169bf 100644 --- a/common/normSimAgent.cpp +++ b/common/normSimAgent.cpp @@ -6,11 +6,9 @@ // of a message stream from the MGEN simulation agent with restrictions. The // current restriction is the MGEN simulation agent -NormSimAgent::NormSimAgent(ProtocolTimerInstallFunc* timerInstaller, - const void* timerInstallData, - UdpSocketInstallFunc* socketInstaller, - void* socketInstallData) - : session(NULL), +NormSimAgent::NormSimAgent(ProtoTimerMgr& timerMgr, + ProtoSocket::Notifier& socketNotifier) + : session_mgr(timerMgr, socketNotifier), session(NULL), address(NULL), port(0), ttl(3), tx_rate(NormSession::DEFAULT_TRANSMIT_RATE), cc_enable(false), unicast_nacks(false), silent_client(false), @@ -25,12 +23,12 @@ NormSimAgent::NormSimAgent(ProtocolTimerInstallFunc* timerInstaller, tracing(false), tx_loss(0.0), rx_loss(0.0) { // Bind NormSessionMgr to this agent and simulation environment - session_mgr.Init(timerInstaller, timerInstallData, - socketInstaller, socketInstallData, - static_cast(this)); + session_mgr.SetController(static_cast(this)); + + interval_timer.SetListener(this, (ProtoTimer::TimeoutHandler)&NormSimAgent::OnIntervalTimeout); + interval_timer.SetInterval(0.0); + interval_timer.SetRepeat(0); - interval_timer.Init(0.0, 0, (ProtocolTimerOwner*)this, - (ProtocolTimeoutFunc)&NormSimAgent::OnIntervalTimeout); memset(mgen_buffer, 0, 64); } @@ -589,9 +587,9 @@ void NormSimAgent::Notify(NormController::Event event, else { // Schedule or queue next "sim file" transmission - if (interval_timer.Interval() > 0.0) + if (interval_timer.GetInterval() > 0.0) { - InstallTimer(interval_timer); + ActivateTimer(interval_timer); } else { @@ -735,7 +733,9 @@ void NormSimAgent::Notify(NormController::Event event, } if (msg_sync && (0 == mgen_pending_bytes)) { - const NetworkAddress& srcAddr = server->GetAddress(); + ProtoAddress srcAddr; + srcAddr.ResolveFromString(server->GetAddress().GetHostString()); + srcAddr.SetPort(server->GetAddress().GetPort()); mgen->HandleMgenMessage(mgen_buffer, mgen_bytes, srcAddr); mgen_bytes = 0; } diff --git a/common/normSimAgent.h b/common/normSimAgent.h index 7b799c6..2fa5e15 100644 --- a/common/normSimAgent.h +++ b/common/normSimAgent.h @@ -1,9 +1,8 @@ // normSimAgent.h - Generic (base class) NORM simulation agent -#include "protoLib.h" -#include "protoSim.h" #include "normSession.h" +#include "protokit.h" #include "mgen.h" // for MGEN instance attachment @@ -25,10 +24,8 @@ class NormSimAgent : public NormController void AttachMgen(Mgen* mgenInstance) {mgen = mgenInstance;} protected: - NormSimAgent(ProtocolTimerInstallFunc* timerInstaller, - const void* timerInstallData, - UdpSocketInstallFunc* socketInstaller, - void* socketInstallData); + NormSimAgent(ProtoTimerMgr& timerMgr, + ProtoSocket::Notifier& socketNotifier); enum CmdType {CMD_INVALID, CMD_NOARG, CMD_ARG}; CmdType CommandType(const char* cmd); virtual unsigned long GetAgentId() = 0; @@ -42,8 +39,8 @@ class NormSimAgent : public NormController class NormServerNode* server, class NormObject* object); - void InstallTimer(ProtocolTimer& theTimer) - {session_mgr.InstallTimer(&theTimer);} + void ActivateTimer(ProtoTimer& theTimer) + {session_mgr.ActivateTimer(theTimer);} bool OnIntervalTimeout(); @@ -88,7 +85,7 @@ class NormSimAgent : public NormController unsigned int mgen_bytes; unsigned int mgen_pending_bytes; - ProtocolTimer interval_timer; + ProtoTimer interval_timer; // protocol debug parameters bool tracing; diff --git a/common/normSimAgent.o b/common/normSimAgent.o deleted file mode 100644 index 757bf3f..0000000 Binary files a/common/normSimAgent.o and /dev/null differ diff --git a/common/version.h b/common/normVersion.h similarity index 98% rename from common/version.h rename to common/normVersion.h index fb37e98..21ef689 100644 --- a/common/version.h +++ b/common/normVersion.h @@ -32,6 +32,6 @@ #ifndef _NORM_VERSION #define _NORM_VERSION -#define VERSION "1.0b2" +#define VERSION "1.1b1" #endif // _NORM_VERSION diff --git a/ns/ns226-Makefile.in b/ns/ns226-Makefile.in new file mode 100644 index 0000000..8cbf8d6 --- /dev/null +++ b/ns/ns226-Makefile.in @@ -0,0 +1,576 @@ +# Copyright (c) 1994, 1995, 1996 +# The Regents of the University of California. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that: (1) source code distributions +# retain the above copyright notice and this paragraph in its entirety, (2) +# distributions including binary code include the above copyright notice and +# this paragraph in its entirety in the documentation or other materials +# provided with the distribution, and (3) all advertising materials mentioning +# features or use of this software display the following acknowledgement: +# ``This product includes software developed by the University of California, +# Lawrence Berkeley Laboratory and its contributors.'' Neither the name of +# the University nor the names of its contributors may be used to endorse +# or promote products derived from this software without specific prior +# written permission. +# THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED +# WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# @(#) $Header: 2002/10/09 15:34:11 + +# +# Various configurable paths (remember to edit Makefile.in, not Makefile) +# + +# Top level hierarchy +prefix = @prefix@ +# Pathname of directory to install the binary +BINDEST = @prefix@/bin +# Pathname of directory to install the man page +MANDEST = @prefix@/man + +BLANK = # make a blank space. DO NOT add anything to this line + +# The following will be redefined under Windows (see WIN32 lable below) +CC = @CC@ +CPP = @CXX@ +LINK = $(CPP) +MKDEP = ./conf/mkdep +TCLSH = @V_TCLSH@ +TCL2C = @V_TCL2CPP@ +AR = ar rc $(BLANK) + +RANLIB = @V_RANLIB@ +INSTALL = @INSTALL@ +LN = ln +TEST = test +RM = rm -f +MV = mv +PERL = @PERL@ + +# for diffusion +#DIFF_INCLUDES = "./diffusion3/main ./diffusion3/lib ./diffusion3/nr ./diffusion3/ns" + +CCOPT = @V_CCOPT@ +STATIC = @V_STATIC@ +LDFLAGS = $(STATIC) +LDOUT = -o $(BLANK) + +DEFINE = -DTCP_DELAY_BIND_ALL -DNO_TK @V_DEFINE@ @V_DEFINES@ @DEFS@ -DNS_DIFFUSION -DSMAC_NO_SYNC -DSTL_NAMESPACE=@STL_NAMESPACE@ -DUSE_SINGLE_ADDRESS_SPACE + +# NRL additions for Protolib, MDP, and NORM extensions +PROTOLIB_INCLUDES = -Iprotolib/common -Iprotolib/ns +MDP_INCLUDES = -Imdp/common -Imdp/ns -Imdp/unix +NORM_INCLUDES = -Inorm/common -Inorm/ns +MGEN_INCLUDES = -Imgen/common -Imgen/ns +NRL_INCLUDES = $(PROTOLIB_INCLUDES) $(MDP_INCLUDES) $(NORM_INCLUDES) $(MGEN_INCLUDES) + +INCLUDES = \ + -I. @V_INCLUDE_X11@ \ + @V_INCLUDES@ \ + -I./tcp -I./common -I./link -I./queue \ + -I./adc -I./apps -I./mac -I./mobile -I./trace \ + -I./routing -I./tools -I./classifier -I./mcast \ + -I./diffusion3/lib/main -I./diffusion3/lib \ + -I./diffusion3/lib/nr -I./diffusion3/ns \ + -I./diffusion3/diffusion -I./asim/ -I./qs \ + $(NRL_INCLUDES) + + +LIB = \ + @V_LIBS@ \ + @V_LIB_X11@ \ + @V_LIB@ \ + -lm @LIBS@ +# -L@libdir@ \ + +# Additional flags for NRL Protolib/MDP/NORM extensions +# These flags have been tested on Linux +NRL_CFLAGS = -g -DNS2 -DSIMULATE -DUNIX -DPROTO_DEBUG -DHAVE_ASSERT -DHAVE_DIRFD + + +CFLAGS = $(CCOPT) $(DEFINE) $(NRL_CFLAGS) + +# Explicitly define compilation rules since SunOS 4's make doesn't like gcc. +# Also, gcc does not remove the .o before forking 'as', which can be a +# problem if you don't own the file but can write to the directory. +# NRL Protolib/MDP/NORM code uses .cpp files so we added a suffix and rule +.SUFFIXES: .cc .cpp # $(.SUFFIXES) + +.cc.o: + @rm -f $@ + $(CPP) -c $(CFLAGS) $(INCLUDES) -o $@ $*.cc + +.c.o: + @rm -f $@ + $(CC) -c $(CFLAGS) $(INCLUDES) -o $@ $*.c + +.cpp.o: + @rm -f $@ + $(CPP) -c $(CFLAGS) $(INCLUDES) -o $@ $*.cpp + + + +GEN_DIR = gen/ +LIB_DIR = lib/ +NS = ns +NSX = nsx +NSE = nse + +# To allow conf/makefile.win overwrite this macro +# We will set these two macros to empty in conf/makefile.win since VC6.0 +# does not seem to support the STL in gcc 2.8 and up. +OBJ_STL = diffusion3/lib/nr/nr.o diffusion3/lib/dr.o \ + diffusion3/ns/diffagent.o diffusion3/ns/diffrtg.o \ + diffusion3/ns/difftimer.o \ + diffusion3/diffusion/diffusion.o \ + diffusion3/lib/main/attrs.o \ + diffusion3/lib/main/iodev.o \ + diffusion3/lib/main/timers.o \ + diffusion3/lib/main/events.o \ + diffusion3/lib/main/message.o \ + diffusion3/lib/main/stats.o \ + diffusion3/lib/main/tools.o \ + diffusion3/lib/drivers/rpc_stats.o \ + diffusion3/apps/sysfilters/gradient.o \ + diffusion3/apps/sysfilters/log.o \ + diffusion3/apps/sysfilters/tag.o \ + diffusion3/apps/sysfilters/srcrt.o \ + diffusion3/lib/diffapp.o \ + diffusion3/apps/pingapp/ping_sender.o \ + diffusion3/apps/pingapp/ping_receiver.o \ + diffusion3/apps/pingapp/ping_common.o \ + diffusion3/apps/pingapp/push_receiver.o \ + diffusion3/apps/pingapp/push_sender.o \ + diffusion3/apps/gear/geo-attr.o \ + diffusion3/apps/gear/geo-routing.o \ + diffusion3/apps/gear/geo-tools.o \ + nix/hdr_nv.o nix/classifier-nix.o \ + nix/nixnode.o nix/nixvec.o \ + nix/nixroute.o + +NS_TCL_LIB_STL = tcl/lib/ns-diffusion.tcl + + + +# WIN32: uncomment the following line to include specific make for VC++ +# !include + +OBJ_CC = \ + tools/random.o tools/rng.o tools/ranvar.o common/misc.o common/timer-handler.o \ + common/scheduler.o common/object.o common/packet.o \ + common/ip.o routing/route.o common/connector.o common/ttl.o \ + trace/trace.o trace/trace-ip.o \ + classifier/classifier.o classifier/classifier-addr.o \ + classifier/classifier-hash.o \ + classifier/classifier-virtual.o \ + classifier/classifier-mcast.o \ + classifier/classifier-bst.o \ + classifier/classifier-mpath.o mcast/replicator.o \ + classifier/classifier-mac.o \ + classifier/classifier-qs.o \ + classifier/classifier-port.o src_rtg/classifier-sr.o \ + src_rtg/sragent.o src_rtg/hdr_src.o adc/ump.o \ + qs/qsagent.o qs/hdr_qs.o \ + apps/app.o apps/telnet.o tcp/tcplib-telnet.o \ + tools/trafgen.o trace/traffictrace.o tools/pareto.o \ + tools/expoo.o tools/cbr_traffic.o \ + adc/tbf.o adc/resv.o adc/sa.o tcp/saack.o \ + tools/measuremod.o adc/estimator.o adc/adc.o adc/ms-adc.o \ + adc/timewindow-est.o adc/acto-adc.o \ + adc/pointsample-est.o adc/salink.o adc/actp-adc.o \ + adc/hb-adc.o adc/expavg-est.o\ + adc/param-adc.o adc/null-estimator.o \ + adc/adaptive-receiver.o apps/vatrcvr.o adc/consrcvr.o \ + common/agent.o common/message.o apps/udp.o \ + common/session-rtp.o apps/rtp.o tcp/rtcp.o \ + common/ivs.o \ + tcp/tcp.o tcp/tcp-sink.o tcp/tcp-reno.o \ + tcp/tcp-newreno.o \ + tcp/tcp-vegas.o tcp/tcp-rbp.o tcp/tcp-full.o tcp/rq.o \ + baytcp/tcp-full-bay.o baytcp/ftpc.o baytcp/ftps.o \ + tcp/scoreboard.o tcp/scoreboard-rq.o tcp/tcp-sack1.o tcp/tcp-fack.o \ + tcp/tcp-asym.o tcp/tcp-asym-sink.o tcp/tcp-fs.o \ + tcp/tcp-asym-fs.o tcp/tcp-qs.o \ + tcp/tcp-int.o tcp/chost.o tcp/tcp-session.o \ + tcp/nilist.o \ + tools/integrator.o tools/queue-monitor.o \ + tools/flowmon.o tools/loss-monitor.o \ + queue/queue.o queue/drop-tail.o \ + adc/simple-intserv-sched.o queue/red.o \ + queue/semantic-packetqueue.o queue/semantic-red.o \ + tcp/ack-recons.o \ + queue/sfq.o queue/fq.o queue/drr.o queue/srr.o queue/cbq.o \ + queue/jobs.o queue/marker.o queue/demarker.o \ + link/hackloss.o queue/errmodel.o queue/fec.o\ + link/delay.o tcp/snoop.o \ + gaf/gaf.o \ + link/dynalink.o routing/rtProtoDV.o common/net-interface.o \ + mcast/ctrMcast.o mcast/mcast_ctrl.o mcast/srm.o \ + common/sessionhelper.o queue/delaymodel.o \ + mcast/srm-ssm.o mcast/srm-topo.o \ + apps/mftp.o apps/mftp_snd.o apps/mftp_rcv.o \ + apps/codeword.o \ + routing/alloc-address.o routing/address.o \ + $(LIB_DIR)int.Vec.o $(LIB_DIR)int.RVec.o \ + $(LIB_DIR)dmalloc_support.o \ + webcache/http.o webcache/tcp-simple.o webcache/pagepool.o \ + webcache/inval-agent.o webcache/tcpapp.o webcache/http-aux.o \ + webcache/mcache.o webcache/webtraf.o \ + webcache/webserver.o \ + webcache/logweb.o \ + empweb/empweb.o \ + empweb/empftp.o \ + realaudio/realaudio.o \ + mac/lanRouter.o classifier/filter.o \ + common/pkt-counter.o \ + common/Decapsulator.o common/Encapsulator.o \ + common/encap.o \ + mac/channel.o mac/mac.o mac/ll.o mac/mac-802_11.o \ + mac/mac-802_3.o mac/mac-tdma.o mac/smac.o \ + mobile/mip.o mobile/mip-reg.o mobile/gridkeeper.o \ + mobile/propagation.o mobile/tworayground.o \ + mobile/antenna.o mobile/omni-antenna.o \ + mobile/shadowing.o mobile/shadowing-vis.o mobile/dumb-agent.o \ + common/bi-connector.o common/node.o \ + common/mobilenode.o \ + mac/arp.o mobile/god.o mobile/dem.o \ + mobile/topography.o mobile/modulation.o \ + queue/priqueue.o queue/dsr-priqueue.o \ + mac/phy.o mac/wired-phy.o mac/wireless-phy.o \ + mac/mac-timers.o trace/cmu-trace.o mac/varp.o \ + dsdv/dsdv.o dsdv/rtable.o queue/rtqueue.o \ + routing/rttable.o \ + imep/imep.o imep/dest_queue.o imep/imep_api.o \ + imep/imep_rt.o imep/rxmit_queue.o imep/imep_timers.o \ + imep/imep_util.o imep/imep_io.o \ + tora/tora.o tora/tora_api.o tora/tora_dest.o \ + tora/tora_io.o tora/tora_logs.o tora/tora_neighbor.o \ + dsr/dsragent.o dsr/hdr_sr.o dsr/mobicache.o dsr/path.o \ + dsr/requesttable.o dsr/routecache.o dsr/add_sr.o \ + dsr/dsr_proto.o dsr/flowstruct.o dsr/linkcache.o \ + dsr/simplecache.o dsr/sr_forwarder.o \ + aodv/aodv_logs.o aodv/aodv.o \ + aodv/aodv_rtable.o aodv/aodv_rqueue.o \ + common/ns-process.o \ + satellite/satgeometry.o satellite/sathandoff.o \ + satellite/satlink.o satellite/satnode.o \ + satellite/satposition.o satellite/satroute.o \ + satellite/sattrace.o \ + rap/raplist.o rap/rap.o rap/media-app.o rap/utilities.o \ + common/fsm.o tcp/tcp-abs.o \ + diffusion/diffusion.o diffusion/diff_rate.o diffusion/diff_prob.o \ + diffusion/diff_sink.o diffusion/flooding.o diffusion/omni_mcast.o \ + diffusion/hash_table.o diffusion/routing_table.o diffusion/iflist.o \ + tcp/tfrc.o tcp/tfrc-sink.o mobile/energy-model.o apps/ping.o tcp/tcp-rfc793edu.o \ + queue/rio.o queue/semantic-rio.o tcp/tcp-sack-rh.o tcp/scoreboard-rh.o \ + plm/loss-monitor-plm.o plm/cbr-traffic-PP.o \ + linkstate/hdr-ls.o \ + mpls/classifier-addr-mpls.o mpls/ldp.o mpls/mpls-module.o \ + routing/rtmodule.o classifier/classifier-hier.o \ + routing/addr-params.o \ + routealgo/rnode.o \ + routealgo/bfs.o \ + routealgo/rbitmap.o \ + routealgo/rlookup.o \ + routealgo/routealgo.o \ + diffserv/dsred.o diffserv/dsredq.o \ + diffserv/dsEdge.o diffserv/dsCore.o \ + diffserv/dsPolicy.o diffserv/ew.o\ + queue/red-pd.o queue/pi.o queue/vq.o queue/rem.o \ + queue/gk.o \ + pushback/rate-limit.o pushback/rate-limit-strategy.o \ + pushback/ident-tree.o pushback/agg-spec.o \ + pushback/logging-data-struct.o \ + pushback/rate-estimator.o \ + pushback/pushback-queue.o pushback/pushback.o \ + common/parentnode.o trace/basetrace.o \ + common/simulator.o asim/asim.o \ + common/scheduler-map.o common/splay-scheduler.o \ + linkstate/ls.o linkstate/rtProtoLS.o \ + pgm/classifier-pgm.o pgm/pgm-agent.o pgm/pgm-sender.o \ + pgm/pgm-receiver.o mcast/rcvbuf.o \ + mcast/classifier-lms.o mcast/lms-agent.o mcast/lms-receiver.o \ + mcast/lms-sender.o \ + @V_STLOBJ@ + + +# don't allow comments to follow continuation lines + +# mac-csma.o mac-multihop.o\ +# sensor-nets/landmark.o mac-simple-wireless.o \ +# sensor-nets/tags.o sensor-nets/sensor-query.o \ +# sensor-nets/flood-agent.o \ + +# what was here before is now in emulate/ +OBJ_C = + +OBJ_COMPAT = $(OBJ_GETOPT) common/win32.o +#XXX compat/win32x.o compat/tkConsole.o + +OBJ_EMULATE_CC = \ + emulate/net-ip.o \ + emulate/net.o \ + emulate/tap.o \ + emulate/ether.o \ + emulate/internet.o \ + emulate/ping_responder.o \ + emulate/arp.o \ + emulate/icmp.o \ + emulate/net-pcap.o \ + emulate/nat.o \ + emulate/iptap.o \ + emulate/tcptap.o + +OBJ_EMULATE_C = \ + emulate/inet.o + +OBJ_GEN = $(GEN_DIR)version.o $(GEN_DIR)ns_tcl.o $(GEN_DIR)ptypes.o + +#NRL additions +OBJ_PROTOLIB_CPP = \ + protolib/ns/nsProtoSimAgent.o protolib/common/protoSimAgent.o \ + protolib/common/protoSimSocket.o protolib/common/protoAddress.o \ + protolib/common/protoTimer.o protolib/common/protoExample.o \ + protolib/common/protoDebug.o + +OBJ_MDP_CPP = \ + mdp/ns/nsMdpAgent.o mdp/common/mdpSimAgent.o \ + mdp/common/mdpBitMask.o mdp/common/mdpMessage.o \ + mdp/common/mdpEncoder.o mdp/common/galois.o \ + mdp/common/mdpSession.o mdp/common/mdpMsgHandler.o \ + mdp/common/mdpNode.o mdp/common/mdpObject.o \ + mdp/unix/mdpFile.o + +OBJ_NORM_CPP = \ + norm/ns/nsNormAgent.o norm/common/normSimAgent.o \ + norm/common/normMessage.o norm/common/normSession.o \ + norm/common/normNode.o norm/common/normObject.o \ + norm/common/normSegment.o norm/common/normBitmask.o \ + norm/common/normEncoder.o norm/common/galois.o \ + norm/common/normFile.o + +OBJ_MGEN_CPP = \ + mgen/ns/nsMgenAgent.o \ + mgen/common/mgen.o mgen/common/mgenEvent.o \ + mgen/common/mgenFlow.o mgen/common/mgenMsg.o \ + mgen/common/mgenSocketList.o mgen/common/mgenPattern.o + +OBJ_CPP = $(OBJ_PROTOLIB_CPP) $(OBJ_MDP_CPP) $(OBJ_NORM_CPP) $(OBJ_MGEN_CPP) + +SRC = $(OBJ_C:.o=.c) $(OBJ_CC:.o=.cc) \ + $(OBJ_EMULATE_C:.o=.c) $(OBJ_EMULATE_CC:.o=.cc) \ + common/tclAppInit.cc common/tkAppInit.cc + +OBJ = $(OBJ_C) $(OBJ_CC) $(OBJ_GEN) $(OBJ_COMPAT) $(OBJ_CPP) + +CLEANFILES = ns nse nsx ns.dyn $(OBJ) $(OBJ_EMULATE_CC) \ + $(OBJ_EMULATE_C) common/tclAppInit.o \ + $(GEN_DIR)* $(NS).core core core.$(NS) core.$(NSX) core.$(NSE) \ + common/ptypes2tcl common/ptypes2tcl.o + +SUBDIRS=\ + indep-utils/cmu-scen-gen/setdest \ + indep-utils/webtrace-conv/dec \ + indep-utils/webtrace-conv/epa \ + indep-utils/webtrace-conv/nlanr \ + indep-utils/webtrace-conv/ucb + +BUILD_NSE = @build_nse@ + +all: $(NS) $(BUILD_NSE) all-recursive + + +all-recursive: + for i in $(SUBDIRS); do ( cd $$i; $(MAKE) all; ) done + +$(NS): $(OBJ) common/tclAppInit.o Makefile + $(LINK) $(LDFLAGS) $(LDOUT)$@ \ + common/tclAppInit.o $(OBJ) $(LIB) + +Makefile: Makefile.in + @echo "Makefile.in is newer than Makefile." + @echo "You need to re-run configure." + false + +$(NSE): $(OBJ) common/tclAppInit.o $(OBJ_EMULATE_CC) $(OBJ_EMULATE_C) + $(LINK) $(LDFLAGS) $(LDOUT)$@ \ + common/tclAppInit.o $(OBJ) \ + $(OBJ_EMULATE_CC) $(OBJ_EMULATE_C) $(LIB) + +ns.dyn: $(OBJ) common/tclAppInit.o + $(LINK) $(LDFLAGS) -o $@ \ + common/tclAppInit.o $(OBJ) $(LIB) + +PURIFY = purify -cache-dir=/tmp +ns-pure: $(OBJ) common/tclAppInit.o + $(PURIFY) $(LINK) $(LDFLAGS) -o $@ \ + common/tclAppInit.o $(OBJ) $(LIB) + +NS_TCL_LIB = \ + tcl/lib/ns-compat.tcl \ + tcl/lib/ns-default.tcl \ + tcl/lib/ns-errmodel.tcl \ + tcl/lib/ns-lib.tcl \ + tcl/lib/ns-link.tcl \ + tcl/lib/ns-mobilenode.tcl \ + tcl/lib/ns-sat.tcl \ + tcl/lib/ns-cmutrace.tcl \ + tcl/lib/ns-node.tcl \ + tcl/lib/ns-rtmodule.tcl \ + tcl/lib/ns-hiernode.tcl \ + tcl/lib/ns-packet.tcl \ + tcl/lib/ns-queue.tcl \ + tcl/lib/ns-source.tcl \ + tcl/lib/ns-nam.tcl \ + tcl/lib/ns-trace.tcl \ + tcl/lib/ns-agent.tcl \ + tcl/lib/ns-random.tcl \ + tcl/lib/ns-namsupp.tcl \ + tcl/lib/ns-address.tcl \ + tcl/lib/ns-intserv.tcl \ + tcl/lib/ns-autoconf.tcl \ + tcl/rtp/session-rtp.tcl \ + tcl/lib/ns-mip.tcl \ + tcl/rtglib/dynamics.tcl \ + tcl/rtglib/route-proto.tcl \ + tcl/rtglib/algo-route-proto.tcl \ + tcl/rtglib/ns-rtProtoLS.tcl \ + tcl/interface/ns-iface.tcl \ + tcl/mcast/BST.tcl \ + tcl/mcast/ns-mcast.tcl \ + tcl/mcast/McastProto.tcl \ + tcl/mcast/DM.tcl \ + tcl/mcast/srm.tcl \ + tcl/mcast/srm-adaptive.tcl \ + tcl/mcast/srm-ssm.tcl \ + tcl/mcast/timer.tcl \ + tcl/mcast/McastMonitor.tcl \ + tcl/mcast/mftp_snd.tcl \ + tcl/mcast/mftp_rcv.tcl \ + tcl/mcast/mftp_rcv_stat.tcl \ + tcl/mobility/dsdv.tcl \ + tcl/mobility/dsr.tcl \ + tcl/ctr-mcast/CtrMcast.tcl \ + tcl/ctr-mcast/CtrMcastComp.tcl \ + tcl/ctr-mcast/CtrRPComp.tcl \ + tcl/rlm/rlm.tcl \ + tcl/rlm/rlm-ns.tcl \ + tcl/session/session.tcl \ + tcl/lib/ns-route.tcl \ + tcl/emulate/ns-emulate.tcl \ + tcl/lan/vlan.tcl \ + tcl/lan/abslan.tcl \ + tcl/lan/ns-ll.tcl \ + tcl/lan/ns-mac.tcl \ + tcl/webcache/http-agent.tcl \ + tcl/webcache/http-server.tcl \ + tcl/webcache/http-cache.tcl \ + tcl/webcache/http-mcache.tcl \ + tcl/webcache/webtraf.tcl \ + tcl/webcache/empweb.tcl \ + tcl/webcache/empftp.tcl \ + tcl/plm/plm.tcl \ + tcl/plm/plm-ns.tcl \ + tcl/plm/plm-topo.tcl \ + tcl/mpls/ns-mpls-classifier.tcl \ + tcl/mpls/ns-mpls-ldpagent.tcl \ + tcl/mpls/ns-mpls-node.tcl \ + tcl/mpls/ns-mpls-simulator.tcl \ + tcl/lib/ns-pushback.tcl \ + tcl/lib/ns-srcrt.tcl \ + tcl/mcast/ns-lms.tcl \ + tcl/lib/ns-qsnode.tcl \ + @V_NS_TCL_LIB_STL@ + +$(GEN_DIR)ns_tcl.cc: $(NS_TCL_LIB) + $(TCLSH) bin/tcl-expand.tcl tcl/lib/ns-lib.tcl @V_NS_TCL_LIB_STL@ | $(TCL2C) et_ns_lib > $@ + +$(GEN_DIR)version.c: VERSION + $(RM) $@ + $(TCLSH) bin/string2c.tcl version_string < VERSION > $@ + +$(GEN_DIR)ptypes.cc: common/ptypes2tcl common/packet.h + ./common/ptypes2tcl > $@ + +common/ptypes2tcl: common/ptypes2tcl.o + $(LINK) $(LDFLAGS) $(LDOUT)$@ common/ptypes2tcl.o + +common/ptypes2tcl.o: common/ptypes2tcl.cc common/packet.h + +install: force install-ns install-man install-recursive + +install-ns: force + $(INSTALL) -m 555 -o bin -g bin ns $(DESTDIR)$(BINDEST) + +install-man: force + $(INSTALL) -m 444 -o bin -g bin ns.1 $(DESTDIR)$(MANDEST)/man1 + +install-recursive: force + for i in $(SUBDIRS); do ( cd $$i; $(MAKE) install; ) done + +clean: + $(RM) $(CLEANFILES) + +nrlclean: + $(RM) $(OBJ_CPP) + + +AUTOCONF_GEN = tcl/lib/ns-autoconf.tcl +distclean: distclean-recursive + $(RM) $(CLEANFILES) Makefile config.cache config.log config.status \ + autoconf.h gnuc.h os-proto.h $(AUTOCONF_GEN); \ + $(MV) .configure .configure- ;\ + echo "Moved .configure to .configure-" + +distclean-recursive: + for i in $(SUBDIRS); do ( cd $$i; $(MAKE) clean; $(RM) Makefile; ) done + +tags: force + ctags -wtd *.cc *.h webcache/*.cc webcache/*.h dsdv/*.cc dsdv/*.h \ + dsr/*.cc dsr/*.h webcache/*.cc webcache/*.h lib/*.cc lib/*.h \ + ../Tcl/*.cc ../Tcl/*.h + +TAGS: force + etags *.cc *.h webcache/*.cc webcache/*.h dsdv/*.cc dsdv/*.h \ + dsr/*.cc dsr/*.h webcache/*.cc webcache/*.h lib/*.cc lib/*.h \ + ../Tcl/*.cc ../Tcl/*.h + +tcl/lib/TAGS: force + ( \ + cd tcl/lib; \ + $(TCLSH) ../../bin/tcl-expand.tcl ns-lib.tcl | grep '^### tcl-expand.tcl: begin' | awk '{print $$5}' >.tcl_files; \ + etags --lang=none -r '/^[ \t]*proc[ \t]+\([^ \t]+\)/\1/' `cat .tcl_files`; \ + etags --append --lang=none -r '/^\([A-Z][^ \t]+\)[ \t]+\(instproc\|proc\)[ \t]+\([^ \t]+\)[ \t]+/\1::\3/' `cat .tcl_files`; \ + ) + +depend: $(SRC) + $(MKDEP) $(CFLAGS) $(INCLUDES) $(SRC) + +srctar: + @cwd=`pwd` ; dir=`basename $$cwd` ; \ + name=ns-`cat VERSION | tr A-Z a-z` ; \ + tar=ns-src-`cat VERSION`.tar.gz ; \ + list="" ; \ + for i in `cat FILES` ; do list="$$list $$name/$$i" ; done; \ + echo \ + "(rm -f $$tar; cd .. ; ln -s $$dir $$name)" ; \ + (rm -f $$tar; cd .. ; ln -s $$dir $$name) ; \ + echo \ + "(cd .. ; tar cfh $$tar [lots of files])" ; \ + (cd .. ; tar cfh - $$list) | gzip -c > $$tar ; \ + echo \ + "rm ../$$name; chmod 444 $$tar" ; \ + rm ../$$name; chmod 444 $$tar + +force: + +test: force + ./validate + +# Create makefile.vc for Win32 development by replacing: +# "# !include ..." -> "!include ..." +makefile.vc: Makefile.in + $(PERL) bin/gen-vcmake.pl < Makefile.in > makefile.vc +# $(PERL) -pe 's/^# (\!include)/\!include/o' < Makefile.in > makefile.vc diff --git a/ns/nsNormAgent.cpp b/ns/nsNormAgent.cpp index 99b238b..b1d0871 100644 --- a/ns/nsNormAgent.cpp +++ b/ns/nsNormAgent.cpp @@ -45,10 +45,7 @@ static class NsNormAgentClass : public TclClass NsNormAgent::NsNormAgent() - : NormSimAgent(ProtoSimAgent::TimerInstaller, - static_cast(this), - ProtoSimAgent::SocketInstaller, - static_cast(this)) + : NormSimAgent(GetTimerMgr(), GetSocketNotifier()) { } @@ -57,7 +54,25 @@ NsNormAgent::~NsNormAgent() { } -int NsNormAgent::command(int argc, const char*const* argv) +bool NsNormAgent::OnStartup(int argc, const char*const* argv) +{ + if (ProcessCommands(argc, argv)) + { + return true; + } + else + { + fprintf(stderr, "NsNormAgent::OnStartup() error processing commands\n"); + return false; + } +} // end NsNormAgent::OnStartup() + +void NsNormAgent::OnShutdown() +{ + NormSimAgent::Stop(); +} // end NsNormAgent::OnShutdown() + +bool NsNormAgent::ProcessCommands(int argc, const char*const* argv) { // Process commands, passing unknown commands to base Agent class int i = 1; @@ -70,8 +85,8 @@ int NsNormAgent::command(int argc, const char*const* argv) // Attach Agent/MGEN to this NormSimAgent if (++i >= argc) { - DMSG(0, "NsNormAgent::command() ProcessCommand(attach-mgen) error: insufficent arguments\n"); - return TCL_ERROR; + DMSG(0, "NsNormAgent::ProcessCommands() ProcessCommand(attach-mgen) error: insufficent arguments\n"); + return false; } Tcl& tcl = Tcl::instance(); NsMgenAgent* mgenAgent = dynamic_cast (tcl.lookup(argv[i])); @@ -83,8 +98,8 @@ int NsNormAgent::command(int argc, const char*const* argv) } else { - DMSG(0, "NsNormAgent::command() ProcessCommand(attach-mgen) error: invalid mgen agent\n"); - return TCL_ERROR; + DMSG(0, "NsNormAgent::ProcessCommands() ProcessCommand(attach-mgen) error: invalid mgen agent\n"); + return false; } } else if (!strcmp(argv[i], "active")) @@ -105,9 +120,9 @@ int NsNormAgent::command(int argc, const char*const* argv) case NormSimAgent::CMD_NOARG: if (!ProcessCommand(argv[i], NULL)) { - DMSG(0, "NsNormAgent::command() ProcessCommand(%s) error\n", + DMSG(0, "NsNormAgent::ProcessCommands() ProcessCommand(%s) error\n", argv[i]); - return TCL_ERROR; + return false; } i++; break; @@ -115,23 +130,23 @@ int NsNormAgent::command(int argc, const char*const* argv) case NormSimAgent::CMD_ARG: if (!ProcessCommand(argv[i], argv[i+1])) { - DMSG(0, "NsNormAgent::command() ProcessCommand(%s, %s) error\n", + DMSG(0, "NsNormAgent::ProcessCommands() ProcessCommand(%s, %s) error\n", argv[i], argv[i+1]); - return TCL_ERROR; + return false; } i += 2; break; case NormSimAgent::CMD_INVALID: - return NsProtoAgent::command(argc, argv); + return false; } } - return TCL_OK; -} // end NsNormAgent::command() + return true; +} // end NsNormAgent::ProcessCommands() -bool NsNormAgent::SendMgenMessage(const NetworkAddress* dstAddr, - const char* txBuffer, - unsigned int len) +bool NsNormAgent::SendMgenMessage(const char* txBuffer, + unsigned int len, + const ProtoAddress& /*dstAddr*/) { return SendMessage(len, txBuffer); } // end NsNormAgent::SendMgenMessage() diff --git a/ns/nsNormAgent.h b/ns/nsNormAgent.h index c2c8215..6b51a12 100644 --- a/ns/nsNormAgent.h +++ b/ns/nsNormAgent.h @@ -33,7 +33,7 @@ #ifndef _NS_NORM_AGENT #define _NS_NORM_AGENT -#include "nsProtoAgent.h" // from ProtoLib +#include "nsProtoSimAgent.h" // from Protolib #include "normSimAgent.h" #include "nsMgenAgent.h" @@ -44,20 +44,23 @@ // IMPORTANT NOTE! NsProtoAgent must be listed _first_ here // (because we can't dynamic_cast install_data void* pointers) -class NsNormAgent : public NsProtoAgent, public NormSimAgent, public MgenSink +class NsNormAgent : public NsProtoSimAgent, public NormSimAgent, public MgenSink { public: NsNormAgent(); ~NsNormAgent(); - // NsProtoAgent base class override - int command(int argc, const char*const* argv); + // NsProtoSimAgent base class overrides + virtual bool OnStartup(int argc, const char*const* argv); + virtual bool ProcessCommands(int argc, const char*const* argv); + virtual void OnShutdown(); + // NormSimAgent override unsigned long GetAgentId() {return (unsigned long)addr();} // MgenSink override - bool SendMgenMessage(const NetworkAddress* dstAddr, - const char* txBuffer, - unsigned int len); + bool SendMgenMessage(const char* txBuffer, + unsigned int len, + const ProtoAddress& dstAddr); }; // end class NsNormAgent diff --git a/unix/Makefile.common b/unix/Makefile.common index a859567..9649a5b 100644 --- a/unix/Makefile.common +++ b/unix/Makefile.common @@ -18,7 +18,7 @@ CFLAGS = -g -DPROTO_DEBUG -DUNIX -O -fPIC $(SYSTEM_HAVES) $(INCLUDES) LDFLAGS = $(SYSTEM_LDFLAGS) # Note: Even command line app needs X11 for Netscape post-processing -LIBS = $(SYSTEM_LIBS) -lm +LIBS = $(SYSTEM_LIBS) -lm -lpthread XLIBS = -lXmu -lXt -lX11 #NOTE: TK_LIB must come before TCL_LIB for some reason @@ -47,9 +47,9 @@ TARGETS = mdp tkMdp $(CC) -c $(CFLAGS) -o $*.o $*.cpp # MDP depends upon the NRL Protean Group's development library -LIBPROTO = $(PROTOLIB)/unix/libProto.a -$(PROTOLIB)/unix/libProto.a: - cd $(PROTOLIB)/unix; $(MAKE) -f Makefile.$(SYSTEM) libProto.a +LIBPROTO = $(PROTOLIB)/unix/libProtokit.a +$(PROTOLIB)/unix/libProtokit.a: + cd $(PROTOLIB)/unix; $(MAKE) -f Makefile.$(SYSTEM) libProtokit.a NORM_SRC = $(COMMON)/normMessage.cpp $(COMMON)/normSession.cpp \ $(COMMON)/normNode.cpp $(COMMON)/normObject.cpp \ @@ -77,7 +77,8 @@ libnormSim.a: $(SIM_OBJ) ranlib $@ # (mdp) command-line file broadcaster/receiver -APP_SRC = $(COMMON)/normApp.cpp $(COMMON)/normPostProcess.cpp +APP_SRC = $(COMMON)/normApp.cpp $(COMMON)/normPostProcess.cpp \ + $(UNIX)/unixPostProcess.cpp APP_OBJ = $(APP_SRC:.cpp=.o) norm: $(APP_OBJ) libnorm.a $(LIBPROTO) diff --git a/unix/Makefile.freebsd b/unix/Makefile.freebsd index ea2eb6f..4233ce2 100644 --- a/unix/Makefile.freebsd +++ b/unix/Makefile.freebsd @@ -2,37 +2,14 @@ # FreeBSD Protean Makefile definitions # -# TO BUILD THE TK GUI VERSION, EDIT THE FOLLOWING NUMBERED -# ITEMS AS NEEDED FOR YOUR SYSTEM -# (This has only been tested with TCL/TK 8.0 but it probably -# will work with Tcl7.x/Tk4.x with a little tweaking to -# the list of TCL_SCRIPTS (library scripts) given below) - -# 1) Where to find the Tcl standard library scripts -# (e.g. init.tcl, ...) -TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0 - -# 2) Where to find the Tk standard library scripts -# (e.g. button.tcl, entry.tcl, ...) -TK_SCRIPT_PATH = /usr/local/lib/tk8.0 - -# 3) Where to find Tcl/Tk header files -# (e.g. tcl.h, tk.h, ...) -TCL_INCL_PATH = -I/usr/local/include/tcl8.0 -I/usr/local/include/tk8.0 - -# 4) Point to specific libtcl.a and libtk.a to use -TCL_LIB = /usr/local/lib/libtcl80.a -TK_LIB = /usr/local/lib/libtk80.a - - -# 5) System specific additional libraries, include paths, etc +# 1) System specific additional libraries, include paths, etc # (Where to find X11 libraries, etc) # -SYSTEM_INCLUDES = -I/usr/X11R6/include -SYSTEM_LDFLAGS = -L/usr/X11R6/lib +SYSTEM_INCLUDES = +SYSTEM_LDFLAGS = SYSTEM_LIBS = -# 6) System specific capabilities +# 2) System specific capabilities # Must choose appropriate for the following: # # A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin() @@ -48,7 +25,7 @@ SYSTEM_LIBS = # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # routine. # -# E) The MDP code's use of offset pointers requires special treatment +# E) The PROTOLIB code's use of offset pointers requires special treatment # for some different compilers. Set -DUSE_INHERITANCE for some # to keep some compilers (gcc 2.7.2) happy. # @@ -62,10 +39,13 @@ SYSTEM_LIBS = # (We export these for other Makefiles as needed) # -export SYSTEM_HAVES = -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) +SYSTEM_HAVES = -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) -export CC = gcc -export RANLIB = ranlib -export AR = ar +SYSTEM_SRC = bsdRouteMgr.cpp + +SYSTEM = freebsd +CC = gcc +RANLIB = ranlib +AR = ar include Makefile.common diff --git a/unix/Makefile.linux b/unix/Makefile.linux index d2dced7..00f862f 100644 --- a/unix/Makefile.linux +++ b/unix/Makefile.linux @@ -28,7 +28,7 @@ TK_LIB = -ltk #/usr/local/lib/libtk8.0.a # 5) System specific additional libraries, include paths, etc # (Where to find X11 libraries, etc) # -SYSTEM_INCLUDES = -I/usr/X11R6/include +SYSTEM_INCLUDES = -Wall -I/usr/X11R6/include SYSTEM_LDFLAGS = -L/usr/X11R6/lib SYSTEM_LIBS = -ldl @@ -62,10 +62,14 @@ SYSTEM_LIBS = -ldl # (We export these for other Makefiles as needed) # -export SYSTEM_HAVES = -DLINUX -DHAVE_IPV6 -DHAVE_GETLOGIN -DHAVE_LOCKF \ +SYSTEM_HAVES = -DLINUX -DHAVE_IPV6 -DHAVE_GETLOGIN -DHAVE_LOCKF \ -DHAVE_OLD_SIGNALHANDLER -DHAVE_DIRFD -DHAVE_ASSERT $(NETSEC) -export CC = gcc +SYSTEM_SRC = + +SYSTEM = linux + +export CC = g++ export RANLIB = ranlib export AR = ar diff --git a/unix/Makefile.macosx b/unix/Makefile.macosx index 7158ad5..09e6b73 100644 --- a/unix/Makefile.macosx +++ b/unix/Makefile.macosx @@ -5,6 +5,7 @@ # 1) System specific additional libraries, include paths, etc # (Where to find X11 libraries, etc) # + SYSTEM_INCLUDES = -I/usr/X11R6/include SYSTEM_LDFLAGS = -L/usr/X11R6/lib SYSTEM_LIBS = @@ -35,7 +36,12 @@ SYSTEM_LIBS = # (We export these for other Makefiles as needed) # -export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) -DSOCKLEN_T=int +export SYSTEM_HAVES = -DMACOSX -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_GETLOGIN -DHAVE_FLOCK -DHAVE_DIRFD $(DNETSEC) -DSOCKLEN_T=int + +SYSTEM_SRC = bsdRouteMgr.cpp + +# The "SYSTEM" keyword can be used for dependent makes +SYSTEM = macosx export CC = g++ export RANLIB = ranlib diff --git a/unix/Makefile.sgi b/unix/Makefile.sgi index 6003e22..3e35337 100644 --- a/unix/Makefile.sgi +++ b/unix/Makefile.sgi @@ -3,11 +3,10 @@ # - # 1) System specific additional libraries, include paths, etc # (Where to find X11 libraries, etc) # -SYSTEM_INCLUDES = -DIRIX -n32 -woff 3333 -cfront +SYSTEM_INCLUDES = -DIRIX -n32 -woff 3333 SYSTEM_LDFLAGS = SYSTEM_LIBS = diff --git a/unix/Makefile.solaris b/unix/Makefile.solaris index 6ff7bcb..532f76f 100644 --- a/unix/Makefile.solaris +++ b/unix/Makefile.solaris @@ -1,36 +1,15 @@ # -# MDPv2 Solaris Makefile +# NORM Solaris Makefile # -# TO BUILD THE TK GUI VERSION OF MDP EDIT THE FOLLOWING NUMBERED -# ITEMS AS NEEDED FOR YOUR SYSTEM -# (This has only been tested with TCL/TK 8.0 but it probably -# will work with Tcl7.x/Tk4.x with a little tweaking to -# the list of TCL_SCRIPTS (library scripts) given below) -# 1) Where to find the Tcl standard library scripts -# (e.g. init.tcl, ...) -TCL_SCRIPT_PATH = /usr/local/lib/tcl8.0 - -# 2) Where to find the Tk standard library scripts -# (e.g. button.tcl, entry.tcl, ...) -TK_SCRIPT_PATH = /usr/local/lib/tk8.0 - -# 3) Where to find Tcl/Tk header files -# (e.g. tcl.h, tk.h, ...) -TCL_INCL_PATH = -I/usr/local/include - -# 4) Point to specific libtcl.a and libtk.a to use -TCL_LIB = /usr/local/lib/libtcl8.0.a -TK_LIB = /usr/local/lib/libtk8.0.a - -# 5) System specific additional libraries, include paths, etc +# 1) System specific additional libraries, include paths, etc # (Where to find X11 libraries, etc) # SYSTEM_INCLUDES = -I/usr/openwin/include SYSTEM_LDFLAGS = -L/usr/openwin/lib -R/usr/openwin/lib -SYSTEM_LIBS = -ldl -lnsl -lsocket +SYSTEM_LIBS = -ldl -lnsl -lsocket -lresolv -# 6) System specific capabilities +# 2) System specific capabilities # Must choose appropriate for the following: # # A) -DHAVE_CUSERID (preferred) or -DHAVE_GETLOGIN for cuserid() or getlogin() @@ -46,24 +25,24 @@ SYSTEM_LIBS = -ldl -lnsl -lsocket # D) Optionally specify -DHAVE_ASSERT if your system has a built-in ASSERT() # routine. # -# E) The MDP code's use of offset pointers requires special treatment -# for some different compilers. Set -DUSE_INHERITANCE for some -# to keep some compilers (gcc 2.7.2) happy. -# -# F) Some systems (SOLARIS/SUNOS) have a few gotchas which require +# E) Some systems (SOLARIS/SUNOS) have a few gotchas which require # some #ifdefs to avoid compiler warnings ... so you might need # to specify -DSOLARIS or -DSUNOS depending on your OS. # -# G) Uncomment this if you have the NRL IPv6+IPsec software +# F) Uncomment this if you have the NRL IPv6+IPsec software #DNETSEC = -DNETSEC -I/usr/inet6/include # # (We export these for other Makefiles as needed) # -export SYSTEM_HAVES = -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS +SYSTEM_HAVES = -DHAVE_IPV6 -DHAVE_ASSERT -DHAVE_CUSERID -DHAVE_LOCKF $(NETSEC) -DSOLARIS -export CC = gcc -export RANLIB = touch -export AR = ar +SYSTEM = solaris + +CC = g++ + +RANLIB = touch + +AR = ar include Makefile.common diff --git a/unix/unixPostProcess.cpp b/unix/unixPostProcess.cpp new file mode 100644 index 0000000..710e843 --- /dev/null +++ b/unix/unixPostProcess.cpp @@ -0,0 +1,411 @@ +/********************************************************************* + * + * AUTHORIZATION TO USE AND DISTRIBUTE + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that: + * + * (1) source code distributions retain this paragraph in its entirety, + * + * (2) distributions including binary code include this paragraph in + * its entirety in the documentation or other materials provided + * with the distribution, and + * + * (3) all advertising materials mentioning features or use of this + * software display the following acknowledgment: + * + * "This product includes software written and developed + * by Brian Adamson and Joe Macker of the Naval Research + * Laboratory (NRL)." + * + * The name of NRL, the name(s) of NRL employee(s), or any entity + * of the United States Government may not be used to endorse or + * promote products derived from this software, nor does the + * inclusion of the NRL written and developed software directly or + * indirectly suggest NRL or United States Government endorsement + * of this product. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + ********************************************************************/ + +// This file contains code for various UNIX MDP post processor options + + +/******************************************************************* + * Netscape[tm] post processor routines + */ + +// Some portions of this code +// Copyright © 1996 Netscape Communications Corporation, +// all rights reserved. + +#include "normPostProcess.h" +#include "protoDebug.h" + +#include +#include // for strerror() +#include +#include +#include +#include +#include +#include // for exit() +#include + +#ifndef sighandler_t +#ifndef sig_t +typedef void (*sighandler_t)(int); +#else +typedef sig_t sighandler_t; +#endif // if/else !sig_t +#endif // !sighandler_t + +#ifdef NETSCAPE_SUPPORT +#include +#include +#include /* for XmuClientWindow() */ + +/* vroot.h is a header file which lets a client get along with `virtual root' + window managers like swm, tvtwm, olvwm, etc. If you don't have this header + file, you can find it at "http://home.netscape.com/newsref/std/vroot.h". + If you don't care about supporting virtual root window managers, you can + comment this line out. + */ +#include "vroot.h" +#define MOZILLA_VERSION_PROP "_MOZILLA_VERSION" +static Atom XA_MOZILLA_VERSION = 0; +bool CheckForNetscape(const char* cmd); +bool NetscapeIsRunning(Window *result); +bool NetscapeCheckWindow(Window window); +#endif // NETSCAPE_SUPPORT + +class UnixPostProcessor : public NormPostProcessor +{ + public: + ~UnixPostProcessor(); + bool IsActive() {return (0 != process_id);} + bool ProcessFile(const char* path); + void Kill(); + + void OnSIGCHLD(); + + private: + friend class NormPostProcessor; + UnixPostProcessor(); + + int process_id; +#ifdef NETSCAPE_SUPPORT + Window window_id; +#endif // NETSCAPE_SUPPORT +}; // end class UnixPostProcessor + + +UnixPostProcessor::UnixPostProcessor() + : process_id(0) +#ifdef NETSCAPE_SUPPORT + ,window_id(0) +#endif // NETSCAPE_SUPPORT +{ +} + +NormPostProcessor* NormPostProcessor::Create() +{ + return static_cast(new UnixPostProcessor); +} // end NormPostProcessor::Create() + +UnixPostProcessor::~UnixPostProcessor() +{ + if (IsActive()) Kill(); +} + +bool UnixPostProcessor::ProcessFile(const char* path) +{ + const char** argv = (const char**)process_argv; + int argc = process_argc; +#ifdef NETSCAPE_SUPPORT + // Special support for finding a Netscape window and + // use the openURL remote command to display received file +#define USE_ACTIVE_WINDOW 0xffffffff + const char* myArgs[32]; + char wid_text[32], url_text[PATH_MAX+64]; + if (CheckForNetscape(argv[0])) + { + int i = 0; + myArgs[i++] = process_argv[0]; + Window w = 0; + // (TBD) We could put in a hack to look for the old + // window if we made "w" static when "window_id" = 0xffffffff + // This would help us capture the proper window for file display + // It's still a hack but it might work a little better without + // too much trouble + if (NetscapeIsRunning(&w)) + { + // Use -remote command to display file in current + // or new window + if (window_id) + { + if (NetscapeCheckWindow(window_id)) + { + // Use the same window as last time + myArgs[i++] = "-id"; + sprintf(wid_text, "0x%lx", window_id); + myArgs[i++] = wid_text; + myArgs[i++] = "-noraise"; + myArgs[i++] = "-remote"; + sprintf(url_text, "openURL(file://%s)", path); + myArgs[i++] = url_text; + } + else if (USE_ACTIVE_WINDOW == window_id) + { + // Capture the open window we found + myArgs[i++] = "-id"; + sprintf(wid_text, "0x%lx", w); + myArgs[i++] = wid_text; + window_id = w; + myArgs[i++] = "-noraise"; + myArgs[i++] = "-remote"; + sprintf(url_text, "openURL(file://%s)", path); + myArgs[i++] = url_text; + } + else // user must have closed old window so open another + { + window_id = USE_ACTIVE_WINDOW; + //myArgs[i++] = "-raise"; + myArgs[i++] = "-remote"; + sprintf(url_text, "openURL(file://%s,new-window)", path); + myArgs[i++] = url_text; + } + + } + else + { + // We're starting fresh, open a new window + window_id = USE_ACTIVE_WINDOW; + //myArgs[i++] = "-raise"; + myArgs[i++] = "-remote"; + sprintf(url_text, "openURL(file://%s,new-window)", path); + myArgs[i++] = url_text; + } + argv = myArgs; + + } + else + { + if (IsActive()) Kill(); + window_id = USE_ACTIVE_WINDOW; + myArgs[i++] = path; + } // end if/else (NetscapeIsRunning()) + myArgs[i] = NULL; + argc = i - 1; + argv = myArgs; + } + else +#endif // NETSCAPE_SUPPORT + { + if (IsActive()) Kill(); + argv[argc] = path; + } + + // 1) temporarily disable signal handling + sighandler_t sigtermHandler = signal(SIGTERM, SIG_DFL); + sighandler_t sigintHandler = signal(SIGINT, SIG_DFL); + sighandler_t sigchldHandler = signal(SIGCHLD, SIG_DFL); + + switch((process_id = fork())) + { + case -1: // error + DMSG(0, "UnixPostProcessor::ProcessFile fork() error: %s\n", strerror(errno)); + process_id = 0; + process_argv[process_argc] = NULL; + return false; + + case 0: // child + if (execvp((char*)argv[0], (char**)argv) < 0) + { + DMSG(0, "UnixPostProcessor::ProcessFile execvp() error: %s\n", strerror(errno)); + exit(-1); + } + break; + + default: // parent + process_argv[process_argc] = NULL; + // Restore signal handlers for parent + signal(SIGTERM, sigtermHandler); + signal(SIGINT, sigintHandler); + signal(SIGCHLD, sigchldHandler); + break; + } + return true; +} // end UnixPostProcessor::ProcessFile() + +void UnixPostProcessor::Kill() +{ + if (!IsActive()) return; + int count = 0; + while((kill(process_id, SIGTERM) != 0) && count < 10) + { + if (errno == ESRCH) break; + count++; + DMSG(0, "UnixPostProcessor::Kill kill() error: %s\n", strerror(errno)); + } + count = 0; + int status; + while((waitpid(process_id, &status, 0) != process_id) && count < 10) + { + if (errno == ECHILD) break; + count++; + DMSG(0, "UnixPostProcessor::Kill waitpid() error: %s\n", strerror(errno)); + } + process_id = 0; +} // end UnixPostProcessor::Kill() + +void UnixPostProcessor::OnSIGCHLD() +{ + // See if post processor exited itself + int status; + if (wait(&status) == process_id) process_id = 0; +} // end UnixPostProcessor::HandleSIGCHLD() + + +#ifdef NETSCAPE_SUPPORT +bool CheckForNetscape(const char* cmd) +{ + // See if it's Netscape post processing + // for which we provide special support + char txt[8]; + const char *ptr = strrchr(cmd, PROTO_PATH_DELIMITER); + if (ptr) + ptr++; + else + ptr = cmd; + strncpy(txt, ptr, 8); + for (int i=0; i<8; i++) txt[i] = toupper(txt[i]); + if (!strncmp(txt, "NETSCAPE", 8)) + return true; + else + return false; +} // end CheckForNetscape() + +bool NetscapeIsRunning(Window *result) +{ + int i; + + Window root2, parent, *kids; + unsigned int nkids; + *result = 0; + + Display *dpy = XOpenDisplay(NULL); + if (!dpy) + { + fprintf(stderr, "mdp: XOpenDisplay() error\n"); + return false; + } + + if (!XA_MOZILLA_VERSION) + XA_MOZILLA_VERSION = XInternAtom(dpy, MOZILLA_VERSION_PROP, False); + + Window root = RootWindowOfScreen(DefaultScreenOfDisplay(dpy)); + + if (!XQueryTree (dpy, root, &root2, &parent, &kids, &nkids)) + { + fprintf(stderr, "mdp: XQueryTree failed on display %s\n", DisplayString (dpy)); + XCloseDisplay(dpy); + return false; + } + + // Note: root != root2 is possible with virtual root WMs. + if (!(kids && nkids)) + { + fprintf(stderr, "mdp: root window has no children on display %s\n", + DisplayString (dpy)); + XCloseDisplay(dpy); + return false; + } + + for (i = nkids-1; i >= 0; i--) + { + Atom type; + int format; + unsigned long nitems, bytesafter; + unsigned char *version = 0; + Window w = XmuClientWindow (dpy, kids[i]); + int status = XGetWindowProperty (dpy, w, XA_MOZILLA_VERSION, + 0, (65536 / sizeof (long)), + False, XA_STRING, + &type, &format, &nitems, &bytesafter, + &version); + if (! version) continue; + XFree (version); + if (status == Success && type != None) + { + *result = w; + break; + } + } + XCloseDisplay(dpy); + return (*result ? true : false); + +} // end NetscapeIsRunning() + +bool NetscapeCheckWindow(Window window) +{ + int i; + Window root2, parent, *kids; + unsigned int nkids; + + Display *dpy = XOpenDisplay(NULL); + if (!dpy) + { + fprintf(stderr, "mdp: XOpenDisplay() error\n"); + return false; + } + + if (!XA_MOZILLA_VERSION) + XA_MOZILLA_VERSION = XInternAtom(dpy, MOZILLA_VERSION_PROP, False); + + Window root = RootWindowOfScreen(DefaultScreenOfDisplay (dpy)); + + if (!XQueryTree (dpy, root, &root2, &parent, &kids, &nkids)) + { + fprintf(stderr, "mdp: XQueryTree failed on display %s\n", DisplayString (dpy)); + XCloseDisplay(dpy); + return false; + } + + // Note: root != root2 is possible with virtual root WMs. + if (!(kids && nkids)) return false; + + for (i = nkids-1; i >= 0; i--) + { + Atom type; + int format; + unsigned long nitems, bytesafter; + unsigned char *version = 0; + Window w = XmuClientWindow (dpy, kids[i]); + int status = XGetWindowProperty (dpy, w, XA_MOZILLA_VERSION, + 0, (65536 / sizeof (long)), + False, XA_STRING, + &type, &format, &nitems, &bytesafter, + &version); + if (!version) continue; + XFree (version); + if (status == Success && type != None) + { + if (w == window) + { + XCloseDisplay(dpy); + return true; + } + else + { + continue; + } + } + } + XCloseDisplay(dpy); + return false; + +} // end NetscapeCheckWindow() +#endif // NETSCAPE_SUPPORT diff --git a/win32/Norm.dsw b/win32/Norm.dsw new file mode 100644 index 0000000..ed0c822 --- /dev/null +++ b/win32/Norm.dsw @@ -0,0 +1,59 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "NormLib"=.\NormLib.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "Protokit"=..\protolib\win32\Protokit.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Project: "norm"=.\norm\norm.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ + Begin Project Dependency + Project_Dep_Name NormLib + End Project Dependency + Begin Project Dependency + Project_Dep_Name Protokit + End Project Dependency +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/win32/Norm.opt b/win32/Norm.opt new file mode 100644 index 0000000..564b238 Binary files /dev/null and b/win32/Norm.opt differ diff --git a/win32/NormLib.dsp b/win32/NormLib.dsp new file mode 100644 index 0000000..8e29e91 --- /dev/null +++ b/win32/NormLib.dsp @@ -0,0 +1,227 @@ +# Microsoft Developer Studio Project File - Name="NormLib" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Static Library" 0x0104 + +CFG=NormLib - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "NormLib.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "NormLib.mak" CFG="NormLib - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "NormLib - Win32 Release" (based on "Win32 (x86) Static Library") +!MESSAGE "NormLib - Win32 Debug" (based on "Win32 (x86) Static Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\common" /I "..\protolib\common" /I "..\protolib\win32" /D "NDEBUG" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /I "..\common" /I "..\protolib\common" /I "..\protolib\win32" /D "_DEBUG" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" /D "WIN32" /D "_MBCS" /D "_LIB" /YX /FD /GZ /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LIB32=link.exe -lib +# ADD BASE LIB32 /nologo +# ADD LIB32 /nologo + +!ENDIF + +# Begin Target + +# Name "NormLib - Win32 Release" +# Name "NormLib - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\common\galois.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\common\normBitmask.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\common\normEncoder.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\common\normFile.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\common\normMessage.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\common\normNode.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\common\normObject.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\common\normSegment.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# Begin Source File + +SOURCE=..\common\normSession.cpp + +!IF "$(CFG)" == "NormLib - Win32 Release" + +# ADD CPP /MD /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ELSEIF "$(CFG)" == "NormLib - Win32 Debug" + +# ADD CPP /MDd /vmg /I "..\common" /I "..\win32" /I "..\protolib\common" /I "..\protolib\win32" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" + +!ENDIF + +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# End Target +# End Project diff --git a/win32/norm/norm.dsp b/win32/norm/norm.dsp new file mode 100644 index 0000000..a76b1aa --- /dev/null +++ b/win32/norm/norm.dsp @@ -0,0 +1,115 @@ +# Microsoft Developer Studio Project File - Name="norm" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=norm - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "norm.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "norm.mak" CFG="norm - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "norm - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "norm - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "norm - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /MD /W3 /vmg /GX /O2 /I "..\..\common" /I "..\..\protolib\common" /I "..\..\protolib\win32" /D "NDEBUG" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 iphlpapi.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "norm - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /MDd /W3 /Gm /vmg /GX /ZI /Od /I "..\..\common" /I "..\..\protolib\common" /I "..\..\protolib\win32" /D "_DEBUG" /D "PROTO_DEBUG" /D "HAVE_IPV6" /D "HAVE_ASSERT" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 iphlpapi.lib ws2_32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "norm - Win32 Release" +# Name "norm - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=..\..\common\normApp.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\common\normPostProcess.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32PostProcess.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/win32/win32PostProcess.cpp b/win32/win32PostProcess.cpp new file mode 100644 index 0000000..3d0190d --- /dev/null +++ b/win32/win32PostProcess.cpp @@ -0,0 +1,255 @@ + + +#include "normPostProcess.h" +#include "protoDebug.h" + +#include +#include +#include + +class Win32PostProcessor : public NormPostProcessor +{ + public: + ~Win32PostProcessor(); + + bool ProcessFile(const char* path); + void Kill(); + bool IsActive() {return (NULL != post_processor_handle);} + + private: + static HDDEDATA CALLBACK DDEClientCallback(UINT uiType, UINT uiFmt, HCONV hConv, + HSZ sz1, HSZ sz2, HDDEDATA hData, + DWORD lData1, DWORD lData2); + friend class NormPostProcessor; + Win32PostProcessor(); + bool Init(); + + // Post Processor DDE state + DWORD lIdInst; // DDE instance id + HCONV hConv; // dde converstation handle + DWORD transaction_id; + DWORD window_id; // dde browser window id + PFNCALLBACK lpDDECallback; + HANDLE post_processor_handle; +}; // end class Win32PostProcessor + + +HDDEDATA CALLBACK Win32PostProcessor::DDEClientCallback(UINT uiType, UINT uiFmt, HCONV hConv, + HSZ sz1, HSZ sz2, HDDEDATA hData, + DWORD lData1, DWORD lData2) +{ + CONVINFO convInfo; + convInfo.cb = sizeof(convInfo); + bool gotInfo; + if (FALSE != DdeQueryConvInfo(hConv, lData1, &convInfo)) + { + gotInfo = true; + } + else + { + DMSG(8, "Win32PostProcessor::DDEClientCallback() DdeQueryInfo error\n"); + gotInfo = false; + } + + switch(uiType) + { + case XTYP_XACT_COMPLETE: + { + if (gotInfo) + { + Win32PostProcessor* processor = (Win32PostProcessor*)convInfo.hUser; + if (processor && + (processor->hConv == hConv) && + (processor->transaction_id == lData1)) + { + DWORD result; + DdeGetData(hData, (unsigned char*)&result, sizeof(DWORD), 0); + // Hack to make IExplore fake working + if (-2 == result) // IExplore success + processor->window_id = -1; + else if (-3 == result) // IExplore failure + processor->window_id = 0x0; + else + processor->window_id = result; + } + else + { + DMSG(0, "Win32PostProcessor::DDEClientCallback() Unknown DDE transaction ID! (proc:%p)\n", + processor); + } + } + break; + } + + case XTYP_REGISTER: + //TRACE("Win32PostProcessor::DDEClientCallback() XTYP_REGISTER \n"); + break; + + case XTYP_UNREGISTER: + //TRACE("Win32PostProcessor::DDEClientCallback() XTYP_UNREGISTER (gotInfo:%d)\n", gotInfo); + break; + + default: + DMSG(4, "Win32PostProcessor::DDEClientCallback() Unknown DDE message type:%u\n", uiType); + break; + } + return NULL; // callback does nothing for now +} + +Win32PostProcessor::Win32PostProcessor() + : lIdInst(0), hConv(NULL), window_id(-1), + post_processor_handle(NULL) +{ + +} + +Win32PostProcessor::~Win32PostProcessor() +{ + Kill(); + if (lIdInst) + { + ::DdeUninitialize(lIdInst); + lIdInst = 0; + } +} + +NormPostProcessor* NormPostProcessor::Create() +{ + Win32PostProcessor* p = new Win32PostProcessor(); + if (p) + { + if (p->Init()) + return static_cast(p); + else + delete p; + } + return NULL; +} // end NormPostProcessor::Create() + +bool Win32PostProcessor::Init() +{ +// Init DDE + if (0 != lIdInst) + { + // already exists + return false; + } + else + { + if (::DdeInitialize(&lIdInst, + (PFNCALLBACK)DDEClientCallback, + APPCLASS_STANDARD | APPCMD_CLIENTONLY, 0ul)) + { + return false; + } + else + { + return true; + } + } +} // end Win32PostProcessor::Init() + + +void Win32PostProcessor::Kill() +{ + if (hConv) + { + DdeDisconnect(hConv); + hConv = NULL; + } + if (post_processor_handle) + { + TerminateProcess(post_processor_handle, 0); + CloseHandle(post_processor_handle); + post_processor_handle = NULL; + } +} // end Win32PostProcessor::Kill() + + +bool Win32PostProcessor::ProcessFile(const char *path) +{ + + // DDE seems to be broken for the moment + // (It does work if the serving applications is _already_ running + // so these two lines of code disable it for the moment) + bool useDDE = false; + if (useDDE) + { + if (NULL == hConv) + { + HSZ szServerName = ::DdeCreateStringHandle(lIdInst, process_argv[0], CP_WINANSI); + HSZ szTopicName = ::DdeCreateStringHandle(lIdInst, "WWW_OpenURL", CP_WINANSI); + DMSG(4, "Win32PostProcessor::ProcessFile() calling DdeConnect(WWW_OpenURL) ...\n"); + if ((hConv = ::DdeConnect(lIdInst, szServerName, szTopicName, 0))) + DMSG(4, "Win32PostProcessor::ProcessFile() DdeConnect() completed successfully.\n"); + else + DMSG(4, "Win32PostProcessor::ProcessFile() DdeConnect() failed\n"); + DdeFreeStringHandle(lIdInst, szTopicName); + DdeFreeStringHandle(lIdInst, szServerName); + } + + if (hConv) + { + char ddeText[PATH_MAX+128]; + sprintf(ddeText, "\"file://%s\",,%d,0,,,NETREPORT", path, window_id); + HSZ szParams = ::DdeCreateStringHandle(lIdInst, ddeText, CP_WINANSI); + TRACE("Win32PostProcessor::ProcessFile() calling DdeClientTransaction() ...\n"); + if(DdeClientTransaction(NULL, 0, hConv, szParams, CF_TEXT, + XTYP_REQUEST, TIMEOUT_ASYNC, + &transaction_id)) + { + DdeSetUserHandle(hConv, transaction_id, (DWORD_PTR)this); + DdeFreeStringHandle(lIdInst, szParams); + return true; + } + else + { + DMSG(0, "Win32PostProcessor::ProcessFile() DdeClientTransaction() failure ...\n"); + DdeFreeStringHandle(lIdInst, szParams); + DdeDisconnect(hConv); + hConv = NULL; + } + } + } // end if (NULL != post_processor_handle) + + // DDE post processor evidently not running + // Launch post processor with shell command + // For now we assume the DDE server name & command name are the + // same and that the post processor command executable is in + // the PATH + + // Kill old PostProcessor first + Kill(); + + // Construct the command line + char args[PATH_MAX+512]; + args[0] = '\0'; + for (unsigned int i = 1; i < process_argc; i++) + { + strcat("%s ", process_argv[i]); + } + strcat(args, path); + + DMSG(4, "Win32PostProcessor::ProcessFile() execing \"%s %s\"\n", process_argv[0], args); + + SHELLEXECUTEINFO exeInfo; + exeInfo.cbSize = sizeof(SHELLEXECUTEINFO); + exeInfo.fMask = SEE_MASK_NOCLOSEPROCESS; + exeInfo.hwnd = NULL; + exeInfo.lpVerb = NULL; + exeInfo.lpFile = process_argv[0]; + exeInfo.lpParameters = args; + exeInfo.lpDirectory = NULL; + exeInfo.nShow = SW_SHOW; + if (!ShellExecuteEx(&exeInfo)) + { + post_processor_handle = NULL; + DMSG(0, "Error launching post processor!\n\"%s %s %s\"", process_argv[0], args); + return false; + } + else + { + post_processor_handle = exeInfo.hProcess; + return true; + } +} // end Win32PostProcessor::ProcessFile()