
/*********************************************************************/
/*                                                                   */
/*     High Level Protokoll : TCP                                    */
/*                                                                   */
/*      Version 0.1                      vom 28. Dezember 1996       */
/*                                                                   */
/*********************************************************************/


#include <tos.h>
#include <stdio.h>
#include <string.h>

#include "transprt.h"
#include "layer.h"


/* Change these values to reflect the compile date of this module.             */
/* M_YEAR is (year - 1980), M_MONTH is the month from 1 (Jan.) to 12 (Dec.),   */
/* and M_DAY is day of month (1 ... 31)                                        */
#define  M_YEAR    16
#define  M_MONTH   12
#define  M_DAY     28


long          get_stik_cookie (void);
int16         install (void);
int16  cdecl  my_TCP_open (uint32 rem_host, int16 rem_port, int16 tos, uint16 size);
int16  cdecl  my_TCP_close (int16 connec, int16 timeout);
int16  cdecl  my_TCP_send (int16 connec, char *buffer, int16 length);
int16  cdecl  my_TCP_wait_state (int16 connec, int16 state, int16 timeout);
int16  cdecl  my_TCP_ack_wait (int16 connec, int16 timeout);
int16  cdecl  my_CNkick (int16 connec);
int16  cdecl  my_CNbyte_count (int16 connec);
int16  cdecl  my_CNget_char (int16 connec);
NDB *  cdecl  my_CNget_NDB (int16 connec);
int16  cdecl  my_CNget_block (int16 connec, char *buffer, int16 length);
CIB *  cdecl  my_CNgetinfo (int16 connec);
int16  cdecl  TCP_handler (IP_DGRAM *dgram);


DRV_LIST  *stik_drivers;
TPL       *tpl;
STX       *stx;
/* Put your name and version number of this module in here. */
LAYER     my_layer = {  "TCP", "00.01", (M_YEAR << 9) | (M_MONTH << 5) | M_DAY, 
                        "Unknown Programmer", 0, NULL   };
CN_FUNCS  cn_vectors = {  my_CNkick, my_CNbyte_count, my_CNget_char, my_CNget_NDB,
                          my_CNget_block, my_CNgetinfo   };
char      fault[] = "TCP.STX : STiK extension module. Only to be started by STiK !";



void  main (argc, argv)

int   argc;
char  *argv[];

{
   if (argc != 2) {
        puts (fault);   return;
      }
   if (strcmp (argv[1], "STiK_Load") != 0) {
        puts (fault);   return;
      }

   stik_drivers = (DRV_LIST *) Supexec (get_stik_cookie);

   if (stik_drivers == 0L)   return;

   if (strcmp (stik_drivers->magic, MAGIC) != 0)
        return;

   tpl = (TPL *) (*stik_drivers->get_dftab) (TRANSPORT_DRIVER);
   stx = (STX *) (*stik_drivers->get_dftab) (MODULE_DRIVER);

   if (tpl != (TPL *) NULL && stx != (STX *) NULL) {
        if (install())
             Ptermres (_PgmSize, 0);
      }
 }


long  get_stik_cookie()

{
   long  *work;

   for (work = * (long **) 0x5a0L; *work != 0L; work += 2)
        if (*work == 'STiK')
             return (*++work);

   return (0L);
 }


int16  install()

{
   LAYER  *layers;

   /* We must announce our presence in order to receive datgrams !             */

   if (PRTCL_announce (P_TCP))
        return (FALSE);

   /* If 'IP_handler' returns FALSE then there is already something else       */
   /* installed that occupies the TCP slot, very strange ...                   */

   if (! IP_handler (P_TCP, TCP_handler, HNDLR_SET))
        return (FALSE);

   /* If you need to do any initializations for the TCP code then do it here   */
   /* in place of this comment. Note that you can rely on the core functions   */
   /* to be present, but not on any other module (like UDP or resolve).        */

   query_chains (NULL, NULL, (void **) & layers);

   while (layers->next)
        layers = layers->next;

   layers->next = & my_layer;

   tpl->TCP_open       = my_TCP_open;
   tpl->TCP_close      = my_TCP_close;
   tpl->TCP_send       = my_TCP_send;
   tpl->TCP_wait_state = my_TCP_wait_state;
   tpl->TCP_ack_wait   = my_TCP_ack_wait;

   return (TRUE);
 }


int16  cdecl  my_TCP_open (rem_host, rem_port, tos, buff_size)

uint32  rem_host;
int16   rem_port, tos;
uint16  buff_size;

{
   int16  handle;

   if ((handle = PRTCL_request (& cn_vectors)) == -1)
        return (E_BADHANDLE);

   /* 'handle' is a connection handle in the range from 0 ... 63, which can be */
   /* used as an index into TCP arrays if those have the size of 64 entries.   */
   /* If used this way, TCP_open finishes with 'return (handle)' if everything */
   /* else is successful.                                                      */
   /* It is suggested to inquire here about local IP address and time-to-live  */
   /* to be used for sending datagrams, and store them in your connection      */
   /* array. Use PRTCL_get_parameters to that end.                             */

   return (E_UNREACHABLE);
 }


int16  cdecl  my_TCP_close (connec, timeout)

int16  connec, timeout;

{
   /* Here do everything that RFC793 requires for closing a TCP connection.    */
   /* Even though 'PRTCL_release' doesn't care, you should check if 'connec'   */
   /* is a valid handle and return E_NORMAL or E_BADHANDLE.                    */

   PRTCL_release (connec);

   return (E_NORMAL);
 }


int16  cdecl  my_TCP_send (connec, buffer, length)

int16  connec, length;
char   *buffer;

{
   /* Check if 'connec' is a valid TCP handle, then do the send stuff.         */
   /* Return an appropriate error code afterwards.                             */

   return (E_BADHANDLE);
 }


int16  cdecl  my_TCP_wait_state (connec, state, timeout)

int16  connec, state, timeout;

{
   /* Check if 'connec' is a valid TCP handle, then do the wait_state stuff.   */
   /* Return an appropriate error code afterwards.                             */

   return (E_BADHANDLE);
 }


int16  cdecl  my_TCP_ack_wait (connec, timeout)

int16  connec, timeout;

{
   /* Check if 'connec' is a valid TCP handle, then do the ack_wait stuff.     */
   /* Return an appropriate error code afterwards.                             */

   return (E_BADHANDLE);
 }


int16  cdecl  my_CNkick (connec)

int16  connec;

{
   /* With the CN* functions you do not need to check whether 'connec' is a    */
   /* valid handle. It won't be called if 'connec' were not valid.             */
   /* So just do the 'kick' stuff here, and return an appropriate error code.  */

   return (E_NORMAL);
 }


int16  cdecl  my_CNbyte_count (connec)

int16  connec;

{
   /* With the CN* functions you do not need to check whether 'connec' is a    */
   /* valid handle. It won't be called if 'connec' were not valid.             */
   /* So just return the number of waiting bytes here, or an error code.       */

   return (0);
 }


int16  cdecl  my_CNget_char (connec)

int16  connec;

{
   /* With the CN* functions you do not need to check whether 'connec' is a    */
   /* valid handle. It won't be called if 'connec' were not valid.             */
   /* So just return the next character here, or an appropriate error code.    */

   return (E_NODATA);
 }


NDB *  cdecl  my_CNget_NDB (connec)

int16  connec;

{
   /* With the CN* functions you do not need to check whether 'connec' is a    */
   /* valid handle. It won't be called if 'connec' were not valid.             */
   /* So unlink the block from the queue here, and return the pointer or NULL. */

   return (NULL);
 }


int16  cdecl  my_CNget_block (connec, buffer, length)

int16  connec, length;
char   *buffer;

{
   /* With the CN* functions you do not need to check whether 'connec' is a    */
   /* valid handle. It won't be called if 'connec' were not valid.             */
   /* So fill in the buffer here, and return the number of bytes filled in.    */

   return (E_NODATA);
 }


CIB *  cdecl  my_CNgetinfo (connec)

int16  connec;

{
   /* With the CN* functions you do not need to check whether 'connec' is a    */
   /* valid handle. It won't be called if 'connec' were not valid.             */
   /* So return the pointer here, or NULL if not available.                    */

   return (NULL);
 }


int16  cdecl  TCP_handler (datagram)

IP_DGRAM  *datagram;

{
   /* This function is called each time an IP datagram arrives.                */
   /* The recommended strategy is to process datagrams that can easily be      */
   /* processed immediately, and return TRUE. If the datagram can not be       */
   /* processed easily now, then return FALSE. Other parts of the TCP module   */
   /* must call IP_fetch from time to time to check for waiting datagrams, and */
   /* process them if any. I'd suggest that datagrams with TCP urgent flag set */
   /* should be processed here.                                                */
   /* If you do not need this feature, then simply delete this function        */
   /* and remove the 'IP_handler' call inside the 'install' function.          */

   return (FALSE);
 }
