/* * 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 "FileSocket.h" #include #include #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 #include /********************************************************************** * argument parsing **********************************************************************/ void FileSocket::parse_args(const char *s, int l) { if(l == -1) l = strlen(s); const char *name_p = NULL; int name_l = 0; const char *flags_p = NULL; int flags_l = 0; const char *mode_p = NULL; int mode_l = 0; if(l == 0) goto finish; while(l > 0 && isspace(*s)) { s++; l--; } name_p = s; while(l > 0 && *s != ',') { s++; l--; name_l++; } if(l == 0) goto finish; else { s++; l--; } while(l > 0 && isspace(*s)) { s++; l--; } flags_p = s; while(l > 0 && *s != ',') { s++; l--; flags_l++; } if(l-- == 0) goto finish; else { s++; l--; } mode_p = s; while(l > 0 && *s != ',') { s++; l--; mode_l++; } finish: if(name_p != NULL) { // remove trailing spaces from filename const char *s = name_p + name_l; while(name_l > 0 && isspace(*--s)) { name_l--; } // set the filename _filename = new char[name_l + 1]; memcpy(_filename, name_p, name_l); _filename[name_l] = 0; } if(flags_p == 0) _oflags = O_CREAT | O_TRUNC; else { _oflags = 0; for(int i = 0; i < flags_l; i++) { switch(char f = tolower(flags_p[i])) { case 'r': _rwmode |= recv_mode; break; case 'w': _rwmode |= send_mode; break; case 'c': _oflags |= O_CREAT; break; case 'a': _oflags |= O_APPEND; break; case 't': _oflags |= O_TRUNC; break; case 'e': _oflags |= O_EXCL; break; case 's': _oflags |= O_SHLOCK; break; case 'x': _oflags |= O_EXLOCK; break; default: WARNING("illegal file flag `%c'", f); } } } if(mode_l == 0) _omode = 0666; else { char b[mode_l + 1]; char *e; memcpy(b, mode_p, mode_l); b[mode_l] = 0; _omode = strtol(b, &e, 0); if(e == b) { WARNING("illegal mode flags `%s'", b); _omode = 0666; } } } /********************************************************************** * ctor, dtor, and copy methods **********************************************************************/ FileSocket::FileSocket(const char *, const char *param, size_t parlen) : Socket() { _fd = -1; parse_args(param, parlen); } FileSocket::FileSocket() : Socket() { _fd = -1; _filename = NULL; _oflags = 0; _omode = 0; } FileSocket::FileSocket(const FileSocket &s) : Socket() { _fd = -1; _filename = strdup(s._filename); _oflags = s._oflags; _omode = s._omode; } FileSocket::~FileSocket() { if(_fd != -1) ::close(_fd); if(_filename != NULL) delete [] _filename; } Socket *FileSocket::ctor(const char *address, const char *param, size_t parlen) { return new FileSocket(address, param, parlen); } Socket *FileSocket::ctor() { return new FileSocket(*this); } /********************************************************************** * socket methods **********************************************************************/ bool FileSocket::connect(flags_t mode) { if(_fd != -1) ::close(_fd); if(_filename == NULL) ERROR("no file"); int oflags; if((mode & _rwmode & send_recv) == send_recv) oflags = _oflags | O_RDWR; else if(mode & _rwmode & send_mode) oflags = _oflags | O_WRONLY; else if(mode & _rwmode & recv_mode) oflags = _oflags | O_RDONLY; _fd = open(_filename, oflags, _omode); if(_fd == -1) ERROS("file open error `%s'", _filename); _state_plus |= connected | ( mode & _rwmode & send_recv ) & ~eox_any; return true; } size_t FileSocket::send(const char *buf, size_t len, int msgf) { if(!(_state_plus & send_mode)) ERROR("illegal operation"); size_t n = write(_fd, 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 FileSocket::recv(char *buf, size_t max, int) { if(!(_state_plus & recv_mode)) ERROR("illegal operation"); size_t n = read(_fd, buf, max); if(n == (size_t)-1) ERROS("read failed"); if( n == 0 ) _state_plus |= eom_seen | eot_seen; return n; } void FileSocket::shutdown(flags_t mode) { _state_plus = _state_plus & ~( mode & send_recv ); } void FileSocket::close(flags_t) { ::close(_fd); _fd = -1; _state_plus = _state_plus & ~connected & ~send_recv; } bool FileSocket::is_sendready(int sec, int usec) const { FdSet rfds; FdSet tfds(_fd, -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 FileSocket::is_recvready(int sec, int usec) const { FdSet rfds; FdSet tfds(_fd, -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 FileSocket::is_exception(int sec, int usec) const { FdSet rfds; FdSet tfds(_fd, -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; }