/*---------------------------------------------------------------------+ | 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 #include #include #include #include #include #include #include #include #include /*-------------------------------------------------------------------------+ | 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); }