// $Id: IOBuffer.cc,v 1.8 2000/07/17 06:39:41 greear Exp $ // $Revision: 1.8 $ $Author: greear $ $Date: 2000/07/17 06:39:41 $ // //ScryMUD Server Code //Copyright (C) 1998 Ben Greear // //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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. // // To contact the Author, Ben Greear: greear@cyberhighway.net, (preferred) // greearb@agcs.com // #include "IOBuffer.h" #include #include #include LogStream* IOBuffer::logfile = NULL; int IOBuffer::string_cnt = 0; int IOBuffer::total_bytes = 0; void IOBuffer::setLogFile(LogStream* dafile) { logfile = dafile; } LogStream* IOBuffer::getLogFile() { return logfile; } void IOBuffer::ensureCapacity(int max_length) { if (getMaxLen() < max_length) { char* tmp = new char[max_length + max_len]; int len = getCurLen(); peekBytes(tmp, len); delete[] string; string = tmp; tail = 0; head = len; total_bytes += max_length; //keep our static statistics max_len += max_length; }//if }//ensureCapacity IOBuffer::IOBuffer() { //default constructor //log("In default const.\n"); string_cnt++; string = new char[200]; head = 0; tail = 0; max_len = 200; total_bytes += 200; } // constructor IOBuffer::IOBuffer(const IOBuffer& S) { string_cnt++; string = new char[S.max_len]; memcpy(string, S.string, S.max_len); head = S.head; tail = S.tail; max_len = S.max_len; total_bytes += max_len; } // constructor IOBuffer::IOBuffer(const int my_len) { int m_len = my_len; string_cnt++; if (m_len > 100000) { m_len = 100000; } if (m_len < 200) { m_len = 200; } string = new char[m_len]; head = tail = 0; max_len = m_len; total_bytes += (max_len); } // constructor IOBuffer::~IOBuffer() { string_cnt--; total_bytes -= (max_len); delete[] string; string = NULL; } //destructor String IOBuffer::toString() { String retval(1000); Sprintf(retval, "max_len: %i head: %i tail: %i cur_len: %i\n [0] ", max_len, head, tail, getCurLen()); char buf[50]; for (int i = 0; i tail) { return head - tail; } else { return max_len - (tail - head); } } int IOBuffer::peekBytes(char* buf, int len_to_get) const { if (len_to_get > getCurLen()) { return -1; } else { if ((max_len - tail) >= len_to_get) { memcpy(buf, string + tail, len_to_get); } else { int mlen = max_len - tail; memcpy(buf, string + tail, mlen); memcpy(buf + mlen, string, len_to_get - mlen); } return len_to_get; } }//peekBytes int IOBuffer::dropFromTail(int len) { int cl = getCurLen(); if (cl == len) { head = tail = 0; } else if (len < cl) { if ((tail + len) <= max_len) { tail += len; } else { tail = (len - (max_len - tail)); } return len; } return -1; } int IOBuffer::write(const int desc) { int this_round = 0; int sofar = 0; if (desc == -1) { //cleans up an error message or two. return -1; }//if if (getCurLen() == 0) { return 0; } while (TRUE) { int len = getCurLen(); if (len > IOBUF_RD_LEN) { len = IOBUF_RD_LEN; } if (len == 0) { return sofar; } else { // TODO: Get rid of this extra copy..just write straight out of the 'string' buffer. peekBytes(read_buf, len); //copy them into this buffer this_round = ::write(desc, read_buf, len); if (this_round < 0) { //some error happened if (errno != EAGAIN) { //== EWOULDBLOCK perror("IOBuffer.Write() err"); if (IO_LOGFILE.ofLevel(WRN)) { IO_LOGFILE << "IOBuffer: WARNING: write err (NOT EAGAIN): " << strerror(errno) << endl; } return -1; }//if else { IO_LOGFILE.log(WRN, "IOBuffer: WARNING: EAGAIN on write.\n"); return sofar; } }//if else if (this_round == 0) { //all done, written to end of the buffer return sofar; }//if else { //wrote some, and all is well. sofar += this_round; dropFromTail(this_round); }//else }//else }//while }//Write (to a descriptor) /** May actually read more than max_to_read, but the buffer won't grow any * bigger than that... (it won't be made smaller if it's already bigger * of course.) * TODO: Read right into the string member. */ int IOBuffer::read(const int desc, const int max_to_read) { int sofar = 0; int this_round = 0; ensureCapacity(max_to_read); int to_rd; while (TRUE) { if (sofar >= max_to_read) return sofar; to_rd = max_to_read - sofar; if (IOBUF_RD_LEN < to_rd) { to_rd = IOBUF_RD_LEN; } this_round = ::read(desc, read_buf, to_rd); if (this_round > 0) { append(read_buf, this_round); //add it to our buffer }//if else { if (this_round < 0) { //some error happened if (errno != EAGAIN) { //== EWOULDBLOCK return -1; }//if else { //this means it read all in buffer return sofar; } }//if else { //this_round == 0 //log("ERROR: EOF encountered on socket read.\n"); return -1; }//else }//else }//while true }//Read (from a descriptor) void IOBuffer::purge() { total_bytes -= (max_len + 1); delete[] string; string = new char[200]; max_len = 200; head = tail = 0; total_bytes += max_len; }//purge void IOBuffer::clear() { head = tail = 0; }//Clear int IOBuffer::append(const char* source, int len) { ensureCapacity(getCurLen() + len); // Here, we know that we have the space, so lets copy it in... int mlen = 0; if ((head + len) > max_len) { mlen = max_len - head; //will have to wrap it a bit memcpy(string + head, source, mlen); head = 0; } // Copy the rest into the buffer starting at 'head'. memcpy(string + head, source + mlen, len - mlen); head += len - mlen; return len; }//append IOBuffer::operator const char*() const { return string; }//to char* operator overload