/* * Copyright (c) 1996 Gunther Schadow. All rights reserved. * * This program 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 of the License, or * (at your option) any later version. * * This program 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; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #pragma implementation #include "StdSocket.h" #include #include #include #ifdef PROTOGEN # include "exception.h" # include "logfile.h" #else # include # include # define ERROR(fmt, args...) { fprintf(stderr, fmt "\n" , ## args); exit(1); } # define ERROS(fmt, args...) { fprintf(stderr, fmt ": " , ## args); \ perror(""); exit(1); } # define FATAL(fmt, args...) { fprintf(stderr, fmt "\n" , ## args); abort(); } # define WARNING(fmt, args...) { fprintf(stderr, fmt "\n" , ## args); } #endif /********************************************************************** * argument parsing **********************************************************************/ #include void StdSocket::parse_args(const char *s, int l) { for(; l > 0; s++, l--) { switch(char f = tolower(*s)) { case 'i': _fdi = 0; _state_plus |= recv_mode; break; case 'o': _fdo = 1; _state_plus |= send_mode; break; case 'e': _fdo = 2; _state_plus |= send_mode; break; default: WARNING("illegal flag %c must be i, o, or e", f); } } } /********************************************************************** * ctor, dtor, and copy methods **********************************************************************/ StdSocket::StdSocket(const char *, const char *param, size_t parlen) : Socket() { _fdi = -1; _fdo = -1; parse_args(param, parlen); _state_plus |= connected; // initially connected } StdSocket::StdSocket() : Socket() { _fdi = -1; _fdo = -1; } StdSocket::StdSocket(const StdSocket &s) : Socket() { _fdi = s._fdi; _fdo = s._fdo; } StdSocket::~StdSocket() { // keep connected if not explicitely closed! } Socket *StdSocket::ctor(const char *address, const char *param, size_t parlen) { return new StdSocket(address, param, parlen); } Socket *StdSocket::ctor() { return new StdSocket(*this); } /********************************************************************** * socket methods **********************************************************************/ inline bool StdSocket::connect(flags_t) { return _state_plus & connected; } size_t StdSocket::send(const char *buf, size_t len, int msgf) { size_t n; // filter out the cases where SIGPIPE wouldn't be appropriate if(! ((len == 0) && (msgf & (msg_eot | msg_eom)))) n = write(_fdo, buf, len); if(n == (size_t)-1) ERROS("write failed"); if( msgf & (msg_eom | msg_eot) ) { shutdown(send_mode); _state_plus |= eom_placed | eot_placed; } return n; } size_t StdSocket::recv(char *buf, size_t max, int) { size_t n = read(_fdi, buf, max); if(n == (size_t)-1) ERROS("read failed"); if( n == 0 ) _state_plus |= eom_seen | eot_seen; return n; } inline void StdSocket::shutdown(flags_t mode) { if(mode & recv_mode) ::close(_fdi); else if(mode & send_mode) ::close(_fdo); else { ::close(_fdi); ::close(_fdo); } _state_plus = _state_plus & ~( mode & send_recv ); } inline void StdSocket::close(flags_t) { ::close(_fdi); ::close(_fdo); _state_plus = _state_plus & ~send_recv & ~connected; } bool StdSocket::async(bool on, pid_t pid) { bool old = _state_plus & async_mode; int flagsi, flagso; if(fcntl(_fdi, F_GETFL, &flagsi) == -1) ERROS("fcntl:F_GETFL:"); if(fcntl(_fdo, F_GETFL, &flagso) == -1) ERROS("fcntl:F_GETFL:"); if(on) { if(pid != 0) { if(fcntl(_fdi, F_SETOWN, &pid) == -1) ERROS("fcntl:F_SETOWN:"); if(fcntl(_fdo, F_SETOWN, &pid) == -1) ERROS("fcntl:F_SETOWN:"); } flagsi |= O_ASYNC; flagso |= O_ASYNC; _state_plus |= async_mode; if(fcntl(_fdi, F_SETFL, &flagsi) == -1) ERROS("fcntl:F_SETFL:"); if(fcntl(_fdo, F_SETFL, &flagso) == -1) ERROS("fcntl:F_SETFL:"); } else // off { flagsi &= ~O_ASYNC; flagso &= ~O_ASYNC; if(fcntl(_fdi, F_SETFL, &flagsi) == -1) ERROS("fcntl:F_SETOWN:"); if(fcntl(_fdo, F_SETFL, &flagso) == -1) ERROS("fcntl:F_SETOWN:"); _state_plus &= ~async_mode; } return old; } bool StdSocket::noblock(bool on) { bool old = _state_plus & noblock_mode; int flagsi, flagso; if(fcntl(_fdi, F_GETFL, &flagsi) == -1) ERROS("fcntl:F_GETFL:"); if(fcntl(_fdo, F_GETFL, &flagso) == -1) ERROS("fcntl:F_GETFL:"); if(on) { flagsi |= O_NONBLOCK; flagso |= O_NONBLOCK; _state_plus |= noblock_mode; if(fcntl(_fdi, F_SETFL, &flagsi) == -1) ERROS("fcntl:F_SETOWN:"); if(fcntl(_fdo, F_SETFL, &flagso) == -1) ERROS("fcntl:F_SETOWN:"); } else // off { flagsi &= ~O_NONBLOCK; flagso &= ~O_NONBLOCK; if(fcntl(_fdi, F_SETFL, &flagsi) == -1) ERROS("fcntl:F_SETFL:"); if(fcntl(_fdo, F_SETFL, &flagso) == -1) ERROS("fcntl:F_SETFL:"); _state_plus &= ~noblock_mode; } return old; } bool StdSocket::is_sendready(int sec, int usec) const { FdSet rfds; FdSet tfds(_fdo, -1); select_again: int n = tfds.select(NULL, &rfds, NULL, sec, usec); if(n == -1) if(errno == EINTR) goto select_again; else ERROS("select"); return n != 0; } bool StdSocket::is_recvready(int sec, int usec) const { FdSet rfds; FdSet tfds(_fdi, -1); select_again: int n = tfds.select(&rfds, NULL, NULL, sec, usec); if(n == -1) if(errno == EINTR) goto select_again; else ERROS("select"); return n != 0; } bool StdSocket::is_exception(int sec, int usec) const { FdSet rfds; FdSet tfds(_fdi, _fdo, -1); select_again: int n = tfds.select(NULL, NULL, &rfds, sec, usec); if(n == -1) if(errno == EINTR) goto select_again; else ERROS("select"); return n != 0; }