home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / alt / sources / 2611 / netio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-23  |  27.5 KB  |  1,440 lines

  1. #ifndef lint
  2. static    char    sccsid[] = "@(#)netio.c 1.2 92/05/28 SMI" ;
  3.     /* from netio.c 1.4 90/05/02 SMI */
  4. #endif
  5.  
  6. /*
  7.  * Copyright (c) 1986 by Sun Microsystems, Inc.
  8.  */
  9.  
  10. /*
  11.  * this is generic network stuff.  Communications functions are:
  12.  *
  13.  * init_netio(username,mastername)
  14.  *    intialize communications.  Called before notifier is started up.
  15.  *
  16.  * net_start_message(who)
  17.  *    start building out-going message, if who=NULL, then this is
  18.  *    a broadcast message.  Implicit flush if who is different than
  19.  *    previous addressee.
  20.  *
  21.  * net_flush()
  22.  *    flush outgoing message queue
  23.  *
  24.  * send_status(obj)
  25.  *    add object's status to outgoing message
  26.  *
  27.  * net_blow_away(weapon, object)
  28.  *    called when we've shot object
  29.  *
  30.  * net_remove_player(id)
  31.  *    remove player from game
  32.  *
  33.  * net_request_missile()
  34.  *    ask master for missile assignment
  35.  *
  36.  * net_poll()
  37.  *    called every 5 seconds to do bookkeeping
  38.  *
  39.  * handle_message(me, fd)
  40.  *    deal with an incoming message
  41.  *
  42.  *
  43.  *
  44.  */
  45.  
  46.  
  47.  
  48. /*    NOTES:
  49.  *
  50.  * There is no more daemon.  The first player to join a local net
  51.  * becomes the master for that net.  The master for a net can
  52.  * be slaved to the master for a game.
  53.  *
  54.  * Algorithms:
  55.  *
  56.  * when the program starts up, it sends a net_joining packet out and
  57.  * starts the game as object id #0.  If, after 5 seconds, no NET_WELCOME
  58.  * packet arrives, it makes itself the master for the subnet.
  59.  *
  60.  * if a NET_WELCOME response is received within five seconds, the program
  61.  * becomes a slave.  It also moves its own status info into the assigned
  62.  * slot.
  63.  *
  64.  * When the master receives a net_joining message, it responds with a
  65.  * net_welcome message followed by a list of object descriptions for
  66.  * all the other players in the game.  It also sends the object
  67.  * description for this player to all the other players.
  68.  *
  69.  * Every ten seconds, the master polls all the players on its subnet
  70.  * to make sure they're alive.  If not, a net_died message is sent out.
  71.  *
  72.  * If player #1 doesn't hear a poll from the master in 20 seconds, it
  73.  * takes over as master.
  74.  *
  75.  *
  76.  * If a program is a master and it has been given a hostname
  77.  * as an argument, it tries to contact the master on that host.  If
  78.  * this is successful, it becomes a "subnet master".  This is like
  79.  * a slave except that it still has certain duties:
  80.  *
  81.  * o It relays net_joining messages to the master.
  82.  *
  83.  */
  84.  
  85.  
  86.  
  87. #include <stdio.h>
  88. #include <fcntl.h>
  89. #include <sys/types.h>
  90. #include <sys/uio.h>
  91. #include <sys/socket.h>
  92. #include <netinet/in.h>
  93. #include <netdb.h>
  94. #include <arpa/inet.h>
  95. #include <sys/time.h>
  96. #ifdef XV
  97. #include <xview/notify.h>
  98. #else
  99. #include <sunwindow/notify.h>
  100. #endif XV
  101. #include <errno.h>
  102. #include <net/if.h>
  103. #include <sys/ioctl.h>
  104.  
  105. #include "dstar.h"
  106. #include "netio.h"
  107.  
  108.  
  109.  
  110. typedef    int    fd ;
  111.  
  112. static    FILE    *iolog ;
  113.  
  114.  
  115. extern    int    debug_level ;
  116.  
  117. static    fd    Socket ;
  118.  
  119. static    struct sockaddr_in    Sock ;
  120.  
  121. static    struct sockaddr_in    myaddr ;
  122.  
  123. static    char            outbuf[MESSAGE_LENGTH] ;
  124. static    char            *Mastername ;
  125. static    char            *outptr ;
  126. static    int            outlen ;
  127. static    struct sockaddr_in    outaddress ;
  128.  
  129. static    Notify_value    handle_message() ;
  130.  
  131.  
  132.  
  133. /*
  134.  * INTERNAL ROUTINES:
  135.  *
  136.  * report_problem    -    print object id, port & net address
  137.  *
  138.  * transmit(address, message, len)
  139.  *            -    send an output packet
  140.  *
  141.  * broadcast(message, len)
  142.  *            -    send packet to everybody
  143.  *
  144.  * net_flush()        -    deliver current message
  145.  *
  146.  * add_message(message, len)
  147.  *            -    buffer up message
  148.  *
  149.  * request_rebroadcast(address, message,len)
  150.  *            -    ask somebody to broadcast something
  151.  *
  152.  * rehash_netlists()    -    rebuild net lists if there's a change
  153.  */
  154.  
  155.  
  156.  
  157.  
  158. static
  159. report_problem(id,addr)
  160.     int    id ;
  161. register struct sockaddr_in    *addr ;
  162. {
  163.     printf("sending to %d at %d, %d.%d.%d.%d\n", id, addr->sin_port,
  164.       addr->sin_addr.S_un.S_un_b.s_b1, addr->sin_addr.S_un.S_un_b.s_b2,
  165.       addr->sin_addr.S_un.S_un_b.s_b3, addr->sin_addr.S_un.S_un_b.s_b4) ;
  166. }
  167.  
  168.  
  169.  
  170. dump_lists()
  171. {
  172. register Object    *object = &objects[0] ;
  173.     int    i ;
  174. static    char    *classes[] = {"empty","static","player","missile"} ;
  175. static    char    *states[] = {"active","sleeping","dead"} ;
  176.  
  177.     fprintf(iolog, "object lists:\n") ;
  178.     for(i = 0; i<MAX_PLAYERS; ++i )
  179.     {
  180.       if(object->class != OBJ_EMPTY)
  181.         printf("   %2d: %-20.20s %-7.7s %-8.8s %-20.20s\n",
  182.           i, object->name, classes[(int) object->class],
  183.           states[(int) object->status],
  184.           object->target != NULL ? object->target->name : "" ) ;
  185.       ++object ;
  186.     }
  187. }
  188.  
  189.  
  190.  
  191.  
  192.  
  193. static
  194. request_rebroadcast(address, message,len)
  195. register struct sockaddr_in    *address ;
  196. register char            *message ;
  197. register int            len ;
  198. {
  199.     int        iret ;
  200.     struct msghdr    msg_hdr ;
  201.     struct iovec    iovecs[2] ;
  202.     Net_broadcast    b_msg ;
  203.  
  204.     b_msg.type = NET_BROADCAST ;
  205.     b_msg.len = sizeof(b_msg) + len ;
  206.     b_msg.id = Me->id ;
  207.     b_msg.sequence = ++sequence_number ;
  208.  
  209.     iovecs[0].iov_base = (char *) &b_msg ;
  210.     iovecs[0].iov_len = sizeof(b_msg) ;
  211.     iovecs[1].iov_base = message ;
  212.     iovecs[1].iov_len = len ;
  213.  
  214.     msg_hdr.msg_name = (char *) address ;
  215.     msg_hdr.msg_namelen = sizeof(struct sockaddr_in) ;
  216.     msg_hdr.msg_iov = iovecs ;
  217.     msg_hdr.msg_iovlen = 2 ;
  218.     msg_hdr.msg_accrights = NULL ;
  219.     msg_hdr.msg_accrightslen = 0 ;
  220.  
  221.     iret = sendmsg(Socket, &msg_hdr, 0) ;
  222.     if(iret < 0)
  223.       perror("dstard: sendto") ;
  224. }
  225.  
  226.  
  227.  
  228. rebroadcast(header)
  229.     Net_broadcast    *header ;
  230. {
  231.     Sock.sin_family = AF_INET ;
  232.     Sock.sin_port = htons(DSTAR_PORT) ;
  233.     Sock.sin_addr.s_addr = Me->net_addr ;
  234.     transmit(&Sock, ((char *)header)+sizeof(Net_broadcast),
  235.         header->len - sizeof(Net_broadcast)) ;
  236. }
  237.  
  238.  
  239.  
  240.  
  241.  
  242.  
  243.  
  244.  
  245. rehash_netlists()
  246. {
  247. register Object    *object, *obj1 ;
  248. register Object *last_net, *last_subnet ;
  249.     int    i,j ;
  250.     int    count = 0 ;
  251.  
  252.     object = &objects[0] ;
  253.     for(i = MAX_PLAYERS; i--; )
  254.     {
  255.       object->net_status = UNKNOWN ;
  256.       object->next_net = NULL ;
  257.       object->next_subnet = NULL ;
  258.       ++object ;
  259.     }
  260.     master_id = -1 ;
  261.  
  262.     last_net = NULL ;
  263.  
  264.     poll_master = 0 ;
  265.  
  266.     object = &objects[0] ;
  267.     for(i = 0; i<MAX_PLAYERS; ++i)
  268.     {
  269.       if( object->class == OBJ_PLAYER )
  270.       {
  271.         if( object == Me  &&  count == 1 )
  272.           poll_master = 1 ;
  273.         else
  274.           ++count ;
  275.  
  276.         if( object->net_status == UNKNOWN )
  277.         {
  278.           if( last_net == NULL )
  279.           {
  280.         object->net_status = MASTER ;
  281.         master_id = object->id ;
  282.           }
  283.           else
  284.           {
  285.         object->net_status = SUBMASTER ;
  286.         last_net->next_net = object ;
  287.           }
  288.           obj1 = last_subnet = last_net = object ;
  289.           object->net_num = 0 ;
  290.  
  291.           ++obj1 ;
  292.           for(j = i+1; j<MAX_PLAYERS; ++j)
  293.           {
  294.         if(obj1->class == OBJ_PLAYER  &&
  295.            obj1->net_addr == object->net_addr)
  296.         {
  297.           ++object->net_num ;
  298.           last_subnet->next_subnet = obj1 ;
  299.           obj1->net_status = SLAVE ;
  300.           last_subnet = obj1 ;
  301.         }
  302.         ++obj1 ;
  303.           }
  304.         }
  305.       }
  306.       ++object ;
  307.     }
  308.  
  309.     need_rehash = 0 ;
  310.  
  311. #ifdef    DEBUG
  312.     if(debug_level >= 2)
  313.     {
  314.       fprintf(iolog,"new net lists:\n") ;
  315.       object = &objects[master_id] ;
  316.       for(object = &objects[master_id];
  317.           object != NULL;
  318.           object = object->next_net)
  319.       {
  320.         fprintf(iolog, "  net %6.6lx\n",object->net_addr) ;
  321.         for(obj1 = object; obj1 != NULL; obj1 = obj1->next_subnet)
  322.           fprintf(iolog, "    %2d: %s\n",obj1->id, obj1->name) ;
  323.       }
  324.     }
  325. #endif    DEBUG
  326. }
  327.  
  328.  
  329.  
  330.  
  331. static
  332. transmit(address,message,len)
  333. register struct sockaddr_in    *address ;
  334. register char            *message ;
  335. register int            len ;
  336. {
  337. register int            iret ;
  338.  
  339.     iret = sendto(Socket, message, len, 0, address,
  340.         sizeof(struct sockaddr_in)) ;
  341.     if(iret < 0)
  342.       perror("dstard: sendto") ;
  343. }
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351. /****
  352.  * this function makes sure that the provided message gets to all the players
  353.  * in the game.  If there's less than a certain number of players
  354.  * on each local net, the message is sent individually.  If there's more
  355.  * players than the threshold, the message is broadcast.
  356.  ****/
  357.  
  358. static
  359. broadcast(message,len)
  360. register char        *message ;
  361. register int        len ;
  362. {
  363. register int        id ;
  364. register int        i,j ;
  365. register Object        *object = &objects[master_id] ;
  366. register Object        *obj2 ;
  367.  
  368.  
  369.     /* send to all other players, active or dead */
  370.  
  371.     if( need_rehash )
  372.       rehash_netlists() ;
  373.  
  374.     if( master_id == -1 )
  375.       return ;
  376.  
  377.  
  378.     for( object = &objects[master_id];
  379.          object != NULL;
  380.          object = object->next_net )
  381.     {
  382.       if(object->net_num <= BROADCAST_THRESH)
  383.       {
  384.         for(obj2 = object; obj2 != NULL; obj2 = obj2->next_subnet)
  385.         {
  386. #ifdef    DEBUG
  387.           if(obj2->class != OBJ_PLAYER)
  388.           {
  389.         fprintf(iolog,
  390.               "%s got into netlists somehow\n",object->name) ;
  391.         rehash_netlists() ;
  392.           }
  393. #endif    DEBUG
  394.           if( obj2 != Me )
  395.         transmit(&obj2->address, message, len) ;
  396.         }
  397.       }
  398.       else if(object->net_addr == Me->net_addr)
  399.       {
  400.         bzero(&Sock, sizeof(Sock)) ;
  401.         Sock.sin_family = AF_INET ;
  402.         Sock.sin_port = htons(DSTAR_PORT) ;
  403.         Sock.sin_addr.s_addr = object->net_addr ;
  404.         transmit(&Sock, message, len) ;
  405.       }
  406.       else
  407.       {
  408.         request_rebroadcast(&object->address, message, len) ;
  409.       }
  410.     }
  411. }
  412.  
  413.  
  414.  
  415.  
  416. net_flush()
  417. {
  418.     int    iret ;
  419.  
  420. #ifdef    DEBUG
  421.     if(Me->id == -1)
  422.     {
  423.       fprintf(iolog, "attempt to transmit while not in game\n") ;
  424.     }
  425. #endif    DEBUG
  426.  
  427.     if(outlen > 0)
  428.     {
  429.       if(Me->id != -1)
  430.         if( outaddress.sin_addr.S_un.S_addr != 0 )
  431.           transmit(&outaddress, outbuf, outlen) ;
  432.         else
  433.           broadcast(outbuf, outlen) ;
  434.  
  435.       outptr = &outbuf[0] ;
  436.       outlen = 0 ;
  437.     }
  438. }
  439.  
  440.  
  441.  
  442.  
  443. net_start_message(who)
  444. register Object    *who ;
  445. {
  446. register u_long    newaddr ;
  447.  
  448.     if( who == NULL )
  449.       newaddr = 0 ;
  450.     else
  451.       newaddr = who->address.sin_addr.S_un.S_addr ;
  452.  
  453.     if( newaddr != outaddress.sin_addr.S_un.S_addr  &&
  454.         outlen > 0 )
  455.       net_flush() ;
  456.  
  457.     if( who == NULL )
  458.       outaddress.sin_addr.S_un.S_addr = 0 ;
  459.     else
  460.       outaddress = who->address ;
  461. }
  462.  
  463.  
  464.  
  465.  
  466. add_message(message, len)
  467. register Net_null    *message ;
  468. register int        len ;
  469. {
  470.     int        iret ;
  471.  
  472.     if(len + outlen > MESSAGE_LENGTH)
  473.       net_flush() ;
  474.  
  475.     bcopy(message, outptr, len) ;
  476.     outptr += len ;
  477.     outlen += len ;
  478. }
  479.  
  480.  
  481.  
  482.  
  483.  
  484.  
  485.  
  486.  
  487. static
  488. join_game()
  489. {
  490.     Net_joining    outmsg ;
  491.     struct hostent    *host ;
  492. register Object        *object = &objects[0] ;
  493. register int        i ;
  494.  
  495.     for(i = MAX_PLAYERS; i--; )
  496.     {
  497.       if( object->class != OBJ_EMPTY  &&  object != Me )
  498.       {
  499.         special_remove_player(object) ;
  500.         object->class = OBJ_EMPTY ;
  501.       }
  502.       ++object ;
  503.     }
  504.  
  505.     Me->id = -1 ;
  506.     Me->target = NULL ;
  507.     Me->net_status = UNKNOWN ;
  508.  
  509.  
  510.  
  511.  
  512.     /* look for other people playing the game */
  513.  
  514.     outmsg.type = NET_JOINING ;
  515.     outmsg.len = sizeof(Net_joining) ;
  516.     outmsg.id = -1 ;
  517.     outmsg.sequence = ++sequence_number ;
  518.     strcpy(outmsg.name, Me->name) ;
  519.     outmsg.class = Me->class ;
  520.     outmsg.address = myaddr ;
  521.  
  522.     bzero(&Sock, sizeof(Sock)) ;
  523.     Sock.sin_family = AF_INET ;
  524.     Sock.sin_port = htons(DSTAR_PORT) ;
  525.  
  526.     if(Mastername == NULL)        /* broadcast */
  527.     {
  528.       Sock.sin_addr.s_addr = Me->net_addr ;
  529.       transmit(&Sock, &outmsg, sizeof(outmsg)) ;
  530.     }
  531.     else                /* send direct to master */
  532.     {
  533.       host = gethostbyname(Mastername) ;
  534.       Sock.sin_addr = *(struct in_addr *) host->h_addr ;
  535.       request_rebroadcast(&Sock, &outmsg, sizeof(outmsg)) ;
  536.     }
  537.  
  538. #ifdef    DEBUG
  539.     if(debug_level >= 1)
  540.     {
  541.       fprintf(iolog, "join game: my name = %s\n",Me->name ) ;
  542.     }
  543. #endif    DEBUG
  544. }
  545.  
  546.  
  547.  
  548.  
  549.  
  550.  
  551.  
  552.  
  553.  
  554. /*    EXTERNAL ROUTINES:
  555.  *
  556.  * init_netio(username,mastername)
  557.  *    intialize communications.  Called before notifier is started up.
  558.  *
  559.  * net_blow_away(weapon, object)
  560.  *    called when we've shot object
  561.  *
  562.  * send_status(obj, who)
  563.  *    send status to specific player
  564.  *
  565.  * send_status_all(obj)
  566.  *    send status to everybody
  567.  *
  568.  * net_remove_player(id)
  569.  *    remove player from game
  570.  *
  571.  * net_request_missile()
  572.  *    ask master for missile assignment
  573.  *
  574.  * net_poll()
  575.  *    called every 5 seconds to do bookkeeping
  576.  */
  577.  
  578.  
  579.  
  580.  
  581. init_netio(username, mastername)
  582.     char        *username ;
  583.     char        *mastername ;
  584. {
  585.     int        iret, i ;
  586.     int        flags ;
  587.     int        nfds, mask, sockmask ;
  588.     int        done ;
  589.     struct hostent    *host ;
  590.     struct timeval    timeout ;
  591.     struct sockaddr_in    broadaddr ;
  592.  
  593.  
  594.  
  595. #ifdef    DEBUG
  596.     if( status_display )
  597.       putchar('\f') ;
  598. #endif    DEBUG
  599.  
  600.  
  601.  
  602.     iolog = stderr ;
  603.  
  604.  
  605.  
  606.     /* create socket for i/o */
  607.  
  608.     Socket = socket(AF_INET, SOCK_DGRAM, 0) ;
  609. #ifdef    COMMENT
  610.     printf("socket done, fd=%d\n",Socket) ;
  611. #endif    COMMENT
  612.     if(Socket<0) {
  613.       perror("Dstar: Init_netio") ;
  614.       exit(1) ;
  615.     }
  616.  
  617.  
  618.     /* make it non-blocking */
  619.  
  620.     flags = fcntl(Socket, F_GETFL, 0) ;
  621.     flags |= FNDELAY ;
  622.     fcntl(Socket, F_SETFL, flags) ;
  623.  
  624.  
  625.  
  626.     /* give it a port & address */
  627.  
  628.     bzero(&Sock, sizeof(Sock)) ;
  629.  
  630.     Sock.sin_family = AF_INET ;
  631.     Sock.sin_port = htons(DSTAR_PORT) ;
  632.     Sock.sin_addr.s_addr = INADDR_ANY ;
  633.  
  634.     iret = bind(Socket, &Sock, sizeof(Sock)) ;
  635. #ifdef    COMMENT
  636.     printf("bind done, iret=%d\n",iret) ;
  637. #endif    COMMENT
  638.     if(iret) {
  639.       perror("dstar: socket") ;
  640.       exit(1) ;
  641.     }
  642.  
  643.     sequence_number = 0 ;
  644.  
  645.  
  646.  
  647.     gethostname(Hostname, 64) ;
  648. #ifdef    COMMENT
  649.     printf("hostname = %s\n",Hostname) ;
  650. #endif    COMMENT
  651.  
  652.     host = gethostbyname(Hostname) ;
  653.     myaddr.sin_family = AF_INET ;
  654.     myaddr.sin_port = htons(DSTAR_PORT) ;
  655.     myaddr.sin_addr = *(struct in_addr *) host->h_addr ;
  656. #ifdef    COMMENT
  657.     printf("dstar net address is %d.%d.%d.%d\n",
  658.       myaddr.sin_addr.S_un.S_un_b.s_b1, myaddr.sin_addr.S_un.S_un_b.s_b2,
  659.       myaddr.sin_addr.S_un.S_un_b.s_b3, myaddr.sin_addr.S_un.S_un_b.s_b4) ;
  660. #endif    COMMENT
  661.  
  662.  
  663.  
  664.     outptr = &outbuf[0] ;
  665.     outlen = 0 ;
  666.     outaddress.sin_addr.S_un.S_addr = 0 ;
  667.  
  668.  
  669.     /* initialize the stuff that special_init didn't do */
  670.  
  671.     sprintf(Me->name, "%s@%s", username, Hostname) ;
  672.     Me->address = myaddr ;
  673.     Me->sequence = ++sequence_number ;
  674.     Me->last_rep = Now ;
  675. #ifdef    COMMENT
  676.     Me->net_addr = myaddr.sin_addr.s_addr & 0xffffff00 ;
  677. #endif    COMMENT
  678.     getbroad(Socket, 1, &broadaddr) ;
  679.     report_problem(0,&broadaddr) ;
  680.     Me->net_addr = broadaddr.sin_addr.s_addr ;
  681.  
  682.     Mastername = mastername ;
  683.  
  684.     puts("checking network for other players...") ;
  685.  
  686.     join_game() ;
  687.  
  688.  
  689.     /* set up to receive messages */
  690.  
  691.     (void) notify_set_input_func(&Socket, handle_message, Socket) ;
  692. }
  693.  
  694.  
  695.  
  696.  
  697.  
  698.  
  699.  
  700.  
  701. send_status(obj)
  702. register Object    *obj ;
  703. {
  704.     Net_current_status    outmsg ;
  705.     int            iret ;
  706.  
  707.     outmsg.type = NET_CURRENT_STATUS ;
  708.     outmsg.len = sizeof(Net_current_status) ;
  709.     outmsg.id = Me->id ;
  710.     outmsg.sequence = ++sequence_number ;
  711.     outmsg.obj_id = obj->id ;
  712.     bcopy(obj->name, outmsg.name, NAMELEN) ;
  713.     outmsg.team = obj->team ;
  714.     outmsg.score = obj->score ;
  715.     outmsg.class = obj->class ;
  716.     outmsg.status = obj->status ;
  717.     outmsg.flags = obj->flags ;
  718.     outmsg.Posn = obj->Posn ;
  719.     outmsg.Forward = obj->Forward ;
  720.     outmsg.Up = obj->Up ;
  721.     outmsg.Right = obj->Right ;
  722.     outmsg.Delta = obj->Delta ;
  723.     outmsg.Pointing = obj->Pointing ;
  724.     outmsg.Speed = obj->Speed ;
  725.     outmsg.target = (obj->target != NULL) ? obj->target->id : -1 ;
  726.     outmsg.description = obj->description ;
  727.     outmsg.address = obj->address ;
  728.     outmsg.net_addr = obj->net_addr ;
  729.  
  730.     add_message(&outmsg, sizeof(outmsg)) ;
  731.  
  732.     obj->last_rep = Now ;
  733. }
  734.  
  735.  
  736.  
  737.  
  738.  
  739.  
  740.  
  741. net_remove_player(id)
  742.     int    id ;
  743. {
  744.     Net_died    died_msg ;
  745.  
  746.     net_start_message( NULL ) ;
  747.     died_msg.type = NET_DIED ;
  748.     died_msg.len = sizeof(Net_died) ;
  749.     died_msg.id = Me->id ;
  750.     died_msg.sequence = ++sequence_number ;
  751.     died_msg.his_id = id ;
  752.     add_message(&died_msg, sizeof(died_msg)) ;
  753.  
  754. #ifdef    DEBUG
  755.     if(debug_level >= 1)
  756.       fprintf(iolog, "net_remove_player: %2d: %s\n",
  757.         id, objects[id].name ) ;
  758. #endif    DEBUG
  759.  
  760.     remove_player(&died_msg) ;
  761.  
  762. #ifdef    DEBUG
  763.     if(status_display)
  764.       status_update() ;
  765. #endif    DEBUG
  766. }
  767.  
  768.  
  769.  
  770. net_blow_away(weapon, object)
  771.     Object    *weapon, *object ;
  772. {
  773.     Net_just_scored        outmsg ;
  774.  
  775.     net_start_message( NULL ) ;
  776.     outmsg.type = NET_JUST_SCORED ;
  777.     outmsg.len = sizeof(Net_just_scored) ;
  778.     outmsg.id = Me->id ;
  779.     outmsg.sequence = ++sequence_number ;
  780.     outmsg.weapon_id = weapon->id ;
  781.     outmsg.his_id = object->id ;
  782.  
  783.     add_message(&outmsg,sizeof(outmsg)) ;
  784.  
  785.     player_scored(&outmsg) ;
  786.  
  787. #ifdef    DEBUG
  788.     if(debug_level >= 1)
  789.       fprintf(iolog, "net_blow_away: %2d: %s with %s\n",
  790.         object->id, object->name, weapon->name ) ;
  791. #endif    DEBUG
  792. }
  793.  
  794.  
  795.  
  796.  
  797. net_request_missile()
  798. {
  799.     Net_request_missile    msg ;
  800.  
  801.     msg.type = NET_REQUEST_MISSILE ;
  802.     msg.len = sizeof(Net_request_missile) ;
  803.     msg.id = Me->id ;
  804.     msg.sequence = ++sequence_number ;
  805.     if(Me->net_status != MASTER)
  806.     {
  807.       net_start_message( &objects[master_id] ) ;
  808.       add_message(&msg, sizeof(msg)) ;
  809.       net_flush() ;
  810.     }
  811.     else
  812.       new_missile(&msg) ;
  813. }
  814.  
  815.  
  816.  
  817.  
  818. net_rename(newid)
  819.     int    newid ;
  820. {
  821.     Net_rename    msg ;
  822.  
  823.     msg.type = NET_RENAME ;
  824.     msg.len = sizeof(msg) ;
  825.     msg.id = Me->id ;
  826.     msg.sequence = ++sequence_number ;
  827.     msg.new_id = newid ;
  828.  
  829.     net_start_message( NULL ) ;
  830.     add_message(&msg, sizeof(msg) ) ;
  831.  
  832.     rename(&msg) ;
  833. }
  834.  
  835.  
  836.  
  837.  
  838.  
  839.  
  840.  
  841.  
  842.  
  843. /*
  844.  * INPUT MESSAGE HANDLING:
  845.  *
  846.  * add_new_player(...)        - handle NET_JOINING
  847.  *
  848.  * welcome(hdr)            - handle NET_WELCOME message
  849.  *
  850.  * reassure_master(header)    - handle NET_ARE_YOU_THERE
  851.  *
  852.  * player_scored(header)    - handle NET_JUST_SCORED
  853.  *
  854.  * new_status(header)        - accept new status
  855.  *
  856.  * new_missile(header)        - handle NET_REQUEST_MISSILE
  857.  *
  858.  * remove_player(header)    - handle NET_DIED
  859.  *
  860.  */
  861.  
  862.  
  863.  
  864.  
  865.  
  866.  
  867.  
  868.  
  869.  
  870. static
  871. welcome(header)
  872. register Net_welcome    *header ;
  873. {
  874. register Object        *object = &objects[0] ;
  875.     int        i ;
  876.  
  877.     for(i = MAX_PLAYERS; i--; )
  878.     {
  879.       if( object->class != OBJ_EMPTY  &&  object != Me )
  880.       {
  881.         special_remove_player(object) ;
  882.         object->class = OBJ_EMPTY ;
  883.       }
  884.       ++object ;
  885.     }
  886.  
  887.  
  888.  
  889.     object = &objects[header->player_id] ;
  890.  
  891.     if(Me != object)
  892.     {
  893.       *object = *Me ;
  894.       Me->class = OBJ_EMPTY ;
  895.       Me = object ;
  896.     }
  897.  
  898.     Me->id = header->player_id ;
  899.     Me->team = header->team ;
  900.     Me->target = NULL ;
  901.     game_type = header->game_type ;
  902.  
  903.     special_welcome() ;
  904.  
  905. #ifdef    DEBUG
  906.     if(status_display)
  907.       status_update() ;
  908.     if(debug_level >= 1)
  909.       fprintf(iolog, "welcome: from %2d: %s\n", header->id,
  910.         objects[header->id].name ) ;
  911. #endif    DEBUG
  912.  
  913.     printf("my id = %d\n",Me->id) ;
  914. }
  915.  
  916.  
  917.  
  918.  
  919.  
  920. static
  921. reassure_master(header)
  922.     Net_are_you_there    *header ;
  923. {
  924.     int    i ;
  925.  
  926. #ifdef    DEBUG
  927.     printf("got a timeout message from %2d: %s\n",
  928.       header->id, objects[header->id].name) ;
  929. #endif    DEBUG
  930.     net_start_message( &objects[header->id] ) ;
  931.     send_status(Me) ;
  932.     for(i=0; i<MAX_MISSILES; ++i)
  933.       if(missiles[i] != NULL)
  934.         send_status(missiles[i]) ;
  935.     net_flush() ;
  936. }
  937.  
  938.  
  939.  
  940.  
  941.  
  942. static
  943. player_scored(header)
  944.     Net_just_scored    *header ;
  945. {
  946. register Object        *object = &objects[header->weapon_id] ;
  947. register Object        *victim = &objects[header->his_id] ;
  948. register Object        *killer = &objects[header->id] ;
  949.  
  950.     if( object->status != OBJ_ACTIVE )
  951.       return ;
  952.  
  953.     if(victim == Me)
  954.       printf("just got blown away by %s",killer->name) ;
  955.     else if(killer == Me)
  956.       printf("just blew away %s",victim->name) ;
  957.     else
  958.       printf("%s just got blown away by %s", victim->name, killer->name);
  959.  
  960.     if( object->class == OBJ_MISSILE )
  961.       printf(" with a missile\n") ;
  962.     else
  963.       putchar('\n') ;
  964.  
  965.     if(victim->f_vector[F_KILLED] != NULL)
  966.       (*victim->f_vector[F_KILLED])(object,victim,killer) ;
  967.  
  968.     if(killer->f_vector[F_SCORED] != NULL)
  969.       (*killer->f_vector[F_SCORED])(object,victim,killer) ;
  970.  
  971. #ifdef    DEBUG
  972.     if(status_display)
  973.       status_update() ;
  974. #endif    DEBUG
  975. }
  976.  
  977.  
  978.  
  979.  
  980. static
  981. accept_new_status(header)
  982. register Net_current_status    *header ;
  983. {
  984. register Object        *object = &objects[header->obj_id] ;
  985. extern    fptr        fighter_vector[VECTOR_LENGTH],
  986.             missile_vector[VECTOR_LENGTH],
  987.             static_vector[VECTOR_LENGTH] ;
  988.  
  989.  
  990.     if(header->obj_id == Me->id)
  991.       fprintf(iolog,
  992.         "got a message about me from %s\n",objects[header->id].name) ;
  993.  
  994.  
  995.     else if( Me->net_status == MASTER  &&
  996.          ( object->class == OBJ_EMPTY ||
  997.            object->address.sin_addr.s_addr !=
  998.             header->address.sin_addr.s_addr ) )
  999.     {
  1000.       /* someone has put themselves into the game without
  1001.          sending a NET_JOINING MESSAGE.  They probably timed
  1002.          out and didn't know they were killed.  Send them
  1003.          a new NET_WELCOME message to re-sync them.  */
  1004.  
  1005. #ifdef    DEBUG
  1006.       fprintf(iolog, "re-syncing %2d: %s\n",header->id, header->name) ;
  1007.       if(debug_level >= 1)
  1008.         if( object->class == OBJ_EMPTY )
  1009.           fprintf(iolog, "because slot is empty\n") ;
  1010.         else
  1011.           fprintf(iolog,
  1012. "because message came from %s@%8.8lx, should have been %s@%8.8lx\n",
  1013.         header->name, header->address.sin_addr.s_addr,
  1014.         object->name, object->address.sin_addr.s_addr) ;
  1015. #endif    DEBUG
  1016.       add_new_player((object->class == OBJ_EMPTY) ? header->id : -1,
  1017.              header->name,
  1018.              &header->address,
  1019.              header->sequence,
  1020.              header->class ) ;
  1021. #ifdef    DEBUG
  1022.       if(debug_level >= 1)
  1023.         dump_lists() ;
  1024. #endif    DEBUG
  1025.     }
  1026.  
  1027.  
  1028.  
  1029.     else
  1030.     {
  1031.       if(object->class == OBJ_EMPTY)
  1032.       {
  1033.         object->id = header->obj_id ;
  1034.         bcopy(header->name, object->name, NAMELEN) ;
  1035.         object->team = header->team ;
  1036.         object->class = header->class ;
  1037.         object->status = header->status ;
  1038.         object->address = header->address ;
  1039.         object->net_addr = header->net_addr ;
  1040.         switch(header->class)
  1041.         {
  1042.           case OBJ_PLAYER:
  1043.         printf("new player: %d, %s\n",header->obj_id,header->name) ;
  1044.         bcopy(fighter_vector,object->f_vector,sizeof(fighter_vector)) ;
  1045.         break ;
  1046.           case OBJ_MISSILE:
  1047.         bcopy(missile_vector,object->f_vector,sizeof(missile_vector)) ;
  1048.         break ;
  1049.           case OBJ_STATIC:
  1050.         printf("new object: %d, %s\n",header->obj_id,header->name) ;
  1051.         bcopy(static_vector,object->f_vector,sizeof(static_vector)) ;
  1052.         break ;
  1053.         }
  1054.  
  1055.         if( object->class == OBJ_PLAYER )
  1056.           need_rehash = 1 ;
  1057.         special_add_player(object) ;
  1058. #ifdef    DEBUG
  1059.         if(debug_level >= 1)
  1060.           dump_lists() ;
  1061. #endif    DEBUG
  1062.       }
  1063.  
  1064.       (*object->f_vector[F_NEWSTAT])(object, header) ;
  1065.     }
  1066. }
  1067.  
  1068.  
  1069.  
  1070.  
  1071.  
  1072.  
  1073.  
  1074.  
  1075. new_status(object, header)
  1076. register Object            *object ;
  1077. register Net_current_status    *header ;
  1078. {
  1079.     bcopy(header->name, object->name, NAMELEN) ;
  1080.     object->score = header->score ;
  1081.     object->status = header->status ;
  1082.     object->flags = header->flags ;
  1083.     object->Posn = header->Posn ;
  1084.     object->Forward = header->Forward ;
  1085.     object->Up = header->Up ;
  1086.     object->Right = header->Right ;
  1087.     object->Delta = header->Delta ;
  1088.     object->Pointing = header->Pointing ;
  1089.     object->Speed = header->Speed ;
  1090.     object->target =
  1091.           (header->target != -1) ? &objects[header->target] : NULL ;
  1092.     object->description = header->description ;
  1093.     object->last_rep = Now ;
  1094.     special_new_status(object) ;
  1095. }
  1096.  
  1097.  
  1098.  
  1099.  
  1100.  
  1101.  
  1102.  
  1103.  
  1104. static
  1105. remove_player(header)
  1106.     Net_died    *header ;
  1107. {
  1108. register Object        *object = &objects[header->his_id] ;
  1109. register Object        *tmp ;
  1110.     int        done ;
  1111.     int        new_master ;
  1112.  
  1113.     if(header->his_id == Me->id  &&  header->id != Me->id)
  1114.     {
  1115.       printf("Hey! %s just pronounced me dead\n",objects[header->id].name) ;
  1116.       join_game() ;
  1117.       return ;
  1118.     }
  1119.  
  1120.     if(object->class == OBJ_EMPTY)
  1121.       return ;
  1122.  
  1123.  
  1124.  
  1125.     if(header->id == header->his_id)
  1126.       printf("%s leaving game\n",object->name) ;
  1127.     else if (objects[header->his_id].class != OBJ_MISSILE)
  1128.       printf("%s removed by %s\n",object->name,objects[header->id].name) ;
  1129.  
  1130.     special_remove_player(object) ;
  1131.  
  1132.     object->class = OBJ_EMPTY ;
  1133.  
  1134.     need_rehash = 1 ;
  1135.  
  1136. #ifdef    DEBUG
  1137.         if(debug_level >= 1)
  1138.           dump_lists() ;
  1139. #endif    DEBUG
  1140.  
  1141.     if( header->his_id == master_id  &&  poll_master )
  1142.       take_over() ;
  1143.  
  1144. #ifdef    DEBUG
  1145.     if(status_display)
  1146.       status_update() ;
  1147. #endif    DEBUG
  1148. }
  1149.  
  1150.  
  1151.  
  1152. static
  1153. rename(header)
  1154.     Net_rename    *header ;
  1155. {
  1156. register Object        *oldobj = &objects[header->id] ;
  1157. register Object        *newobj = &objects[header->new_id] ;
  1158.  
  1159. #ifdef    DEBUG
  1160.     if(debug_level >= 1)
  1161.       fprintf(iolog,
  1162.         (newobj->class != OBJ_EMPTY) ?
  1163.           "error: %d: %s taking over non-empty slot %d\n" :
  1164.           "%d: %s taking over slot %d\n",
  1165.         header->id, oldobj->name, header->new_id) ;
  1166. #endif    DEBUG
  1167.  
  1168.     *newobj = *oldobj ;
  1169.     newobj->id = header->new_id ;
  1170.  
  1171.     oldobj->class = OBJ_EMPTY ;
  1172.  
  1173.     need_rehash = 1 ;
  1174. }
  1175.  
  1176.  
  1177.  
  1178. static    Notify_value
  1179. handle_message(me, fd)
  1180.     int    *me ;
  1181.     int    fd ;
  1182. {
  1183.     struct sockaddr_in    from ;
  1184.     int            fromlen, msglen ;
  1185.     int            iret ;
  1186.     char            buf[MESSAGE_LENGTH] ;
  1187.     int            done = 0 ;
  1188. register char            *ptr ;
  1189. register Net_null        *header ;
  1190. extern    fptr            fighter_vector[VECTOR_LENGTH] ;
  1191.  
  1192. #ifdef    DEBUG
  1193.     if(me != &Socket)
  1194.     {
  1195.       fprintf(iolog,"? wrong value for handle in handle_message") ;
  1196.       return(NOTIFY_IGNORED) ;
  1197.     }
  1198.  
  1199.     if(fd != Socket)
  1200.     {
  1201.       fprintf(iolog,"? wrong value for fd in handle_message") ;
  1202.       return(NOTIFY_IGNORED) ;
  1203.     }
  1204. #endif    DEBUG
  1205.  
  1206.  
  1207.     while(!done)
  1208.     {
  1209.       fromlen = sizeof(from) ;
  1210.       msglen = recvfrom(Socket, buf, sizeof(buf), 0, &from, &fromlen) ;
  1211.       if(msglen<0)
  1212.       {
  1213.         done = 1 ;
  1214.         if(errno != EWOULDBLOCK)
  1215.           perror("dstar: recvfrom") ;
  1216.       }
  1217.       else
  1218.       {
  1219.         ptr = &buf[0] ;
  1220.         while(msglen > 0)
  1221.         {
  1222.           header = (Net_null *) ptr ;
  1223.  
  1224.           if(msglen < sizeof(Net_null)  ||  msglen < header->len)
  1225.           {
  1226.         fprintf(iolog,
  1227.           "incomplete record in message, msglen=%d, len=%d\n",
  1228.           msglen, header->len) ;
  1229.         if(msglen < sizeof(Net_null))
  1230.           msglen = 0 ;
  1231.           }
  1232.           else if( header->id != Me->id  ||
  1233.                from.sin_addr.s_addr != Me->address.sin_addr.s_addr)
  1234.           {
  1235.         if(header->id >= 0)
  1236.         {
  1237.           objects[header->id].sequence = header->sequence ;
  1238.           objects[header->id].last_rep = Now ;
  1239.         }
  1240.  
  1241.         switch(header->type)
  1242.         {
  1243.           default:
  1244.             printf("got an unknown header type: %d\n",
  1245.               (int) header->type) ;
  1246.             break ;
  1247.  
  1248.           case NET_NULL:
  1249.             puts("null") ;
  1250.             break ;
  1251.  
  1252.           case NET_JOINING:
  1253.             if(Me->net_status == UNKNOWN)
  1254.               become_master() ;
  1255.  
  1256.             if(Me->net_status == SUBMASTER)
  1257.             {
  1258.               net_start_message(&objects[master_id]) ;
  1259.               add_message(header, header->len) ;
  1260.             }
  1261.             else if(Me->net_status == MASTER)
  1262.               add_new_player( -1,
  1263.                       ((Net_joining *)header)->name,
  1264.                       &((Net_joining *)header)->address,
  1265.                       ((Net_joining *)header)->sequence,
  1266.                       ((Net_joining *)header)->class ) ;
  1267.             break ;
  1268.  
  1269.           case NET_WELCOME:
  1270.             if(Me->net_status == UNKNOWN)
  1271.               Me->net_status = SLAVE ;
  1272.             welcome(header) ;
  1273.             break ;
  1274.  
  1275.           case NET_ARE_YOU_THERE:
  1276.             reassure_master(header) ;
  1277.             break ;
  1278.  
  1279.           case NET_JUST_SCORED:
  1280.             if(Me->net_status != UNKNOWN)
  1281.               player_scored(header) ;
  1282.             break ;
  1283.  
  1284.           case NET_NEW_SCORES:
  1285.             puts("new scores") ;
  1286.             break ;
  1287.  
  1288.           case NET_CURRENT_STATUS:
  1289.             if(Me->net_status != UNKNOWN)
  1290.               accept_new_status(header) ;
  1291.             break ;
  1292.  
  1293.           case NET_REQUEST_MISSILE:
  1294.             if(Me->net_status != MASTER)
  1295.               puts("?request missile") ;
  1296.             else
  1297.               new_missile(header) ;
  1298.             break ;
  1299.  
  1300.           case NET_MISSILE:
  1301.             if(Me->net_status != UNKNOWN)
  1302.               missile_armed(((Net_missile *)header)->missile_id) ;
  1303. #ifdef    DEBUG
  1304.             if(status_display)
  1305.               status_update() ;
  1306. #endif    DEBUG
  1307.             break ;
  1308.  
  1309.           case NET_DIED:
  1310.             if(Me->net_status == UNKNOWN)
  1311.               join_game() ;
  1312.             else
  1313.               remove_player(header) ;
  1314.             break ;
  1315.  
  1316.           case NET_RENAME:
  1317.             rename(header) ;
  1318.             break ;
  1319.  
  1320.           case NET_BROADCAST:
  1321.             rebroadcast(header) ;
  1322.             break ;
  1323.         }
  1324.           }
  1325.  
  1326.           ptr += header->len ;
  1327.           msglen -= header->len ;
  1328.         }
  1329.       }
  1330.     }
  1331.  
  1332.     if( Me->id != -1 )
  1333.       net_flush() ;
  1334.  
  1335.     return(NOTIFY_DONE) ;
  1336. }
  1337.  
  1338.  
  1339.  
  1340.  
  1341.  
  1342.  
  1343. static int
  1344. getbroad(fd, n, addrs)
  1345.     int            fd, n ;
  1346.     struct sockaddr_in    *addrs ;
  1347. {
  1348.     int        iret, i ;
  1349.     struct ifconf    ifc ;
  1350.     u_char        buffer[1024] ;
  1351.     struct sockaddr_in    *sin ;
  1352.     int        num_freq ;
  1353.     int        nret = 0 ;
  1354.  
  1355.  
  1356.  
  1357.     /*
  1358.      * get list of interfaces
  1359.      */
  1360.  
  1361.     ifc.ifc_len = sizeof(buffer) ;
  1362.     ifc.ifc_buf = (caddr_t) buffer ;
  1363.  
  1364.     if( ioctl(fd, SIOCGIFCONF, &ifc) < 0)
  1365.       return -1 ;
  1366.  
  1367.     
  1368.     /*
  1369.      * for each interface...
  1370.      */
  1371.  
  1372.     num_freq = ifc.ifc_len/sizeof(struct ifreq) ;
  1373.  
  1374.     for(i=0; i<num_freq; ++i)
  1375.     {
  1376.       /*
  1377.        * copy the interface structure to a work area
  1378.        */
  1379.       sin = (struct sockaddr_in *) &ifc.ifc_req[i].ifr_addr ;
  1380.  
  1381.       if( ifc.ifc_req[i].ifr_addr.sa_family == AF_INET )
  1382.       {
  1383.         /*
  1384.          * get the flags
  1385.          */
  1386.         if( ioctl(fd, SIOCGIFFLAGS, &ifc.ifc_req[i]) >= 0)
  1387.         {
  1388.           /*
  1389.            * if it's an interface that supports broadcast...
  1390.            */
  1391.           if( (ifc.ifc_req[i].ifr_flags & IFF_BROADCAST)  &&
  1392.           (ifc.ifc_req[i].ifr_flags & IFF_UP) )
  1393.           {
  1394.         /*
  1395.          * get the broadcast address
  1396.          */
  1397.         if( ioctl(fd, SIOCGIFBRDADDR, &ifc.ifc_req[i]) >= 0)
  1398.         {
  1399.           ++nret ;
  1400.           *addrs++ = *sin ;
  1401.         }
  1402.           }
  1403.         }
  1404.       }
  1405.     }
  1406.     return nret ;
  1407. }
  1408.  
  1409.  
  1410.  
  1411.  
  1412. #ifdef    DEBUG
  1413.  
  1414. status_update()
  1415. {
  1416. register int    i ;
  1417. register Object    *object = &objects[0] ;
  1418. static    char    *classes[] = {"empty","static","player","missile"} ;
  1419. static    char    *states[] = {"active","sleeping","dead"} ;
  1420.  
  1421.     printf("\033[3;1H \n\n\n") ;
  1422.     for(i = 0; i<MAX_PLAYERS; ++i)
  1423.     {
  1424.       int i2 = i ;  Object *obj2 = object ;
  1425.       if(object->class != OBJ_EMPTY)
  1426.         printf("   %2d: %-20.20s %-7.7s %-8.8s %-20.20s %4d\033[K\n",
  1427.           i, object->name, classes[(int) object->class],
  1428.           states[(int) object->status],
  1429.           object->target != NULL ? object->target->name : "",
  1430.           Now.tv_sec - object->last_rep.tv_sec ) ;
  1431.       else
  1432.         printf("\033[K\n") ;
  1433.       ++object ;
  1434.     }
  1435.     printf("\n\n\n") ;
  1436. }
  1437.  
  1438.  
  1439. #endif    DEBUG
  1440.