Listing 3

/* CB Radio server */
/* 1996, Joe Novosel */


/* Net defs */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#define SERV_TCP_PORT 3507
/* end Net defs */

#include <stdio.h>
#include <sys/time.h>

#define QLEN 5
#define BUFSIZE 4096

/* This is the CB specific defines and data structures */

#define BUFSIZE 4096
#define HANDLE_MAX 20
#define MESSAGE_MAX 100
#define MAX_CLIENTS 10
#define MAX_CHANNELS 40

/* Commands */
#define CB_ON 1
#define CB_OFF 2
#define SET_CHAN 3
#define WHO_CHAN 4
#define WHO_ALL 5
#define SVR_STATS 6
#define SEND_MESSAGE 7
int i;

struct CB_Data_Packet {
  int channel;
  int command;
  char handle[HANDiLE_MAX];
  char message[MESSAGE_MAX];
};

/* This is the client's data structure.*/
/* I store the file descriptor and */
/* handle of each connected client in an array. */
/* This array is searched when a message*/
/* arrives to see who needs to get */
/* the message. */
struct client_data{
  int channel;
/* Channel 0 if no connection */

char handle[HANDLE_MAX];
};


/* array of structures for client data */
/* can't index as usual, must subtract 3*/
/*from fd to account for */
/* stdin, stdout, stderr, and msock */
struct client_data clients[MAX_CLIENTS];

struct CB_Data_Packet rcv_packet;

/*end of CB specific defines and data structures*/

void CBinit(void)
/* Taken out of the main part of code */
/* for clarity */
/* This just initializes the cb client array */
{  for (i=0;i<MAX_CLIENTS;i++)
       /*  Clear all client's channel data */
  clients[i].channel = 0;
}

int rdmsg (int s, char* p, int len)
/*read message from a socket s, of length len */
{
  int m,n;
  m = len;
  while (m>0)
    {
      n=read(s,p,m);
      m = m - n;
      p = p + n;
    }
  return n;
}

@cx:main()
{
  struct hostent *phe;
   /* pointer to host information entry*/
  struct sockaddr_in sin;
   /* an Internet endpoint address*/
  int alen;
       /*from-address length*/
  struct sockaddr_in fsin;
  int msock, ssock;
       /*master and slave socket*/
  int count,i,k,n,sum,avg,tmp =0;
  fd_set rfds;
  fd_set afds;
  int fd,nfds;

  CBinit;
/*Set up CB specific server code*/

  memset((char *)&rcv_packet,0,sizeof(rcv_packet));
  /* clear out rcv packet */
  memset((char *)&sin, 0, sizeof(sin));
  sin.sin_family = AF_INET;
   /* address family, inet */
  sin.sin_port =htons(SERV_TCP_PORT);

  /* Allocate a socket */
  msock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);

  if (msock < 0) {
    printf("can't create socket \n");
    exit(1);
  }

  /* Bind the socket */
  if (bind(msock, (struct sockaddr *)&sin, sizeof(sin)) < 0)
    {
      printf("can't bind to port.\n");
      exit(1);
    }
  if(listen(msock, QLEN) < 0){
    printf("can't listen on port. \n");
    exit(1);
  }

  nfds = getdtablesize();
  FD_ZERO(&afds);
  /* Clear out the active file descriptor set */
  FD_SET(msock,&afds);
  /* Add the master socket to the afds */

 /* main loop of program. Here, we listen,*/
 /* get a packet, process and return */
  while(1==1) {
    bcopy ((char *)&afds, (char *)&rfds,sizeof(rfds));

  /*  Look for a new connection */
    if (select(nfds, &rfds, (fd_set *)0, (fd_set *)0,(struct timeval
*)0) <0)
      {
   printf("select error\n");
   exit(1);
      }

/* If someone wants to connect through*/
/* the master socket,  */
/* Give them a new socket and add it to*/
/* the active file descriptor set */
    if (FD_ISSET(msock,&rfds)) {
      int ssock;
      alen = sizeof(fsin);
      ssock = accept(msock, (struct sockaddr *)&fsin, &alen);
      printf("new connection # %d\n",ssock);
      if (ssock<0)
   {
     printf("accept failed\n");
     exit(1);
   }
      FD_SET(ssock,&afds);
    }

/*Cycle through all open file descriptors*/
    for (fd=0; fd<nfds; ++fd)
      if (fd != msock && FD_ISSET(fd,&rfds))
   {
/* From here on down, this is the code*/
/* to change if you want your */
/* Server to do something else. */

/* Process command from client */
         (void)rdmsg (fd, (char *)
&rcv_packet,sizeof(rcv_packet));
     switch (ntohl(rcv_packet.command))  {
       /* CB_ON,  set the client's handle and */
            /* initial channel to 19. */
       /* Transmit a hello message to the client */

     case CB_ON:{
       clients[fd-4].channel=19;
       strncpy
(&clients[fd-4].handle,&rcv_packet.handle,HANDLE_MAX);
       strcpy(&rcv_packet.message,"Hello, welcome to the CB
simulator");
       write (fd,(char *) &rcv_packet,sizeof(rcv_packet));
     } break;

     case (CB_OFF):{
       (void) close(fd);
       FD_CLR(fd,&afds);
       clients[fd-4].channel = 0;
            /* show that nobody is connected here */
       printf("closing # %d \n",fd);}
     break;
       /* SET_CHAN, changes the client's current*/
            /* channel. message is ignored */

     case SET_CHAN:{
       clients[fd-4].channel =
ntohl(rcv_packet.channel);
       strcpy(&clients[fd-4].handle,&rcv_packet.handle);
     } break;
     /* WHO_CHAN, will create a message (or messages)*/
          /* with the handles of the  */
     /* other clients on the channel indicated*/
          /* in the data packet */

     case WHO_CHAN:{

       for(k=0;k&lt;MAX_CLIENTS;k++)
         if (clients[k].channel == ntohl(rcv_packet.channel))
      {
        strcat(&rcv_packet.message,&clients[k].handle);
        strcat(&rcv_packet.message,&" ");}

       strcpy(&rcv_packet.handle,&"System: WHO");
       write(fd,(char *) &rcv_packet,sizeof(rcv_packet));

     } break;
  /* WHO_ALL, will create a message (or messages)*/
  /* with the handles of all clients */
  /* currently connected to the server and*/
  /* the channel they are listening to */

     case WHO_ALL:{
       printf("Who all\n");
     } break;
  /* SVR_STATS, will send a message of the */
  /* current server stats */

     case SVR_STATS:{
     } break;
  /* SEND_MESSAGE, will send the message contained*/
  /* in the data packet to all */
  /* parties subscribed to the sending client's channel */

     case SEND_MESSAGE:{
       /* Cycle through the clients and see */
            /* who gets this message */
       /* If it's from channel 9, send it to everyone */
       for(i=0;i<MAX_CLIENTS;i++){

         if ((clients[i].channel ==
ntohl(rcv_packet.channel))||
        (ntohl(rcv_packet.channel)==9)){
      write(i+4,(char *)
&rcv_packet,sizeof(rcv_packet));}
       } break;
     }
     }
     }
/*end of main cb server code*/

  } /* end of myrcvr */
}