// tcp.cc include <net/cs/tcp/dataconn.h> include <net/cs/tcp/listenconn.h> include <net/cs/tcp/client.h> include <net/cs/tcp/clientimp.h> include <net/cs/tcp/server.h> include <net/cs/tcp/serverimp.h> include <net/cs/dataconn.h> include <net/cs/listenconn.h> include <net/cs/csaddress.h> include <net/cs/inetaddr.h> include <net/cs/cs.h> include <net/cs/samlib.h> include <errno.h> include <unistd.h> include <string.h> include <sys/types.h> include <sys/socket.h> include <netinet/in.h> include <arpa/inet.h> include <netdb.h> include <stdio.h> include <signal.h> include <fcntl.h> include <sys/fcntl.h> include <stdlib.h> // IMPLEMENTATION NOTE: man socket states that SIGPIPE will be raised if a // process writes to a broken pipe (when the other side // has hung up). So for robustness, this signal has to // be handled. //---------------------------- tcpsocket implementation ------------------- int tcpsocket::_got_sigpipe = 0; int tcpsocket::_handler_installed = 0; void (*tcpsocket::_old_sigpipe_handler)(int) = NULL; void tcpsocket::sigpipe_handler(int signr) { if (cs_trace) printf("tcpsocket::sigpipe_handle begin\n"); signal(SIGPIPE, sigpipe_handler); _got_sigpipe = 1; if ((_old_sigpipe_handler != SIG_IGN) && (_old_sigpipe_handler != SIG_DFL)) (*_old_sigpipe_handler)(signr); if (cs_trace) printf("tcpsocket::sigpipe_handler(%d) end\n", signr); } tcpsocket::tcpsocket() { if (!_handler_installed) { _old_sigpipe_handler = signal(SIGPIPE, sigpipe_handler); _handler_installed = 1; if (cs_trace > 5) printf("tcpsocket::tcpsocket : SIGPIPE handler installed\n"); } _portnr = -1; _name.sin_family = 0; _name.sin_port = 0; _name.sin_addr.s_addr = 0; _sd = -1; } int tcpsocket::portnr() const { struct sockaddr addr; int addrlen; // hack for keeping this function 'const' tcpsocket* sptr = (tcpsocket*) this; if (_portnr != -1) return _portnr; // portnumber already known addrlen = sizeof(addr); if (getsockname(_sd, &addr, &addrlen) < 0) { warn("tcp_listenconn::portnr : getsockname failed (%s)", strerror(errno)); return -1; } struct sockaddr_in* ptr = (struct sockaddr_in*) &addr; sptr -> _portnr = ntohs(ptr -> sin_port); return sptr -> _portnr; } void tcpsocket::close() { ::close(_sd); _sd = -1; } //--------------------------- tcp_dataconn implementation -------------------- tcp_dataconn::tcp_dataconn(const csaddress* addr) :tcpsocket(), data_connection(addr) { if (addr == NULL) { warn("tcp_dataconn::tcp_dataconn : addr = NULL"); return; } // make socket connection struct hostent* hp; inet_address* a = (inet_address*) addr; char* hname = (char*) a -> hostname(); if ((_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { warn("tcp_dataconn::tcp_dataconn : couldn't create socket (%s)", strerror(errno)); return; } _name.sin_family = AF_INET; _name.sin_port = htons(a -> portnr()); if ((hname == NULL) || (strlen(hname) == 0)) { warn("tcp_dataconn::tcp_dataconn : hostname = NULL or \"\""); ::close(_fd); return; } else { hp = gethostbyname(hname); if (hp == NULL) hp = gethostbyaddr(hname, strlen(hname), AF_INET); if (hp == NULL) { warn("tcp_dataconn::tcp_dataconn : unknown host %s", hname); ::close(_fd); return; } memcpy(&_name.sin_addr.s_addr, hp -> h_addr, hp -> h_length); } if (connect(_fd, (struct sockaddr*) &_name, sizeof(_name)) < 0) { warn("tcp_dataconn::tcp_dataconn : couldn't connect (%s)", strerror(errno)); ::close(_fd); return; } // set socketdescriptor _sd = _fd; _connected = 1; } tcp_dataconn::tcp_dataconn(int fd) :tcpsocket(), data_connection() { _fd = fd; _sd = fd; // since this constructor will be called by the receiving side of a // connection, the connection is already a fact _connected = 1; } tcp_dataconn::~tcp_dataconn() { close(); } int tcp_dataconn::readmsg(char* buf, int nrbytes) { int retval; if (_fd < 0) { warn("tcp_dataconn::readmsg : no valid filedescriptor %d", _fd); return -1; } if (!_connected) { warn("tcp_dataconn::readmsg : connection is closed"); return -1; } retval = read_package(_fd, buf, nrbytes); if (retval <= 0) _connected = 0; return retval; } int tcp_dataconn::writemsg(const char* buf, int nrbytes) { int retval; if (_fd < 0) { warn("tcp_dataconn::writemsg : no valid filedescriptor %d", _fd); return -1; } if (!_connected) { warn("tcp_dataconn::writemsg : connection is closed"); return -1; } retval = write_package(_fd, buf, nrbytes); if (retval <= 0) _connected = 0; if (_got_sigpipe) { _connected = 0; _got_sigpipe = 0; } return retval; } //------------------------ tcp_listenconn implementation -------------------- tcp_listenconn::tcp_listenconn(const csaddress* addr) :tcpsocket(), listen_connection(addr) { // make socket connection struct hostent* hp; inet_address* a = (inet_address*) _address; // this should be tested!!! char* hname = NULL; if ((_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { warn("tcp_listenconn::tcp_listenconn : couldn't create socket (%s)", strerror(errno)); return; } _name.sin_family = AF_INET; if (a != NULL) { //hname = (char*) a -> hostname(); // only portnr of listenconn // can be set hname = NULL; _name.sin_port = htons(a -> portnr()); } else { hname = NULL; _name.sin_port = 0; } if (hname == NULL) _name.sin_addr.s_addr = INADDR_ANY; else { hp = gethostbyname(hname); if (hp == NULL) hp = gethostbyaddr(hname, strlen(hname), AF_INET); if (hp == NULL) { warn("tcp_listenconn::tcp_listenconn : unknown host %s", hname); ::close(_fd); return; } memcpy(&_name.sin_addr.s_addr, hp -> h_addr, hp -> h_length); } if (bind(_fd, (struct sockaddr*) &_name, sizeof(_name)) < 0) { warn("tcp_listenconn::tcp_listenconn : couldn't bind socket (%s)", strerror(errno)); ::close(_fd); return; } if (listen(_fd, 5) < 0) { warn("tcp_listenconn::tcp_listenconn : listen failed (%s)", strerror(errno)); ::close(_fd); return; } // set socketdescriptor _sd = _fd; _connected = 1; // we're on the air now } tcp_listenconn::~tcp_listenconn() { close(); } data_connection* tcp_listenconn::waitconnect() { int new_sd; data_connection* new_conn; if ((new_sd = accept(_fd, 0, 0)) < 0) return NULL; if (!(new_conn = new tcp_dataconn(new_sd))) { warn("tcp_listenconn::waitconnect : couldn't create new " "data_connection"); return NULL; } return new_conn; } //------------------------ tcp_client implementation --------------------- tcp_client::tcp_client() :csclient(_tcpimp = new tcp_clientimp()) { _inetaddr = NULL; } tcp_client::tcp_client(const char* hostname, int portnr) :csclient(_tcpimp = new tcp_clientimp(), _inetaddr = new inet_address(hostname, portnr)) { } tcp_client::~tcp_client() { if (_inetaddr != NULL) delete _inetaddr; delete _tcpimp; } int tcp_client::connect(const char* hostname, int portnr) { if (_inetaddr) delete _inetaddr; _inetaddr = new inet_address(hostname, portnr); write_to_log("tcp_client::connect with %s at port %d", hostname, portnr); return csclient::connect(_inetaddr); } //------------------------ tcp_server implementation --------------------- tcp_server::tcp_server() :csserver(_tcpimp = new tcp_serverimp()) { _tcpaddr = NULL; } tcp_server::tcp_server(int portnr) :csserver(_tcpimp = new tcp_serverimp(), _tcpaddr = new inet_address("", portnr)) { } tcp_server::~tcp_server() { delete _tcpimp; if (_tcpaddr != NULL) delete _tcpaddr; } int tcp_server::portnr() const { tcp_listenconn* tlc = (tcp_listenconn*) listenconn(); if (tlc != NULL) return tlc -> portnr(); else return -1; } //--------------------- tcp_clientimp implementation ----------------------- tcp_clientimp::tcp_clientimp() { } data_connection* tcp_clientimp::createdata(const csaddress* addr) const { return new tcp_dataconn(addr); } //------------------------- tcp_serverimp ------------------------------ tcp_serverimp::tcp_serverimp() { } listen_connection* tcp_serverimp::createlisten(const csaddress* addr) const { return new tcp_listenconn(addr); }
Hush Online Technology
hush@cs.vu.nl
09/09/98 |
![]() |
![]() |