// Filename: bbsipc.C // Contents: the bbs IPC object // Author: Greg Shaw // Created: 6/13/93 /* This file is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. In addition to the permissions in the GNU General Public License, the Free Software Foundation gives you unlimited permission to link the compiled version of this file with other programs, and to distribute those programs without any restriction coming from the use of this file. (The General Public License restrictions do apply in other respects; for example, they cover modification of the file, and distribution when not linked into another program.) This file is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING. If not, write to the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ #ifndef _BBSIPC_C_ #define _BBSIPC_C_ #undef DEBUG #include "bbshdr.h" // include *EVERYTHING* // Function: bbsipc constructor // Purpose: initialize the bbs ipc object. // Inputs: none // Outputs: none - constructor may not return values // Author: Greg Shaw // Created: 6/13/93 bbsipc::bbsipc() { server = 0; // server mode hostname[0] = 0; // host name sock_open = 0; // open socket sock_fd = 0; // socket file descriptor serv_sock_fd = 0; // server socket file descriptor sockt = 0; // socket number connected = 0; // not connected } // Function: bbsipc destructor // Purpose: clean up the bbsipc object (close socket) // Inputs: none // Outputs: none // Author: Greg Shaw // Created: 6/16/93 bbsipc::~bbsipc() { close_sock(0); }; // Function: close_sock // Purpose: close the sockets (if open) // Inputs: none // Outputs: none // Author: Greg Shaw // Created: 6/16/93 int bbsipc::close_sock(int client_only) { if (sock_open) close(sock_fd); if (!client_only) { if (server) close(serv_sock_fd); server = 0; sock_open = 0; } connected = 0; return(0); }; // Function: open_sock // Purpose: open a socket for reading, writing or as a server. // Inputs: name - name of host to contact (NULL for server mode) // socknum - the socket number to contact // Outputs: -1 for error // Author: Greg Shaw // Created: 6/16/93 int bbsipc::open_sock(char *name, int socknum) { char macname[MAXHOSTNAMELEN+1]; // system information struct sockaddr_in sa; // socket information struct hostent *hp; // host entry information sockt = socknum; // save socket number if (name == NULL) // server mode? { #ifdef DEBUG fprintf(stderr,"creating server socket.\r\n"); #endif // yup, create socket server = 1; memset(&sa, 0, sizeof(struct sockaddr_in)); // nuke sa contents gethostname(macname,MAXHOSTNAMELEN); // get this host's name hp = gethostbyname(macname); // get host info if (hp == NULL) // no info for me? { fprintf(stderr,"Unable to get host name.\n"); return(-1); // get out } sa.sin_family = hp->h_addrtype; // set host address sa.sin_port= htons(socknum); // set port number // create new socket if ((serv_sock_fd = socket(AF_INET, SOCK_STREAM,0)) < 0) { fprintf(stderr,"Unable to open socket.\n"); return(-1); // can't create socket } if (bind(serv_sock_fd,(struct sockaddr *)&sa,(int)sizeof(sa)) < 0) { close(serv_sock_fd); fprintf(stderr,"Unable to bind socket.\n"); return(-1); } listen(serv_sock_fd,5); // 5 pending connections max sock_open = 1; } else { // connect to socket #ifdef DEBUG printf("attempting to connect client socket.\r\n"); #endif strcpy(hostname, name); server = 0; if ((hp = gethostbyname(hostname)) == NULL) // get host addr { #ifdef DEBUG printf("Couldn't get hostname to connect to.\r\n"); #endif errno = ECONNREFUSED; // connection refused return(-1); } memset(&sa, 0, sizeof(struct sockaddr_in)); // nuke sa contents memcpy((char *)&sa.sin_addr, (char *)hp->h_addr, hp->h_length); sa.sin_family = hp->h_addrtype; sa.sin_port = htons((unsigned short)socknum); if ((sock_fd = socket(hp->h_addrtype, SOCK_STREAM,0)) < 0) return(-1); if (connect(sock_fd,(struct sockaddr *)&sa,sizeof(sa)) < 0) { #ifdef DEBUG printf("client connect failed.\r\n"); #endif close(sock_fd); return(-1); } #ifdef DEBUG printf("client connect successful.\r\n"); #endif connected = 1; sock_open = 1; } return(0); // exit normally }; // Function: connect // Purpose: connect to another process via server socket // Inputs: none // Outputs: returns true if socket connection successful // Author: Greg Shaw // Created: 6/18/93 int bbsipc::do_connect(void) { struct sockaddr_in isa; // socket address info int i_size; // socket address size i_size = sizeof(isa); getsockname(serv_sock_fd,(struct sockaddr *)&isa,&i_size); if ((sock_fd = accept(serv_sock_fd,(struct sockaddr *)&isa,&i_size)) < 0)// accept connection { #ifdef DEBUG printf("server: accept failed.\r\n"); #endif return(-1); } #ifdef DEBUG printf("server: accept succeeded.\r\n"); #endif connected = 1; return(0); }; // Function: send // Purpose: send a message via the socket // Inputs: msg - the message to send (null terminated string) // Outputs: non-zero for error // Author: Greg Shaw // Created: 6/16/93 int bbsipc::send(char *msg) { int cw; char eom = ETX; // send a message #ifdef DEBUG printf("send: Sending %s.\r\n",msg); #endif if (!sock_open && !connected) { #ifdef DEBUG printf("send: socket not open.\r\n"); #endif return(-1); } if (cw = write(sock_fd,msg,strlen(msg)), cw != strlen(msg)) { #ifdef DEBUG printf("Unable to write message!\r\n"); #endif return(-1); } if (cw = write(sock_fd,&eom,1), cw != 1) { #ifdef DEBUG printf("send: unable to send end of message.\r\n"); #endif return(-1); } #ifdef DEBUG printf("send: sent %s.\r\n",msg); #endif return(0); }; // Function: receive // Purpose: receive a message from the other end of the socket // Inputs: none // Outputs: msg - the message to be received. // Author: Greg Shaw // Created: 6/22/93 int bbsipc::receive(char *msg) { char c; // character read char eom; // end of message found? int count; // byte counter int byr; // number of bytes read #ifdef DEBUG printf("receive: start\r\n"); #endif count = 0; byr = 0; eom = 0; while (!eom) { // look for trailing null if ((byr = read(sock_fd,&c,(unsigned)1)), byr > 0) { #ifdef DEBUG printf("%x char read\r\n",c); #endif if (c == ETX) eom++; else msg[count++] = c; // add to msg } else if (byr == 0) // connection is closed for 0 chars read return(-1); } msg[count] = 0; /* add terminating null */ return(count); }; // Function: msg_avail // Purpose: poll the socket to determine whether a message is available // for reading. // Input: none // Output: non-zero for a message available // Author: Greg Shaw // Created: 6/22/93 int bbsipc::msg_avail(char wait) { // NOTE: below may be a problem. In a server, it should not be // possible for a particular connection to tie up the server. If the // below is left as is (wait forever for message), it could happen that // the calling process might die before sending the message, hence a // forever wait for a message that will never come. This would cause a // lockup of the server (and that would be a Bad Thing. fd_set pfd; // file descriptor set FD_ZERO(&pfd); FD_SET(sock_fd,&pfd); struct timeval waittime; waittime.tv_sec = 0; waittime.tv_usec = 100; // 100msec if (!wait) // wait? { select(FD_SETSIZE,&pfd,NULL,NULL,&waittime); return(FD_ISSET(sock_fd,&pfd)); // don't wait, return immed. } else { select(FD_SETSIZE,&pfd,NULL,NULL,NULL); // wait forever return(FD_ISSET(sock_fd,&pfd)); } }; // Function: two_connect // Purpose: connect to a server master socket, get socket from server, // disconnect and connect to new socket number. // (a two level socket connect) // Inputs: none // Outputs: ipc object will connect if possible // Notes: this is a client version only. The server version will be // much much more complex. // Author: Greg Shaw // Created: 7/23/93 int bbsipc::two_connect(char *name, int socknum) { char tmpstr[50]; // attempt to connect to server to get socket number if (open_sock(name,socknum) == 0) { // gotcha! if (msg_avail(1) < 0) // wait for message return(-1); // now get new socket number receive(tmpstr); // get socket # if (sscanf(tmpstr,"%d",&sockt) != 1) return(-1); else close_sock(0); // close current socket if (open_sock(name,sockt) == 0) { // got new socket return(0); } } return(-1); }; #endif // _BBSIPC_C_