Annotation of libwww/Library/src/HTNet.html, revision 2.43

2.1       frystyk     1: <HTML>
                      2: <HEAD>
2.36      eric        3:   <!-- Changed by: Henrik Frystyk Nielsen, 13-Apr-1996 -->
2.37      frystyk     4:   <!-- Changed by: Eric Prud'hommeaux, 14-May-1996 -->
2.43    ! frystyk     5:   <!-- Changed by: Henrik Frystyk Nielsen,  5-Jul-1996 -->
        !             6:   <TITLE>W3C Reference Library libwww HTNet Class</TITLE>
2.1       frystyk     7: </HEAD>
                      8: <BODY>
2.43    ! frystyk     9: <H1>
        !            10:   The Net Class
2.36      eric       11: </H1>
2.5       frystyk    12: <PRE>
                     13: /*
2.8       frystyk    14: **     (c) COPYRIGHT MIT 1995.
2.5       frystyk    15: **     Please first read the full copyright statement in the file COPYRIGH.
                     16: */
                     17: </PRE>
2.36      eric       18: <P>
2.38      frystyk    19: The Net class manages information related to a "thread" in libwww. As libwww
                     20: threads are not really threads but a notion of using interleaved, non-blocking
                     21: I/O for accessing data objects from the network (or local file system), they
                     22: can be used on any platform with or without support for native threads. In
                     23: the case where you have an application using real threads the Net class is
                     24: simply a object maintaining links to all other objects involved in serving
                     25: the request. If you are using the libwww pseudo threads then the Net object
                     26: contains enough information to stop and start a request based on which BSD
                     27: sockets are ready. In practise this is of course transparent to the application
                     28: - this is just to explain the difference.
                     29: <P>
                     30: When a <A HREF="HTReq.html">Request object</A> is passed to the Library ,
                     31: the core creates a new HTNet object pr <A HREF="HTChannl.html">channel</A>
                     32: used by the request. In many cases a request only uses a single
                     33: <A HREF="HTChannl.html">channel object </A>but for example FTP requests use
                     34: at least two - one for the control connection and one for the data connection.
                     35: <P>
                     36: You can find more information about the libwww pseudo thread model in the
                     37: <A HREF="../User/Architecture/"> Multithread Specifications</A>.
2.36      eric       38: <P>
                     39: This module is implemented by <A HREF="HTNet.c">HTNet.c</A>, and it is a
                     40: part of the <A HREF="http://www.w3.org/pub/WWW/Library/">W3C Reference
                     41: Library</A>.
2.1       frystyk    42: <PRE>
2.17      frystyk    43: #ifndef HTNET_H
                     44: #define HTNET_H
2.1       frystyk    45: </PRE>
2.36      eric       46: <P>
                     47: The <CODE>HTNet</CODE> object is the core of the request queue management.
                     48: This object contains information about the socket descriptor, the input read
                     49: buffer etc. required to identify and service a request.
2.1       frystyk    50: <PRE>
2.18      frystyk    51: typedef struct _HTNet HTNet;
2.34      frystyk    52: 
2.36      eric       53: #include "HTEvent.h"
2.34      frystyk    54: #include "HTReq.h"
                     55: #include "HTTrans.h"
                     56: #include "HTHost.h"
                     57: #include "HTChannl.h"
                     58: #include "HTDNS.h"
2.1       frystyk    59: </PRE>
2.36      eric       60: <H2>
2.43    ! frystyk    61:   <A NAME="callout">Before and After Filters</A>
2.36      eric       62: </H2>
                     63: <P>
2.43    ! frystyk    64: Filter functions can be registered to be called <EM>before</EM> and
2.36      eric       65: <EM>after</EM> a request has either been started or has terminated. The following
                     66: functions are the generic registration mechanisms where we use lists as the
2.43    ! frystyk    67: basic data container. Then there is two methods for binding a list of filter
2.36      eric       68: functions to the set which is called <EM>before</EM> and to the set set which
                     69: is called <EM>after</EM>
                     70: <P>
2.43    ! frystyk    71: In both cases there can be more than one filter function which are called
        !            72: on turn and each filter function can be associated with a status code of
        !            73: the request. For example one filter function can be registered for
2.38      frystyk    74: <CODE>HT_LOADED</CODE>, another for <CODE>HT_ERROR</CODE> etc.
2.36      eric       75: <H3>
2.43    ! frystyk    76:   Register a Net Filter
2.36      eric       77: </H3>
                     78: <P>
2.43    ! frystyk    79: Several filters can be registered in which case all of them are called in
        !            80: the reverse order of which they were registered (last one first). We name
        !            81: the calling mechansm of calling the filter for the <EM>before</EM> loop and
        !            82: the <EM>after</EM> loop.
2.36      eric       83: <P>
2.43    ! frystyk    84: In case the filter function is registered as being called <EM>after</EM>
        !            85: the request has terminated the result of the request is passed to the function.
2.36      eric       86: The status signifies which call back function to call depending of the result
                     87: of the request. This can be
2.17      frystyk    88: <DL>
2.36      eric       89:   <DT>
                     90:     HT_ERROR
                     91:   <DD>
                     92:     An error occured
                     93:   <DT>
                     94:     HT_LOADED
                     95:   <DD>
                     96:     The document was loaded
                     97:   <DT>
                     98:     HT_NO_DATA
                     99:   <DD>
                    100:     OK, but no data
                    101:   <DT>
2.43    ! frystyk   102:     HT_NO_ACCESS
        !           103:   <DD>
        !           104:     The request could not be succeeded due to lack of credentials
        !           105:   <DT>
        !           106:     HT_NO_PROXY_ACCESS
        !           107:   <DD>
        !           108:     The request could not be succeeded due to lack of credentials for accessing
        !           109:     an intermediate proxy
        !           110:   <DT>
2.36      eric      111:     HT_RETRY
                    112:   <DD>
                    113:     Retry request after at a later time
                    114:   <DT>
2.40      frystyk   115:     HT_PERM_REDIRECT
2.36      eric      116:   <DD>
2.40      frystyk   117:     The request has been permanently redirected and we send back the new URL
                    118:   <DT>
                    119:     HT_TEMP_REDIRECT
                    120:   <DD>
                    121:     The request has been temporaryly redirected and we send back the new URL
2.36      eric      122:   <DT>
                    123:     HT_ALL
                    124:   <DD>
                    125:     All of above
2.17      frystyk   126: </DL>
2.36      eric      127: <P>
2.43    ! frystyk   128: Any filter can return any code it likes, but <B>IF NOT</B> the code is
        !           129: <EM>HT_OK</EM>, then the filter loop is stopped. If we are in the
        !           130: <EM>before</EM> loop and a filter returns anything else than <EM>HT_OK</EM>
2.36      eric      131: then we immediately jump to the <EM>after</EM> loop <B>passing</B> the last
                    132: return code from the <EM>before</EM> loop.
2.1       frystyk   133: <PRE>
2.35      frystyk   134: typedef int HTNetCallback (HTRequest * request, void * param, int status);
2.17      frystyk   135: 
2.35      frystyk   136: extern BOOL HTNetCall_add (HTList * list, HTNetCallback *cbf,
                    137:                          void * param, int status);
2.9       frystyk   138: </PRE>
2.36      eric      139: <H3>
2.43    ! frystyk   140:   Delete a single Filter
2.36      eric      141: </H3>
                    142: <P>
2.43    ! frystyk   143: Removes a filter function from a list
2.9       frystyk   144: <PRE>
2.24      frystyk   145: extern BOOL HTNetCall_delete (HTList * list, HTNetCallback *cbf);
2.1       frystyk   146: </PRE>
2.36      eric      147: <H3>
2.43    ! frystyk   148:   Delete a list of Filters
2.36      eric      149: </H3>
                    150: <P>
2.24      frystyk   151: Unregisters all call back functions in the list
                    152: <PRE>
                    153: extern BOOL HTNetCall_deleteAll (HTList * list);
                    154: </PRE>
2.36      eric      155: <H3>
2.43    ! frystyk   156:   Call List of Registered Filter Functions
2.36      eric      157: </H3>
                    158: <P>
2.43    ! frystyk   159: Call all the filters registered in the list <I>IF</I> not the status is
        !           160: <CODE>HT_IGNORE</CODE>. The filters are called in the order of which they
        !           161: were registered. At the moment an application filter is called, it can free
        !           162: the request object - it is no longer used by the Library. Returns what the
        !           163: last filter returns
2.24      frystyk   164: <PRE>
                    165: extern int HTNetCall_execute (HTList * list, HTRequest * request, int status);
                    166: </PRE>
2.36      eric      167: <H3>
2.43    ! frystyk   168:   Handling BEFORE Filters
2.36      eric      169: </H3>
                    170: <P>
2.43    ! frystyk   171: Global set of filters BEFORE the request is issued. The list can be NULL.
2.24      frystyk   172: <PRE>
2.35      frystyk   173: extern BOOL HTNetCall_addBefore        (HTNetCallback *cbf, void * param, int status);
2.42      frystyk   174: extern BOOL HTNetCall_deleteBefore (HTNetCallback * cbf);
                    175: 
2.24      frystyk   176: extern BOOL HTNet_setBefore    (HTList * list);
                    177: extern HTList * HTNet_before   (void);
2.42      frystyk   178: 
2.24      frystyk   179: extern int HTNet_callBefore    (HTRequest *request, int status);
                    180: </PRE>
2.36      eric      181: <H3>
2.43    ! frystyk   182:   Handling AFTER Filters
2.36      eric      183: </H3>
                    184: <P>
2.43    ! frystyk   185: Global set of filters AFTER the request is issued. The list can be NULL
2.10      frystyk   186: <PRE>
2.35      frystyk   187: extern BOOL HTNetCall_addAfter (HTNetCallback *cbf, void * param, int status);
2.42      frystyk   188: extern BOOL HTNetCall_deleteAfter (HTNetCallback * cbf);
                    189: 
2.24      frystyk   190: extern BOOL HTNet_setAfter     (HTList * list);
                    191: extern HTList * HTNet_after    (void);
2.42      frystyk   192: 
2.24      frystyk   193: extern int HTNet_callAfter     (HTRequest *request, int status);
2.10      frystyk   194: </PRE>
2.36      eric      195: <H2>
2.43    ! frystyk   196:   Socket Resource Management
2.36      eric      197: </H2>
                    198: <P>
                    199: The request queue ensures that no more than a fixed number of TCP connections
                    200: are open at the same time. If more requests are handed to the Library, they
                    201: are put into the pending queue and initiated when sockets become free.
                    202: <H3>
                    203:   Number of Simultanous open TCP connections
                    204: </H3>
                    205: <P>
                    206: Set the max number of simultanous sockets. The default value is HT_MAX_SOCKETS
                    207: which is 6. The number of persistent connections depend on this value as
                    208: a deadlock can occur if all available sockets a persistent (see the
                    209: <A HREF="HTDNS.html">DNS Manager</A> for more information on setting the
                    210: number of persistent connections). The number of persistent connections can
                    211: never be more than the max number of sockets-2, so letting newmax=2 prevents
                    212: persistent sockets.
2.1       frystyk   213: <PRE>
2.17      frystyk   214: extern BOOL HTNet_setMaxSocket (int newmax);
                    215: extern int  HTNet_maxSocket (void);
2.1       frystyk   216: </PRE>
2.36      eric      217: <H3>
2.43    ! frystyk   218:   Socket Counters
        !           219: </H3>
        !           220: <PRE>
        !           221: extern void HTNet_increaseSocket (void);
        !           222: extern void HTNet_decreaseSocket (void);
        !           223: 
        !           224: extern int HTNet_availableSockets (void);
        !           225: </PRE>
        !           226: <H3>
        !           227:   Persistent Socket Counters
        !           228: </H3>
        !           229: <PRE>
        !           230: extern void HTNet_increasePersistentSocket (void);
        !           231: extern void HTNet_decreasePersistentSocket (void);
        !           232: 
        !           233: extern int HTNet_availablePersistentSockets (void);
        !           234: </PRE>
        !           235: <H3>
        !           236:   Any Ongoing Connections?
        !           237: </H3>
        !           238: <P>
        !           239: Returns whether there are active requests. Idle persistent sockets do not
        !           240: count as active.
        !           241: <PRE>
        !           242: extern BOOL HTNet_isIdle (void);
        !           243: </PRE>
        !           244: <H3>
2.36      eric      245:   List Active Queue
                    246: </H3>
                    247: <P>
                    248: Returns the list of active requests that are currently having an open connection.
                    249: Returns list of HTNet objects or NULL if error.
2.1       frystyk   250: <PRE>
2.17      frystyk   251: extern HTList *HTNet_activeQueue (void);
2.22      frystyk   252: extern BOOL HTNet_idle (void);
2.29      frystyk   253: </PRE>
2.36      eric      254: <H3>
                    255:   Are we Active?
                    256: </H3>
                    257: <P>
                    258: We have some small functions that tell whether there are registered requests
                    259: in the Net manager. There are tree queues: The <EM>active</EM>, the
                    260: <EM>pending</EM>, and the <EM>persistent</EM>. The <EM>active</EM> queue
                    261: is the set of requests that are actively sending or receiving data. The
                    262: <EM>pending</EM> is the requests that we have registered but which are waiting
                    263: for a free socket. The <EM>Persistent</EM> queue are requets that are waiting
                    264: to use the same socket in order to save network resoures (if the server
                    265: understands persistent connections).
                    266: <H4>
                    267:   Active Reqeusts?
                    268: </H4>
                    269: <P>
2.29      frystyk   270: Returns whether there are requests in the <EM>active</EM> queue or not
                    271: <PRE>
                    272: extern BOOL HTNet_idle (void);
                    273: </PRE>
2.36      eric      274: <H4>
                    275:   Registered Requests?
                    276: </H4>
                    277: <P>
                    278: Returns whether there are requests registered in any of the lists or not
2.29      frystyk   279: <PRE>
                    280: extern BOOL HTNet_isEmpty (void);
2.1       frystyk   281: </PRE>
2.36      eric      282: <H3>
                    283:   List Pending Queue
                    284: </H3>
                    285: <P>
                    286: Returns the list of pending requests that are waiting to become active. Returns
                    287: list of HTNet objects or NULL if error
2.1       frystyk   288: <PRE>
2.17      frystyk   289: extern HTList *HTNet_pendingQueue (void);
2.1       frystyk   290: </PRE>
2.36      eric      291: <H2>
2.37      frystyk   292:   Creation and Deletion Methods
2.36      eric      293: </H2>
                    294: <P>
2.37      frystyk   295: The Net object is intended to live as long as the request is still active.
                    296: In that regard it is very similar to the <A HREF="HTReq.html">Request Object
                    297: </A>. However, the main difference is that a Net object represents a "thread"
                    298: in the Library and a request may have multiple "threads" - an example is
                    299: a FTP request which has a thread to handle the control connection and one
                    300: to handle the data connections.
                    301: <H3>
                    302:   Create a new Object
                    303: </H3>
                    304: <P>
                    305: If we have more than HTMaxActive connections already then put this into the
                    306: pending queue, else start the request by calling the call back function
                    307: registered with this access method. Returns YES if OK, else NO
2.27      frystyk   308: <PRE>
2.28      frystyk   309: extern BOOL HTNet_newClient (HTRequest * request);
2.27      frystyk   310: </PRE>
2.36      eric      311: <P>
                    312: You can create a new HTNet object as a new request to be handled. If we have
                    313: more than HTMaxActive connections already then return NO. Returns YES if
                    314: OK, else NO
2.17      frystyk   315: <PRE>
2.39      frystyk   316: extern BOOL HTNet_newServer (HTRequest * request, HTNet * net, char *access);
2.26      frystyk   317: </PRE>
2.36      eric      318: <P>
2.27      frystyk   319: And you can create a plain new HTNet object using the following method:
2.26      frystyk   320: <PRE>
2.39      frystyk   321: extern HTNet * HTNet_new (SOCKET sockfd, HTRequest * request);
2.20      frystyk   322: </PRE>
2.36      eric      323: <H3>
2.37      frystyk   324:   Duplicate an existing Object
2.36      eric      325: </H3>
                    326: <P>
                    327: Creates a new HTNet object as a duplicate of the same request. Returns YES
                    328: if OK, else NO.
2.20      frystyk   329: <PRE>
2.30      frystyk   330: extern HTNet * HTNet_dup (HTNet * src);
2.17      frystyk   331: </PRE>
2.37      frystyk   332: <H3>
2.43    ! frystyk   333:   Launch a Net Object
        !           334: </H3>
        !           335: <P>
        !           336: Start a Net obejct by calling the protocol module.
        !           337: <PRE>extern BOOL HTNet_start (HTNet * net);
        !           338: </PRE>
        !           339: <H3>
2.37      frystyk   340:   Delete an Object
                    341: </H3>
                    342: <P>
                    343: Deletes the HTNet object from the list of active requests and calls any
                    344: registered call back functions IF not the status is HT_IGNORE. This is used
                    345: if we have internal requests that the app doesn't know about. We also see
                    346: if we have pending requests that can be started up now when we have a socket
2.43    ! frystyk   347: free. The filters are called in the reverse order of which they were registered
        !           348: (last one first);
2.37      frystyk   349: <PRE>
                    350: extern BOOL HTNet_delete (HTNet * me, int status);
                    351: </PRE>
                    352: <H3>
                    353:   Delete ALL HTNet Objects
                    354: </H3>
                    355: <P>
                    356: Deletes all HTNet object that might either be active or pending We DO NOT
                    357: call the call back functions - A crude way of saying goodbye!
                    358: <PRE>
                    359: extern BOOL HTNet_deleteAll (void);
                    360: </PRE>
2.36      eric      361: <H2>
2.38      frystyk   362:   Net Class Methods
2.36      eric      363: </H2>
                    364: <H3>
                    365:   Make an Object Wait
                    366: </H3>
                    367: <P>
                    368: Let a net object wait for a persistent socket. It will be launched from the
                    369: HTNet_delete() function when the socket gets free.
2.19      frystyk   370: <PRE>
                    371: extern BOOL HTNet_wait (HTNet *net);
                    372: </PRE>
2.36      eric      373: <H3>
                    374:   Priority Management
                    375: </H3>
                    376: <P>
                    377: Each HTNet object is created with a priority which it inherits from the
                    378: <A HREF="HTReq.html">Request manager</A>. However, in some stuations it is
                    379: useful to be to change the current priority after the request has been started.
                    380: These two functions allow you to do this. The effect will show up the first
                    381: time (which might be imidiately) the socket blocks and control returns to
                    382: the event loop. Also have a look at how you can do this before the request
                    383: is issued in the <A HREF="HTReq.html">request manager</A>.
2.23      frystyk   384: <PRE>
                    385: extern HTPriority HTNet_priority (HTNet * net);
                    386: extern BOOL HTNet_setPriority (HTNet * net, HTPriority priority);
                    387: </PRE>
2.36      eric      388: <H3>
                    389:   Persistent Connections
                    390: </H3>
                    391: <P>
                    392: You can set a Net object to handle persistent connections for example using
                    393: HTTP, NNTP, or FTP. You can control whether a Net object supports persistent
                    394: connections or not using this function.
2.33      frystyk   395: <PRE>
                    396: extern BOOL HTNet_persistent (HTNet * net);
                    397: </PRE>
2.36      eric      398: <P>
                    399: You can set or disable a Net object supporting persistent connections using
                    400: this function:
2.33      frystyk   401: <PRE>
2.43    ! frystyk   402: extern BOOL HTNet_setPersistent (HTNet *           net,
        !           403:                                  BOOL              persistent,
        !           404:                                  HTTransportMode   mode);
2.33      frystyk   405: </PRE>
2.36      eric      406: <H3>
                    407:   Kill a Request
                    408: </H3>
                    409: <P>
                    410: Kill the request by calling the call back function with a request for closing
                    411: the connection. Does not remove the object. This is done by HTNet_delete()
                    412: function which is called by the load routine. Returns OK if success, NO on
                    413: error
2.1       frystyk   414: <PRE>
2.17      frystyk   415: extern BOOL HTNet_kill (HTNet * me);
2.1       frystyk   416: </PRE>
2.36      eric      417: <H3>
                    418:   Kill ALL requests
                    419: </H3>
                    420: <P>
                    421: Kills all registered (active+pending) requests by calling the call back function
                    422: with a request for closing the connection. We do not remove the HTNet object
                    423: as it is done by HTNet_delete(). Returns OK if success, NO on error
2.1       frystyk   424: <PRE>
2.17      frystyk   425: extern BOOL HTNet_killAll (void);
2.28      frystyk   426: </PRE>
2.36      eric      427: <H3>
                    428:   Create Input and Output Streams
                    429: </H3>
                    430: <P>
                    431: You create the input stream and bind it to the channel using the following
                    432: methods. Please read the description in the
                    433: <A HREF="HTIOStream.html">HTIOStream module</A> on the parameters
                    434: <EM>target</EM>, <EM>param</EM>, and <EM>mode</EM>. Both methods return YES
                    435: if OK, else NO.
2.34      frystyk   436: <PRE>
                    437: extern HTInputStream * HTNet_getInput (HTNet * net, HTStream * target,
                    438:                                       void * param, int mode);
                    439: 
                    440: extern HTOutputStream * HTNet_getOutput (HTNet * net, void * param, int mode);
                    441: </PRE>
2.37      frystyk   442: <H3>
                    443:   Net Context Descriptor
                    444: </H3>
2.36      eric      445: <P>
2.37      frystyk   446: Just like the <A HREF="../../../../WWW/Library/src/HTReq.html#context">request
                    447: object</A>, a net object can be assigned a context which keeps track of context
                    448: dependent information. The Library does not use this information nor does
                    449: it depend on it but it allows the application to customize a net object to
                    450: specific uses.
                    451: <PRE>extern BOOL HTNet_setContext (HTNet * net, void * context);
                    452: extern void * HTNet_context (HTNet * net);
                    453: </PRE>
2.36      eric      454: <H3>
                    455:   Socket Descriptor
                    456: </H3>
2.28      frystyk   457: <PRE>
                    458: extern BOOL HTNet_setSocket (HTNet * net, SOCKET sockfd);
                    459: extern SOCKET HTNet_socket (HTNet * net);
2.17      frystyk   460: </PRE>
2.36      eric      461: <H3>
2.39      frystyk   462:   The Request Object
                    463: </H3>
                    464: <P>
2.43    ! frystyk   465: The <A HREF="HTReq.html">Request object</A> is normally set up automatically
        !           466: but can be changed at a later time.
2.39      frystyk   467: <PRE>
                    468: extern BOOL HTNet_setRequest (HTNet * net, HTRequest * request);
                    469: extern HTRequest * HTNet_request (HTNet * net);
                    470: </PRE>
                    471: <H3>
2.36      eric      472:   The Transport Object
                    473: </H3>
                    474: <P>
2.34      frystyk   475: The <A HREF="HTTransport.html">transport object</A> is normally set up
                    476: automatically but can be changed at a later time.
2.17      frystyk   477: <PRE>
2.34      frystyk   478: extern BOOL HTNet_setTransport (HTNet * net, HTTransport * tp);
                    479: extern HTTransport * HTNet_transport (HTNet * net);
                    480: </PRE>
2.36      eric      481: <H3>
                    482:   The Channel Object
                    483: </H3>
2.34      frystyk   484: <PRE>
                    485: extern BOOL HTNet_setChannel (HTNet * net, HTChannel * channel);
                    486: extern HTChannel * HTNet_channel (HTNet * net);
                    487: </PRE>
2.36      eric      488: <H3>
                    489:   The Host Object
                    490: </H3>
2.34      frystyk   491: <PRE>
                    492: extern BOOL HTNet_setHost (HTNet * net, HTHost * host);
                    493: extern HTHost * HTNet_host (HTNet * net);
                    494: </PRE>
2.36      eric      495: <H3>
                    496:   The DNS Object
                    497: </H3>
2.43    ! frystyk   498: <P>
        !           499: The DNS object keeps track of the DNS entries that we have already checked
        !           500: out.
2.34      frystyk   501: <PRE>
                    502: extern BOOL HTNet_setDns (HTNet * net, HTdns * dns);
                    503: extern HTdns * HTNet_dns (HTNet * net);
                    504: </PRE>
2.43    ! frystyk   505: <P>
        !           506: If we are talking to a multi-homed host then we may connect to any of the
        !           507: homes. In that case we store the current home in the Net object so that we
        !           508: can query about it later.
2.41      frystyk   509: <PRE>
                    510: extern int HTNet_home (HTNet * net);
                    511: </PRE>
2.34      frystyk   512: <PRE>
2.17      frystyk   513: #endif /* HTNET_H */
2.1       frystyk   514: </PRE>
2.36      eric      515: <P>
                    516:   <HR>
2.34      frystyk   517: <ADDRESS>
2.43    ! frystyk   518:   @(#) $Id: HTNet.html,v 2.42 1996/08/08 02:16:55 frystyk Exp $
2.34      frystyk   519: </ADDRESS>
2.36      eric      520: </BODY></HTML>

Webmaster