Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members  

StreamFDModule.h

00001 #ifndef _STR_StreamFDModule_H_  //-*-c++-*-
00002 
00003 /*
00004  * Copyright 1991-2002 Eric M. Hopper <hopper@omnifarious.org>
00005  * 
00006  *     This program is free software; you can redistribute it and/or modify it
00007  *     under the terms of the GNU Lesser General Public License as published
00008  *     by the Free Software Foundation; either version 2 of the License, or
00009  *     (at your option) any later version.
00010  * 
00011  *     This program is distributed in the hope that it will be useful, but
00012  *     WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *     Lesser General Public License for more details.
00015  * 
00016  *     You should have received a copy of the GNU Lesser General Public
00017  *     License along with this program; if not, write to the Free Software
00018  *     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 #ifdef __GNUG__
00022 #  pragma interface
00023 #endif
00024 
00025 /* $Header: /home/hopper/src/cvs/C++/StrMod/StrMod/StreamFDModule.h,v 1.28 2002/11/25 05:40:05 hopper Exp $ */
00026 
00027 // See ../ChangLog for log.
00028 // $Revision: 1.28 $
00029 
00030 //! author="Eric Hopper" lib=StrMod
00031 
00032 #include <cstddef>  // size_t
00033 
00034 #include <UniEvent/EventPtr.h>
00035 #include <UniEvent/EventPtrT.h>
00036 #include <UniEvent/UnixEventRegistry.h>
00037 #include <UniEvent/UNIXError.h>
00038 
00039 #ifndef _STR_StreamModule_H_
00040 #   include <StrMod/StreamModule.h>
00041 #endif
00042 #ifndef _STR_StrChunkPtr_H_
00043 #   include <StrMod/StrChunkPtr.h>
00044 #endif
00045 
00046 #define _STR_StreamFDModule_H_
00047 
00048 template <class enum_t, enum_t first, enum_t last> class enum_set;
00049 
00050 namespace strmod {
00051 namespace strmod {
00052 
00053 class GroupVector;
00054 
00055 /** \class StreamFDModule StreamFDModule.h StrMod/StreamFDModule.h
00056  * \brief This module is for communicating outside your program via UNIX IO.
00057  *
00058  * One side of this module is a UNIX file descriptor, and the other side is the
00059  * plug.  Everything written to the plug is written to the file descriptor, and
00060  * everything read from the file descriptor is read from the plug.
00061  *
00062  * There are (or will be) ways of asking for events to be posted when stuff
00063 //  * happens that the StreamFDModule can't deal with directly, such has EOF,
00064  * read or write errors, or unexpected file descriptor closings.
00065  */
00066 class StreamFDModule : public StreamModule
00067 {
00068  protected:
00069    class FPlug;
00070    friend class FPlug;
00071  private:
00072    class BufferList;
00073    class EvMixin;
00074    friend class StreamFDModule::EvMixin;
00075    class FDPollRdEv;
00076    friend class StreamFDModule::FDPollRdEv;
00077    class FDPollWrEv;
00078    friend class StreamFDModule::FDPollWrEv;
00079    class FDPollErEv;
00080    friend class StreamFDModule::FDPollErEv;
00081    class ResumeReadEv;
00082    friend class StreamFDModule::ResumeReadEv;
00083    class ResumeWriteEv;
00084    friend class StreamFDModule::ResumeWriteEv;
00085 
00086  public:
00087    /** What directions is IO checked in?
00088     * This is used for file descriptors that are open only for reading, or only
00089     * for writing.
00090     */
00091    enum IOCheckFlags {
00092       CheckNone,  //!< Don't bother with checking for reading or writing.
00093       CheckRead,  //!< Only check file descriptor for reading.
00094       CheckWrite, //!< Only check file descriptor for writing.
00095       CheckBoth   //!< Check file descriptor for reading and writing.
00096    };
00097    /** What kinds of errors are possible?
00098     */
00099    enum ErrorType {
00100       ErrRead,  //!< Error while reading, might have read an EOF.  Must be lowest enum value.
00101       ErrWrite, //!< Error while writing, might have written an EOF.
00102       ErrGeneral,  //!< General error affecting both reading and writing.
00103       ErrFatal  //! General, fatal error affecting both reading and writing.  Must be highest enum value.
00104    };
00105    //! Typedef for set of error types.
00106    typedef lcore::enum_set<ErrorType, ErrRead, ErrFatal> ErrorSet;
00107 
00108 
00109    static const STR_ClassIdent identifier;
00110    /** \brief This is the maximum number of bytes to read or write without going
00111     * back to the dispatcher.
00112     *
00113     * If the socket on this class has enough data going through it to saturate
00114     * the CPU, the StreamFDModule may never give the CPU to any of the other
00115     * StreamFDModules unless it voluntarily gives it up after passing a certain
00116     * amount of data.  This is the constant that determines how much data is
00117     * enough.
00118     *
00119     * This should possibly be a configurable value, but it isn't yet.  If it is
00120     * too low, you call back the dispatcher too often, and high bandwidth
00121     * connections are handled slightly less efficiently than they could be.  If
00122     * it's too high you'll get choppy response.  It's kinda like the
00123     * multitasking timeslice value in an OS.
00124     */
00125    static const size_t S_max_bytes_without_dispatch = 256U * 1024U;
00126 
00127    /** Constructs a StreamFDModule from an OS file descriptor.
00128     *
00129     * @param fd The file descriptor to attach to.
00130     *
00131     * @param disp The strmod::unievent::Dispatcher to use for posting an event
00132     * to when it becomes apparent that this module is in danger of hogging the
00133     * CPU.
00134     *
00135     * @param ureg The strmod::unievent::UnixEventRegistry to use to register to
00136     * recieve file descriptor events.  A reference to the event registry is kept
00137     * until object destruction.  The StreamFDModule doesn't 'own' the registry.
00138     *
00139     * @param checkmask Describes what kinds of IO that can be done (and
00140     * therefore, should be checked for) on <code>fd</code>.
00141     */
00142    StreamFDModule(int fd,
00143                   unievent::Dispatcher &disp,
00144                   unievent::UnixEventRegistry &ureg,
00145                   IOCheckFlags checkmask = CheckBoth);
00146    //! Closes the associated file descriptor.
00147    virtual ~StreamFDModule();
00148 
00149    inline virtual int AreYouA(const lcore::ClassIdent &cid) const;
00150 
00151    inline virtual bool canCreate(int side) const;
00152    inline virtual bool ownsPlug(const Plug *p) const;
00153    inline virtual bool deletePlug(Plug *p);
00154 
00155    //! Check for an error in the given category.
00156    bool hasErrorIn(ErrorType err) const throw ();
00157    //! Check for an error in one of the categories given by the set.
00158    bool hasErrorIn(const ErrorSet &set) const throw ();
00159    /** Ask to post an event when the given error type happens.
00160     * Currently only one event per error type is allowed.  If there is already
00161     * an event for a particular error type, that event will be forgotten about
00162     * and not posted.
00163     */
00164    void onErrorIn(ErrorType err, const unievent::EventPtr &ev) throw();
00165    /** Reset the error value for a particular category.
00166     * This does not work for the ErrFatal category.
00167     */
00168    void resetErrorIn(ErrorType err) throw ();
00169    //! Get the error value for a particular category.
00170    const unievent::UNIXError &getErrorIn(ErrorType err) const throw ();
00171 
00172    //! Set whether or not and EOFStrChunk is sent when an EOF is read.
00173    inline void setSendChunkOnEOF(bool newval) throw();
00174    //! Does this module send a chunk on EOF?
00175    inline bool getSendChunkOnEOF() throw()          { return flags_.chunkeof; }
00176 
00177    //! Sets the maximum block size to be read in a single read operation.
00178    inline void setMaxChunkSize(size_t mbs);
00179    //! Returns the maximum block size to be read in a single read operation.
00180    size_t getMaxChunkSize() const                   { return(max_block_size_); }
00181 
00182    /** This returns the optimal IO blocksize for this descriptor
00183     *
00184     * This returns the st_blksize member of the stat structure returned by
00185     * fstat'ing the file descriptor.  If the stat cannot be performed, or
00186     * st_blksize is 0, a default value (most likely 4096) is returned.
00187     *
00188     * In a certain special case, if 0 < st_blksize < 64, 64 is returned.
00189     */
00190    size_t getBestChunkSize() const;
00191 
00192    /** Mostly equivalent to setMaxChunkSize(BestChunkSize())
00193     * If the value returned by BestChunkSize is an 'unreasonable' value such as
00194     * less than 1024 (1k) bytes, or more than 65536 (64k) bytes, the value is
00195     * set to the closest 'reasonable' value.
00196     */
00197    inline void setMaxToBest();
00198 
00199 
00200  protected:
00201    class MyPollEvent;
00202    friend class MyPollEvent;
00203    //: This plug is the rather simple plug for a StreamFDModule.
00204    class FPlug : public Plug {
00205       friend class StreamFDModule;
00206     public:
00207       static const STR_ClassIdent identifier;
00208 
00209       //: Note that this can ONLY be constructed using a StreamFDModule.
00210       FPlug(StreamFDModule &parent) : Plug(parent)      { }
00211       virtual ~FPlug()                                  { }
00212 
00213       //: See base class.
00214       inline virtual int AreYouA(const lcore::ClassIdent &cid) const;
00215 
00216       //: Grab Plug::getParent, and cast it to the real type of the parent.
00217       inline StreamFDModule &getParent() const;
00218 
00219       //: This plug is always on side 0.
00220       virtual int side() const                          { return(0); }
00221 
00222     protected:
00223       //: See base class.
00224       virtual const lcore::ClassIdent *i_GetIdent() const {
00225          return &identifier;
00226       }
00227 
00228       //: Forwards to getParent()->plugRead()
00229       inline virtual const StrChunkPtr i_Read();
00230       //: Forwards to getParent()->plugWrite()
00231       inline virtual void i_Write(const StrChunkPtr &ptr);
00232    };
00233 
00234    virtual const lcore::ClassIdent *i_GetIdent() const  { return &identifier; }
00235 
00236    inline virtual Plug *i_MakePlug(int side);
00237 
00238    //! Called by FPlug::i_Write.
00239    virtual void plugWrite(const StrChunkPtr &ptr);
00240    //! Called by FPlug::i_Read.
00241    virtual const StrChunkPtr plugRead();
00242 
00243    /** Read from fd into buffed_read_
00244     *
00245     * Assumes that buffed_read_ is empty, that there are no read errors, no
00246     * fatal errors, and that EOF has not been read.
00247     *
00248     * If the read returns '0' and the EOF on read flag (flags_.chunkeof,
00249     * possibly set by setSendChunkOnEOF() ) is set, buffed_read_ will contain an
00250     * EOFStrChunk.
00251     */
00252    virtual void doReadFD();
00253    /** Write to fd from cur_write_, using the info in write_vec_.
00254     *
00255     * Assumes that cur_write_ isn't empty, that there are no write errors, no
00256     * fatal errors, and that EOF has not been written.
00257     *
00258     * If cur_write_ is an EOFStrChunk, it will call writeEOF().
00259     */
00260    virtual void doWriteFD();
00261 
00262    /** An EOF indication has been written.  This function has to handle it.
00263     * This function follows the template method pattern from Design Patterns.
00264     *
00265     * Do whatever is needed to write an EOF to the file descriptor for
00266     * this module.
00267     */
00268    virtual void writeEOF();
00269 
00270    //! Set an error in a particular category.
00271    void setErrorIn(ErrorType err, const unievent::UNIXError &errval);
00272 
00273    //! Called by readev_ and resumeread_'s triggerEvent.
00274    void eventRead();
00275    //! Called by writeev_ and resumewrite_'s triggerEvent.
00276    void eventWrite();
00277    //! Called by errorev_'s triggerEvent.
00278    void eventError();
00279    //! Called by resumeread_'s triggerEvent
00280    void eventResumeRead();
00281    //! Called by resumewrite_'s triggerEvent
00282    void eventResumeWrite();
00283 
00284    //! Get the file descriptor so a derived class can do something to it.
00285    int getFD() const throw()                       { return fd_; }
00286 
00287  private:
00288    struct ErrorInfo;
00289 
00290    int fd_;
00291    struct {
00292       unsigned int plugmade   : 1;
00293       unsigned int checkingrd : 1;
00294       unsigned int checkingwr : 1;
00295       unsigned int readeof    : 1;
00296       unsigned int eofwritten : 1;
00297       unsigned int chunkeof   : 1;
00298    } flags_;
00299 //   int errvals[ErrFatal + 1];
00300    FPlug plug_;
00301    StrChunkPtr buffed_read_;
00302    StrChunkPtr cur_write_;
00303    BufferList &curbuflist_;
00304    unsigned int max_block_size_;
00305    unsigned int read_since_read_posted_;
00306    unsigned int written_since_write_posted_;
00307    // Non reference counted pointers, used for housekeeping.
00308    EvMixin *parenttrackers_[5];
00309    // The following 5 members are duplicates of the pointers held in the
00310    // previous array.  They are reference counted.
00311    typedef unievent::EventPtr EventPtr;
00312    EventPtr readev_;
00313    EventPtr writeev_;
00314    EventPtr errorev_;
00315    unievent::EventPtr resumeread_;
00316    unievent::EventPtr resumewrite_;
00317    ErrorInfo &errorinfo_;
00318    unievent::Dispatcher &disp_;
00319    unievent::UnixEventRegistry &ureg_;
00320 };
00321 
00322 //-----------------inline functions for class StreamFDModule-------------------
00323 
00324 inline int StreamFDModule::AreYouA(const lcore::ClassIdent &cid) const
00325 {
00326    return((identifier == cid) || StreamModule::AreYouA(cid));
00327 }
00328 
00329 inline bool StreamFDModule::canCreate(int side) const
00330 {
00331    return (side == 0 && !flags_.plugmade);
00332 }
00333 
00334 inline bool StreamFDModule::ownsPlug(const Plug *p) const
00335 {
00336    return(flags_.plugmade && (p == &plug_));
00337 }
00338 
00339 inline bool StreamFDModule::deletePlug(Plug *p)
00340 {
00341    if (ownsPlug(p)) {
00342       flags_.plugmade = 0;
00343       return(true);
00344    } else
00345       return(false);
00346 }
00347 
00348 inline void StreamFDModule::setSendChunkOnEOF(bool newval) throw()
00349 {
00350    flags_.chunkeof = newval;
00351 }
00352 
00353 inline void StreamFDModule::setMaxChunkSize(size_t mbs)
00354 {
00355    assert(mbs > 0);
00356 
00357    if (mbs > 0)
00358    {
00359       max_block_size_ = mbs;
00360    }
00361 }
00362 
00363 inline void StreamFDModule::setMaxToBest()
00364 {
00365    setMaxChunkSize(getBestChunkSize());
00366 }
00367 
00368 inline StreamModule::Plug *StreamFDModule::i_MakePlug(int side)
00369 {
00370    if (canCreate(side))
00371    {
00372       flags_.plugmade = 1;
00373       return(&plug_);
00374    }
00375    else
00376    {
00377       return(0);
00378    }
00379 }
00380 
00381 //-------------inline functions for class StreamFDModule::FPlug----------------
00382 
00383 inline int StreamFDModule::FPlug::AreYouA(const lcore::ClassIdent &cid) const
00384 {
00385    return((identifier == cid) || Plug::AreYouA(cid));
00386 }
00387 
00388 inline StreamFDModule &StreamFDModule::FPlug::getParent() const
00389 {
00390    return(static_cast<StreamFDModule &>(Plug::getParent()));
00391 }
00392 
00393 inline const StrChunkPtr StreamFDModule::FPlug::i_Read()
00394 {
00395    return(getParent().plugRead());
00396 }
00397 
00398 inline void StreamFDModule::FPlug::i_Write(const StrChunkPtr &ptr)
00399 {
00400    getParent().plugWrite(ptr);
00401 }
00402 
00403 }  // namespace strmod
00404 }  // namespace strmod
00405 
00406 #endif

Generated on Wed Jan 29 00:32:44 2003 for libNet by doxygen1.3-rc1