Server Sockets in C++ with SysV IPC?

Server Sockets in C++ with SysV IPC?

Post by Freeman Lowe » Sat, 23 Jul 1994 02:55:38



This is a strange problem. I wrote this class for G++ to handle some of
the more annoying maintainence for socket connections. When I create the
ip_serv object as an automatic variable in main(), and then telnet to the
port I start() the server on, saccept() bombs out with EBADF: bad file
descriptor. When I creat the ip_serv object in a shared memory area (using
SysV IPC), it works just fine. Any ideas?

------------------------------------------------------------------------------

// connections.h: IP socket connections class in C++
// Phil Nadeau 7/13/94 v.10
// This class is simplified to the most common type of interprocess connection:
// IP socket, accepts connections from any hardware interface, mostly text.

#include <strings.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

#if !defined TRUE
#define TRUE 1
#endif

#if !defined FALSE
#define FALSE 0
#endif

#if !defined READ
#define READ 0
#endif

#if !defined WRITE
#define WRITE 1
#endif

#if !defined FD_IO_SIZE
#define FD_IO_SIZE 250
#endif

#if !defined DEFAULT_PROTOCOL
#define DEFAULT_PROTOCOL 0
#endif

class fd_io {
public:
  int connFD; //client's connection descriptor number on server
  char mbuff[FD_IO_SIZE]; //temporary buffer. Fragments are placed here
    //until lcheck encounters a newline character, then they are copied out.
  //
  fd_io();           //constructor. Simply closes FD.
  int lread(char*);  //doesn't return until a newline is read
    //Assumes spec'd buffer is large enough, returns # of bytes read
  int lcheck(char*); //returns TRUE if a full line is present, otherwise
    //returns FALSE. Only loads spec'd buffer if there is a line available.
  int lwrite(char*); //writes the spec'd buffer to the socket.

Quote:};

class ip_conn : public fd_io {
public:
  struct sockaddr_in address; //client's address in IP domain
  int addlen; //address length. Only here for paranoia re: accept
  //
  ip_conn();  //constructor. Closes old connection before init'ing

Quote:};

class ip_server {
  struct sockaddr_in address; // addresses in the IP domain
public:
  int connFD; // connections file descriptor
  ip_server(); //constructor: closes open connection (if any) and clears object
  int start(int); //closes open connection and makes a new one on port spec'd
  int saccept(ip_conn*);  //make this socket into a server on the port spec'd
    //returns TRUE on connect, FALSE on no pending connections, or -int on err
  int sclose();  //close this server

Quote:};

// connections.cc: IP socket connections class in C++
// Phil Nadeau 7/13/94 v.10
// This class is simplified to the most common type of interprocess connection:
// IP socket, accepts connections from any hardware interface, mostly text.

fd_io::fd_io() {
  close(connFD);
  strcpy(mbuff,"");

Quote:};

int fd_io::lread(char* obuff) {
  //Will read a message from the inbound stream and assemble
  //the data using the stuff already in mbuff. Won't return until a newline.
  int countr;
  char tmc[10];
  char *tmpnt;
  do {
    if (strlen(mbuff) > (FD_IO_SIZE - 10)) return (-1);
    countr = 0;
    if ((countr = read(connFD, tmc, 9)) <0) {
      if (EAGAIN != errno) return (errno);
    } else {
      tmc[countr] = '\0';
      strcat(mbuff, tmc);
    };
  } while (NULL == strchr(mbuff,'\n'));
  strcpy(obuff, mbuff);
  tmpnt = strchr(obuff,'\n');
  ++tmpnt;
  strcpy(mbuff, tmpnt);
  *tmpnt = '\0';
  return (strlen(obuff));

Quote:};

int fd_io::lcheck(char* obuff) {
  //Will read a message from the inbound stream. Will return 0 if no newline
  //is found, + # of characters if found, or - # on error
  int countr;
  char *tmpnt;
  char tmc[10];
  if (strlen(mbuff) > (FD_IO_SIZE - 10)) return (-1);
  countr = 0;
  if ((countr = read(connFD, tmc, 9)) <0) {
    if (EAGAIN != errno) return (errno);
  } else {
    tmc[countr] = '\0';
    strcat(mbuff, tmc);
  };
  if (NULL == strchr(mbuff,'\n')) {return (0);}
  else {
    strcpy(obuff, mbuff);
    tmpnt = strchr(obuff,'\n');
    ++tmpnt;
    strcpy(mbuff, tmpnt);
    *tmpnt = '\0';
    return (strlen(obuff));
  };

Quote:};

int fd_io::lwrite(char* obuff) {
  return (write(connFD, obuff, strlen(obuff)));
Quote:};

//-------------------------------------------------------------------------

ip_conn::ip_conn() : fd_io() {
  addlen = sizeof(address);
  bzero((char*) &address, addlen);

Quote:};

//-------------------------------------------------------------------------

ip_server::ip_server() {
  close(connFD);
  bzero((char*) &address, sizeof(address));

Quote:};

int ip_server::sclose() {
  return (close(connFD));

Quote:};

int ip_server::start(int portnum) {
  ip_server();
  if ((connFD = socket (AF_INET, SOCK_STREAM, DEFAULT_PROTOCOL))<0)
    { return (-1); };
  if ((fcntl(connFD, F_SETFL, O_NONBLOCK))<0) { return (-2); };
  address.sin_family = AF_INET;
  address.sin_addr.s_addr = htonl(INADDR_ANY);
  address.sin_port = htons(portnum);
  if (bind(connFD, (struct sockaddr*) &address, sizeof(address)) != 0)
    { return (-3); };
  if (listen(connFD, 5) != 0)
    { return (-4); };
  return (0);

Quote:};

int ip_server::saccept(ip_conn *newconn) {
  ip_conn nuke;
  (nuke.ip_conn());
  if ((nuke.connFD=accept(connFD,
       (struct sockaddr*) &(nuke.address) ,
       &(nuke.addlen)) )>0)
  {
    fcntl((nuke.connFD), F_SETFL, O_NONBLOCK);
    *newconn = nuke;
    return (TRUE);
  } else {
    switch (errno){
      case ENOTSOCK :
        return (-2); break;
      case EBADF :
        return (-1); break;
      case EWOULDBLOCK :
        return (FALSE);  break;
      default :
        return (-3);
    };
  };
Quote:};

 
 
 

1. Posix.1b IPC and SysV IPC

 I'm studying a book on UNIX programming and in the SysV IPC chapter
the book states that these interfaces will soon be obsoleted by
improved Posix interfaces to solve the same IPC problems. I tried
finding info on this and all I came up with was that Posix.1b now
incorporates these calls and that shared memory is implemented as
mmap() in Posix.1b. Are these the only changes? What about semaphores
and message queues? Do these "new" Posix calls use file descriptors or
are they still non-UNIX-oriented as the SysV calls?

        Thanks,
        Yoav

2. x86 gcc Binary install

3. Berkeley IPC & SysV IPC

4. maintenance worse than install :-(

5. Making Linux server sockets connect with Borland C++ builder Client Sockets?

6. Problems when removing SCSI-HDD

7. Does uemacs really work ins SysV.2?

8. telnet/ftp open delays

9. Server design using sockets & IPC

10. How to discover current SYSV IPC status under Solaris 5.3

11. SYSV IPC:function not implemented

12. SYSV/Posix IPC with fds.

13. SysV IPC question