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

  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. */

/**************************************************************************
  IPXC_TL1.C
***************************************************************************

 IPXC_TL1.C works in conjunction with IPXS_TL1.C to demonstrate IPX
 connectionless mode communication between two NLMs.  IPXC_TL1.C (the
 "client" application) sends a test message to a server and then receives
 the same message back.

  Complete the following steps to run this example:

  1.  Load IPXS_TL1.NLM on a test server, entering the server's name as
      a command-line parameter (ex. LOAD A:IPXS_TL1 MY_TEST_SERVER). The
      server will respond with the following message:

      Server: MY_TEST_SERVER is ready ...

  2.  Load IPXC_TL1.NLM on another test server, entering the previous
      server's name and a test message as command-line paramters (ex.
      LOAD IPXC_TL1 MY_TEST_SERVER "My Test Message")

  3.  Unload IPXS_TL1.NLM when the program has finished running
      (IPXC_TL1.NLM unloads automatically).

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

  2.  CALNLM32.NLM, CLXNLM32.NLM, TLI.NLM and IPXS.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 <tiuser.h>     
#include <poll.h>       
#include <nwipxspx.h>  
#include <fcntl.h>      


#define TLI_TYPE   0x9000       /* Server type          */

main( int argc, char **argv )
{
   struct pollfd pfh;           /* poll structure       */
   BYTE   pv[128];              /* holds property value */
   BYTE   dc[1];                /* don't care BYTE      */
   struct t_unitdata *udata;
   int    flags;

   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 != 3 ) 
   {
      printf("Usage: %s <server> <message>\n", argv[0]);
      exit(1);
   }

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

   /* open a connection and obtain a connection handle */
   /* 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("NWReadPropertyValue failed: %X\n",ccode);
      printf("Server %s is not available.\n", argv[1]);
      exit(1);
   }

   /* Close connection to the server */
   ccode = NWCCCloseConn(connHandle);
   if(ccode)
      printf("NWCCCloseConn: failed %04X", ccode);

   /* Open an endpoint, blocking mode, no info needed */
   if ((pfh.fd = t_open("/dev/nipx", O_RDWR, NULL)) == -1)
   {
      t_error("t_open");
      exit(1);
   }
   
   /* Request the provider to assign an address */
   if ( t_bind(pfh.fd, NULL, NULL) == -1 )
   {
      t_error("t_bind");
      exit(1);
   }

   /* Allocate space for data transfer and error message */
   udata=(struct t_unitdata *)t_alloc(pfh.fd,T_UNITDATA,T_ALL);
   if( udata == NULL )
   {
      t_error("t_unitdata or t_uderr");
      exit(1);
   }

   /* Fill in the unitdata structure */
   udata->addr.len = sizeof( InternetAddress );
   memcpy(udata->addr.buf, pv, udata->addr.len);

   udata->udata.len = strlen(argv[2]) + 1;
   if( udata->udata.maxlen < udata->udata.len )
   {
      printf("Buffer to small: %d\n", udata->udata.maxlen);
      exit(1);
   }
   strcpy(udata->udata.buf, argv[2]);

   /* Send message, blocked until send completed */
   printf("Sending: %s\n", udata->udata.buf);
   if( t_sndudata(pfh.fd, udata) == -1 )
   {
      t_error("t_sndudata");
      exit(1);
   }

   /* Wait up to 5 seconds for response from server */ 
   pfh.events = POLLIN;
   if( poll( &pfh, 1, 5000 ) == -1 )
   {
      perror("poll");
      exit(1);
   }

   if( pfh.revents == POLLIN )
   {
      if( t_rcvudata(pfh.fd, udata, &flags) == -1 )
      {
         t_error("t_rcvudata");
         exit(1);
      }
      printf("Received: %s\n", udata->udata.buf);
   }
   else
      printf("Server didn't respond.\n");

   /* Unbind the address from the endpoint */
   if( t_unbind(pfh.fd) == -1 )
   {
      t_error("t_unbind");
      exit(1);
   }

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

   /* Close the endpoint */
   if( t_close(pfh.fd) == -1 )
   {
      t_error("t_close");
      exit(1);
   }

   exit(0);
} 
