/*---------------------------------------------------------------------+
| Copyright (c) 1996, SAS Institute Inc. |
| Unpublished - All Rights Reserved |
| S A S / C S A M P L E |
| |
| NAME: TCPOEC |
| LANGUAGE: C |
| PURPOSE: Demonstrate a TCP Client application that connects to |
| a TCPOED, an open edition daemon. The client |
| connects to TCPOED, then does a send() and recv(). |
| MVS - |
| COMPILE, LINK, and EXECUTE: SUBMIT prefix.SAMPLE.AUX(TCPOEC) |
| where "prefix" is the installation defined high-level- |
| qualifier for the SAS/C product. |
| NOTES: On the //EXEC statement add a: ,PARM.GO='host_name' |
| where "host_name" is an optional hostname value |
| NOTES: TCPOEC 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(TCPOEC)' 'host_name' |
| where "host_name" is an optional hostname value |
| NOTES: TCPOEC assumes a working TCP/IP environment on both |
| the local and remote hosts. Refer to MISC NOTES: |
| |
| OE - In order to compile, link, and execute under the OE shell, |
| the source file should first be copied to an HFS directory. |
| You may use the following commands to move the program to |
| the HFS system: |
| ALLOC F(TCPOEC) DS('prefix.SAMPLE.C(TCPOEC)') SHR |
| ALLOC F(HFSFIL) PATH('/path/tcpoec.c') PATHDISP(KEEP,DELETE) |
| PATHMODE(SIRUSR,SIWUSR) PATHOPTS(ORDWR,OCREAT) |
| OCOPY INDD(TCPOEC) OUTDD(HFSFIL) TEXT PATHOPTS(USE) |
| NOTE: Refer to the Open Edition MVS User's Guide for more |
| details, SC23-3013-02 |
| |
| COMPILE/LINK: sascc370 -Krent -o /path/tcpoec /path/tcpoec.c |
| NOTE: Refer to the SAS/C Compiler and Library User's Guide, |
| 4th Edition, Release 6.00, and the SAS/C Installation |
| Instructions for details on using the compiler and library|
| under the OE Shell. |
| EXECUTE: TCPOEC host_name |
| where "host_name" is an optional hostname value |
| NOTES: TCPOEC 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: TCPOEC host_name |
| where "host_name" is an optional hostname value |
| NOTES: TCPOEC assumes a working TCP/IP environment on both |
| the local and remote hosts. Refer to MISC NOTES: |
| MISC NOTES: TCPOEC needs to be customized for the local TCP/IP |
| environment. The local information required by |
| TCPOEC is: |
| HOST_NAME - host name running TCPOED. Ensure |
| the TCP/IP environment has been configured |
| for name resolution, |
| default is: "mvs" |
| HOST_PORT - port TCPOED has been configured to do a |
| listen(), default is 6177. |
| HOST_CNT - number of iterations TCPOEC will execute, |
| default is: 20 |
| HOST_TOK - Token sent to TCPOED child process. |
| The keywords and values are customized by #define's |
| immediately following the #include statements below: |
+---------------------------------------------------------------------*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
/*-------------------------------------------------------------------------+
| function prototypes |
+-------------------------------------------------------------------------*/
int init_sock(struct sockaddr_in *sa);
char *build_tok(void);
int send_data(int sockfd, char *buffer, int buf_len);
int recv_int(int sock_fd, int len);
char *recv_data(int sock_fd, int len);
/*-------------------------------------------------------------------------+
| Customize the values below to identify the host and port as configured |
| for the tcpoed application, token, and number of iterations. |
+-------------------------------------------------------------------------*/
#define HOST_NAME "sdcesa" /* Host name running TCPOED */
#define HOST_PORT 6177 /* tcpoed "well known port" */
#define HOST_CNT 10 /* Number of iterations for TCPOEC */
#define HOST_TOK "childtok" /* Token sent to TCPOED child process */
#define TOK_MAX 8 /* Token size */
#define BUF_SIZE 8192 /* Default TCPIP databufferpoolsize */
main(int argc, char *argv[])
{
struct hostent *hp; /* gethostbyname() structure */
struct sockaddr_in sa; /* connect() structure */
int i, recv_rc, send_rc, sockfd;
int sock_go; /* when enabled, issue socket calls */
char *message, *h_name, *h_tok;
/*-------------------------------------------------------------------------+
| call gethostbyname() with the HOST_NAME or argv[1] l |
+-------------------------------------------------------------------------*/
if (argc < 2)
h_name = HOST_NAME;
else
h_name = argv[1];
hp = gethostbyname(h_name);
if (!hp)
{
printf("unable to resolve host name: %s\n",h_name);
return (-1);
}
h_tok = build_tok();
if (h_tok == NULL)
{
printf("unable to build token\n");
return (-1);
}
/*-------------------------------------------------------------------------+
| initialize the sockaddr_in structure |
+-------------------------------------------------------------------------*/
memset(&sa,'\0',sizeof(sa)); /* initialize "sa" */
sa.sin_family = AF_INET;
sa.sin_port = htons(HOST_PORT);
sa.sin_addr.s_addr = *(unsigned long *) hp->h_addr;
/*-------------------------------------------------------------------------+
| print values used to connect to daemon |
+-------------------------------------------------------------------------*/
printf("\nUsing the following values to connect to tcpoed\n");
printf("IP address: %s\n",inet_ntoa(sa.sin_addr));
printf("Port number: %d\n",sa.sin_port);
printf("Execution count: %d\n\n",HOST_CNT);
/*-------------------------------------------------------------------------+
| Do the work: issue a socket(), connect(), send() and recv(). If any |
| socket fuction fails, set sock_go=0, and call socktrm(). |
+-------------------------------------------------------------------------*/
for (i=1; i <= HOST_CNT; i++)
{
printf("Iteration number: %d\n", i);
sock_go = 1;
sockfd = init_sock(&sa);
if (sockfd < 0)
sock_go = 0;
/*------------------------------------------------------------------------+
| send_data() - with socket descriptor, h_tok value, and length |
+------------------------------------------------------------------------*/
if (sock_go)
{
send_rc = send_data(sockfd, h_tok, strlen(h_tok));
if (send_rc < 0)
sock_go = 0;
}
/*------------------------------------------------------------------------+
| recv() - get the message length - first four bytes of data |
+------------------------------------------------------------------------*/
if (sock_go)
{
recv_rc = recv_int(sockfd, sizeof(int));
if (recv_rc < 0)
sock_go = 0;
}
/*------------------------------------------------------------------------+
| recv() - get the message and print |
+------------------------------------------------------------------------*/
if (sock_go)
{
message = recv_data(sockfd, recv_rc);
if (message == NULL)
sock_go = 0;
else
printf("data received ==> %s\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". |
+-------------------------------------------------------------------------*/
if (sock_go)
{
close(sockfd);
}
/*-------------------------------------------------------------------------+
| if sock_go is not enabled an error occured. When on MVS or CMS |
| issue socktrm(), else exit with an error. |
+-------------------------------------------------------------------------*/
if (!sock_go)
#if defined(OSVS) | defined(CMS)
socktrm();
#else
exit(-1);
#endif
} /* end of for() loop */
printf("tcpoec complete\n");
return(0);
}
/*-------------------------------------------------------------------------+
| create a socket, connect to server and return socket number |
+-------------------------------------------------------------------------*/
int init_sock(struct sockaddr_in *sa)
{
int sockfd;
sockfd = socket(AF_INET,SOCK_STREAM,0);
if (sockfd == -1)
{
perror("socket call failed");
return(-1);
}
if (connect(sockfd, sa, sizeof(struct sockaddr_in)) == -1)
{
perror("connect () failed");
return(-1);
}
return(sockfd);
}
/*-------------------------------------------------------------------------+
| build a token, translate if required and return token to caller |
+-------------------------------------------------------------------------*/
char *build_tok()
{
char *h_tok;
int s_len;
#if defined(OSVS) | defined(CMS)
int si; /* used for htoncs() */
#endif
h_tok = (char * ) calloc(TOK_MAX + 1, sizeof(char));
if (h_tok == NULL)
return(NULL);
strncpy(h_tok,HOST_TOK,TOK_MAX);
s_len = strlen(h_tok);
/*-------------------------------------------------------------------------+
| When running on MVS or CMS convert HOST_TOK 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_tok[si] = htoncs(h_tok[si]);
#endif
return(h_tok);
}
/*-------------------------------------------------------------------------+
| send data to server, return length sent or an error |
+-------------------------------------------------------------------------*/
int send_data(int sockfd, char *buffer, int buf_len)
{
int msg_len;
msg_len = send(sockfd, buffer, buf_len, 0);
if (msg_len <0)
{
perror("send() call failed");
return(-1);
}
return(msg_len);
}
/*-------------------------------------------------------------------------+
| read an int from the socket and return the value or -1 |
+-------------------------------------------------------------------------*/
int recv_int(int sock_fd, int len)
{
int *ptr, recv_rc, bytes_rem, ret_val;
ret_val = 0;
ptr = &ret_val;
bytes_rem = len;
while (bytes_rem > 0)
{
recv_rc = recv(sock_fd, ptr, bytes_rem, 0);
if (recv_rc <= 0 )
{
perror("recv() failed");
return(-1);
}
else
{
bytes_rem -= recv_rc;
ptr += recv_rc;
}
}
ret_val = ntohl(ret_val);
return(ret_val);
}
/*-------------------------------------------------------------------------+
| read data from the socket, convert to ebcdic if required, return |
| NULL or a pointer to the data received. |
+-------------------------------------------------------------------------*/
char *recv_data(int sock_fd, int len)
{
char *message, *ptr;
int recv_rc, bytes_rem;
#if defined(OSVS) | defined(CMS)
int xi;
#endif
message = (char * ) malloc(len + 1);
if (message == NULL)
{
printf("recv_data() malloc failed\n");
return(NULL);
}
memset(message, '\0', len + 1);
ptr = message;
bytes_rem = len;
while (bytes_rem > 0)
{
recv_rc = recv(sock_fd, ptr, bytes_rem, 0);
if (recv_rc <= 0 )
{
perror("recv() failed");
return(NULL);
}
else
{
bytes_rem -= recv_rc;
ptr += recv_rc;
}
}
#if defined(OSVS) | defined(CMS)
for ( xi = 0; xi < len; xi++)
message[xi] = ntohcs(message[xi]);
#endif
return(message);
}
|