home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / radio2.0.2 / part02 / radio.c < prev   
Encoding:
C/C++ Source or Header  |  1993-04-15  |  16.0 KB  |  733 lines

  1. /***********************************************************
  2. Copyright 1991, 1992 by Stichting Mathematisch Centrum, Amsterdam, The
  3. Netherlands.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Stichting Mathematisch
  12. Centrum or CWI not be used in advertising or publicity pertaining to
  13. distribution of the software without specific, written prior permission.
  14.  
  15. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  18. FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  21. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  
  23. ******************************************************************/
  24.  
  25. /* Receive audio UDP packets transmitted by broadcast.
  26.  
  27.    Command line options:
  28.  
  29.    -p port    tune to this port number (default 54321)
  30.                 (port numbers 1..99 are shorthands for 54321 and up)
  31.    -v volume    output volume (range 0-100; default unchanged)
  32.         (you can auso use [x_]gaintool or a similar tool to
  33.         set the output volume etc.)
  34.    -c port    use this control port (default 54320)
  35.    -s        'secure' mode: don't listen to the control port
  36.    -f        work as a filter: send output to stdout instead of
  37.         directly to the audio hardware
  38.    -l addr    listen only for packets to <arg> ip address
  39.    -r addr    listen only for packets from <arg>
  40.    -d        debug packets
  41.    -n           noninterruptable -- by default radio will be interruptable
  42.         by other sound outputting programs, hoping they do not
  43.         take too long.  This option turns off that feature.
  44.    -t        tee mode: send output to stdout as well as to audio h/w
  45.    -m mcastgrp    multicast group (SGI only)
  46. */
  47.  
  48. #include "radio.h"
  49. #include "patchlevel.h"
  50.  
  51. #include <stdio.h>
  52. #include <errno.h>
  53. #include <stdlib.h>
  54. #include <fcntl.h>
  55. #include <signal.h>
  56. #include <netdb.h>
  57. #include <sys/types.h>
  58. #include <sys/socket.h>
  59. #include <sys/time.h>
  60. #include <netinet/in.h>
  61.  
  62. #include "adpcm.h"
  63.  
  64. #ifdef HAVE_MCAST
  65. #include <arpa/inet.h>
  66.  
  67. #ifdef DEFMCAST
  68. char defmcast[] = DEFMCAST;
  69. #else
  70. char *defmcast = 0;
  71. #endif /* DEFMCAST */
  72.  
  73. #endif /* HAVE_MCAST */
  74.  
  75. #ifdef USE_AL
  76. #include <audio.h>
  77. #include "libst.h"
  78.  
  79. long savestate[] = {
  80.     AL_OUTPUT_RATE, 0,
  81.     /* The following two must be the last pairs! */
  82.     AL_LEFT_SPEAKER_GAIN, 0,
  83.     AL_RIGHT_SPEAKER_GAIN, 0,
  84. };
  85.  
  86. ALport aport;
  87.  
  88. void cleanup_handler();
  89. #endif /* USE_AL */
  90.  
  91. #ifdef USE_SUN
  92. #include <stropts.h>
  93. #include <sun/audioio.h>
  94.  
  95. #define AUDIO_IODEV     "/dev/audio"
  96. #define AUDIO_CTLDEV    "/dev/audioctl"
  97.  
  98. int interruptable = 1;
  99. int actlfd = -1;
  100. int afd = -1;
  101.  
  102. void sigpoll_handler();
  103. #endif /* USE_SUN */
  104.   
  105. #ifdef USE_NX
  106. #include <sound/sound.h>
  107. #define NUM_BUFFER 10
  108. SNDSoundStruct *snd[NUM_BUFFER];
  109. #endif /* USE_NX */
  110.  
  111. #ifdef CHECK_X_SERVER
  112. #include <X11/Xlib.h>
  113. Display *xdisplay = 0;
  114. #endif /* CHECK_X_SERVER */
  115.  
  116. /* getopt() interface */
  117. extern int optind;
  118. extern char * optarg;
  119.  
  120. /* Globals */
  121. int pausing = 0; /* Flag set when pausing */
  122. int ofd = -1; /* Output file descriptor */
  123. int volume = -1; /* -v parameter */
  124. int pdebug = 0; /* -p parameter */
  125. char *mcastgrp = 0; /* -m parameter */
  126.  
  127. /* Forward functions */
  128. void open_speaker();
  129. void close_speaker();
  130. void checkalive();
  131. void setmcast(); /* Forward */
  132.  
  133. main(argc, argv)
  134.     int argc;
  135.     char **argv;
  136. {
  137.     int receiveport = RCVPORT;
  138.     int ctlport = RADIOCTLPORT;
  139.     char real_buf[BUFFERSIZE + HEADERSIZE];
  140.     char tmp_buf[BUFFERSIZE];
  141.     int encoding;
  142.     char *buf;
  143.     int s, ctls, curs;
  144.     struct sockaddr from;
  145.     int fromlen;
  146.     int c;
  147.     int filter = 0;
  148.     int tee = 0;
  149.     int nfds;
  150.     fd_set inputset;
  151.     int n;
  152.     char *localname = (char *) NULL;
  153.     char *remotename = (char *) NULL;
  154.     struct timeval timeout;
  155.     int packetcount;
  156.     struct adpcm_state state;
  157. #ifdef USE_AL
  158.     short obuf[BUFFERSIZE];
  159.     int i;
  160.     int curdatalinear;
  161. #endif
  162. #ifdef USE_NX
  163.     int akt_buf;
  164. #endif
  165.  
  166. /* Always change these two macros and the following switch together! */
  167. #define OPTIONS "c:dfl:m:np:r:stv:"
  168. #define USAGE "usage: %s [options]\n\
  169. User options:\n\
  170. -p port      : port to listen to (default 54321; 1..99 ==> 54321..54419)\n\
  171. -v volume    : volume setting (1-100; default unchanged)\n\
  172. Expert options:\n\
  173. -f           : filter mode (write data to stdout)\n\
  174. -t           : tee mode (write data to stdout as well as to audio device)\n\
  175. -n           : not interruptable by other sources (Sun only)\n\
  176. -c ctlport   : control port for tuner programs (default 54320)\n\
  177. -s           : secure mode: no control port (disallow tuner programs)\n\
  178. Guru options:\n\
  179. -l localhost : listen to packets to this host only\n\
  180. -r remothost : receive packets from that host only\n\
  181. -m mcastgrp  : multicast group (not always supported)\n\
  182. -d           : debugging mode (writes messages to stderr)\n\
  183. "
  184.  
  185.     while ((c = getopt(argc, argv, OPTIONS)) != EOF) {
  186.         switch (c) {
  187.         case '?':
  188.             fprintf(stderr, USAGE, argv[0]);
  189.             exit(2);
  190.         case 'p':
  191.             receiveport = atoi(optarg);
  192.             if (0 < receiveport && receiveport < 100)
  193.                 receiveport += RCVPORT-1;
  194.             break;
  195.         case 'c':
  196.             ctlport = atoi(optarg);
  197.             break;
  198.         case 'l':
  199.             localname = optarg;
  200.             break;
  201.         case 'r':
  202.             remotename = optarg;
  203.             break;
  204.         case 'd':
  205.             pdebug = 1;
  206.             break;
  207.         case 'm':
  208. #ifdef HAVE_MCAST
  209.             mcastgrp = optarg;
  210. #else
  211.             fprintf(stderr, "(-m not supported here)\n");
  212. #endif
  213.             break;
  214.         case 'n':
  215. #ifdef USE_SUN
  216.             interruptable = 0;
  217. #else
  218.             fprintf(stderr, "(-n not supported here)\n");
  219. #endif
  220.             break;
  221.         case 's':
  222.             ctlport = -1;
  223.             break;
  224.         case 'f':
  225.             filter = 1;
  226.             tee = 0;
  227.             break;
  228.         case 't':
  229.             tee = 1;
  230.             filter = 0;
  231.             break;
  232.         case 'v':
  233.             volume = atoi(optarg);
  234.             break;
  235.         }
  236.     }
  237.  
  238.     /* Meaning of the 'tee' and 'filter' flags:
  239.        At most one of these can be on.
  240.        if tee is on: write stdout and "/dev/audio";
  241.        if filter is on: write stdout only;
  242.        if both are off: write "/dev/audio" only;
  243.        where "/dev/audio" stands for whatever audio hardware we have. */
  244.  
  245.     if (filter || tee)
  246.         ofd = fileno(stdout);
  247.     if (!filter) {
  248.         open_speaker();
  249. #ifdef CHECK_X_SERVER
  250.         xdisplay = XOpenDisplay((char *)NULL);
  251.         if (xdisplay == NULL) {
  252.             fprintf(stderr,
  253. "radio: warning: no X server -- you must kill radio when you log out!\n");
  254.         }
  255. #endif
  256.     }
  257.  
  258.     if (ctlport >= 0)
  259.         ctls = opensock("control", (char *)NULL, ctlport,
  260.                 (char *)NULL, 0, 0);
  261.     else
  262.         ctls = -1;
  263.  
  264.     s = opensock("data", localname, receiveport, remotename, SENDPORT, 0);
  265. #ifdef HAVE_MCAST
  266.     if (mcastgrp)
  267.         setmcast(s, mcastgrp);
  268.     else if (defmcast)
  269.         setmcast(s, defmcast);
  270. #endif
  271.  
  272.     packetcount = 0;
  273.  
  274.     for (;;) {
  275.         /*
  276.         ** Wait until one of the sockets becomes ready
  277.         */
  278.         for (;;) {
  279.             nfds = (s > ctls ? s : ctls) + 1;
  280.             FD_ZERO(&inputset);
  281.             FD_SET(s, &inputset);
  282.             if (ctls >= 0)
  283.                 FD_SET(ctls, &inputset);
  284.             timeout.tv_sec = 30;
  285.             timeout.tv_usec = 0;
  286.             n = select(nfds, &inputset, 0, 0, &timeout);
  287.             if (n > 0)
  288.                 break;
  289.             if (n == 0) {
  290.                 checkalive();
  291.             }
  292.             else if (errno != EINTR) {
  293.                 perror("select");
  294.                 exit(1);
  295.             }
  296.         }
  297.         if (ctls >= 0 && FD_ISSET(ctls, &inputset))
  298.             curs = ctls;
  299.         else if (FD_ISSET(s, &inputset))
  300.             curs = s;
  301.         /*
  302.         ** Read, and check for control packet
  303.         */
  304.         fromlen = sizeof(from);
  305.         buf = real_buf;
  306.         n = recvfrom(curs, buf, HEADERSIZE + BUFFERSIZE, 0,
  307.                  &from, &fromlen);
  308.         if (n <= 0) {
  309.             if (n == 0)
  310.                 continue; /* Ignore empty packets */
  311.             perror("read");
  312.             break;
  313.         }
  314.         if (pdebug) {
  315.             if(pdebug == 8) {
  316.                 fprintf(stderr, "8 packets received\n");
  317.                 pdebug = 1;
  318.             }
  319.             else
  320.                 pdebug++;
  321.         }
  322.         if (n <= CTLPKTSIZE) {
  323.             /*
  324.             ** It looks like a control packet. Check it.
  325.             */
  326.             buf[n] = '\0';
  327.             if (strncmp(buf, "radio:", 6) == 0) {
  328.                 if (pdebug)
  329.                     fprintf(stderr, "control packet\n");
  330.                 switch(buf[6]) {
  331.                 case 'e':        /* Echo */
  332.                     buf[6] = 'E';
  333.                     sendto(curs, buf, n, 0,
  334.                            &from, fromlen);
  335.                     break;
  336.                 case 'S':    /* Status from broadcast */
  337.                     if (pdebug)
  338.                         fprintf(stderr,
  339.                             "Status %s\n", buf);
  340.                     break;
  341.                 case 't':        /* Tune */
  342.                     if (curs != ctls) {
  343.                         if (pdebug)
  344.                           fprintf(stderr,
  345.                             "radio: illegal tune\n");
  346.                         break;
  347.                     }
  348. #ifdef USE_SUN
  349.                     if (!filter) {
  350.                         (void) ioctl(ofd, I_FLUSH,
  351.                                  FLUSHW);
  352.                     }
  353. #endif /* USE_SUN */
  354.                     receiveport = atoi(buf+8);
  355.                     close(s);
  356.                     s = opensock("new data", localname,
  357.                              receiveport, remotename,
  358.                              SENDPORT, 0);
  359.                     if (mcastgrp)
  360.                         setmcast(s, mcastgrp);
  361.                     break;
  362.                 case 'i':        /* Info */
  363.                     sprintf(buf, "radio:I:%d:%d:%s.%d",
  364.                         !pausing, receiveport,
  365.                         VERSION, PATCHLEVEL);
  366.                     sendto(curs, buf, strlen(buf), 0,
  367.                            &from, fromlen);
  368.                     break;
  369. #ifndef USE_NX /* XXX I don't know how to close_speaker() on the NeXT */
  370.                 case 'p':        /* Pause */
  371.                 case '0': /* Backward compatibility */
  372.                     if (!filter && !pausing) {
  373.                         close_speaker();
  374.                         pausing = 1;
  375.                     }
  376.                     break;
  377.                 case 'c':        /* Continue */
  378.                 case '1': /* Backward compatibility */
  379.                     if (pausing) {
  380.                         open_speaker();
  381.                         pausing = 0;
  382.                     }
  383.                     break;
  384. #endif /* USE_NX */
  385.                 default:
  386.                     if (pdebug)
  387.                         fprintf(stderr,
  388.                           "radio: illegal cmd '%c'\n",
  389.                           buf[6]);
  390.                 }
  391.             }
  392.             else if (pdebug) {
  393.                 fprintf(stderr,
  394.                     "radio: ill-formatted command\n");
  395.             }
  396.         }
  397.         else if (!pausing) {
  398.             encoding = PCM_64;
  399. #ifdef USE_AL
  400.             curdatalinear = 0;
  401. #endif /* USE_AL */            
  402.             if ((buf[0]&0xff) == AUDIO_TYPE) {
  403.                 encoding = buf[1]&0xff;
  404.                 buf += HEADERSIZE;
  405.                 n -= HEADERSIZE;
  406.             }
  407.             else {
  408.                 if (pdebug)
  409.                     fprintf(stderr,
  410.                         "radio: non-IVS packet\n");
  411.                 continue;
  412.             }
  413.             switch (encoding) {
  414.  
  415.             case PCM_64:
  416.                 break;
  417.  
  418.             case ADPCM_32:
  419.                 n = n*2;
  420. #ifdef USE_AL
  421.                 /*
  422.                 ** For SGI and non-filter mode, don't convert
  423.                 ** via ulaw but straight to linear
  424.                 */
  425.                 if (!filter) {
  426.                     curdatalinear = 1;
  427.                     adpcm_decoder(buf, obuf, n,
  428.                               (struct adpcm_state *)0);
  429.                 }
  430.                 else
  431. #endif /* USE_AL */
  432.                 {
  433.                     adpcm_ulaw_decoder(buf, tmp_buf, n,
  434.                            (struct adpcm_state *)0);
  435.                     buf = tmp_buf;
  436.                 }
  437.                 break;
  438.  
  439.             case ADPCM_32_W_STATE:
  440.                 state.valprev =
  441.                     ((buf[0]&0xff)<<8) | (buf[1]&0xff);
  442.                 state.index = buf[2]&0xff;
  443.                 buf += 3;
  444.                 n -= 3;
  445.                 n = n*2;
  446. #ifdef USE_AL                
  447.                 if (!filter) {
  448.                     adpcm_decoder(buf, obuf, n, &state);
  449.                     curdatalinear = 1;
  450.                 }
  451.                 else
  452. #endif /* USE_AL */
  453.                 {
  454.                     adpcm_ulaw_decoder(buf, tmp_buf, n,
  455.                                &state);
  456.                     buf = tmp_buf;
  457.                 }
  458.                 break;
  459.  
  460.             default:
  461.                 if (pdebug)
  462.                     fprintf(stderr,
  463.                         "radio: unknown encoding %d\n",
  464.                         encoding);
  465.                 /* Ignore the package */
  466.                 continue;
  467.  
  468.             }
  469. #ifdef USE_AL
  470.             if (!filter) {
  471.                     if (!curdatalinear)
  472.                     for (i = 0; i < n; i++)
  473.                         obuf[i] =
  474.                         st_ulaw_to_linear(buf[i]&0xff);
  475.                 ALwritesamps(aport, obuf, (long)n);
  476.             }
  477. #endif /* USE_AL */
  478. #ifdef USE_NX
  479.             if (!filter) {
  480.                 int dummy;
  481.                 char *ptr;
  482.                 
  483.                 (void) SNDGetDataPointer(snd[akt_buf], &ptr,
  484.                              &dummy, &dummy);
  485.                 
  486.                 SNDWait(akt_buf+1);
  487.                 memcpy(ptr, buf, n);
  488.                 snd[akt_buf] -> dataSize = n;
  489.                 SNDStartPlaying(snd[akt_buf],
  490.                         akt_buf+1, 5, 0, 0, 0);
  491.                 akt_buf = (akt_buf + 1) % NUM_BUFFER;
  492.             }
  493. #endif /* USE_NX */
  494. #ifdef USE_SUN
  495.             if (!filter) {
  496.                 if (write(afd, buf, n) != n) {
  497.                     perror("write afd");
  498.                     break;
  499.                 }
  500.             }
  501. #endif /* USE_SUN */
  502.             if (filter || tee) {
  503.                 if (write(ofd, buf, n) != n) {
  504.                     perror("write ofd");
  505.                     break;
  506.                 }
  507.             }
  508.         }
  509.         if (++packetcount > (30*SAMPLINGRATE / BUFFERSIZE)) {
  510.             checkalive();
  511.             packetcount = 0;
  512.         }
  513.     }
  514.  
  515.     exit(0);
  516. }
  517.  
  518. #ifdef USE_AL
  519.  
  520. void open_speaker()
  521. {
  522.     ALconfig config;
  523.     long pvbuf[6];
  524.     
  525.     /* Fetch the original state */
  526.     ALgetparams(AL_DEFAULT_DEVICE, savestate,
  527.             sizeof(savestate) / sizeof(long));
  528.     
  529.     /* Set signal handlers */
  530.     signal(SIGINT, cleanup_handler);
  531.     signal(SIGTERM, cleanup_handler);
  532.     
  533.     /* Set the output sampling rate */
  534.     pvbuf[0] = AL_OUTPUT_RATE;
  535.     pvbuf[1] = SAMPLINGRATE; /* XXX Assume AL_RATE_n is n */
  536.     
  537.     /* Maybe also set the volume */
  538.     if (volume >= 0) {
  539.         pvbuf[2] = AL_LEFT_SPEAKER_GAIN;
  540.         pvbuf[3] = volume*255/100;
  541.         pvbuf[4] = AL_RIGHT_SPEAKER_GAIN;
  542.         pvbuf[5] = volume*255/100;
  543.         ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 6L);
  544.     }
  545.     else
  546.         ALsetparams(AL_DEFAULT_DEVICE, pvbuf, 2L);
  547.     
  548.     /* Configure and open an SGI audio port */
  549.     config = ALnewconfig();
  550.     ALsetchannels(config, AL_MONO);
  551.     ALsetwidth(config, AL_SAMPLE_16);
  552.     ALsetqueuesize(config, 16000); /* 2 seconds slop */
  553.     aport = ALopenport("radio", "w", config);
  554.     if (aport == NULL) {
  555.         perror("ALopenport");
  556.         exit(1);
  557.     }
  558. }
  559.  
  560. void close_speaker()
  561. {
  562.     ALcloseport(aport);
  563.     aport = NULL;
  564. }
  565.  
  566. void cleanup_handler(sig)
  567.     int sig;
  568. {
  569.     signal(sig, SIG_DFL);
  570.     if (!pausing) {/* Don't reset anything if we're pausing */
  571.         long n = sizeof(savestate) / sizeof(long);
  572.         if (volume < 0)
  573.             n -= 4; /* Don't reset volume if we didn't set it */
  574.         ALsetparams(AL_DEFAULT_DEVICE, savestate, n);
  575.     }
  576.     kill(getpid(), sig);
  577. }
  578.  
  579. #endif /* USE_AL */
  580.  
  581.  
  582. #ifdef USE_SUN
  583.  
  584. void open_speaker()
  585. {    
  586.     audio_info_t info;
  587.  
  588.     /* Write to AUDIO_IODEV */
  589.     if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  590.         perror(AUDIO_IODEV);
  591.         exit(1);
  592.     }
  593.  
  594.     /* Set the volume */
  595.     if (volume >= 0) {
  596.         AUDIO_INITINFO(&info);
  597.         info.play.gain = (AUDIO_MAX_GAIN * volume) / 100;
  598.         if (ioctl(afd, AUDIO_SETINFO, &info))
  599.             perror("volume setting");
  600.     }
  601.  
  602.     /* We need to open the audio control port to detect
  603.        if someone else wants to output to /dev/audio.
  604.        If this fails (e.g., in SunOS 4.0), print a message
  605.        but don't exit. */
  606.     if (interruptable) {
  607.         if ((actlfd = open(AUDIO_CTLDEV, O_RDWR)) < 0) {
  608.             perror(AUDIO_CTLDEV);
  609.         }
  610.         else if (ioctl(actlfd, I_SETSIG, S_MSG) < 0) {
  611.             perror("I_SETSIG");
  612.         }
  613.         else if (signal(SIGPOLL, sigpoll_handler) < 0) {
  614.             perror("signal(SIGPOLL)");
  615.             exit(1);
  616.         }
  617.     }
  618. }
  619.  
  620. void close_speaker()
  621. {
  622.     (void) ioctl(afd, I_FLUSH, FLUSHW);
  623.     close(afd);
  624.     close(actlfd);
  625.     afd = actlfd = -1;
  626. }
  627.  
  628. void sigpoll_handler()
  629. {
  630.     audio_info_t ap;
  631.  
  632.     if (ioctl(actlfd, AUDIO_GETINFO, &ap) < 0) {
  633.         perror("AUDIO_GETINFO");
  634.     }
  635.     else if (ap.play.waiting) {
  636.         (void) ioctl(afd, I_FLUSH, FLUSHW);
  637.         close(afd);
  638.         /* The open() call blocks until we can use the device again */
  639.         if ((afd = open(AUDIO_IODEV, O_WRONLY)) < 0) {
  640.             perror(AUDIO_IODEV);
  641.             exit(1);
  642.         }
  643.         ap.play.waiting = 0;
  644.         if (ioctl(actlfd, AUDIO_SETINFO, &ap) < 0) {
  645.             perror("AUDIO_SETINFO");
  646.         }
  647.     }
  648. }
  649.  
  650. #endif /* USE_SUN */
  651.  
  652.  
  653. #ifdef USE_NX
  654.  
  655. void open_speaker()
  656. {
  657.     int akt_buf;
  658.     int err;
  659.  
  660.     /* Alloc NUM_BUFFER Sounds */
  661.     for (akt_buf = NUM_BUFFER; akt_buf > 0; akt_buf--) {
  662.         if (err = SNDAlloc(&snd[akt_buf-1], BUFFERSIZE,
  663.                    SND_FORMAT_MULAW_8,
  664.                    SND_RATE_CODEC, 1, 4)) {
  665.             fprintf(stderr, "init: %s\n", SNDSoundError(err));
  666.             exit(1);
  667.         }
  668.     }
  669.     akt_buf = 0;
  670. }
  671.  
  672. void close_speaker()
  673. {
  674.     /* XXX how to do this? */
  675. }
  676.  
  677. #endif /* USE_NX */
  678.  
  679.  
  680. void checkalive()
  681. {
  682. #ifdef CHECK_X_SERVER
  683.     if (xdisplay) {
  684.         Window focus;
  685.         int revert_to;
  686.         if (pdebug)
  687.             fprintf(stderr, "polling X server...\n");
  688.         /* Do a simple X request that needs a server round trip...
  689.            The error handler will kill us when the server is dead,
  690.            so that radio dies when the user logs out. */
  691.         XGetInputFocus(xdisplay, &focus, &revert_to);
  692.         if (pdebug)
  693.             fprintf(stderr, "X server OK\n");
  694.     }
  695.     else if (pdebug)
  696.         fprintf(stderr, "checkalive() is a no-op\n");
  697. #endif /* CHECK_X_SERVER */
  698. }
  699.  
  700. void setmcast(s, group)
  701.     int s;
  702.     char *group;
  703. {
  704. #ifdef HAVE_MCAST
  705.     struct hostent *hostentry;
  706.     struct in_addr grpaddr;
  707.     struct in_addr ifaddr;
  708.     struct ip_mreq mreq;
  709.  
  710.     if (hostentry = gethostbyname(group))
  711.     {
  712.         bcopy(hostentry->h_addr, &grpaddr.s_addr, sizeof(grpaddr.s_addr));
  713.     }
  714.     else
  715.         grpaddr.s_addr = inet_addr(group);
  716.  
  717.     if (!IN_MULTICAST(grpaddr.s_addr)) {
  718.         fprintf(stderr, "Bad multicast group: %s\n", group);
  719.         exit(1);
  720.     }
  721.     
  722.     ifaddr.s_addr = htonl(INADDR_ANY);
  723.     
  724.     mreq.imr_multiaddr = grpaddr;
  725.     mreq.imr_interface = ifaddr;
  726.     if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP,
  727.                &mreq, sizeof(mreq)) < 0) {
  728.         perror("setsockopt mreq");
  729.         exit(1);
  730.     }
  731. #endif /* HAVE_MCAST */
  732. }
  733.