// Copyright (c) 2002 David Muse
// See the COPYING file for more information.

#ifndef RUDIMENTS_FILEDESCRIPTOR_H
#define RUDIMENTS_FILEDESCRIPTOR_H

#include <rudiments/private/filedescriptorincludes.h>

// The filedescriptor class is a base class for other classes that utilize
// file descriptors.

#ifdef RUDIMENTS_NAMESPACE
namespace rudiments {
#endif

class listener;

class filedescriptorprivate;

class filedescriptor {
        public:
                        filedescriptor();
                                // Creates an uninitialized filedescriptor.
                        filedescriptor(const filedescriptor &f);
                filedescriptor  &operator=(const filedescriptor &f);
                virtual       ~filedescriptor();
                                // Calls close() if it hasn't already been
                                // called.


                virtual       bool  close();
                                // Closes the file descriptor.
                                // Returns true on success and false on failure.

                int   getFileDescriptor() const;
                                // Returns the file descriptor.
                void  setFileDescriptor(int filedesc);
                                // Sets the file descriptor associated with
                                // the class to "filedesc".

                int   duplicate() const;
                                // Duplicates the file descriptor and returns
                                // the handle of the duplicate descriptor.  The
                                // old and new descriptors may be used
                                // interchangeably, they share locks, position
                                // pointers, flags (except the close-on-exec
                                // flag), etc.
                                //
                                // Returns the lowest-numbered unused descriptor
                                // on success or -1 on failure.
                bool  duplicate(int newfd) const;
                                // Sets file descriptor handle "newfd" to be a
                                // duplicate of this file descriptor.  If
                                // "newfd" is already open, it will be closed
                                // first.
                                //
                                // Returns true on success and false on failure.

                #ifdef RUDIMENTS_HAS_SSL
                void  setSSLContext(SSL_CTX *ctx);
                                // Associates SSL context "ctx" with the
                                // filedescriptor.  Passing in a NULL for "ctx"
                                // has the additional side effect of calling
                                // deInitializeSSL() below.
                SSL_CTX *getSSLContext();
                                // Returns the SSL context currently associated
                                // with the filedescriptor or NULL if none
                                // is currently associated.
                bool  initializeSSL();
                                // Should be called after calling
                                // setSSLContext() and one of open(),
                                // create() or connect() (from socket child
                                // classes). Causes the appropriate SSL
                                // function to be called instead of or in
                                // concert with read(), write(), connect(),
                                // accept() and close() methods.
                                //
                                // Returns true on success and false on failure
                SSL     *getSSL() const;
                                // Returns a pointer to the currently
                                // initialized SSL handle or NULL if
                                // initializeSSL() has not been called or
                                // failed.
                void  deInitializeSSL();
                                // Causes read(), write(), connect(), accept()
                                // and close() methods to be performed
                                // without the accompanying SSL-specific
                                // functions.

                int   getSSLResult() const;
                                // Returns the result code of the previously
                                // executed SSL command.  If a method fails
                                // but errno is 0 then an SSL-related error
                                // occurred.  You may call SSL_get_error()
                                // on the result of this method to determine
                                // the exact error.
                #endif

                virtual bool  useNonBlockingMode() const;
                                // Puts the file descriptor in non-blocking
                                // mode.  Returns true on success and false on
                                // failure.
                virtual bool  useBlockingMode() const;
                                // Puts the file descriptor in blocking mode.
                                // Returns true on success and false on
                                // failure.
                bool          isUsingNonBlockingMode() const;
                                // Returns true if the file descriptor is in
                                // non-blocking mode and false otherwise.

                // Write methods - write data to the file descriptor.
                // These methods return the number of bytes that were
                // successfully written or RESULT_ERROR if an error occurred.
                ssize_t       write(uint16_t number) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(uint32_t number) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(uint64_t number) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(int16_t number) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(int32_t number) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(int64_t number) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(float number) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(double number) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(unsigned char character) const;
                                // Write "character" to the file descriptor.
                ssize_t       write(char character) const;
                                // Write "character" to the file descriptor.
                ssize_t       write(bool value) const;
                                // Write "value" to the file descriptor.
                ssize_t       write(const unsigned char *string) const;
                                // Write "string" to the file descriptor.  Note
                                // that "string" must be NULL-terminated.
                ssize_t       write(const char *string) const;
                                // Write "string" to the file descriptor.  Note
                                // that "string" must be NULL-terminated.
                ssize_t       write(const unsigned char *string, size_t size) const;
                                // Write "size" bytes from "string" to the file
                                // descriptor.  Note that it is possible to
                                // write beyond the string's NULL terminator
                                // using this method.
                ssize_t       write(const char *string, size_t size) const;
                                // Write "size" bytes from "string" to the file
                                // descriptor.  Note that it is possible to
                                // write beyond the string's NULL terminator
                                // using this method.
                ssize_t       write(const void *buffer, size_t size) const;
                                // Write "size" bytes from "buffer" to the file
                                // descriptor.


                // Write methods - write data to the file descriptor with a
                // timeout of "sec" seconds and "usec" microseconds.
                // These methods return the number of bytes that were
                // successfully written, RESULT_ERROR if an error occurred or
                // RESULT_TIMEOUT if a timeout occurred.
                ssize_t       write(uint16_t number, long sec, long usec) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(uint32_t number, long sec, long usec) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(uint64_t number, long sec, long usec) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(int16_t number, long sec, long usec) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(int32_t number, long sec, long usec) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(int64_t number, long sec, long usec) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(float number, long sec, long usec) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(double number, long sec, long usec) const;
                                // Write "number" to the file descriptor.
                ssize_t       write(unsigned char character,
                                        long sec, long usec) const;
                                // Write "character" to the file descriptor.
                ssize_t       write(char character, long sec, long usec) const;
                                // Write "character" to the file descriptor.
                ssize_t       write(bool value, long sec, long usec) const;
                                // Write "value" to the file descriptor.
                ssize_t       write(const unsigned char *string,
                                        long sec, long usec) const;
                                // Write "string" to the file descriptor.  Note
                                // that "string" must be NULL-terminated.
                ssize_t       write(const char *string,
                                        long sec, long usec) const;
                                // Write "string" to the file descriptor.  Note
                                // that "string" must be NULL-terminated.
                ssize_t       write(const unsigned char *string, size_t size,
                                        long sec, long usec) const;
                                // Write "size" bytes from "string" to the file
                                // descriptor.  Note that it is possible to
                                // write beyond the string's NULL terminator
                                // using this method.
                ssize_t       write(const char *string, size_t size,
                                        long sec, long usec) const;
                                // Write "size" bytes from "string" to the file
                                // descriptor.  Note that it is possible to
                                // write beyond the string's NULL terminator
                                // using this method.
                ssize_t       write(const void *buffer, size_t size,
                                        long sec, long usec) const;
                                // Write "size" bytes from "buffer" to the file
                                // descriptor.


                // Read methods - read data from the file descriptor.
                // These methods return the number of bytes that were
                // successfully read or RESULT_ERROR if an error occurred.
                ssize_t       read(uint16_t *buffer) const;
                                // Reads sizeof(uint16_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(uint32_t *buffer) const;
                                // Reads sizeof(uint32_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(uint64_t *buffer) const;
                                // Reads sizeof(uint64_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(int16_t *buffer) const;
                                // Reads sizeof(int16_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(int32_t *buffer) const;
                                // Reads sizeof(int32_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(int64_t *buffer) const;
                                // Reads sizeof(int64_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(float *buffer) const;
                                // Reads sizeof(float) bytes from the file
                                // descriptor into "buffer".
                ssize_t       read(double *buffer) const;
                                // Reads sizeof(double) bytes from the file
                                // descriptor into "buffer".
                ssize_t       read(unsigned char *buffer) const;
                                // Reads sizeof(unsigned char) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(char *buffer) const;
                                // Reads sizeof(char) bytes from the file
                                // descriptor into "buffer".
                ssize_t       read(bool *buffer) const;
                                // Reads sizeof(bool) bytes from the file
                                // descriptor into "buffer".
                ssize_t       read(unsigned char *buffer, size_t size) const;
                                // Reads "size" bytes from the file descriptor
                                // into "buffer".
                ssize_t       read(char *buffer, size_t size) const;
                                // Reads "size" bytes from the file descriptor
                                // into "buffer".
                ssize_t       read(void *buf, size_t size) const;
                                // Reads "size" bytes from the file descriptor
                                // into "buffer".
                ssize_t       read(char **buffer, char *terminator) const;
                                // Reads from the file desciptor into "buffer"
                                // until "terminator" is encountered.  Note
                                // that "buffer" is allocated internally and
                                // must be freed by the calling program.


                // Read methods - read data from the file descriptor with a
                // timeout of "sec" seconds and "usec" microseconds.
                // These methods return the number of bytes that were
                // successfully read, RESULT_ERROR if an error occurred or
                // RESULT_TIMEOUT if a timeout occurred.
                ssize_t       read(uint16_t *buffer, long sec, long usec) const;
                                // Reads sizeof(uint16_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(uint32_t *buffer, long sec, long usec) const;
                                // Reads sizeof(uint32_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(uint64_t *buffer, long sec, long usec) const;
                                // Reads sizeof(uint64_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(int16_t *buffer, long sec, long usec) const;
                                // Reads sizeof(int16_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(int32_t *buffer, long sec, long usec) const;
                                // Reads sizeof(int32_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(int64_t *buffer, long sec, long usec) const;
                                // Reads sizeof(int64_t) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(float *buffer, long sec, long usec) const;
                                // Reads sizeof(float) bytes from the file
                                // descriptor into "buffer".
                ssize_t       read(double *buffer, long sec, long usec) const;
                                // Reads sizeof(double) bytes from the file
                                // descriptor into "buffer".
                ssize_t       read(unsigned char *buffer,
                                        long sec, long usec) const;
                                // Reads sizeof(unsigned char) bytes
                                // from the file descriptor into "buffer".
                ssize_t       read(char *buffer, long sec, long usec) const;
                                // Reads sizeof(char) bytes from the file
                                // descriptor into "buffer".
                ssize_t       read(bool *buffer, long sec, long usec) const;
                                // Reads sizeof(bool) bytes from the
                                // file descriptor into "buffer".
                ssize_t       read(unsigned char *buffer, size_t size,
                                        long sec, long usec) const;
                                // Reads "size" bytes from the file descriptor
                                // into "buffer".
                ssize_t       read(char *buffer, size_t size,
                                        long sec, long usec) const;
                                // Reads "size" bytes from the file descriptor
                                // into "buffer".
                ssize_t       read(void *buf, size_t size,
                                        long sec, long usec) const;
                                // Reads "size" bytes from the file descriptor
                                // into "buffer".
                ssize_t       read(char **buffer, char *terminator,
                                        long sec, long usec) const;
                                // Reads from the file desciptor into "buffer"
                                // until "terminator" is encountered.  Note
                                // that "buffer" is allocated internally and
                                // must be freed by the calling program.


                // Wait methods.
                int   waitForNonBlockingRead(long sec, long usec) const;
                                // Causes the application to wait until a read()
                                // will proceed without blocking or until "sec"
                                // seconds and "usec" microseconds have elapsed.
                                //
                                // Entering -1 for either parameter causes the
                                // method to wait indefinitely.  
                                //
                                // Entering 0 for both parameters causes the
                                // method to fall through immediately unless a
                                // data is immediately available.
                                //
                                // Returns RESULT_ERROR on error, RESULT_TIMEOUT
                                // on timeout and otherwise returns the number
                                // of file descriptors that are ready to be
                                // read from.
                                //
                                // This will usually be 1, indicating that the
                                // file descriptor represented by the class is
                                // ready to be read from.  However, if
                                // useListener() has been called, it may be
                                // greater than 1, indicating that a set of
                                // file descriptors that the listener is
                                // listening on are all ready to be read from.
                int   waitForNonBlockingWrite(long sec, long usec) const;
                                // Causes the application to wait until a
                                // write() will proceed without blocking or
                                // until "sec" seconds and "usec" microseconds
                                // have elapsed.
                                //
                                // Entering -1 for either parameter causes the
                                // method to wait indefinitely.  
                                //
                                // Entering 0 for both parameters causes the
                                // method to fall through immediately unless a
                                // data is immediately available.
                                //
                                // Returns RESULT_ERROR on error, RESULT_TIMEOUT
                                // on timeout and otherwise returns the number
                                // of file descriptors that are ready to be
                                // written to.
                                //
                                // This will usually be 1, indicating that the
                                // file descriptor represented by the class is
                                // ready to be written to.  However, if
                                // useListener() has been called, it may be
                                // greater than 1, indicating that a set of
                                // file descriptors that the listener is
                                // listening on are all ready to be written to.


                // By default, if a read or write is occurring and a signal
                // interrupts it, the read or write returns with errno set to
                // EINTR and must be retried.  These methods override that
                // behavior.
                void  retryInterruptedReads();
                        // Causes reads to automatically retry if interrupted
                        // by a signal.
                void  dontRetryInterruptedReads();
                        // Causes reads not to automatically retry if
                        // interrupted by a signal.
                void  retryInterruptedWrites();
                        // Causes writes to automatically retry if
                        // interrupted by a signal.  This is the default.
                void  dontRetryInterruptedWrites();
                        // Causes writes not to automatically retry if
                        // interrupted by a signal.
                void  retryInterruptedWaits();
                        // Causes waits to automatically retry if
                        // interrupted by a signal.  This is the default.
                void  dontRetryInterruptedWaits();
                        // Causes waits not to automatically retry if
                        // interrupted by a signal.
                void  retryInterruptedFcntl();
                        // Causes fcntl() to automatically retry if
                        // interrupted by a signal.  This is the default.
                void  dontRetryInterruptedFcntl();
                        // Causes fcntl() not to automatically retry if
                        // interrupted by a signal.
                void  retryInterruptedIoctl();
                        // Causes ioctl() to automatically retry if
                        // interrupted by a signal.  This is the default.
                void  dontRetryInterruptedIoctl();
                        // Causes ioctl() not to automatically retry if
                        // interrupted by a signal.


                // By default, read() will attempt to read the specified number
                // of bytes from the file descriptor, in several passes if
                // necessary.  No single pass will try to read more than
                // SSIZE_MAX bytes.  These methods override that behavior.
                void  allowShortReads();
                        // Causes a read to return the number of bytes that
                        // were read in a single pass from the file descriptor.
                        // Note that reads longer than SSIZE_MAX will always
                        // return SSIZE_MAX or fewer bytes.  This is useful,
                        // for example, when reading from devices which block
                        // rather than returning 0 for EOF.
                void  dontAllowShortReads();
                        // Causes a read to attempt to read the specified
                        // number of bytes from the file descriptor, in several
                        // passes if necessary.

                // By default, write() will attempt to write the specified
                // number of bytes from the file descriptor, in several passes
                // if necessary.  No single pass will try to read more than
                // SSIZE_MAX bytes.  These methods override that behavior.
                void  allowShortWrites();
                        // Causes a write to return the number of bytes that
                        // were written in a single pass from the file
                        // descriptor.  Note that writes longer than SSIZE_MAX
                        // will always return SSIZE_MAX or fewer bytes.  This
                        // is useful, for example, when writing to devices
                        // which block rather than returning 0 for EOF.
                void  dontAllowShortWrites();
                        // Causes a write to attempt to write the specified
                        // number of bytes from the file descriptor, in several
                        // passes if necessary.


                // By default, calls to waitForNonBlockingRead() and
                // waitForNonBlockingWrite() will wait using the select()
                // system call.  These methods override that behavior.
                void  useListener(listener *lstnr);
                        // Causes calls to waitForNonBlockingRead() and
                        // waitForNonBlockingWrite() to in turn call
                        // lstnr->waitForNonBlockingRead() or
                        // lstnr->waitForNonBlockingWrite().
                void  dontUseListener();
                        // Causes calls to waitForNonBlockingRead() and
                        // waitForNonBlockingWrite() to use select().
                        // This is the default.
                listener        *getListener();
                        // Returns the listener set previously by useListener() 
                        // or NULL if none has been set.
                void  useListenerInsideReads();
                void  dontUseListenerInsideReads();
                        // FIXME: document this
                void  useListenerInsideWrites();
                void  dontUseListenerInsideWrites();
                        // FIXME: document this


                virtual bool  passFileDescriptor(int descriptor) const;
                virtual bool  receiveFileDescriptor(int *descriptor) const;

                void  translateByteOrder();
                void  dontTranslateByteOrder();

                int   fcntl(int command, long arg) const;
                int   ioctl(int command, void *arg) const;
                        // Interfaces for performing varions miscellaneous
                        // operations on the file descriptor.

                bool  useNaglesAlgorithm();
                        // Causes small write()'s to be collected up and
                        // sent together when the buffer is full or when
                        // a maximum of 0.2 seconds has gone by.  This is
                        // the default. (enables Nagle's algorithm)
                        //
                        // Returns true on success and false on failure.
                bool  dontUseNaglesAlgorithm();
                        // Causes all write()'s to be sent immediately.
                        // (disables Nagle's algorithm)
                        //
                        // Returns true on success and false on failure.

                bool  getTcpWriteBufferSize(int *size);
                bool  setTcpWriteBufferSize(int size);
                bool  getTcpReadBufferSize(int *size);
                bool  setTcpReadBufferSize(int size);

                const char    *getType() const;

                char          *getPeerAddress() const;
                                // Returns the IP address of the client at
                                // the other end of the connection if 
                                // the filedescriptor is an inet socket or
                                // NULL otherwise.
                                //
                                // Note that the buffer for the address is
                                // allocated internally and must be freed by
                                // the calling program.


                // If an application does many small writes, the overhead of
                // all of those ::write() system calls can slow the application
                // down substantially.  To address that issue, the
                // filedescriptor class can buffer data passed in to any of it's
                // write() methods and only make ::write() system calls when
                // the buffer is full or when it's flushed manually.  Note that
                // when using buffered writes, the data is not actually written
                // to the file descriptor until the buffer is full or until
                // it's flushed manually.
                bool          setWriteBufferSize(ssize_t size) const;
                                // Discards the current write buffer and sets
                                // the size of the write buffer to "size".  A
                                // size of 0 means don't buffer writes at all.
                                // A size less than 0 will return false.
                bool          flushWriteBuffer(long sec, long usec) const;
                                // Causes the contents of the write buffer to
                                // be written to the filedescriptor immediately.


                bool          setReadBufferSize(ssize_t size) const;

                // These methods manipulate or return the close-on-exec status
                // of the file descriptor.  If close-on-exec is false (the
                // default), then the file descriptor will remain open across
                // an execve() call, otherwise it will be closed.
                bool          closeOnExec();
                                // sets the close-on-exec status to true
                bool          dontCloseOnExec();
                                // sets the close-on-exec status to false
                bool          getCloseOnExec();
                                // Returns true if the close-on-exec status
                                // is set true and false otherwise.

        #include <rudiments/private/filedescriptor.h>
};

#ifdef RUDIMENTS_NAMESPACE
}
#endif

#endif