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++ #include <strings.h> #if !defined TRUE #if !defined FALSE #if !defined READ #if !defined WRITE #if !defined FD_IO_SIZE #if !defined DEFAULT_PROTOCOL class fd_io { fd_io::fd_io() { ip_conn::ip_conn() : fd_io() { ip_server::ip_server() {
// 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 <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>
#define TRUE 1
#endif
#define FALSE 0
#endif
#define READ 0
#endif
#define WRITE 1
#endif
#define FD_IO_SIZE 250
#endif
#define DEFAULT_PROTOCOL 0
#endif
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.
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
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
// 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.
close(connFD);
strcpy(mbuff,"");
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));
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));
};
int fd_io::lwrite(char* obuff) {
return (write(connFD, obuff, strlen(obuff)));
//-------------------------------------------------------------------------
addlen = sizeof(address);
bzero((char*) &address, addlen);
//-------------------------------------------------------------------------
close(connFD);
bzero((char*) &address, sizeof(address));
int ip_server::sclose() {
return (close(connFD));
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);
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);
};
};