return to first page linux journal archive
keywordscontents

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<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 */
}