home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / unix / timelord.shr / timelord.c < prev    next >
C/C++ Source or Header  |  1991-01-29  |  7KB  |  337 lines

  1. /*
  2.  *    timelord - UNIX Macintosh Time Server 
  3.  *
  4.  *    Provides:
  5.  *        Time Server
  6.  *
  7.  *    written    1.0    May '89        djh@munnari.oz
  8.  *    revised    1.1    28/05/89    djh@munnari.oz    Add Boot/Chooser log
  9.  *
  10.  *    You may use and distribute (but NOT SELL!) 
  11.  *    this freely providing that...
  12.  *        + any improvements/bug fixes return to the author
  13.  *        + this notice remains intact.
  14.  */
  15.  
  16. #include <sys/types.h>
  17. #include <sys/ioctl.h>
  18. #include <sys/file.h>
  19.  
  20. #include <signal.h>
  21. #include <stdio.h>
  22. #include <errno.h>
  23. #include <ctype.h>
  24. #include <time.h>
  25.  
  26. #include <netat/appletalk.h>
  27. #include "timelord.h"
  28.  
  29. #define forever() for(;;)
  30.  
  31. extern int errno;
  32.  
  33. time_t now;
  34. int skt, debug = 0;
  35. int doRequest(), cleanup();
  36. char logf[150], obj[33], type[33], *index();
  37.  
  38. main(argc, argv)
  39. int argc;
  40. char *argv[];
  41. {
  42.     int f, err;
  43.     char *s;            /* argument parsing        */
  44.     char *cp;            /* general char pointer        */
  45.     char requestBuffer[atpMaxData];    /* A/TALK packet buffer        */
  46.     AddrBlock addr;
  47.     ABusRecord abr;
  48.     atpProto *atPtr;        /* pointer to ATP record    */
  49.     
  50.     signal(SIGQUIT, cleanup);
  51.     signal(SIGTERM, cleanup);
  52.     signal(SIGINT, cleanup);
  53.     signal(SIGHUP, cleanup);
  54.     
  55.     strncpy(logf, LOGFILE, sizeof(logf));
  56.     strncpy(type, MACSERVER, sizeof(type));
  57.     gethostname(obj, sizeof(obj));
  58.     if((cp = index(obj, '.')) != NULL)    /* strip domain names */
  59.         *cp = 0;
  60.  
  61.     while(--argc > 0 && (*++argv)[0] == '-')
  62.         for(s = argv[0]+1 ; *s != '\0' ; s++)
  63.             switch (*s) {
  64.                 case 'd':
  65.                 case 'D':
  66.                     --argc;
  67.                     debug++;
  68.                     dbugarg(*++argv);
  69.                     break;
  70.                 case 'l':
  71.                 case 'L':
  72.                     --argc;
  73.                     strncpy(logf, *++argv, sizeof(logf));
  74.                     break;
  75.                 case 'n':
  76.                 case 'N':
  77.                     --argc;
  78.                     strncpy(obj, *++argv, sizeof(obj));
  79.                     break;
  80.                 case 't':
  81.                 case 'T':
  82.                     --argc;
  83.                     strncpy(type, *++argv, sizeof(type));
  84.                     break;
  85.                 default:
  86.                     fprintf(stderr, "Bad argument %s\n", s);
  87.                     break;
  88.             }
  89.     
  90.     if(!debug) {
  91.         if(fork())
  92.             exit(0);
  93.         for(f = 0; f < 32; f++)
  94.             (void) close(f);
  95.         (void) open("/dev/null", 0);
  96.         (void) dup2(0, 1);
  97.         if((f = open("/dev/tty", 2)) >= 0) {
  98.             ioctl(f, TIOCNOTTY, (char *)0);
  99.             (void) close(f);
  100.         }
  101.     
  102.         if((f = open(logf, O_WRONLY|O_APPEND|O_CREAT, 0644)) >= 0) {
  103.             if(f != 2) {
  104.                 (void) dup2(f, 2);
  105.                 (void) close(f);
  106.             }
  107.         }
  108.     }
  109.     
  110.     (void) time(&now);
  111.     log("timelord server starting\n");
  112.     
  113.     abInit(debug);
  114.     nbpInit();
  115.     
  116.     addr.net = addr.node = addr.skt = 0; /* accept from anywhere */
  117.     skt = 0;    /* Get Dynamic ATP Socket */
  118.     
  119.     if ((err = ATPOpenSocket(&addr, &skt)) < 0) {
  120.         log("ATPopen() failed, code %d\n", err);
  121.         exit(1);
  122.     }
  123.     doNBPRemove(obj, type, ZONE);    /* if one already running */
  124.     if ((err = doNBPRegister(obj, type, ZONE, skt)) != noErr) {
  125.         log("NBP register error: %d\n", err);
  126.         exit(1);
  127.     }
  128.     
  129.     atPtr = &abr.proto.atp;
  130.     forever() {
  131.         atPtr->atpDataPtr = requestBuffer;
  132.         atPtr->atpReqCount = atpMaxData;
  133.         atPtr->atpSocket = skt;
  134.         if((err = ATPGetRequest(&abr, FALSE)) != noErr)
  135.             log("ATPGetRequest error: %d\n",err);
  136.         doRequest(&abr);
  137.     }
  138. }
  139.  
  140. /*
  141.  * process a new request
  142.  */
  143.  
  144. doRequest(abr)
  145. ABusRecord *abr;
  146. {
  147.     char *q;
  148.     int request;
  149.     unsigned long mactime, mact;
  150.     register long diff;
  151.     struct tm gmt, local, *localtime(), *gmtime();
  152.     atpProto *atPtr = &abr->proto.atp;
  153.     
  154.     (void) time(&now);
  155.     
  156.     /* request data depends on the user data field */
  157.     abr->proto.atp.atpUserData = ntohl(abr->proto.atp.atpUserData);
  158.     request = abr->proto.atp.atpUserData;
  159.     
  160.     if (debug)
  161.         fprintf(stderr, "Request %d from %d/%d:%x\n", request,
  162.             htons(abr->proto.atp.atpAddress.net),
  163.             abr->proto.atp.atpAddress.node,
  164.             abr->proto.atp.atpAddress.skt);
  165.     
  166.     switch(request) {
  167.     case GETTIME:
  168.         q = (char *) abr->proto.atp.atpDataPtr;
  169.         /*
  170.          * Do this by determining what the given time
  171.          * is when converted to local time, and when
  172.          * converted to GMT and taking the difference.
  173.          * This works correctly regardless of whether
  174.          * local time is Daylight Savings Time or not.
  175.          *
  176.          *    - courtesy kre@munnari.oz
  177.          */
  178.         gmt = *gmtime((time_t *)&now);
  179. #define    isleap(yr) ((yr) % 4 == 0 && ((yr) % 100 != 0 || (yr) % 400 == 0))
  180.         local = *localtime((time_t *)&now);
  181.         diff = gmt.tm_year - local.tm_year;
  182.         diff *= 365;
  183.         if(gmt.tm_year > local.tm_year) {
  184.             if(isleap(local.tm_year))
  185.                 diff++;
  186.         } else
  187.             if(local.tm_year > gmt.tm_year) {
  188.                 if(isleap(gmt.tm_year))
  189.                     diff--;
  190.             }
  191.         diff += gmt.tm_yday - local.tm_yday;
  192.         diff *= 24;
  193.         diff += gmt.tm_hour - local.tm_hour;
  194.         diff *= 60;
  195.         diff += gmt.tm_min - local.tm_min;
  196.         diff *= 60;
  197.         diff += gmt.tm_sec - local.tm_sec;
  198.         now -= diff;
  199. #undef    isleap
  200.         mactime = now + TIME_OFFSET;
  201.         if(abr->proto.atp.atpActCount > 0) {
  202.             bcopy(q+1, &mact, sizeof(long));
  203.             mact = ntohl(mact);
  204.             log("Get Time:  %-16s %6d secs (%s)\n", 
  205.                 (*(q+5) == '\0') ? "<nobody>" : q+5,
  206.                 mact - mactime,
  207.                 (*q == 0) ? "Boot" : "Chooser");
  208.         } else
  209.             log("Get Time\n");
  210.         mactime = htonl(mactime);
  211.         sendReply(abr, ENONE, &mactime, sizeof(mactime));
  212.         break;
  213.     default:
  214.         sendMsg(abr, ENOPERM, "Bad Request");
  215.         log("Bad Request [%x]\n", request);
  216.         break;
  217.     }
  218. }
  219.  
  220. /*
  221.  * send back an (error) message.
  222.  */
  223.  
  224. sendMsg(abr, code, msg)
  225. ABusRecord *abr;
  226. int code;
  227. char *msg;
  228. {
  229.     char buffer[atpMaxData];    /* room for translated message */
  230.     
  231.     buffer[0] = (char) strlen(msg);
  232.     bcopy(msg, &buffer[1], buffer[0]);
  233.     sendReply(abr, code, buffer, buffer[0]+1);
  234. }
  235.     
  236. /*
  237.  * send a reply back (fill in the BDS junk and then send it)
  238.  *
  239.  */
  240.  
  241. ABusRecord res_abr;
  242. sendReply(abr, userdata, data, length)
  243. ABusRecord *abr;
  244. int userdata;
  245. char *data;
  246. int length;
  247. {
  248.     BDS bds[1];
  249.     
  250.     userdata = htonl(userdata);
  251.     bds[0].userData = userdata;
  252.     bds[0].buffPtr = data;
  253.     bds[0].buffSize = length;
  254.     return(sendReplyBDS(abr, bds, 1));
  255. }
  256.     
  257. /*
  258.  *  send the BDS block
  259.  *
  260.  */
  261.  
  262. sendReplyBDS(abr, bds, bdslen)
  263. ABusRecord *abr;
  264. BDS bds[];
  265. int bdslen;
  266. {
  267.     register atpProto *atPtr;
  268.     
  269.     atPtr = &res_abr.proto.atp;
  270.     atPtr->atpAddress = abr->proto.atp.atpAddress;
  271.     atPtr->atpTransID = abr->proto.atp.atpTransID;
  272.     atPtr->atpSocket = abr->proto.atp.atpSocket;
  273.     atPtr->atpRspBDSPtr = bds;
  274.     atPtr->atpNumBufs = bdslen;
  275.     atPtr->atpBDSSize = bdslen;
  276.     atPtr->fatpEOM = 1;
  277.     return(ATPSndRsp(&res_abr, FALSE));
  278. }
  279.     
  280. /*
  281.  * Log an error message.
  282.  */
  283.  
  284. log(fmt, a1, a2, a3, a4, a5, a6)
  285. char *fmt, *a1, *a2, *a3, *a4, *a5, *a6;
  286. {
  287.     char *ctime();
  288.     
  289.     (void) time(&now);
  290.     fprintf(stderr, "%.*s\t", 24-5, ctime(&now));
  291.     fprintf(stderr, fmt, a1, a2, a3, a4, a5, a6);
  292.     fflush(stderr);    /* especially for SUN's    */
  293. }
  294.  
  295. cleanup()
  296. {
  297.       doNBPRemove(obj, type, ZONE); /* if one already running */
  298.     nbpShutdown();
  299.     ATPCloseSocket(skt);
  300.     exit(0);
  301. }
  302.  
  303. doNBPRemove(sobj, stype, szone)
  304. char *sobj, *stype, *szone;
  305. {
  306.     EntityName en;
  307.     int err;
  308.  
  309.       strncpy(en.objStr.s, sobj, sizeof(en.objStr.s));
  310.       strncpy(en.typeStr.s, stype, sizeof(en.typeStr.s));
  311.       strncpy(en.zoneStr.s, szone, sizeof(en.zoneStr.s));
  312.     return(NBPRemove(&en));
  313. }
  314.  
  315. doNBPRegister(sobj, stype, szone, skt)
  316. char *sobj, *stype, *szone;
  317. int skt;
  318. {
  319.     EntityName en;
  320.     nbpProto nbpr;            /* nbp proto        */
  321.     NBPTEntry nbpt[1];        /* table of entity names */
  322.     
  323.     strncpy(en.objStr.s, sobj, sizeof(en.objStr.s));
  324.     strncpy(en.typeStr.s, stype, sizeof(en.typeStr.s));
  325.     strncpy(en.zoneStr.s, szone, sizeof(en.zoneStr.s));
  326.     
  327.     nbpr.nbpAddress.skt = skt;
  328.     nbpr.nbpRetransmitInfo.retransInterval = 10;
  329.     nbpr.nbpRetransmitInfo.retransCount = 3;
  330.     nbpr.nbpBufPtr = nbpt;
  331.     nbpr.nbpBufSize = sizeof(nbpt);
  332.     nbpr.nbpDataField = 1;    /* max entries */
  333.     nbpr.nbpEntityPtr = &en;
  334.     
  335.     return((int) NBPRegister(&nbpr,FALSE));    /* try synchronous */
  336. }
  337.