Chapter 2. Sample Transaction Programs

These sample transaction programs are for descriptive purposes only and are not considered part of the production system. Two sample programs are illustrated. The first describes a transaction program to send a file, and the second describes a program to receive a file.

Sample Program: Send a File

OBJECT: 

s2_fsnd.c

FULL NAME: 

Send a file

TYPE: 

End-user Package Main

FUNCTION: 

Sends a file to another computer, either UNIX® or IBM. The program will confirm delivery.

Without any option flags, the program uses a basic conversation, performs no transformation on the file, and evokes the remote program s2frcv. With option flags, a user can request the program to translate the file into EBCDIC, use a mapped conversation, or evoke a different remote program.

INPUTS: Required:

  • Pathname of local node

  • Local LU name

  • Remote LU name

  • Mode name

  • Pathname of the file to send

  • Name(s) of the file on the remote side

If the remote system requires multiple names to identify a file (for example, library name, data set name), enter them here separately. Each name is then passed to the remote program as a separate parameter.

INPUTS: 

Optional:

-m 

Use a mapped conversation

-e 

Translate the file to EBCDIC before sending

This option assumes text is being sent. New lines are stripped and text is shipped in packets of eighty characters or less. This option cannot be used when document mode is specified.

-r 

Evokes “Program name”

-d 

Document mode

All flags must come on the command line before the required names. The required names must be in the order given. All parameters are translated to EBCDIC before sending, regardless of whether the -e option is taken. It is the responsibility of the remote program to transform them if necessary.

OUTPUTS: 

An exit code of 0 if the remote system confirms successful delivery; otherwise, an exit code of -1.

/*.........................................................*/
/*DATA DEFINITION SECTION						 */
/*.........................................................*/

#include <stdio.h>
#include <fcntl.h>
#include "global.h"/ *SNA62 global variables*/
#include "basic.h"/ *SNA62 Basic Verb Header*/

long  cnvid; */ Conversation Identifier*/
#define  BUFFSIZE  802
#define  RECSIZE   84
#define  REMOTPGM  "s2_frcv"

/*.........................................................*/
/*MAINLINE                  */
/*.........................................................*/

main(argc, argv)
int   argc;
char**argv;
{
extern interrno;
extern intoptind;
extern intopterr;
extern char*optarg;
intrc;
intfildes;
FILE*stream;
char*ch;
		int	nbyte;
		int	c;
		int	start = 2;/* Default to basic*/
		int	mapped = 0;	/* Default to basic*/
		int	ebcdic = 0;	/* Default to ascii*/
		int	doc = 0	/* Default to not a document*/

		char	**names;
		char	*rpgm;

		struct	snddta_ds	snddta_ds;

		union	{
				short II
						hex	buff[BUFFSIZE];
			} s;
		
		union	{
			short II
			hex	buff[RECSIZE];
			} e;


/*.........................................................*/
/*	Find Option flags -m, -e, -d, and -r			 */
/*.........................................................*/

opterr = 1;		/* Turn off option error	 */
rpgm = REMOTPGM;

while(   (c=getopt(argv, "mer:d")   )		!=EOF)

		{
		switch (c)

			{
			case 'm':
				mapped = 1;
				start = 4;
				break;

			case 'e':
				if (doc)
					{
					printf("-e for ebcdic assumes 							document mode./n");
					printf("-e and -d cannot be 							specified						
							simultaneously.\n");
					exit(-1);
					}
				ebcdic = 1;
	
					break;
			case 'r':
				rpgm = optarg;
				if( !rpgm )
					{
					printf("A program name is							required with the -r
							option.\n");
					printf("s2_fsnd exiting.\n");
					exit(-1);
					}
					break;
			case 'd':
				if ( ebcdic )
					{
					printf("-e for ebcdic assumes 							document mode.\n");
					printf("-e and -d cannot be 							specified
							simultaneously.\n");
					exit(-1);
					}
				doc = 1;
				break;

				}
			}

		names = (argv + optind);


/*.........................................................*/
/*	Six parameters must be entered.  Exit if not		 */
/*.........................................................*/
if ( (argc - optind) <6 )
		{
		printf("These parameters must be entered to
						s2_fsnd:\n");
		printf("The configuration file name, the local LU,
							the partner LU, the mode,
							\n");
		printf("the file you wish to transfer, and its name
							on the remote system.\n");
		printf("The -m -e and -r flags are optional, but
							must come first if present.
							\n");
		printf("s2_fsnd exiting.\n");
		exit(-1);
		}


/*.........................................................*/
/*	Open a local file.  Exit if it cannot be opened		 */
/*.........................................................*/

	if ( (fildes = open( *(names + 4), O_RDONLY )  ) == -1 )
		{
		printf("File %s open unsuccessful, errno %d\n",
								*(names + 4),errno);
		printf("s2_fsnd exiting.\n"); exit(-1);
		}

	else if ( doc || ebcdic)
		{
		if(   !(stream = fdopen(fildes, "r") )  )
			{
			printf("File %s open unsuccessful, errno %d\n", 
				*(names + 4), errno);
			printf("s2_fsnd exiting.\n"); exit(-1);
			}
		}


/*.........................................................*/
	LOCALLY ATTACH THE PROGRAM

	LATTACH requires the node name, local LU name, and transaction 	program name to be present as parameters.
/*.........................................................*/

	rc = lattach( *(names + 0), *(names + 1), argv[0] );

	if( rc == S2_ERR )
			{
			prterr(names);
			exit( -1 );
			}


/*.........................................................*/
	ALLOCATE THE CONVERSATION

	Pass mapped and ebcdic values, the remote pgm name, and the pointer to the array of pointers that contain the names.
/*.........................................................*/


	rc = lconv( mapped, ebcdic, rpgm, names); /* Allocate
									Conversation*/

	if (rc == S2_ERR )
			{
			prterr(names);
			exit( -1 );
			}
/*.........................................................*/
	READ AND SEND DATA

	If ebcdic, call sndibm - else call sndunix.
/*.........................................................*/

if ( ebcdic )
		{
		sndibm(snddta_ds, mapped, stream, start, names);
		}

else
		{
		sndunix(snddta_ds, mapped, stream, start, names,
							doc, fildes, ebcdic);
		}

/*.........................................................*/
	DEALLOCATE, FLUSH

	If the deallocate returns OK, detach from the LU and end the program. 	If the deallocate fails, (a negative response was received), deallocate locally, detach, and end program with an abend code.
/*.........................................................*/

if ( snamaj != S2_OK )
		{
		cleanup( );
		}

else
		{
		rc = ldealloc( DC_SYNC );

		if ( rc == S2_NOERR )
			{
			rc = detach( );
			rc = 0;
			}

		else
			{
			prterr(names);
			cleanup();
			}
		}

exit( rc );
		/* END SPEEDL  */


/*.........................................................*/
	LOCAL ATTACH
/*.........................................................*/

lattach( pfile, llu, tpn )
char *pfile, *llu, *tpn;

		{
		struct	attach_ds attach_ds;
		int	rc;

		attach_ds.type		= AT_LU
		attach_ds.path		= pfile;
		attach_ds.name		= llu;
		attach_ds.tpn		= tpn;
		attach_ds.wait		= NO;

		rc = attach(&attach_ds);
		return( rc );
		}


/*.........................................................*/
	LALLOC
/*.........................................................*/

lconv(mapped, ebcdic, rpgm, names)
int mapped;
int ebcdic;
char *rpgm;
char *names[ ];
		{
		int rc, i, j;
		char wrkrlu[8];
		char wrkmode[8];
		struct alcnv_ds alcnv_ds;

		alcnv_ds.rlu 		= names[2];	
		alcnv_ds.mode		= names[3];					alcnv_ds.tpn 		= rpgm;
		
			alcnv_ds.when = AC_WHEN;	/* Delay	*/
			alcnv_ds.type = mapped;	/* Basic or mapped   */
			alcnv_ds.sync = 1;

			alcnv_ds.user = NULL;
			alcnv_ds.pass = NULL;
			alcnv_ds.sec = 0;

			alcnv_ds.pipused = 1;
			if ( ebcdic )
				alcnv_ds.pipa[0] = "EBCDIC";
			else
				alcnv_ds.pipa(0) = "ASCII";
		atoe( alcnv_ds.pipa[0], strlen(alcnv_ds.pipa[0]) );

		strcpy(wrkrlu, alcnv_ds.rlu);

				alcnv_ds.pipa(1) = wrkrlu;

		atoe( alcnv_ds.pipa{1}, strlen(alcnv_ds.pipa[1]) );

		strcpy(wrkmode, alcnv_ds.mode);

		alcnv_ds.pipa(2) = wrkmode;

		atoe( alcnv_ds.pipa{2}, strlen(alcnv_ds.pipa[2]) );

		for( i = 5, j = 3; names[i]; i++, j++ )
			{
			alcnv_ds.pipa[j] = names[i];
			atoe( alcnv_ds.pipa[j],
						strlen(alcnv_ds.pipa[j]) );
			}


		alcnv_ds.pipa[j] = NULL;
		rc = alcnv(&alcnv_ds);
		cnvid = alcnv_ds.cnvid;
		return( rc );
		}

/*.........................................................*/
	LDEALLOC
/*.........................................................*/

ldealloc(type)
int type;
		{
		int rc;

		if( snastat == S2_DLCED )
			type = DC_LOCAL;

		rc = dalcnv(cnvid,type,NULL);

		return( rc );
		}

/*.........................................................*/
	PRTERR
/*.........................................................*/

prterr(names)
char *names[];

			{
			if( !(snamaj == S2_DEALC && snamin == S2_DNORM ) )
				{
				printf("Major code: %-4d %s\n", snamaj,
	 					dspmaj(snamaj));
				printf("Minor code: %-4d %s\n", snamin,
 						dspmin(snamaj,snamin));
				printf("Error in s2_fsnd, file '%s' not sent
						to '%s'\n", names[4], names[2] );
				}
			}


/*.........................................................*/
	CLEANUP
	Called if a conversation terminates abnormally.
/*.........................................................*/

	cleanup()
		{
		ldealloc( DC_AB_PGM );
		detach( );
		exit(-1);
		}


/*.........................................................*/
	READ FROM THE FILE, SEND THE DATA, UNIX TO IBM

	Leave the first two bytes for the logical record length field.
	Read eighty bytes of data or less at one time.
/*.........................................................*/

sndibm(snddta_ds, mapped, stream, start, names)
		 
		struct	snddta_ds		snddta_ds;
		int	mapped;
		FILE	*stream;
		int	start;
		char	**names;
		
		{

		int	nbyte;
		int	rc;
		union {
			short		II
			hex		buff[RECSIZE];
			} e;

snddta_ds.cnvid = cnvid;
snddta_ds.data = e.buff;

/* while snastat is in send state, and read is successful,
   is successful, perform the send data */

	while( snastat == S2_SEND &&
	(fgets(e.buff + start, RECSIZE - start, stream)) )
		{

		nbyte = strlen( e.buff +start );

		if( e.buff[nbyte + start -1] =='\n' )	nbyte--;

		atoe( e.buff + start, nbyte );

		e.II = nbyte + start;

		snddta_ds.length = nbyte + start ;

		if( mapped )
			{
			*( e.buff + 2 ) = 0x12;
			*( e.buff + 3 ) = 0xFF;
			}

		rc = snddta( &snddta_ds );

		if( rc == S2_ERR )
			prterr(names);

		}
}


/*.........................................................*/
   READ FROM THE FILE, SEND THE DATA, UNIX TO UNIX

Leave the first two bytes for the logical record length field.
/*.........................................................*/

sndunix(snddta_ds, mapped, stream, start, names, doc, fildes,
									ebcdic)
		 
		struct	snddta_ds	snddta_ds;
		int	mapped;
		FILE	*stream;
		int	start;
		char	**names;
		int	doc;
		int	fildes;
		int	ebcdic;
		
		{

		int	nbyte;
		int	rc;
		union {
			short		II
			hex		buff[BUFFSIZE];
			} s;

		snddta_ds.cnvid = cnvid;
		snddta_ds.data = s.buff;

		/* while snastat is in send state, and either of 
		   the read types are successful, perform the
		   send data */

		while( snastat == S2_SEND && ( (!doc && (nbyte =
			read(fildes, s.buff + start, 
			BUFFSIZE - start ) )  
			&& (nbyte != -1)) ||
			(doc&& (fgets(s.buff + start,
			BUFFSIZE - start,stream)) ) ) ) 

			{

			if( doc )   nbyte = strlen( s.buff + start );

			if( ebcdic )
			atoe( s.buff + start, nbyte );

			s.II = nbyte + start;
			snddta_ds.length = nbyte F+ start ;

			if( mapped )

			{

			*( s.buff + 2 ) = 0x12;
			*( s.buff + 3 ) = 0xFF;

			}
			rc = snddta( &snddta_ds );
			if( rec == S2_ERR )
			prterr(names);
			}

		}

Sample Program: Receive a File

OBJECT: 

s2_frcv.c

FULL NAME: 

Receive a file

TYPE: 

End-user Package Main

FUNCTION: 

Program reads the open conversation and writes to
the file name input as a parameter. If the file is sent in
EBCDIC, this program translates it to ASCII. This
program can read from either a basic or mapped
conversation: it simply checks to see what type of
conversation has evoked it and acts accordingly.

INPUTS: 

Node name, conversation ID, EBCDIC or ASCII, (depending on which language the file is in), the RLU name, mode name, and pathname of the file. Node name and conversation ID are provided by the LU; a programmer wishing to write a different source program provides the EBCDIC or ASCII string and the pathname of the file. This program does not use RLU and mode, a part of the PIP data required by IBM System/36 programs.

OUTPUTS: 

A return code of 0 if the file is successfully written to disk; otherwise, -1.

............................................................
***/ 

#ifndef GOLD static char SCCSID[] = "@(#)s2_frcv.c 1.4";#endif


/*.........................................................*/
/*	DATA DEFINITION SECTION 					  */
/*.........................................................*/

#include <fcntl.h>
#include <string.h>
#include "global.h"		/* SNA62 global variables	*/ 	
#include "basic.h"		/* SNA62 Basic Verb Header	*/

#define	BUFFSIZE   802 #define
 		RECSIZE     80

union {
		short II;
		hex 	buff[BUFFSIZE];
		} r;

long		cnvid;		/* Conversation Identifier	*/


/*.........................................................*/
/*	MAINLINE								  */
/*.........................................................*/

main(argc, argv)
int	   argc;
char	  *argv[];
		{
		extern  	int	errno;
		int	rc;
		struct	rcvwt_ds rcvwt_ds;
		int	fildes;
		char	*fspc;
		int	start = 2; 
		int	mapped = 0;	/* Default to basic*/
		int	ebcdic = 0;	/* Default to ascii*/
		


/*.........................................................*/
/*	REMOTELY ATTACH THE PROGRAM				       */
/*.........................................................*/

		rc = lrattach( argv[1], argv[2] );
		if( rc == S2_ERR )
			{
			cleanup();
			exit(-1);
			}


/*.........................................................*/
/*	Determine the type of conversation, set LL offset		  */
/*.........................................................*/
		
			mapped = gtype( cnvid );
			if( mapped == S2_ERR )
				{
				cleanup();
				exit(-1);
				}
			if( mapped )
				start = 4;
			else
				start = 2;



/*.........................................................*/
/*Check parameters, which are in EBCDIC.  Abend if     /* /*parms not here.  Determine if EBCDIC to ASCII       /*
/*transform is needed.                                /*
/*.........................................................*/
		
			if( !argv[3] || !argv[6] )
			if( mapped == S2_ERR )
				{
				cleanup();
				exit(-1);
				}

			etoa( argv[3], strlen(argv[3] ) );
			if( !(strcmp( argv[3], "EBCDIC" ) ))
				ebcdic = 1;
			etoa( argv[6], strlen( argv[6] ) );
				fspc = strchr(argv[6], ' ');
			if( *fspc != '\0';


/*.........................................................*/
/*	Open local file.  Exit if it cannot be open.				  */
/*.........................................................*/

			if ( (fildes = open( argv[6], O_WRONLY | O_CREAT, 
				0777 )) == -1 )
					{
					cleanup();
					exit(-1);
					}



/*.........................................................*/
/*	          Receive the data and write it out.	  */
/*.........................................................*/

		rcvwt_ds.cnvid = cnvid;
		rcvwt_cs.fill = RW_LL;
		rcvwt_ds.data = r.buff;

		while( snastat == SW_RECV && rc !=S2_ERR )

				{
				rcvwt_ds.length = BUFFSIZE;
				
				rc = rcvwt( &rcvwt_ds );
	
				if (rc != S2_ERR && snastat == S2_RECV &&
							rcvwt_ds.what == RW_CMPL )
					{
					if( ebcdic )
					{
					 etoa( r.buff + start, rcvwt_ds.length - 						start ); 
rc = ctus(r.buff + start, rcvwt+ds.length 									- start, fildes);
						}
					else
					{
					rc = write( fildes. r.buff + start, 
								rcvwt_ds.length - start );
					}

				if ( rc == -1)
					(
					cleanup();
					exit(-1);
					}
		}



/*.........................................................*/
	CONFIRM DEALLOCATE
If a confirm deallocate arrives, send back a positive 
response.  A negative response would have been sent prior to this.
/*.........................................................*/

if( snastat == S2_CDELC )
		{
		cnfrmed( cnvid );
		}


/*.........................................................*/
	DEALLOCATE

	If the deallocate returns OK, detach from the LU and end the program.  	If the deallocate fails, (a negative response wasreceived), deallocate 	locally, detach, and end program with an abend code.
/*.........................................................*/

if (snastat == S2_DLCED )
		{
		rc = ldealloc( DC_LOCAL );
		rc = detach();
		rc = 0;
		}

else	
		{
		cleanup();
		rc = -1;
		}
		exit( rc );

		}	/* END FRCV		  	 */
/*.........................................................*/
/*	REMOTE ATTACH		             */
/*.........................................................*/

lrattach(pfile,cconv)
char		*pfile;
char		*cconv;
		
		{
		int	rc;

		cnvid = rattach(pfile, cconv, AT_NOMAX);

		return( cnvid );
		}
/*.........................................................*/
/*	      LDEALLOC				  */
/*.........................................................*/

ldealloc(type)
		
int		type;

		{
		int	rc;

		if ( snastat == S2_DLCED )
			type = DC_LOCAL;
			 
		rc = dalcnv(cnvid,type,NULL);

		return( rc );
		}



/*.........................................................*/
	CLEANUP
	Called if a conversation terminates abnormally.
/*.........................................................*/

cleanup()
		{
		ldealloc( DC_AB_PGM );
		detach();
		}


/*.........................................................*/
  	CTUX
Converts EBCDIC source file to UNIX.  Adds new line termination 
and 	strips spaces at ends of line.  Called if a conversation terminates abnormally.
/*.........................................................*/

ctux(buf, noc, fd)
char	*buf;			/* pointer to buffer */
int	noc;			/* number of characters */
int	fd;			/* file descriptor */
{
char *a, *b;
	
	a = buf;

	while( noc > 0 )
		{
		b = a + RECSIZE - 1;
		while( *b-- == ' ' )
			;

		if( write(fd, a, (unsigned)(b - a + 2)) == -1 )
			return( -1 );

		if( write(fd, "\n", 1) == -1 )
			return( -1 );

		a += RECSIZE;
		noc -= RECSIZE;
		}
	return( 0 );
} 


/*.........................................................*/
	CLEANUP
	Called if a conversation terminates abnormally.
/*.........................................................*/

cleanup()
		{
		ldealloc( DC_AB_PGM );
		detach();
		}
/*.........................................................*/
  	CTUX
Converts EBCDIC source file to UNIX.  Adds new line termination 
and 	strips spaces at ends of line.  Called if a conversation terminates abnormally.
/*.........................................................*/

ctux(buf, noc, fd)
char	*buf;			/* pointer to buffer */
int	noc;			/* number of characters */
int	fd;			/* file descriptor */
{
char *a, *b;
	
	a = buf;

	while( noc > 0 )
		{
		b = a + RECSIZE - 1;
		while( *b-- == ' ' )
			;

		if( write(fd, a, (unsigned)(b - a + 2)) == -1 )
			return( -1 );

		if( write(fd, "\n", 1) == -1 )
			return( -1 );

		a += RECSIZE;
		noc -= RECSIZE;
		}
	return( 0 );
}