summaryrefslogtreecommitdiff
path: root/comm/Channel.cc
diff options
context:
space:
mode:
authorchatty1993-04-07 11:50:31 +0000
committerchatty1993-04-07 11:50:31 +0000
commitba066c34dde204aa192d03a23a81356374d93731 (patch)
tree39391f6235d2cf8a59a0634ac5ea430cdd21f5d4 /comm/Channel.cc
parent05ab076e1c2a9ca16472f9a6b47b8d22914b3783 (diff)
downloadivy-league-ba066c34dde204aa192d03a23a81356374d93731.zip
ivy-league-ba066c34dde204aa192d03a23a81356374d93731.tar.gz
ivy-league-ba066c34dde204aa192d03a23a81356374d93731.tar.bz2
ivy-league-ba066c34dde204aa192d03a23a81356374d93731.tar.xz
Initial revision
Diffstat (limited to 'comm/Channel.cc')
-rw-r--r--comm/Channel.cc402
1 files changed, 402 insertions, 0 deletions
diff --git a/comm/Channel.cc b/comm/Channel.cc
new file mode 100644
index 0000000..b8178aa
--- /dev/null
+++ b/comm/Channel.cc
@@ -0,0 +1,402 @@
+/*
+ * The Unix Channel
+ *
+ * by Michel Beaudouin-Lafon
+ *
+ * Copyright 1990-1993
+ * Laboratoire de Recherche en Informatique (LRI)
+ *
+ * File descriptors, channels
+ *
+ * $Id$
+ * $CurLog$
+ */
+
+#include "Channel.h"
+#include "MsgBuffer.h"
+#include "error.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/socket.h>
+
+CH_HANDLER UchChannel::ReadHandler = 0;
+CH_HANDLER UchChannel::WriteHandler = 0;
+
+//
+// this section implements refcounts for file descriptors, so that they
+// are closed only when the last occurence is deleted
+//
+static int Refs [NFILE];
+static int Inited = 0;
+
+/*?nodoc?*/
+void
+_AddRef (int fd)
+{
+ if (fd < 0)
+ return;
+ if (! Inited) {
+ Inited = 1;
+ for (int i = 0; i < NFILE; i++)
+ Refs [i] = 0;
+ Refs [0] = Refs [1] = Refs [2] = 1;
+ }
+ Refs [fd]++;
+#ifdef SMART_DEBUG
+ dbgprintf ("AddRef %d -> %d\n", fd, Refs [fd]);
+#endif
+#ifdef _TRACE2
+ _TRACE2 (fd, Refs [fd]);
+#endif
+}
+
+/*?nodoc?*/
+void
+_DelRef (int fd)
+{
+ if (fd < 0)
+ return;
+ if (--Refs [fd] == 0)
+ close (fd);
+#ifdef SMART_DEBUG
+ dbgprintf ("DelRef %d -> %d\n", fd, Refs [fd]);
+#endif
+#ifdef _TRACE2
+ _TRACE2 (fd, Refs [fd]);
+#endif
+}
+
+/*?nodoc?*/
+char*
+UchFilDes :: StrRepr (char* buf)
+{
+ sprintf (buf, "%d", Fd);
+ return buf;
+}
+
+/*?class UchFilDes
+This class implements objects representing Unix file descriptors.
+When the associated file descriptor is -1, the \typ{UchFilDes} is said to be closed,
+else it is said to be opened.
+Because several objects of this class can refer to the same file descriptor,
+the destructor closes the file descriptor only if it is the last object referring to this file descriptor.
+This is implemented with the help of a reference count, the overloading of \fun{operator =}
+and the definition of the constructor \fun{UchFilDes(UchFilDes &)}.
+All member functions described here are inline for maximum efficiency.
+?*/
+
+#ifdef DOC
+
+/*?
+Construct a closed file descriptor.
+?*/
+UchFilDes :: UchFilDes ()
+{ }
+
+/*?
+Construct an open file descriptor for the Unix file descriptor \var{fd}.
+In particular, this makes it possible to pass an integer where a \typ{UchFilDes} is normally expected.
+This is most useful when using Unix file descriptors.
+?*/
+UchFilDes :: UchFilDes (int fd)
+{ }
+
+/*?
+This conversion operator makes it possible to pass a \typ{UchFilDes} argument where
+an integer is expected. This is most useful for system calls.
+?*/
+int
+UchFilDes :: operator int ()
+{ }
+
+/*?
+Return the Unix file descriptor, or -1 if it is closed.
+?*/
+int
+UchFilDes :: FilDes ()
+{ }
+
+/*?
+Open the object on file descriptor \var{fd}.
+If it was already opened, it is closed first.
+?*/
+void
+UchFilDes :: Open (int fd)
+{ }
+
+/*?
+Close a file descriptor. If it is opened, this actually closes the file descriptor
+only if it was the last reference to it.
+\fun{Close} is automatically called by the destructor.
+?*/
+void
+UchFilDes :: Close ()
+{ }
+
+/*?
+Return TRUE if the object is opened, FALSE else.
+?*/
+bool
+UchFilDes :: Opened ()
+{ }
+
+/*?
+Read at most \var{n} bytes into buffer \var{b} and return the number of bytes actually read.
+This is the Unix \fun{read} system call.
+For efficiency, this function does not test whether the file descriptor is opened.
+?*/
+int
+UchFilDes :: Read (byte* b, int n)
+{ }
+
+/*?
+Write at most \var{n} bytes of buffer \var{b} and return the number of bytes actually written.
+This is the Unix \fun{write} system call.
+For efficiency, this function does not test whether the file descriptor is opened.
+?*/
+int
+UchFilDes :: Write (byte* b, int n)
+{ }
+
+#endif /* DOC */
+
+/*?class UchChannel
+A \typ{UchChannel} is basically a file descriptor, with more strict semantics than a \typ{UchFilDes}.
+A channel is immutable: once initialized, it cannot change its file descriptor.
+It has a mode, of type \typ{^{IOMODE}}, with possible values
+\var{IONone}, \var{IORead}, \var{IOWrite}, \var{IOReadWrite},
+\var{IOSelect}, \var{IOReadSelect}, \var{IOWriteSelect}, \var{IOAll}.
+\index{IOMODE :: IONone}\index{IOMODE :: IORead}\index{IOMODE :: IOWrite}\index{IOMODE :: IOReadWrite}\index{IOMODE :: IOSelect}\index{IOMODE :: IOReadSelect}\index{IOMODE :: IOWriteSelect}\index{IOMODE :: IOAll}
+Before being initialized, a UchChannel.has mode \var{IONone} and is said to be closed.
+
+A UchChannel.has a number of virtual functions.
+The destructor is virtual; this is useful for classes that store pointers to objects
+of a class derived from \typ{UchChannel} (like in the class \typ{UchSocket}).
+The functions \fun{HandleSelect}, \fun{HandleRead} and \fun{HandleWrite}
+are intended to give a channel the ability to automatically handle input/output,
+for instance for use with the \fun{select} system call.
+Such capabilities are used and thus illustrated in class \typ{UchMultiplexer}.
+
+The class \typ{^{pUchChannel}} implements smart pointers to channels.
+Smart pointers behave like pointers but they manage a reference count on the
+pointed to objects for an automatic reclaim of dynamically allocated objects.
+This is very useful especially in the class \typ{UchMultiplexer} because arrays of
+(smart) pointers to buffers are used.
+?*/
+
+/*?
+Construct a closed channel.
+?*/
+UchChannel :: UchChannel ()
+: Fd (),
+ Mode (IONone)
+{
+}
+
+/*?
+Construct an open channel on file descriptor \var{fd} with mode \var{io}.
+?*/
+UchChannel :: UchChannel (int fd, IOMODE io)
+: Fd (fd),
+ Mode (io)
+{
+}
+
+/*?nodoc?*/
+UchChannel :: UchChannel (const UchChannel& ch)
+: Fd (ch.Fd),
+ Mode (ch.Mode)
+{
+}
+
+#ifdef DOC
+/*?
+Open the channel on file descriptor \var{fd}.
+A channel can only be opened once, and it cannot be closed.
+This function is useful when the channel was created with the default contructor,
+in order to associate a file descriptor to it.
+Because a channel is immutable, this can be done only once.
+?*/
+void
+UchChannel :: Open (int fd)
+{ }
+
+/*?nextdoc?*/
+IOMODE
+UchChannel :: IOMode ()
+{
+}
+
+/*?
+Return/set the mode of the channel.
+?*/
+void
+UchChannel :: SetMode (IOMODE io)
+{ }
+
+#endif /* DOC */
+
+
+/*?nodoc?*/
+UchChannel :: ~UchChannel ()
+{
+ // nothing special here
+}
+
+/*?nodoc?*/
+UchChannel*
+UchChannel :: Copy () const
+{
+ return new UchChannel (*this);
+}
+
+/*?nextdoc?*/
+void
+UchChannel :: AddNotify (UchMultiplexer&)
+{
+}
+
+/*?
+These virtual functions are called whenever a channel is added to (resp. removed from)
+a multiplexer. The default implementation does nothing.
+?*/
+void
+UchChannel :: RemoveNotify (UchMultiplexer&)
+{
+}
+
+/*?nextdoc?*/
+void
+UchChannel :: HandleWrite ()
+{
+ if (! UchChannel::WriteHandler)
+ Error (ErrFatal, "UchChannel::HandleWrite", ErrorTable [ErrShouldImplement]);
+ else
+ (* UchChannel::WriteHandler) (this);
+}
+
+/*?
+These virtual functions are called by a \typ{UchMultiplexer} when data can be written
+to the channel or read from the channel.
+They are are normally redefined in derived classes.
+The default implementation is the following:
+if the static members \var{UchChannel::ReadHandler} (resp. \var{UchChannel::WriteHandler}) is set,
+it is called by \fun{HandleRead} (resp. \fun{HandleWrite});
+else an error message is output.
+These members are public so that they can be assigned directly at any time.
+By default they are not set.
+The type of these static members is \typ{^{CH_HANDLER}}:
+pointer to void function with one argument of type \typ{UchChannel*}.
+?*/
+void
+UchChannel :: HandleRead ()
+{
+ if (! UchChannel::ReadHandler)
+ Error (ErrFatal, "UchChannel::HandleRead", ErrorTable [ErrShouldImplement]);
+ else
+ (* UchChannel::ReadHandler) (this);
+}
+
+/*?
+This virtual function is called by a \typ{UchMultiplexer} before making a \fun{select} call.
+It is intended to handle any background task or buffered input/output associated to the channel.
+If it returns TRUE, the channel set scan functions will return before performing the select call.
+See the class \typ{UchMultiplexer} for more details.
+The default implementation does nothing but returning FALSE.
+?*/
+bool
+UchChannel :: HandleSelect ()
+{
+ return FALSE;
+}
+
+#ifdef DOC
+
+/*?nextdoc?*/
+int
+UchChannel :: Read (byte* b, int n)
+{ }
+
+/*?
+The Unix \fun{read} and \fun{write} system calls, as in class \typ{UchFilDes}.
+?*/
+int
+UchChannel :: Write (byte* b, int n)
+{ }
+
+#endif /* DOC */
+
+/*?nextdoc?*/
+int
+UchChannel :: Read (UchMsgBuffer& b)
+{
+ int l = b.FreeLength ();
+ if (! l)
+ return -2;
+ int n = read (Fd, (char*) b.Free (), l);
+ if (n > 0)
+ b.More (n);
+ return n;
+}
+
+/*?
+The Unix \fun{read} and \fun{write} system calls applied to a \typ{UchMsgBuffer}.
+They return the number of bytes transferred, -1 if a system error occurred,
+-2 if the buffer is empty when writing or full when reading.
+?*/
+int
+UchChannel :: Write (UchMsgBuffer& b)
+{
+ int l = b.BufLength ();
+ if (! l)
+ return -2;
+ int n = write (Fd, (const char*) b.Buffer (), l);
+ if (n > 0)
+ b.Flush (n);
+ return n;
+}
+
+/*?nextdoc?*/
+bool
+UchChannel :: ReadBuffer (UchMsgBuffer& b)
+{
+ int n;
+ errno = 0;
+ while ((n = Read (b)) > 0);
+ return bool (n == -2);
+}
+
+/*?
+These functions repeatedly call \fun{Read} or \fun{Write} until the whole buffer is
+transferred or a system error occurred. In case of an error, they return FALSE, else TRUE.
+?*/
+bool
+UchChannel :: WriteBuffer (UchMsgBuffer& b)
+{
+ int n;
+ errno = 0;
+ while ((n = Write (b)) > 0);
+ return bool (n == -2);
+}
+
+/*?
+This function is intended for sockets that accept connections.
+It returns a dynamically allocated new channel that is opened on the accepted connection.
+If it fails, it returns 0.
+?*/
+UchChannel*
+UchChannel :: Accept ()
+{
+ int fd;
+
+ errno = 0;
+ if (Fd < 0)
+ return (UchChannel*) 0;
+
+ if ((fd = accept (Fd, 0, 0)) < 0)
+ return (UchChannel*) 0;
+
+ return new UchChannel (fd);
+}
+