libnet documentation     sixth revision    by gfoot and dwi   04/03/98
______________________________________________________________________

                            |o|   _  _ . 
                            |||-.| |/_)|-
                            '''-'' '`- `-

    libnet is (c) Copyright Chad Catlett and George Foot 1997-1998
______________________________________________________________________


This is the main documentation for libnet.  Most of it is relevant to 
end-users, but some of it is more relevant to driver authors.  You 
should read the instructions in readme.txt before this.



0. Contents
~~~~~~~~~~~
   0 - Contents
   1 - Basic aims
   2 - Functions
   3 - Drivers
   4 - Config files
   5 - Structs
     + a) NET_PACKET
     + b) NET_CHANNEL
     + c) NET_STREAM
     + d) NET_DRIVER
     + e) NET_DRIVERNAME
   6 - Improvements
   7 - Contacting the authors



1. Basic aims
~~~~~~~~~~~~~
   Aims of this project:


   * Make a generic interface to a variety of network drivers

     Such an interface will enable people to write programs with
     networking capabilities without having to tie them down to
     particular types of network. The same program code will be
     able to use any supported network (e.g. Winsock, IPX, 
     serial, ...) neither becoming cluttered nor requiring much
     effort to adapt.


   * Offer basic functionality only

     Restricting the functionality means that more classes of
     network can be implemented and makes it easy for new users
     to get used to.


   * Make addition of new drivers painless

     Naturally, writing a new driver will require an amount of
     research and testing; however, adding new drivers to the
     library should not be a painful process.


   * Start with a core library, and a few sample drivers; invite
     other people to contribute new drivers.

     We can test whether the theory is workable, as well as
     creating sample programs to show people how to use the
     library. Hopefully they will then contribute missing
     drivers.



2. Functions
~~~~~~~~~~~~
   The following functions can be used to communicate with the
   library:


   int net_init();

      This function initialises the library, and should be
      called before any others.


   int net_loadconfig (char *filename);

      This loads a configuration file and invites the various
      drivers to extract information from it.  If `filename' is
      NULL it loads `libnet.cfg' from the program's home 
      directory (as in argv[0]).  If `filename' is a directory
      the file `libnet.cfg' is loaded from that directory.  If
      `filename' is a file, that file is loaded.

      See the separate chapter on config files for full 
      information about them.


   NET_DRIVERNAME *net_getdrivernames (int which);

      This function returns an array of NET_DRIVERNAME structs,
      which contain the reference numbers and names of the
      drivers specified by `which', plus the `nonet' driver and
      a terminating entry with a NULL pointer for the driver 
      name. The list is malloced, and should be freed by the 
      caller.  If the above description is unclear, please see 
      tests/getdrvnm.c for a short example.


   int net_detectdrivers (int which);

      `which' is a combination of the NET_DRIVER_* flags,
      indicating which drivers to attempt to detect.
      NET_DRIVER_ALL can be given to detect all drivers. The
      function returns a similar bitset showing which of drivers
      were actually detected.

      This function can be called once to detect all drivers at
      once, for example, or it can be called several times (e.g.
      once per driver to detect). The return value only shows
      which of the drivers specified were detected; in the
      latter case this is not the entire list of detected
      drivers.


   int net_initdrivers (int which);

      This function operates similarly to the net_detectdrivers
      function, but it initialises the specified drivers rather
      than detecting them. Also, it returns the complete list of
      initialised (i.e. ready-for-use) drivers.


   int net_shutdown();

      Shuts everything down nicely, returning 0 on success. This
      will close any open channels and shut down all initialised
      drivers.


   NET_CHANNEL *net_openchannel(int type);

      Opens a communications channel for use over the specified
      network type. It returns a pointer to the CHANNEL struct
      created, or NULL on error.


   NET_CHANNEL *net_openinputchannel (int type);

      Opens a channel intended for receiving connections.  Only
      one should exist per driver.

      In most respects this is just like a normal channel.  The
      difference as far as the Winsock driver is concerned is 
      that the port is known -- it's either the default value or
      an override value from the config file.  This means users
      don't need to know the port address to connect.


   int net_closechannel(NET_CHANNEL *channel);

      Closes a previously opened channel. This will not
      necessarily inform the remote machine; it will simply
      discard the channel record, after inviting the network
      driver responsible to tidy things up. Returns 0 on
      success.


   int net_assigntarget(NET_CHANNEL *channel, char *target);

      Sets the target of the given channel. The format of the
      target address depends upon the network type being used by
      the channel.


   char *net_getlocaladdress(NET_CHANNEL *channel);

      Returns the channel's recorded local address.  This might
      be the address to which other computers should send data,
      but for some drivers it might not be.  For example, a
      serial port driver would have no way of knowing what port
      the other computer should use.  The Internet sockets 
      drivers have a bit of trouble with this too.


   int net_send(CHANNEL *channel,void *buffer,int size);

      Sends data down a channel, returning zero to indicate
      success or non-zero if an error occurs.


   int net_receive(CHANNEL *channel,void *buffer,int maxsize,char *from);

      Receives data from a channel, maximum `maxsize' bytes,
      storing the data in `buffer' and, if `from' is not NULL,
      putting the source's address in that buffer (which should
      be at least NET_MAX_ADDRESS_LENGTH characters in length).
      Returns the number of bytes received.  0 is valid; there
      was no data to read.  -1 indicates that an error occured.


   int net_query(CHANNEL *channel);

      Returns nonzero if data is ready for reading from the
      given channel.



   The following functions are planned but not implemented:


   NET_STREAM *net_createstream();
      Create new stream.

   int net_stream_addsource (NET_STREAM *stream, int networktype, ...);
      Adds an input source to a stream.

   int net_stream_getpacket (NET_STREAM *stream, NET_PACKET *packet);
      Gets a packet from a stream.

   int net_closestream();
      Closes a stream.



3. Drivers
~~~~~~~~~~
   More information on the drivers can be found in their
   individual documentation.

   At present, the following drivers are implemented and fully
   functional:


   NET_DRIVER_NONET     -       No networking

      This driver will return success codes for everything, but
      won't actually do anything. It's a dummy driver, in case
      no others are available. Target and return addresses are
      meaningless; send an empty string to net_assigntarget.


   NET_DRIVER_WSOCK     -       Winsock driver

      This driver uses the UDP protocol over the internet via
      Windows 95's or Windows 3.11's Winsock.  The target address
      should be given either in IP format as four unsigned chars 
      separated by full stops or in hostname format, and either 
      type of address can optionally be followed by a colon and
      a port number.  If the port number is omitted, the default
      port is used (24785 if not overridden in the config file).
      For example, setting the target to "127.0.0.1:12345" would
      cause data to be looped back to the host, coming in on port
      12345, and setting it to "www.lycos.com" would refer to the
      Lycos web search engine using the default port of 24785.

      With this driver, the return address is awkward to complete.
      The port number is correct but the IP may not be.  More
      information is given in the docs/wsock.txt file; in general
      though, clients should connect to a host using any IP 
      address that refers to the host, and the port given in the 
      return address here.

      Note that DNS resolution will only work if there are some 
      "nameserver = x.x.x.x" lines in the config file.

      For further information please see docs/wsock.txt.
      
    
   NET_DRIVER_SOCKETS   -       Unix sockets driver
   
      This driver is the Unix counterpart to the Winsock driver.  
      It too uses the UDP protocol over the Internet, through
      Berkeley sockets.  The address format is the same; DNS
      resolution is not yet implemented; nor is any form of 
      local IP detection other than the obvious config file 
      check.
      
      This driver has been tested on Linux (i386) and OSF/1
      (DEC Alpha).  To use it, just build Libnet on the machine
      in question; the DOSish drivers will be disabled and this 
      one will be activated.  Caveat particularly emptor on this
      one though, it's far less tested.


   An IPX driver is being worked on by Chad Catlett. DOS-based 
   internet drivers (UDP and TCP) via PPP are being worked on 
   by Ove Kaaven.

   Serial and modem drivers would be much appreciated, as would 
   any other useful drivers. Contact dwi or gfoot (see below for 
   details).



4. Config files
~~~~~~~~~~~~~~~
   The library will work without config files by using hardwired
   defaults, but if you want to use other settings config files
   are what you need.

   The system for config files was designed to allow other non-
   libnet data to be included in the same file.  It uses a 
   similar system to many other packages, like Windows' *.ini
   files.

      - Config files are plain text files

      - They are split into several sections

      - Each section starts with a line containing only a title
        in square brackets (`[',`]') and ends with the next such
        title

      - Inside the sections there may be several settings of the
        form:  option = setting

   In fact what goes on inside the sections is entirely up to the
   driver that owns the section; the above system is recommended
   though.

   libnet drivers won't mind at all if you put garbage at the 
   start or end of the file provided you don't duplicate any of
   its section headings and the trailing garbage has a section
   name separating it from the last libnet driver.

   For full details of what sections each driver looks for and
   which settings within those sections it recognises please see
   the individual driver documentation.

   To load a config file you use the net_loadconfig function,
   passing it one of:

      [a]  a filename (with or without a path) to load
      [b]  a path with no filename
      [c]  NULL

   For [b] and [c] a default filename of `libnet.cfg' will be
   used.  For [c] the file will be checked for in the program's
   home directory (taken from argv[0]).



5. Structs
~~~~~~~~~~
   libnet.h defines three structs - NET_CHANNEL, NET_DRIVER and 
   NET_DRIVERNAME. NET_CHANNEL is used by user programs and 
   internally to hold information about a channel. NET_DRIVER is
   used internally to hold information about network drivers. 
   NET_DRIVERNAME is used to hold a driver's reference number and
   name; an array of these is returned by the net_getdrivernames
   function.


   a) The NET_PACKET struct
   """"""""""""""""""""""""
      This struct holds information about a received packet. 
      The `nettype' field is the numeric code for the network 
      driver which supplied the packet.  The `source' specifies
      where the packet came from, in the network's address 
      format.  `size' hold the size of the packet in bytes, and
      `data' points to the received data.


      typedef struct NET_PACKET {
       int nettype;                    /* network type */
       char *source;                   /* source of data */
       int size;                       /* size in bytes */
       void *data;                     /* pointer to the data */
      } NET_PACKET;



   b) The NET_CHANNEL struct
   """""""""""""""""""""""""
      The user should not use the information in this struct
      directly; it contains the type of connection, a pointer to
      the network driver's NET_DRIVER record, the target address
      (if any), the return address (if any), and a data block
      for the driver's internal use.


      typedef struct NET_CHANNEL {
       int type;                        /* network type */
       NET_DRIVER *driver;              /* network driver */
       char *target_addr;               /* target address */
       char *return_addr;               /* return address */
       void *data;
      } NET_CHANNEL;



   c) The NET_STREAM struct
   """"""""""""""""""""""""
      Again, the fields in this struct aren't for the user's 
      use.



   d) The NET_DRIVER struct
   """"""""""""""""""""""""
      This struct is used as a virtual function table for the
      network drivers. Writing a new driver is as simple as
      writing the necessary functions, creating a NET_DRIVER
      struct containing their addresses, and updating libnet.h.


      typedef struct NET_DRIVER {
       char *name;                                                        /* driver name */
       char *desc;                                                        /* description string */

       int (*detect)();                                                   /* auto-detect function (0 = absent) */
       int (*init)();                                                     /* initialise (0 = okay) */
       int (*exit)();                                                     /* undo the above initialisation */

       int (*init_channel) (NET_CHANNEL *chan);                           /* perform low-level initialisation on a channel */
       int (*init_inputchannel) (NET_CHANNEL *chan);                      /* initialise a channel to receive connections */
       int (*destroy_channel) (NET_CHANNEL *chan);                        /* undo the above initialisation */

       int (*update_target) (NET_CHANNEL *chan);                          /* update private data for change of target address */
       int (*send) (NET_CHANNEL *chan, void *buf, int size);              /* send data */
       int (*recv) (NET_CHANNEL *chan, void *buf, int max, char **from);  /* receive data */
       int (*query) (NET_CHANNEL *chan);                                  /* query for incoming data */

       void (*load_config) (FILE *fp);                                    /* load configuration data */
      } NET_DRIVER;


      This structure is clearly based on Allegro's handling of
      sound, MIDI and graphics drivers. The `name' field should
      be statically initialised. `desc' should be set by the
      `detect' function to reflect information about the driver.

      The `detect' function should return NET_DETECT_YES if it
      thinks the driver can work. If it is not possible to
      detect outright whether the driver can work, it should
      return NET_DETECT_MAYBE. Returning NET_DETECT_NO (zero)
      indicates that without a doubt the driver cannot operate.
      This function should tidy up after itself.

      The `init' function will be called once to initialise the
      driver if the user so requests. This will occur only if
      `detect' has already returned non-zero, and will occur
      before any functions other than `detect' and `init' are
      called. It should return zero to indicate success, or non-
      zero on error.

      The `exit' function exists primarily to undo any
      initalisation events which need undoing, such as memory
      allocation. It should also deallocate any memory other
      functions of this driver have left allocated. No driver
      function calls will follow the `exit' call, apart from
      `detect' or `init', until `init' is called successfully
      again. It should return zero to indicate success, or non-
      zero on error.

      The `init_channel' function invites the driver to prepare
      to send or receive data using the given channel. This
      function should fill in the return_addr field of the
      NET_CHANNEL struct with a suitable value. It may allocate
      memory, pointing the `data' member of the NET_CHANNEL
      struct to it, if it needs to. It should return zero to
      indicate success, or non-zero on error.

      `init_inputchannel' should behave like `init_channel', but
      should make the channel use some sort of default `port' (IP
      speak) so that other computers can connect to the channel
      given only the computer's address.  Config files come in 
      handy here :).

      The `destroy_channel' function asks the driver to undo
      everything the `init_channel' function did. The data block
      should be freed neatly. If memory for the `return_addr'
      was allocated, it should be freed too. It should return
      zero to indicate success, or non-zero on error.

      The `update_target' function will be called primarily
      (only?) after the target address of the channel has been
      changed by a call to net_assigntarget. It should do
      anything it needs to do to be able to use the given
      address (e.g. resolving an internet hostname to an IP
      address), and return zero if it can use the given address,
      or non-zero if it can't.

      The `send', `recv' and `query' functions work in exactly
      the same way as netlib_send, netlib_receive and
      netlib_query.

      The `load_config' function invites the driver to read 
      whatever it wants from the (already open) FILE *.  There
      are a few useful functions declared in "config.h":


        __libnet_internal__seek_section (FILE *fp, char *section);

           This searches the file (from the beginning) for a line
           containing only "[xxxxx]", where "xxxxx" is the string
           `section'.  It leaves the file ready to read the next 
           line.  It returns zero if it finds the section, 
           non-zero if not.

        __libnet_internal__get_setting (FILE *fp, char **option, char **value);

           This reads through the file line by line from the 
           current position until it finds one containing a `='
           sign.  It then sets `*option' to point at whatever is
           left of the sign and `*value' to point at the right 
           hand side.  Leading and trailing whitespace is 
           stripped from both strings, lines beginning with `#'
           are ignored, and a line beginning with `[' aborts the
           function.  It returns zero if it found an option-value
           pair, non-zero if not.


      Technically it doesn't matter what the function reads from
      the file or where it leaves the file position, but it ought
      to stick to its own section.  For an example of using the 
      above two functions see drivers/wsock.c.



   e) The NET_DRIVERNAME struct
   """"""""""""""""""""""""""""
      This struct holds the reference number and name of a network
      driver.

      typedef struct NET_DRIVERNAME {
       int num;                          /* the driver's reference number */
       char *name;                       /* the driver's name */
      } NET_DRIVERNAME;

      When you get your array of these from net_getdrivernames, you
      can step through it like this:

      drivernames = net_getdrivernames (NET_DRIVER_ALL);

      while (drivernames->name) {
       /* do something with the data... like: */
       printf("%d\t%s\n",drivernames->num,drivernames->name);
       /* now increase to point to the next driver */
       drivernames++;
      }

      free (drivernames);

      Note that you should not free the `name' fields; they're static
      strings.



6. Improvements
~~~~~~~~~~~~~~~
   Suggestions for improvement are of course always welcome.


   - Rather than querying all channels one by one, there could
     be a function to query them all at once, perhaps setting a
     flag in the NET_CHANNEL struct if data is waiting. The user
     program could then issue one query call, and afterwards
     just check this flag.


   - Option to open a reliable data channel. Currently, 
     transmission of information is not guarranteed, although 
     some drivers might naturally be reliable. This option would
     force all drivers to guarrantee packet delivery and ordering.
     Doing so might involve software checks, if it's not supported
     by the hardware. Reliable communication will necessarily be 
     slower; it's intended more for file transfers, etc, than real-
     time game communication.



7. Contacting the authors
~~~~~~~~~~~~~~~~~~~~~~~~~
   Authors' email addresses:

      George Foot (gfoot): george.foot@merton.oxford.ac.uk
      Chad Catlett (dwi): catlettc@canvaslink.com


   Before making queries about specific drivers, please see the
   documentation for the driver in question.



