/*---------------------------------------------------------------------+
| Copyright (c) 1995, SAS Institute Inc. |
| Unpublished - All Rights Reserved |
| S A S / C S A M P L E |
| |
| NAME: TCPCLNT |
| LANGUAGE: C |
| PURPOSE: Demonstrate a TCP Client application that connects to |
| a TCP Listener, TCPLISTN, on MVS. The client |
| connects to TCPLISTN, then issues a send() and recv(). |
| MVS - |
| COMPILE, LINK, and EXECUTE: SUBMIT prefix.SAMPLE.AUX(TCPCLNT) |
| where "prefix" is the installation defined high-level- |
| qualifier for the SAS/C product. |
| NOTES: TCPCLNT assumes a working TCP/IP environment on both |
| the local and remote hosts, refer to MISC NOTES. |
| TSO - |
| COMPILE: LC370 CLIST - options ENXREF EXTNAME RENT |
| LINK: CLK370 CLIST |
| EXECUTE: call 'your.load.library(TCPCLNT)' |
| NOTES: TCPCLNT assumes a working TCP/IP environment on both |
| the local and remote hosts. Refer to MISC NOTES: |
| CMS - |
| COMPILE: LC370 EXEC - options ENXREF EXTNAME RENT |
| LINK: CLINK EXEC |
| EXECUTE: TCPCLNT |
| NOTES: TCPCLNT assumes a working TCP/IP environment on both |
| the local and remote hosts. Refer to MISC NOTES: |
| MISC NOTES: TCPCLNT needs to be customized for the local TCP/IP |
| environment. The local information required by |
| TCPCLNT is: |
| HOST_NAME - hostname running TCPLISTN. Ensure |
| the TCP/IP environment has been configured |
| for hostname resolution, |
| default is: "mvs" |
| HOST_PORT - port TCPLISTN has been configured to do a |
| listen(), default is 13. |
| HOST_CNT - number of iterations TCPCLNT will execute, |
| default is: 2 |
| HOST_SERV - module name that TCPLISTN "attaches", |
| default is: TCPTSERV |
| The keywords and values are customized by #define's |
| immediately following the #include statements below: |
+---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#if __SASC__ == 550
#include <fcntl.h>
#else
#include <unistd.h>
#endif
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
/*-------------------------------------------------------------------------+
| Customize the values below to identify the host and port as configured |
| for the TCPLISTN and TCPTSERV application, iterations and server name. |
+-------------------------------------------------------------------------*/
#define HOST_NAME "mvs" /* Host name running TCPLISTN */
#define HOST_PORT 13 /* TCPLISTN "well known port" */
#define HOST_CNT 20 /* Number of iterations for TCPCLNT */
#define HOST_SERV "TCPTSERV" /* Name of server TCPLISTN "attaches" */
#define SERV_MAX 8 /* Number of bytes for server name */
#define BUF_SIZE 8192 /* Default TCPIP databufferpoolsize */
main()
{
struct hostent *hp; /* gethostbyname() structure */
struct sockaddr_in sa; /* connect() structure */
int count, i, sockfd, msg_len, s_len, so_optval;
char *message, *h_serv;
#if defined(OSVS) | defined(CMS) /* variables used for htoncs() and */
int si, xi; /* ntohcs() */
#endif
message = (char * ) malloc(BUF_SIZE+1);
memset(message,'\0',sizeof(BUF_SIZE+1));
memset(&sa,'\0',sizeof(sa)); /* initialize "sa" */
/*-------------------------------------------------------------------------+
| call gethostbyname() using the HOST_NAME value. If this fails then call |
| printf() and return. |
| |
+-------------------------------------------------------------------------*/
hp = gethostbyname(HOST_NAME);
if (!hp)
{
printf("unable to resolve host name: %s\n",HOST_NAME);
return (-1);
}
else
sa.sin_addr.s_addr = *(unsigned long *) hp->h_addr;
/*-------------------------------------------------------------------------+
| assign #define values to application variables |
| |
+-------------------------------------------------------------------------*/
count = HOST_CNT;
sa.sin_port = htons(HOST_PORT);
/*-------------------------------------------------------------------------+
| print TCPLISTN and TCPTSERV information for user consumption |
| |
+-------------------------------------------------------------------------*/
printf("\nUsing the following values to connect to TCPLISTN\n");
printf("IP address: %s\n",inet_ntoa(sa.sin_addr));
printf("Port number: %d\n",sa.sin_port);
printf("Execution count: %d\n",count);
printf("Server name: %s\n\n",HOST_SERV);
/*-------------------------------------------------------------------------+
| Do the work: issue a socket(), connect(), send() and recv(). If any |
| socket call fails, then perror() and return. |
+-------------------------------------------------------------------------*/
for (i=1; i <=count; i++)
{
printf("iteration number: %d\n", i);
sa.sin_family = AF_INET;
printf("socket called()\n");
sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd == -1)
{
perror("socket call failed");
return -1;
}
else
printf("socket number: %d\n",sockfd);
/*-------------------------------------------------------------------------+
| demonstrate how one may set a specific socket option with setsockopt(). |
| SO_KEEPALIVE - informs TCP to periodically pool the remote host and |
| terminate the connection, if a condition exists where: the connection is |
| no longer active and has NOT gone through close() processing. |
+-------------------------------------------------------------------------*/
so_optval = 1;
if (setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, (char *) &so_optval,
sizeof(SO_KEEPALIVE)) == -1)
perror("setsockopt() so_keepalive failed");
else
printf("setsockopt() so_keepalive successful\n");
if (connect(sockfd,&sa,sizeof(sa)) == -1)
{
perror("connect () failed");
return -1;
}
else
printf("connect() successful\n");
h_serv = (char * ) calloc(SERV_MAX + 1, sizeof(char));
strncpy(h_serv,HOST_SERV,SERV_MAX);
s_len = strlen(h_serv);
/*-------------------------------------------------------------------------+
| When running on MVS or CMS convert HOST_SERV from a host character set |
| to a network character set, EBCDIC to ASCII |
+-------------------------------------------------------------------------*/
#if defined(OSVS) | defined(CMS)
for ( si = 0; si < s_len; si++ )
h_serv[si] = htoncs(h_serv[si]);
#endif
/*------------------------------------------------------------------------+
| Call send() with the socket, HOST_SERV value, length, and flags |
+------------------------------------------------------------------------*/
msg_len = send(sockfd,h_serv,s_len +1 ,0);
if (msg_len <0)
{
perror("send() failed");
close(sockfd);
return -1;
}
printf("send() successful\n");
msg_len = recv(sockfd,message,BUF_SIZE,0);
if (msg_len <0)
{
perror("recv() failed");
close(sockfd);
return -1;
}
else
{
/*-------------------------------------------------------------------------+
| When running on MVS or CMS convert the message received from a network |
| character set to a host character set, ASCII to EBCDIC. |
+-------------------------------------------------------------------------*/
#if defined(OSVS) | defined(CMS)
for ( xi = 0; xi < msg_len; xi++)
message[xi] = ntohcs(message[xi]);
#endif
printf("recv() successful\n");
printf("length of data received: %d\n",msg_len);
printf("data received: %s\n\n",message);
}
/*-------------------------------------------------------------------------+
| issue a close() after each socket connection is complete. A mis-behaved |
| application could leave the socket open and let the OS clean-up the |
| socket, at environment termination. Keeping the socket open may cause |
| buffer or storage "anomalies". |
+-------------------------------------------------------------------------*/
close(sockfd);
} /* end of for() loop */
printf("TCPCLNT complete\n");
return(0);
}
|