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