home *** CD-ROM | disk | FTP | other *** search
/ Network Support Encyclopedia 96-1 / novell-nsepro-1996-1-cd2.iso / download / netware / xtli1.exe / FILETX.C < prev    next >
Text File  |  1994-09-13  |  21KB  |  808 lines

  1. /****************************************************************************
  2. ** File: FILETX.C
  3. **
  4. **    Description:
  5. **
  6. **        Sample TLI server application for NLM environment.  Program will send
  7. **        a specified file to client TLI endpoints.  Companion product is FILERX
  8. **        (FILERX.C and FILERX.EXE).
  9. **
  10. **    Disclaimer:
  11. **
  12. **        Novell, Inc. makes no representations or warranties with respect to
  13. **        any NetWare software, and specifically disclaims any express or
  14. **        implied warranties of merchantability, title, or fitness for a
  15. **        particular purpose.  
  16. **
  17. **        Distribution of any NetWare software is forbidden without the
  18. **        express written consent of Novell, Inc.  Further, Novell reserves
  19. **        the right to discontinue distribution of any NetWare software.
  20. **
  21. **        Novell is not responsible for lost profits or revenue, loss of use
  22. **        of the software, loss of data, costs of re-creating lost data, the
  23. **        cost of any substitute equipment or program, or claims by any party
  24. **        other than you.  Novell strongly recommends a backup be made before
  25. **        any software is installed.   Technical support for this software
  26. **        may be provided at the discretion of Novell.
  27. **
  28. **    QMK386 options used:
  29. **
  30. **        /it - TLI symbols
  31. **
  32. **    Programmers:
  33. **
  34. **        Ini    Who                    Firm
  35. **        -----------------------------------------------------------------------
  36. **        ABJ    Adam B. Jerome        Novell Developer Support
  37. **
  38. **    History:
  39. **
  40. **        When        Who    What
  41. **        -----------------------------------------------------------------------
  42. **        07-01-94    ABJ    First code.
  43. **
  44. */
  45.  
  46. /****************************************************************************
  47. ** Include headers, macros, structures, typedefs, etc.
  48. */
  49.     /*------------------------------------------------------------------------
  50.     **    ANSI 
  51.     */
  52.    #include <stdio.h>         /*    FILE, size_t, fopen(), gets(), printf(), sprintf(), fread(), feof(), fclose */
  53.     #include <malloc.h>         /* malloc(), free() */
  54.    #include <string.h>        /* strupr() */
  55.     #include <conio.h>         /* getch(), kbhit() */
  56.    #include <process.h>     /* delay(), exit(), atexit(), ThreadSwitch(), BeginThread() */
  57.    #include <sys/types.h>     /* fd_set */
  58.    #include    <fcntl.h>         /*    O_RDWR */
  59.  
  60.     /*------------------------------------------------------------------------
  61.     **    NetWare.
  62.     */
  63.     #include <niterror.h>    /* NetWareErrno        */
  64.    #include <sap.h>          /* AdvertiseService(), ShutdownAdvertising()    */
  65.     #include    <tiuser.h>         /*    T_BIND, T_CALL, T_MORE, T_LOOK, T_DISCONNECT,... */
  66.  
  67.     /*------------------------------------------------------------------------
  68.     **    Filetx
  69.     */
  70.    #define SERVER_TYPE    0x0275    /* Novell Developer Support test server type */
  71.  
  72. /****************************************************************************
  73. ** Global storage.
  74. */
  75. struct t_call *tCall            = NULL;
  76. struct t_bind *tBind            = NULL;
  77. int                exitingNLM    = FALSE;
  78. int                threadCnt    = 0;
  79. LONG             sapHandle    = 0;
  80. int                fh             = (-1);
  81. int                bound            = (-1);
  82. char              *sendFile        = NULL;
  83.  
  84. /****************************************************************************
  85. **    Program shut-down (graceful).
  86. */
  87. void Uninit(void)
  88.     {
  89.     /*------------------------------------------------------------------------
  90.     **    Function sign-in.
  91.     */                                                               
  92.     printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<    SHUT DOWN   >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
  93.     exitingNLM=TRUE;
  94.  
  95.     /*------------------------------------------------------------------------
  96.     **    Kill the SAP.
  97.     */                     
  98.    if(sapHandle != 0)
  99.         {
  100.         printf("Stopping SAP Advertising...");                                       
  101.         ShutdownAdvertising(sapHandle);
  102.         printf("Stopped.\n");
  103.         }
  104.  
  105.     /*------------------------------------------------------------------------
  106.     **    Free TLI allocations.
  107.     */
  108.     printf("Freeing TLI allocations...");                 
  109.    if(tBind != NULL)        t_free((char *)tBind, T_BIND);
  110.    if(tCall != NULL)        t_free((char *)tCall, T_CALL);
  111.     printf("Freed.\n");
  112.  
  113.     /*------------------------------------------------------------------------
  114.     ** Unbind TLI protocol address.
  115.     */
  116.     if(bound != (-1))
  117.         {
  118.         printf("Unbinding TLI address...");
  119.         t_unbind(fh);
  120.         printf("Unbound.\n");
  121.         }
  122.  
  123.     /*------------------------------------------------------------------------
  124.     ** Closing TLI device handle.
  125.     */
  126.     if(bound != (-1))
  127.         {
  128.         printf("Closing TLI handle...");
  129.        t_close(fh);
  130.         printf("Closed.\n");
  131.         }
  132.  
  133.     --threadCnt;  /* See Init() for the ++threadCnt. */
  134.     exit(0);
  135.     }
  136.  
  137. /****************************************************************************
  138. **    Convert an IPX address to a string.
  139. */
  140. char *IPXaddr2str(char *szStr, void *addr)
  141.     {
  142.     char *a;
  143.  
  144.     a=(char *)addr;
  145.  
  146.     sprintf(szStr,
  147.         "%02X%02X%02X%02X:%02X%02X%02X%02X%02X%02X:%02X%02X",
  148.         (0x00FF & a[ 0]),
  149.         (0x00FF & a[ 1]),
  150.         (0x00FF & a[ 2]),
  151.         (0x00FF & a[ 3]),
  152.         
  153.         (0x00FF & a[ 4]),
  154.         (0x00FF & a[ 5]),
  155.         (0x00FF & a[ 6]),
  156.         (0x00FF & a[ 7]),
  157.         (0x00FF & a[ 8]),
  158.         (0x00FF & a[ 9]),
  159.  
  160.         (0x00FF & a[10]),
  161.         (0x00FF & a[11])
  162.         );
  163.  
  164.     return(szStr);
  165.     }
  166.  
  167. /****************************************************************************
  168. ** ATEXIT registered function.
  169. */
  170. void TerminateNLM(void)
  171.    {
  172.     exitingNLM = TRUE;                    /* Signal all threads to die.               */
  173.     while(threadCnt) ThreadSwitch();    /* Wait for all threads to die.             */
  174.     delay(5);                                /* Give some time for things to calm.    */
  175.    return;
  176.    }
  177.  
  178. /****************************************************************************
  179. ** Handle connection. (child process)
  180. **
  181. **    This is where communication really happens.
  182. */
  183. void ChildProcess(int *newFh)
  184.    {
  185.     int     cCode;
  186.    char     buf[48];
  187.     int     exitingProcess=FALSE;
  188.     FILE    *fp;
  189.     size_t bytes;
  190.  
  191.     ++threadCnt;
  192.  
  193.     /*------------------------------------------------------------------------
  194.     **    Send client a text file.
  195.     */
  196.     fp=fopen(sendFile, "r");
  197.     if(fp != NULL)
  198.         {
  199.         while((bytes=fread(buf, 1, sizeof(buf), fp)))
  200.             {
  201.             /*---------------------------------------------------------------------
  202.             ** Echo (send) packet back to the client.
  203.             */
  204.           cCode = t_snd(
  205.                 /* I-    fd            */    *newFh,
  206.                 /* I-    buf        */    buf,
  207.                 /*    I-    nbytes    */    bytes,
  208.                 /*    I-    flags        */    feof(fp) ? 0 : T_MORE 
  209.                 );
  210.           if(cCode == (-1))
  211.                 {
  212.                 /*------------------------------------------------------------------
  213.                 ** I don't care what happened, we are shutting down this process.
  214.                 */
  215.                 exitingProcess=TRUE;
  216.             
  217.                 /*------------------------------------------------------------------
  218.                 ** Now, what happened?
  219.                 */
  220.                 switch(t_errno) 
  221.                  {
  222.                     /*---------------------------------------------------------------
  223.                     **    An asynchronous event has occured on the transport endpoint
  224.                     **    specified by fd.
  225.                     */
  226.                     case TLOOK:
  227.  
  228.                         /*---------------------------------------------------------------------
  229.                         **    Ok, What's this all important event?
  230.                         */
  231.                           cCode=t_look(*newFh);
  232.                           switch(cCode)
  233.                             {
  234.                             /*---------------------------------------------------------------------
  235.                             **    Other endpoint wants to disconnect?
  236.                             */
  237.                             case T_DISCONNECT:
  238.                                 break;
  239.                     
  240.                             /*---------------------------------------------------------------------
  241.                             **    t_look blew up?
  242.                             */
  243.                             case (-1):
  244.                                 switch(t_errno)
  245.                                     {
  246.                                     case TBADF:
  247.                                     case TSYSERR:
  248.                                     default:
  249.                                         t_error("[CHILD]t_look");
  250.                                         break;
  251.                                     }
  252.                                 break;
  253.  
  254.                             /*---------------------------------------------------------------------
  255.                             **    We expect that it is not one of these.
  256.                             */
  257.                             case 0:                /* No event has occured. */
  258.                             case T_LISTEN:          /*    Connect indication recieved. */
  259.                             case T_CONNECT:      /* Connection confirmation received. */
  260.                             case T_DATA:          /*    Normal data received. */
  261.                             case T_EXDATA:          /* Expedited data received. */
  262.                             case T_UDERR:          /* Datagram error indication. */
  263.                             case T_ORDREL:          /* Orderly release indication. */
  264.                             case T_GODATA:          /* Flow control restrictions on normal data flow have been lifted. */
  265.                             case T_GOEXDATA:     /* Flow control restrictions on expedited data flow have been lifted. */
  266.                             default:                /* Undocumented elephant trap. */
  267.                               printf("[CHILD]t_look:{%d}\n", cCode);
  268.                                 break;
  269.         
  270.                             }
  271.                    
  272.                         break;
  273.  
  274.                    /*---------------------------------------------------------------
  275.                     **    We expect that it is not one of these.
  276.                     */
  277.                     case TBADDATA:        
  278.                     case TBADF:            
  279.                     case TBADFLAG:    
  280.                     case TFLOW:
  281.                     case TNOTSUPPORT:    
  282.                     case TOUTSTATE:    
  283.                     case TSYSERR:    
  284.                     default:
  285.                        t_error("[CHILD]t_snd");
  286.                           break;
  287.                  }
  288.              }
  289.  
  290.             }
  291.  
  292.  
  293.         fclose(fp);
  294.         }
  295.  
  296.     /*------------------------------------------------------------------------
  297.     **    Lets tell the other endpoint that we would like to go away now.
  298.     */
  299.     cCode=t_snddis(
  300.         /*    I-    fd        */    *newFh,
  301.         /*    I- call    */    NULL
  302.         );
  303.     if(cCode == (-1))    switch(t_errno) 
  304.       {
  305.         /*---------------------------------------------------------------------
  306.         **    We expect none of these.
  307.         */
  308.         case TBADF:         
  309.         case TOUTSTATE:
  310.         case TBADDATA:    
  311.         case TBADSEQ:     
  312.         case TNOTSUPPORT:
  313.         case TSYSERR:
  314.         default:
  315.             t_error("[CHILD]t_snddis");
  316.              break;
  317.       }
  318.  
  319.     /*------------------------------------------------------------------------
  320.     **    Wait for disconnect message.
  321.     */
  322.     do    {
  323.         ThreadSwitch();
  324.         cCode=t_rcvdis(
  325.             /* I-    fd            */    *newFh,
  326.             /* -O    discon    */    NULL
  327.             );
  328.         if(cCode == -1) switch(t_errno)
  329.             {
  330.             case TNODIS:
  331.                 break;
  332.  
  333.             /*------------------------------------------------------------------
  334.             **    We expect none of these.
  335.             */
  336.             case TBADF:
  337.             case TBUFOVFLW:
  338.             case TNOTSUPPORT:
  339.             case TOUTSTATE:
  340.             case TSYSERR:
  341.             default:
  342.                 t_error("[CHILD]t_rcvdis");
  343.                 break;
  344.             }
  345.  
  346.         } while(cCode == TNODIS);
  347.  
  348.  
  349.     /*------------------------------------------------------------------------
  350.     **    Unbinding the new TLI endpoint.
  351.     */
  352.     cCode=t_unbind(*newFh);
  353.     if(cCode) switch(t_errno)
  354.         {
  355.         /*---------------------------------------------------------------------
  356.         **    We expect none of these.
  357.         */
  358.         case TBADF:
  359.         case TOUTSTATE:
  360.         case TLOOK:
  361.         case TSYSERR:
  362.         default:
  363.             t_error("[CHILD]t_unbind");
  364.             break;
  365.         }
  366.     
  367.     /*------------------------------------------------------------------------
  368.     **    Closing the new TLI endpoint.
  369.     */
  370.     cCode=t_close(*newFh);
  371.     if(cCode == -1) switch(t_errno)
  372.         {
  373.         case TBADF:
  374.         default:
  375.             t_error("[CHILD]t_close");
  376.             break;
  377.         }
  378.     
  379.     /*------------------------------------------------------------------------
  380.     **    Free the allocated handle.
  381.     */
  382.     if(newFh != NULL) free(newFh);
  383.    
  384.     --threadCnt;
  385.  
  386.     /*------------------------------------------------------------------------
  387.     **    End of thread.
  388.     */
  389.     return;
  390.    }                         
  391.  
  392. /****************************************************************************
  393. ** Progam core proccess loop; Service connection requests.  Spawn new threads
  394. **    to handle connections.
  395. */
  396. void CoreProc(void)
  397.    {
  398.    int                *newFh;
  399.    char               szTemp[256];
  400.     int                 cCode;
  401.     int                  newBindFlag     = -1;
  402.  
  403.     /*------------------------------------------------------------------------
  404.     **    Function sign-in.
  405.     */                                                               
  406.     printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<   CORE PROCESS  >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
  407.  
  408.     /*------------------------------------------------------------------------
  409.     ** Answer the phone loop.
  410.     */
  411.       while(!exitingNLM)
  412.       {
  413.         /*------------------------------------------------------------------------
  414.         **    Check for user exit request.
  415.         */
  416.       ThreadSwitch();
  417.         if(kbhit())
  418.             {
  419.             /*------------------------------------------------------------------
  420.             **    Flush the keyboard buffer.
  421.             */
  422.             while(kbhit()) if(!getch()) getch();
  423.  
  424.             do    {
  425.                printf("Exit? (Y/N): ");
  426.                gets(szTemp);
  427.                strupr(szTemp);
  428.                 } while((szTemp[0] != 'N') && (szTemp[0] != 'Y'));
  429.  
  430.             if(szTemp[0] == 'Y')
  431.                 {
  432.                exitingNLM=TRUE;
  433.                 break;
  434.                 }
  435.             }
  436.  
  437.         /*---------------------------------------------------------------------
  438.         ** Wait for the phone to ring...
  439.         */
  440.         printf("Listening...");
  441.       cCode=t_listen(
  442.             /* I-    fd        */    fh,
  443.             /*    -O    call    */    tCall
  444.             );
  445.         if(cCode == (-1))
  446.             {
  447.             switch(t_errno)
  448.                 {
  449.                 /*------------------------------------------------------------------
  450.                 ** We opened in polling mode.  As we poll, and nobody is there, we
  451.                 ** will get this case.  Ignore it and go on, but do not attempt to
  452.                 ** connect.
  453.                 */
  454.                 case TNODATA:
  455.                     printf("\r");
  456.                     continue;
  457.         
  458.                 /*------------------------------------------------------------------
  459.                 ** We don't want any of these to happen.
  460.                 */
  461.                 case TBADF:
  462.                 case TBADQLEN:
  463.                 case TBUFOVFLW:
  464.                 case TLOOK:
  465.                 case TNOTSUPPORT:
  466.                 case TOUTSTATE:
  467.                 case TSYSERR:
  468.                 default:
  469.                     t_error("ERROR");
  470.                     exitingNLM=TRUE;
  471.                     continue;
  472.                 }
  473.             }
  474.  
  475.         /*---------------------------------------------------------------------
  476.         ** "Ring..."
  477.         */
  478.         printf("RING!!!\n");
  479.     
  480.         /*------------------------------------------------------------------
  481.         **    Malloc memory for newFh. (Being that we cannot pass objects from 
  482.         ** our stack to a child process).     Child process will free this 
  483.         ** memory (if we are successful).
  484.         */
  485.         printf("Allocating new file handle...");
  486.         newFh=(int *)malloc(sizeof(int));
  487.         if(newFh == NULL)
  488.             {
  489.             printf("ERROR:  Out of memory.\n");
  490.             goto CONNECT_ERR;
  491.             }
  492.         printf("Allocated.\n");
  493.  
  494.         /*------------------------------------------------------------------------
  495.         **    Open a new endpoint to service connection.
  496.         */
  497.         printf("Opening new endpoint...");
  498.         *newFh = t_open(
  499.             /* I-    path    */    "/dev/nspx",
  500.             /*    I-    oflag    */    O_RDWR,
  501.             /*    -O    info    */    NULL
  502.             );
  503.         if(*newFh == (-1))
  504.           {
  505.             switch(t_errno)
  506.                 {
  507.                 case TSYSERR:
  508.                 case TBADFLAG:
  509.                 case TBADNAME:
  510.                 default:
  511.                   t_error("ERROR");
  512.                     break;
  513.                 }
  514.             goto CONNECT_ERR;
  515.           }
  516.         printf("Open.\n");
  517.  
  518.         /*------------------------------------------------------------------------
  519.         **    Bind it as appropriate (Transport provider will provide an address).
  520.         */
  521.         printf("Binding new endpoint...");
  522.           newBindFlag=t_bind(
  523.             /* I-    fd        */    *newFh,
  524.             /*    I-    req    */    NULL,
  525.             /*    -O    ret    */    NULL
  526.             );
  527.           if(newBindFlag == -1)
  528.           {
  529.           t_error("ERROR");
  530.             goto CONNECT_ERR;
  531.           }
  532.         printf("Bound.\n");
  533.  
  534.         /*------------------------------------------------------------------------
  535.         **    Accept the call from a client to the alloced fileHandle.
  536.         */
  537.         printf("Accepting call...");
  538.           if(t_accept(fh, *newFh, tCall) == -1)
  539.           {
  540.           t_error("ERROR");
  541.             goto CONNECT_ERR;
  542.           }
  543.         printf("Accepted.\n");
  544.  
  545.         /*------------------------------------------------------------------------
  546.         **    Check for disconnect request.    (Client may have changed his mind).
  547.         */
  548.         ThreadSwitch();
  549.         printf("Checking for a disconnect request...");
  550.         cCode=t_look(*newFh);
  551.         if(cCode == T_DISCONNECT)
  552.             {
  553.             printf("ERROR:  Disconnect request encountered.\n");
  554.             
  555.             /*---------------------------------------------------------------
  556.             **    Recieve the disconnect request.
  557.             */
  558.             printf("Recieving disconnect...");
  559.             cCode=t_rcvdis(
  560.                 /*    fd         */    *newFh,
  561.                 /*    discon    */    NULL
  562.                 );
  563.             if(cCode < 0)
  564.                 t_error("ERROR");
  565.             else
  566.                 printf("Recieved.\n");
  567.             
  568.             goto CONNECT_ERR;
  569.             }
  570.         printf("Not encountered.\n");
  571.  
  572.         /*------------------------------------------------------------------------
  573.         **    Spawn child process to handle it from here.
  574.         */
  575.         printf("Spawning child process...");
  576.       cCode=BeginThread(ChildProcess, NULL, NULL, newFh);
  577.         if(cCode == (-1))
  578.             {
  579.             printf("ERROR: Failed.\n");
  580.             goto CONNECT_ERR;
  581.             }
  582.         else
  583.             {
  584.             printf("Child process is ON-LINE.\n");
  585.             continue;
  586.             }
  587.  
  588. CONNECT_ERR:
  589.         exitingNLM=TRUE;
  590.  
  591.         /*------------------------------------------------------------------------
  592.         **    Unbinding the new TLI endpoint.
  593.         */
  594.           if(newBindFlag != (-1))
  595.            {
  596.             printf("Unbinding new endpoint...");
  597.             if(t_unbind(*newFh))
  598.                 t_error("t_unbind");
  599.             else
  600.                 printf("Unbound.\n");
  601.             }
  602.  
  603.         /*------------------------------------------------------------------------
  604.         **    Closing the new TLI endpoint.
  605.         */
  606.         if(*newFh != (-1))
  607.            {
  608.             printf("Closing new endpoint...");
  609.             if(t_close(*newFh))
  610.                 t_error("t_close");
  611.             else
  612.                 printf("Closed.\n");
  613.             }
  614.  
  615.         /*------------------------------------------------------------------------
  616.         **    Freeing new handle.
  617.         */
  618.         if(newFh != NULL)
  619.             {
  620.             printf("Freeing new handle...");
  621.             free(newFh);
  622.             printf("Freed.\n");
  623.             }
  624.         }
  625.  
  626.     return;
  627.     }
  628.  
  629. /****************************************************************************
  630. ** Program initialization.                  
  631. */
  632. void Init(int argc, char *argv[])
  633.    {
  634.     struct t_info     tInfo;
  635.    char               szTemp[256];
  636.     FILE                *fp;
  637.  
  638.     ++threadCnt;    /* See Uninit() for the --threadswitch. */
  639.     
  640.     /*------------------------------------------------------------------------
  641.     **    Function sign-in.
  642.     */
  643.     printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<  INITIALIZATION >>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
  644.  
  645.     /*------------------------------------------------------------------------
  646.     **    Check command line args.
  647.     */
  648.    if(argc != 3)
  649.       {
  650.       printf("Usage: LOAD %s <server's name> <filename>\n", argv[0]);
  651.         printf("\n");
  652.         printf("   <server's name>   Name that this NLM will be known as\n");
  653.         printf("                     on the network.\n");
  654.         printf("\n");
  655.         printf("   <filename>        Name of file (including path) that will\n");
  656.         printf("                     be sent to requesting client endpoints\n");
  657.         printf("\n");
  658.       Uninit();
  659.       }
  660.  
  661.     /*------------------------------------------------------------------------
  662.     **    Get (and verify existance of) specified file.
  663.     */
  664.     sendFile=argv[2];
  665.     fp=fopen(sendFile, "r");
  666.     if(fp != NULL) fclose(fp);
  667.     else
  668.         {
  669.         printf("ERROR:  Cannot open file: %s\n", sendFile);
  670.         exitingNLM = TRUE;
  671.       Uninit();
  672.         }
  673.  
  674.     /*------------------------------------------------------------------------
  675.     **    Register exit procedure.
  676.     */
  677.    if(atexit(TerminateNLM) != NULL) 
  678.       {
  679.       printf("ERROR: atexit failed.\n");
  680.       Uninit();
  681.       }
  682.  
  683.     /*------------------------------------------------------------------------
  684.     ** Initialize a TLI endpoint to listen for connection requests.    
  685.     */
  686.     printf("Opening TLI endpoint...");
  687.    fh=t_open(
  688.         /* I-    path    */    "/dev/nspx",
  689.         /* I-    oflag    */    O_RDWR|O_NDELAY,
  690.         /*    -O    info    */    &tInfo
  691.         );
  692.    if(fh == -1)
  693.       {
  694.         switch(t_errno)
  695.             {
  696.             case TBADFLAG:    /* Invalid flag was specified. */
  697.             case TBADNAME:    /* Invalid transport provider name was specified. */
  698.             case TSYSERR:    /*    System error occured. */
  699.             default:
  700.               t_error("ERROR");
  701.                 break;
  702.             }
  703.       Uninit();
  704.       }
  705.     printf("Opened.\n");
  706.  
  707.     /*------------------------------------------------------------------------
  708.     ** Allocate and initialize TLI structures.
  709.     */
  710.     printf("Allocating...");
  711.       tBind = (struct t_bind *)t_alloc(
  712.         /* I-    fd             */    fh,
  713.         /* I-    struct_type    */    T_BIND,
  714.         /* I-    fields        */    T_ALL
  715.         );
  716.     if(tBind == NULL)
  717.         {
  718.         switch(t_errno)
  719.             {
  720.             case TBADF:
  721.             case TSYSERR:
  722.             case TNOTSUPPORT:
  723.             case TNOSTRUCTYPE:
  724.             default:
  725.                t_error("ERROR:");
  726.             }
  727.        Uninit();
  728.         }
  729.  
  730.       tCall = (struct t_call *)t_alloc(
  731.         /* I-    fd             */    fh,
  732.         /* I-    struct_type    */    T_CALL,
  733.         /* I-    fields        */    T_ADDR
  734.         );
  735.     if(tCall == NULL)
  736.         {
  737.         switch(t_errno)
  738.             {
  739.             case TBADF:
  740.             case TSYSERR:
  741.             case TNOTSUPPORT:
  742.             case TNOSTRUCTYPE:
  743.             default:
  744.                t_error("ERROR:");
  745.             }
  746.        Uninit();
  747.         }
  748.     printf("Allocated.\n");
  749.  
  750.     /*------------------------------------------------------------------------
  751.     ** Associate specified protocol address with the TLI endpoint
  752.     ** Fill out tBind structure, requesting address (dynamic IPX socket
  753.     **    number) be assigned.
  754.     */
  755.     printf("Binding...");
  756.     tBind->qlen = 1;
  757.     tBind->addr.len = 0;
  758.    bound=t_bind(
  759.         /* I-    fd        */    fh,
  760.         /*    I-    req    */    tBind,
  761.         /*    -O    ret    */    tBind
  762.         );
  763.    if(bound == (-1))
  764.       {
  765.         switch(t_errno)
  766.             {
  767.             case TBADF:
  768.             case TOUTSTATE:
  769.             case TBADADDR:
  770.             case TBUFOVFLW:
  771.             case TSYSERR:
  772.             case TADDRBUSY:
  773.             default:
  774.                t_error("ERROR: t_bind");
  775.             }
  776.       Uninit();
  777.       }
  778.     printf("Bound. [%s]\n", IPXaddr2str(szTemp, tBind->addr.buf));
  779.  
  780.     /*-------------------------------------------------------------------------
  781.     **    Use the above (dynamically assigned) IPX socket number to begin SAPping.
  782.     */
  783.     printf("Begin SAPping...");
  784.      sapHandle=AdvertiseService(
  785.         /* I-    serverType        */    SERVER_TYPE,
  786.         /*    I-    serverName        */    argv[1],
  787.         /* I-    serviceSocket    */    *(WORD *)(((IPX_ADDR *)tBind->addr.buf)->ipxa_socket)
  788.         );
  789.     if(sapHandle == -1)
  790.         {
  791.         printf("ERROR: #%d.\n", NetWareErrno);
  792.         Uninit();
  793.         }
  794.     printf("Initiated.\n");
  795.  
  796.     return;
  797.     }
  798.  
  799. /****************************************************************************
  800. **    Program start.
  801. */
  802. void main(int argc, char *argv[])
  803.     {
  804.     Init(argc, argv);
  805.     CoreProc();
  806.     Uninit();     
  807.     }
  808.