//Sample code file: spxc_rw/spxc_rw.c

//Warning: This code has been marked up for HTML

/*************************************************************************

  Copyright (c) 1997 Novell, Inc.  All Rights Reserved.

  With respect to this file, Novell hereby grants to Developer a 
  royalty-free, non-exclusive license to include this sample code 
  and derivative binaries in its product. Novell grants to Developer 
  worldwide distribution rights to market, distribute or sell this 
  sample code file and derivative binaries as a component of 
  Developer's product(s).  Novell shall have no obligations to 
  Developer or Developer's customers with respect to this code.
  
  DISCLAIMER:
  
  Novell disclaims and excludes any and all express, implied, and 
  statutory warranties, including, without limitation, warranties 
  of good title, warranties against infringement, and the implied 
  warranties of merchantibility and fitness for a particular purpose.  
  Novell does not warrant that the software will satisfy customer's 
  requirements or that the licensed works are without defect or error 
  or that the operation of the software will be uninterrupted.  
  Novell makes no warranties respecting any technical services or 
  support tools provided under the agreement, and disclaims all other 
  warranties, including the implied warranties of merchantability and 
  fitness for a particular purpose. */

/**************************************************************************
   SPXC_RW.C
***************************************************************************

  Ioctl Read/Write Client

  SPXC_RW.C is an example NLM that works in conjunction with either 
  SPXS_TLI.C or SPXS_MUL.C to demonstrate SPX TLI functions.  This example, 
  representing the client portion of the demonstration, connects to a 
  server (see SPXS_TLI.C or SPXS_MUL.C), receives a file and prints it to 
  the screen.  The two "server" pieces are similar, the major difference 
  being that SPXS_MUL.C supports multiple connections.

  Complete the following steps to run this example:

  1. Make sure there's a file available for the server application 
     (SPXS_TLI.NLM or SPXS_MUL.NLM) to open and transmit 
     (SERVER\SYS:README.TXT).  This file should contain a test message.

  2. Load either SPXS_TLI.NLM or SPXS_MUL.NLM on a test server using the 
     server's name as a command-line parameter 
     (ex. LOAD A:SPXS_TLI  MY_TEST_SERVER).  The program will respond with a 
     message similar to the following: "SERVER:  my_test_server is ready ... "  
     SPXS_MUL.NLM requires the number of connections (up to 10) as an 
     additional command line parameter (ex. LOAD A:SPXS_MUL MY_TEST_SERVER 5)

  3. Load SPXC_RW.NLM (the client NLM) on another test server, using the 
     previous server's name as a command-line parameter 
     (ex. LOAD A:SPXC_RW.NLM MY_TEST_SERVER).  This NLM will exit after 
     displaying the contents of README.TXT transmitted from the other server 
     by SPXS_TLI.NLM or SPXS_MUL.NLM

  4. Unload the server application (SPXS_TLI.NLM or SPXS_MUL.NLM), 
     SPXC_RW.NLM unloads automatically.

  NOTES:
 
  1.  QMK386.EXE can be used to generate a Watcom makefile for this 
      example:     QMK386 IPXS_TL1

  2.  CALNLM32.NLM, CLXNLM32.NLM, TLI.NLM and SPXS.NLM must be running on 
      the server for this example to work properly.

*************************************************************************/

#include <stdio.h> 
#include <stdlib.h>
#include <string.h>     
#include <nwcalls.h>
#include <nwclxcon.h>
#include <unistd.h>
#include <stropts.h>
#include <fcntl.h>     
#include <nlm\tiuser.h>     
#include <nwipx.h> 

#define TLI_TYPE 0x9000       /* Server type (dynamic area) */

main(int argc, char **argv)
{
   int            fh;
   char           iobuf[132];
   struct         t_call  *sndcall;
   BYTE           pv[128];          /* holds property value */
   BYTE           dc[1];            /* don't care BYTE      */
   NWCONN_HANDLE  connHandle,startConnHandle;
   NWCCODE        ccode;
   nuint          openState;

   startConnHandle=0;   /* set to zero if you don't care which connection
                           should be used to resolve the name. */
   openState = NWCC_OPEN_UNLICENSED;

   if( argc != 2 )
   {
      printf("Usage: %s <server's name>\r\n", argv[0]);
      exit(1);
   }

   /* NWCallsInit() must be called before any other NetWare SDK functions */
   ccode = NWCallsInit( NULL, NULL);
   if (ccode)
   {
      printf("NWCallsInit failed: %X\n", ccode);
      exit(1);
   }   

   /* Open a connection to a server                    */
   /* Note:  A connection is established to a server only for the
             convenience of reading the net address from the 
          Bindery.  This server connection is not necessary
          for the transport functions to work.      */

   ccode = NWCCOpenConnByName(
            /*  start Conn Handle */ startConnHandle,
            /*  Name of Server    */ (pnstr8) argv[1],
            /*  Name format       */ NWCC_NAME_FORMAT_BIND,
            /*  open state        */ openState,
            /*  Novell reserved   */ NWCC_RESERVED,
            /*  Connection Handle */ &connHandle);

   if (ccode)
   {
      printf( "\nNWCCOpenConnByName: failed %04x", ccode );
      exit(1);
   }

   /* Check if the server is active, read the net address */
   ccode = NWReadPropertyValue(
            /* connection handle   */  connHandle, 
            /* server name         */  argv[1], 
            /* object type         */  NWWordSwap(TLI_TYPE), 
            /* property name       */  "NET_ADDRESS",
            /* segment no. of data */  1, 
            /* data buffer         */  pv, dc, dc);
   if(ccode)
   {
      printf("Server %s is not available.\r\n", argv[1]);
      exit(1);
   }

   /* Close server connection */
   ccode = NWCCCloseConn(connHandle);
   if(ccode)
      printf("\nNWCCCloseConn: failed %04x", ccode);

   /* Open an endpoint, no info needed */
   if ((fh = t_open("/dev/nspx", O_RDWR, NULL)) == -1)
   {
      t_error("t_open");
      exit(1);
   }

   /* Request the provider to assign an address */
   if ( t_bind(fh, NULL, NULL) == -1 )
   {
      t_error("t_bind");
      exit(1);
   }

   /* Allocate space for server's address */
   sndcall = (struct t_call *) t_alloc(fh, T_CALL, T_ADDR);
   if (sndcall == NULL)
   {
      t_error("sndcall");
      exit(1);
   }

   /* Copy address of the server into t_call structure */
   sndcall->addr.len = sizeof( InternetAddress );
   memcpy(sndcall->addr.buf, pv, sndcall->addr.len);

   /* Innitiate connect with a server */
   if (t_connect(fh, sndcall, NULL) == -1)
   {
      t_error("t_connect");
      exit(1);
   }

   /* ioctl push tirdwr module */
   if ( ioctl(fh, I_PUSH, "tirdwr") == -1 )
   {
      perror("ioctl");
      exit(1);
   }

   /* Receive line at a time and print it on the screen */
   while( read(fh, iobuf, (LONG)sizeof(iobuf)) > 0 )
   {
      printf("%s",iobuf);
   }

   /* Free allocated structures */
   if( t_free((char *) sndcall, T_CALL) == -1 )
   {
      t_error("t_free");
      exit(1);
   }

   /* Close the endpoint */
   if( close(fh) == -1 )
   {
      perror("close");
      exit(1);
   }
   exit(0);
}