/* * 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 "SockBuf.h" #ifdef PROTOGEN # include "exception.h" #else # include # define ERROR(fmt, args...) { fprintf(stderr, fmt , ## args); exit(1); } # define FATAL(fmt, args...) { fprintf(stderr, fmt , ## args); abort(); } #endif /********************************************************************** * ctor, dtor, and copy methods **********************************************************************/ SockBuf::SockBuf() : streambuf(), Socket() { xsetflags(_IO_LINE_BUF); } SockBuf::SockBuf(const char *address) : streambuf(), Socket(address) { xsetflags(_IO_LINE_BUF); } SockBuf::~SockBuf() { sync(); if(! (xflags() & _IO_DELETE_DONT_CLOSE)) close(); // FIXME! must be propagated to ~Socket() if(!(xflags() & _IO_USER_BUF) && base() != NULL) delete [] base(); } /********************************************************************** * streambuf methods **********************************************************************/ #ifndef BUFSIZ # define BUFSIZ 1024 #endif int SockBuf::underflow() { if(xflags() & _IO_NO_READS) return EOF; else if(gptr() < egptr()) return *(unsigned char*)gptr (); else if(base() == NULL && doallocate() == 0) return EOF; else { int bufsz = unbuffered() ? 1: BUFSIZ; int rval = recv(base(), bufsz); if(rval == 0) { xsetflags(_IO_EOF_SEEN); return EOF; } else if(rval == 0) return EOF; setg(eback(), base(), base() + rval); return *(unsigned char*)gptr (); } } int SockBuf::overflow(int c) // if c == EOF, return flush_output(); // if c == '\n' and linebuffered, insert c and // return (flush_output()==EOF)? EOF: c; // otherwise insert c into the buffer and return c { if(c == EOF) return sync(); if(xflags() & _IO_NO_WRITES) return EOF; if(pbase() == 0 && doallocate() == 0) return EOF; if(pptr () >= epptr() && sync() == EOF) return EOF; else { xput_char(c); if((unbuffered() || linebuffered() && c == '\n' || pptr() >= epptr()) && sync() == EOF) return EOF; return c; } } int SockBuf::doallocate() // return 1 on allocation and 0 if there is no need { if(base() == NULL) { char* buf = new char[2*BUFSIZ]; setb(buf, buf+BUFSIZ, 0); setg(buf, buf, buf); buf += BUFSIZ; setp(buf, buf+BUFSIZ); return 1; } else return 0; } int SockBuf::sync() // return 0 when there is nothing to flush or when the flush is a success // return EOF when it could not flush { if(pptr() <= pbase()) return 0; else if(! (xflags() & _IO_NO_WRITES)) { int wlen = pptr() - pbase(); send(pbase(), wlen); if(unbuffered()) setp(pbase(), pbase()); else setp(pbase(), pbase() + BUFSIZ); return 0; } else return EOF; } int SockBuf::xsputn(char *buf, streamsize size) { if(size <= 0) return 0; else { const unsigned char* p = (const unsigned char*)buf; for(int i = 0; i < size; i++, p++) { if (*p == '\n') { if(overflow(*p) == EOF) return i; } else if(sputc(*p) == EOF) return i; } return size; } } streamsize SockBuf::xsgetn(char *buf, streamsize size) { return (streamsize)recv(buf, (size_t)size, 0); } streamsize SockBuf::sys_read(char* buf, streamsize size) { return (streamsize)recv(buf, size, 0); } streamsize SockBuf::sys_write(const char *buf, streamsize size) { send(buf, (size_t)size, 0); return size; } int SockBuf::sys_close() { close(); return 0; }