Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

rotorooter.cc

Go to the documentation of this file.
00001 // $ID:  rotorooter.C,v 1.2 1998/09/14 16:25 rhatcher Exp $
00002 //
00003 // rotorooter: server for MINOS ROOT file writing
00004 
00005 #include <iostream>
00006 #include <stdlib.h>
00007 /* #include <getopt.h> seems to be part of <unistd.h> */
00008 #include <unistd.h>
00009 
00010 #include "OnlineUtil/msgLogLib/msgLog.h"
00011 #include "OnlineUtil/minosDaq.h" /* msgLog node ids defined here */
00012 
00013 #include <signal.h>
00014 #include <string>
00015 #include <map>
00016 
00017 #include "TROOT.h"
00018 #include "TRint.h"
00019 #include "TVirtualX.h"
00020 #include "TGuiFactory.h"
00021 
00022 #include "TServerSocket.h"
00023 #include "TSocket.h"
00024 #include "TMessage.h"
00025 
00026 #include "Rotorooter/RotoServer.h"
00027 #include "Rotorooter/RotoObjectifier.h"
00028 #include "Rotorooter/MsgLogTErrorHandler.h"
00029 
00030 #include "RawData/RawBlockId.h"
00031 #include "RawData/RawBlockRegistry.h"
00032 #include "RawData/RawBlockProxy.h"
00033 #include "RawData/RawDataBlock.h"
00034 
00035 #include "RawData/RawRecord.h"
00036 
00037 //---- Global sever ----------------------------------------------------
00038 
00039 RotoServer* server = 0;
00040 
00041 //---- Signal handler --------------------------------------------------
00042 static void roto_sighandler(int dummy)
00043 {
00044    if (server) {
00045       logNotice("roto_sighandler signal %d; attempt shutdown",dummy);
00046 
00047       // make sure the clean up code is called
00048       delete server;
00049       logNotice("roto_sighandler exit");
00050 
00051    } else {
00052       logNotice("roto_sighandler signal %d, but no server",dummy);
00053 
00054    }
00055 
00056    msgLogCleanup();
00057 
00058    exit(1);
00059 }
00060 
00061 //---- Forward declarations --------------------------------------------
00062 int config_autosave(const char* config);
00063 int config_compress(const char* config);
00064 int config_basketsize(const char* config);
00065 int parse_port(const char* opt, string& inputFileName);
00066 
00067 //---- Main program ----------------------------------------------------
00068 
00069 int main(int argc, char **argv)
00070 {
00071    int   copt;
00072 
00073    Bool_t allow_overwrite = kFALSE;
00074    string inputFileName;
00075    Int_t  port   = ROOTER_PORT_DAQ;
00076    Int_t  nwords = 2*1024*1024;
00077    Int_t  tcp_nodelay_flag = 1;  /* on by default */
00078    const Char_t* autosave_config = 0;
00079    const Char_t* compress_config = 0;
00080    const Char_t* basketsize_config = 0;
00081    const Char_t* bin_output_file = 0;
00082    const Char_t* symlink_config = 0;
00083 
00084    // install error handler for Info(),Warning(),Error(),SysError()
00085    // that redirects messages to msgLog
00086    //ErrorHandlerFunc_t old_errhndlr = 
00087    SetErrorHandler(MsgLogTErrorHandler);
00088 
00089 #ifdef ALLOW_FORCE
00090    Detector::Detector_t forceDetector = Detector::kUnknown;
00091    SimFlag::SimFlag_t forceSimFlag = SimFlag::kUnknown;
00092    const char* optlist = "aep:b:c:C:B:D:v:z:hd:sl:";
00093 #else
00094    const char* optlist = "aep:b:c:C:B:D:v:z:hl:";
00095 #endif
00096 
00097    /*
00098     * parse the options and filenames
00099     *     -a: allow overwrite
00100     *     -p: port # (or "dcp"/"daq", "dcs", "beammon")
00101     *     -b: initial buffer size
00102     *     -c: autosave config    "streamName,nrec,nsec[;streamName,nrec,nsec]" 
00103     *     -C: compression config "streamName,level[;streamName,level]"
00104     *     -B: basketsize config  "streamName,size[;streamName,size]"
00105     *            both -c,-C,-B use "*" as streamName to set all legal streams
00106     *     -D: tcp_nodelay flag
00107     *     -e: msgLog local echo
00108     *     -v: verbosity level
00109     *     -d: force detector
00110     *     -s: force simflag
00111     *     -l: Make symlink to current file
00112     *     -z: write a binary copy of received data to this file
00113     *     -h: help
00114     */
00115 
00116    msgLogInit(argv[0]);
00117    msgLogNodeIdSet(MINOS_ROOTER);
00118    logInfo("rotorooter command line configuration\n");
00119 
00120    while ((copt = getopt(argc, argv, optlist)) != EOF) {
00121       switch (copt) {
00122       case 'a':
00123          allow_overwrite = kTRUE;
00124          break;
00125       case 'e':
00126          msgLogLocalEchoSet(1);
00127          break;
00128       case 'p':
00129 //       Handle port number or file name
00130          port = parse_port(optarg, inputFileName);
00131          break;
00132       case 'b':
00133          nwords = atoi(optarg);
00134          break;
00135       case 'c':  /* autosave config string */
00136          autosave_config = optarg;
00137          break;
00138       case 'C':  /* compression config string */
00139          compress_config = optarg;
00140          break;
00141       case 'B':  /* basketsize config string */
00142          basketsize_config = optarg;
00143          break;
00144       case 'D':
00145          tcp_nodelay_flag = atoi(optarg);
00146          break;
00147       case 'v':
00148          logDebugLevelSet(atoi(optarg));
00149          break;
00150       case 'z':
00151         bin_output_file = optarg;
00152         break;
00153       case 'h':
00154          printf(" usage: %s -a -p<port#> -b<buffersize> -e\n", argv[0]);
00155          printf("   -a: allow file overwriting\n");
00156          printf("   -p: port number rotorooter is listening on\n");
00157          printf("       or file name or \"dcs\"/\"daq\", \"dcs\", \"beammon\"\n");
00158          printf("   -b: initial buffer size in long words\n");
00159          printf("   -e: direct msgLog errors to stdout as well\n");
00160          printf("   -v: msgLog debug level\n");
00161          printf("   -c: autosave config \"streamName,nrec,nsec[;streamName,nrec,nsec]\"\n");
00162          printf("   -C: compression config \"streamName,level[;streamName,level]\"\n");
00163          printf("   -B: basketsize config \"streamName,size[;streamName,size]\"\n");
00164          printf("   -D: TCP_NODELAY flag\n");
00165          printf("   -z: make copy of flat data to binary file\n");
00166 #ifdef ALLOW_FORCE
00167          printf("   -d: detector override\n");
00168          printf("   -s: simflag override\n");
00169 #endif
00170          printf("   -l: symlink to this file on each successful open\n");
00171          printf("   -h: print this message\n");
00172          exit(1);
00173          break;
00174       default:
00175          printf(" unrecognized option '%c'\n",(char)optopt);
00176          exit(1);
00177          break;
00178 #ifdef ALLOW_FORCE
00179       case 'd':
00180          {
00181             // be very strict!
00182             Detector::Detector_t dlist[] = { Detector::kNear, 
00183                                              Detector::kFar, 
00184                                              Detector::kCalDet };
00185             int n = sizeof(dlist)/sizeof(forceDetector);
00186             string user = optarg;
00187             // look for a match
00188             for (int i = 0; i < n; i++) {
00189                if ( Detector::AsString(dlist[i]) == user) 
00190                   forceDetector = dlist[i];
00191             }
00192             // complain if value didn't match
00193             if (Detector::kUnknown == forceDetector) {
00194                printf(" -d flag (force detector type) unknown value: %s\n",
00195                       user.c_str());
00196                printf("   must be followed by exactly one of: %s",
00197                       Detector::AsString(dlist[0]));
00198                for (int i = 1; i < n; i++ ) printf(", %s",
00199                       Detector::AsString(dlist[i]));
00200                printf("\n");
00201                forceDetector = Detector::kUnknown;
00202                exit(1);
00203             }
00204          }
00205          break;
00206       case 's':
00207          {
00208             // be very strict!
00209             SimFlag::SimFlag_t slist[] = { SimFlag::kData, 
00210                                            SimFlag::kDaqFakeData, 
00211                                            SimFlag::kMC, 
00212                                            SimFlag::kReroot };
00213             int n = sizeof(slist)/sizeof(forceSimFlag);
00214             string user = optarg;
00215             // look for a match
00216             for (int i = 0; i < n; i++) {
00217                if ( SimFlag::AsString(slist[i]) == user) 
00218                   forceSimFlag = slist[i];
00219             }
00220             // complain if value didn't match
00221             if (SimFlag::kUnknown == forceSimFlag) {
00222                printf(" -s flag (force simflag) unknown value: %s\n",
00223                       user.c_str());
00224                printf("   must be followed by exactly one of: %s",
00225                       SimFlag::AsString(slist[0]));
00226                for (int i = 1; i < n; i++ ) printf(", %s",
00227                       SimFlag::AsString(slist[i]));
00228                printf("\n");
00229                forceSimFlag = SimFlag::kUnknown;
00230                exit(1);
00231             }
00232          }
00233          break;
00234 #endif
00235       case 'l':
00236           symlink_config = optarg;
00237           break;
00238       }
00239    }
00240 
00241    logNotice("starting %s port %d, inputFileName '%s'",
00242              argv[0],port,inputFileName.c_str());
00243 
00244    // use global so handler can do a clean shutdown
00245    if ( port ) 
00246      server = new RotoServer(port,nwords,allow_overwrite,tcp_nodelay_flag);
00247    else 
00248      server = new RotoServer(inputFileName.c_str(),nwords,allow_overwrite);
00249 
00250    /* Trap HUP, INT and TERM signals so that we close down gracefully */
00251    struct sigaction termAction ;
00252    termAction.sa_handler = roto_sighandler ;
00253    sigemptyset (&termAction.sa_mask) ;
00254    termAction.sa_flags = 0 ;
00255    sigaction (SIGHUP, &termAction, NULL) ;
00256    sigaction (SIGINT, &termAction, NULL) ;
00257    sigaction (SIGTERM, &termAction, NULL) ;
00258 
00259 #ifdef ALLOW_FORCE
00260    if (Detector::kUnknown != forceDetector) {
00261       // DANGER! DANGER! DANGER!
00262       logNotice("DANGER! overriding detector in all block IDs: %s",
00263                 Detector::AsString(forceDetector));
00264       RotoObjectifier::SetForceDetector(forceDetector);
00265    }
00266    if (SimFlag::kUnknown != forceSimFlag) {
00267       // DANGER! DANGER! DANGER!
00268       logNotice("DANGER! overriding simflag in all block IDs: %s",
00269                 SimFlag::AsString(forceSimFlag));
00270       RotoObjectifier::SetForceSimFlag(forceSimFlag);
00271    }
00272 #endif
00273 
00274    // run ROOT in batch mode (ie. no X11)
00275    // based on what root does when passed -b flag
00276    gROOT->SetBatch();
00277    if (gGuiFactory != gBatchGuiFactory) delete gGuiFactory;
00278    gGuiFactory = gBatchGuiFactory;
00279 #ifndef WIN32
00280    if (gVirtualX != gGXBatch) delete gVirtualX;
00281 #endif
00282    gVirtualX = gGXBatch;
00283 
00284    // configure initial autosave and compression values
00285    Int_t nerr = 0;
00286    if (autosave_config)   nerr += config_autosave(autosave_config);
00287    if (compress_config)   nerr += config_compress(compress_config);
00288    if (basketsize_config) nerr += config_basketsize(basketsize_config);
00289 
00290    if (bin_output_file)   nerr += server->SetFlatBinaryOutputFile(bin_output_file);
00291 
00292    if (symlink_config) server->SetSymlink(symlink_config);
00293 
00294    server->Run();
00295    delete server;
00296 
00297    logNotice("stopping %s",argv[0]);
00298    msgLogCleanup();
00299 
00300    return 0;
00301 }
00302 
00303 /*
00304  *=========================================================================
00305  * config_autosave(const char* config)
00306  * 
00307  * Purpose:
00308  *    Send autosave config to the rotorooter, parsed from string
00309  *
00310  * Arguments:
00311  *    config:  configuration string of form:
00312  *             "streamName,nrec,nsec[;streamName,nrec,nsec]"
00313  *             use "*" as streamName to set all legal streams
00314  * 
00315  * Return Value:
00316  *    non-zero indicates there was an error
00317  *=========================================================================
00318  */
00319 int config_autosave(const char* config)
00320 {
00321    int nerr = 0;
00322    int len = strlen(config);
00323    char *wcopy = (char*)malloc(len+1);  /* a writable copy of config string */
00324    char stream[1024];
00325    const char *p1;
00326    char *p2;
00327    char achar;
00328    int nrec,nsec, nitems;
00329 
00330    /* make a copy, replacing all the commas with blanks*/
00331    p1 = config; p2 = wcopy;
00332    while (p2 < wcopy+len) {
00333       achar = *p1;
00334       if (achar != ',') *p2 = achar;
00335       else              *p2 = ' ';
00336       p1++; p2++;
00337    }
00338 
00339    p2 = wcopy;
00340    while (p2  < wcopy+len) {
00341       nitems = sscanf(p2,"%s %d %d",stream,&nrec,&nsec);
00342       if (nitems != 3) {
00343          logNotice("config_autosave: only %d items from \"%s\"\n",nitems,p2);
00344          nerr += 1;
00345       }
00346       else 
00347          nerr += server->SetAutoSaveConfig(stream,nrec,nsec);
00348 
00349       p2 = strchr(p2,';'); /* move to the semicolon         */
00350       if (!p2) break;      /* in case of no final semicolon */
00351       p2++;                /* start just beyond semicolon   */
00352    }
00353 
00354 
00355    free(wcopy);  /* return the allocated space */
00356    wcopy = 0;
00357 
00358    return nerr;
00359 }
00360 
00361 /*
00362  *=========================================================================
00363  * config_compress(const char* config)
00364  * 
00365  * Purpose:
00366  *    Send compression config to the rotorooter, parsed from string
00367  *
00368  * Arguments:
00369  *    config:  configuration string of form:
00370  *             "streamName,level[;streamName,level]"
00371  *             use "*" as streamName to set all legal streams
00372  * 
00373  * Return Value:
00374  *    non-zero indicates there was an error
00375  *=========================================================================
00376  */
00377 int config_compress(const char* config)
00378 {
00379    int nerr = 0;
00380    int len = strlen(config);
00381    char *wcopy = (char*)malloc(len+1);  /* a writable copy of config string */
00382    char stream[1024];
00383    const char *p1;
00384    char *p2;
00385    char achar;
00386    int level, nitems;
00387 
00388    /* make a copy, replacing all the commas with blanks*/
00389    p1 = config; p2 = wcopy;
00390    while (p2 < wcopy+len) {
00391       achar = *p1;
00392       if (achar != ',') *p2 = achar;
00393       else              *p2 = ' ';
00394       p1++; p2++;
00395    }
00396 
00397    p2 = wcopy;
00398    while (p2  < wcopy+len) {
00399       nitems = sscanf(p2,"%s %d",stream,&level);
00400       if (nitems != 2) {
00401          logNotice("config_compress: only %d items from \"%s\"\n",nitems,p2);
00402          nerr += 1;
00403       }
00404       else 
00405          nerr += server->SetCompressConfig(stream,level);
00406 
00407       p2 = strchr(p2,';'); /* move to the semicolon         */
00408       if (!p2) break;      /* in case of no final semicolon */
00409       p2++;                /* start just beyond semicolon   */
00410    }
00411 
00412 
00413    free(wcopy);  /* return the allocated space */
00414    wcopy = 0;
00415 
00416    return nerr;
00417 }
00418 
00419 /*
00420  *=========================================================================
00421  * config_basketsize(const char* config)
00422  * 
00423  * Purpose:
00424  *    Send basketsize config to the rotorooter, parsed from string
00425  *
00426  * Arguments:
00427  *    config:  configuration string of form:
00428  *             "streamName,size[;streamName,size]"
00429  *             use "*" as streamName to set all legal streams
00430  * 
00431  * Return Value:
00432  *    non-zero indicates there was an error
00433  *=========================================================================
00434  */
00435 int config_basketsize(const char* config)
00436 {
00437    int nerr = 0;
00438    int len = strlen(config);
00439    char *wcopy = (char*)malloc(len+1);  /* a writable copy of config string */
00440    char stream[1024];
00441    const char *p1;
00442    char *p2;
00443    char achar;
00444    int basketsize, nitems;
00445 
00446    /* make a copy, replacing all the commas with blanks*/
00447    p1 = config; p2 = wcopy;
00448    while (p2 < wcopy+len) {
00449       achar = *p1;
00450       if (achar != ',') *p2 = achar;
00451       else              *p2 = ' ';
00452       p1++; p2++;
00453    }
00454 
00455    p2 = wcopy;
00456    while (p2  < wcopy+len) {
00457       nitems = sscanf(p2,"%s %d",stream,&basketsize);
00458       if (nitems != 2) {
00459          logNotice("config_basketsize: only %d items from \"%s\"\n",nitems,p2);
00460          nerr += 1;
00461       }
00462       else 
00463          nerr += server->SetBasketSizeConfig(stream,basketsize);
00464 
00465       p2 = strchr(p2,';'); /* move to the semicolon         */
00466       if (!p2) break;      /* in case of no final semicolon */
00467       p2++;                /* start just beyond semicolon   */
00468    }
00469 
00470 
00471    free(wcopy);  /* return the allocated space */
00472    wcopy = 0;
00473 
00474    return nerr;
00475 }
00476 
00477 /*
00478  *=========================================================================
00479  * parse_port(const char* optarg, string& inputFileName)
00480  * 
00481  * Purpose:
00482  *    Parse the -p argument for port # or file name
00483  *       numeric values get converted and returned
00484  *       "daq", "dcp", "dcs", "beammon" return the correct numeric #
00485  *       others are treated as filenames
00486  *
00487  * Arguments:
00488  *    optarg:          option value associated w/ -p flag
00489  *    inputFileName:   file to use if value doesn't resolve to numeric port #
00490  * 
00491  * Return Value:
00492  *    port # to use, 0 if one is to use inputFileName.
00493  *=========================================================================
00494  */
00495 int parse_port(const char* optarg, string& inputFileName)
00496 {
00497   int  port = ROOTER_PORT_DAQ;
00498 
00499   enum ptype { kNumeric, kSpecial, kIsFile };
00500   ptype pType = kNumeric;  // start by assuming numeric value
00501   // bool input_from_file = kFALSE;
00502 
00503   // look for non-digit characters
00504   const char* c = optarg;
00505   while ( *c != '\0' ) {
00506     if ( ! isdigit(*c) ) {
00507       //input_from_file = kTRUE;
00508       pType = kIsFile;
00509       inputFileName = optarg;
00510       break;
00511     }
00512     c++;
00513   }
00514 
00515   // if (provisionally) from a file (ie. not all digits) 
00516   // look for special cases
00517   //if ( input_from_file ) {
00518   if ( pType != kNumeric ) {
00519 
00520     std::map<string,int> specialNames;
00521     specialNames["dcp"]     = ROOTER_PORT_DAQ;
00522     specialNames["DCP"]     = ROOTER_PORT_DAQ;
00523     specialNames["daq"]     = ROOTER_PORT_DAQ;
00524     specialNames["DAQ"]     = ROOTER_PORT_DAQ;
00525     specialNames["dcs"]     = ROOTER_PORT_DCS;
00526     specialNames["DCS"]     = ROOTER_PORT_DCS;
00527     specialNames["beammon"] = ROOTER_PORT_BEAMMON;
00528     specialNames["BEAMMON"] = ROOTER_PORT_BEAMMON;
00529     specialNames["BeamMon"] = ROOTER_PORT_BEAMMON;
00530 
00531     int specialPort = specialNames[inputFileName];
00532     if (specialPort) { 
00533       port = specialPort;
00534       //input_from_file = kFALSE;
00535       pType = kSpecial;
00536     }
00537   }
00538 
00539   if      ( pType == kNumeric) port = atoi(optarg);
00540   else if ( pType == kIsFile ) port = 0;
00541 
00542   return port;
00543 }

Generated on Mon Nov 23 05:28:20 2009 for loon by  doxygen 1.3.9.1