/*---------------------------------------------------------------------+ | 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 #include #include #if __SASC__ == 550 #include #else #include #endif #include #include #include #include #include #include /*-------------------------------------------------------------------------+ | 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); }