/*
 * ttcptest.c
 *
 * Small example for a T/TCP-compliant client.
 *
 * This client tries to connect to the auth (identd) port of the
 * specified host using T/TCP. If T/TCP is not supported it falls
 * back to TCP.
 *
 * (C) Copyright 1996,1997 by Nordic Global Inc. All rights reserved.
 * T/TCP code for use with Miami only.
 *
 * 01/15/97
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/ttcp.h>
#include <proto/exec.h>


static struct Library *MiamiBase=0;
static int dottcp=0;

#define REQUEST "1 : 1\r\n"

void get_response(int sockfd,char *buf,int max) {
	int len=0,le;
	while(len<max-1) {
		le=recv(sockfd,buf+len,max-len-1,0);
		if(le==0) {
			buf[len]=0;
			return;
		}
		if(le<0) {
			fprintf(stderr,"recv: error %d\n",Errno());
			exit(10);
		}
		len+=le;
	}
	buf[max-1]=0;
}	

void main(int argc,char **argv) {
	struct hostent *he;
	struct servent *se;
	int sockfd,n=1,err;
	char buf[256];
	struct sockaddr_in sin;

	if(argc==0)
		exit(0);
	if(argc!=2) {
		fprintf(stderr,"Usage: %s host\n",argv[0]);
		exit(10);
	}


	/* miami.library versions >= 3 support T/TCP */

	if(MiamiBase=OpenLibrary("miami.library",3)) {
		CloseLibrary(MiamiBase);
		dottcp=1;
	}


	if(!(he=gethostbyname(argv[1]))) {
		fprintf(stderr,"Host not found\n");
		exit(10);
	}
	if(!(se=getservbyname("auth","tcp"))) {
		fprintf(stderr,"Service `auth' not found\n");
		exit(10);
	}
	if(0>(sockfd=socket(PF_INET,SOCK_STREAM,0))) {
		fprintf(stderr,"Unable to create socket\n");
		exit(10);
	}

	sin.sin_family=AF_INET;
	sin.sin_len=sizeof(sin);
	memcpy(&sin.sin_addr,he->h_addr,he->h_length);
	sin.sin_port=se->s_port;

	/* ---- start of T/TCP stuff */
	if(dottcp) {

		/* The following call is useful if a sendto() may be larger than
		   the MSS, to ensure that packets are packed tightly. (If this seems
		   strange, that's probably because it is. It has to do with some
		   odd quirks in the implementation of sosend() in all BSD-derived
		   TCP/IP stacks. Don't ask any questions -- just add this call
		   to your program :-)).

           HOWEVER: only add the call if you do NOT reuse your TCP connection
           for multiple requests. If you want to transmit multiple pairs of
           "transaction"/"response" across the same TCP link (e.g. HTTP 1.1
           "persistent TCP connections"), then do NOT add the following
           call. */

		setsockopt(sockfd,IPPROTO_TCP,TCP_NOPUSH,(char *)&n,sizeof(n));

		
		/* Instead of the usual connect() followed by send(), for T/TCP you
		   use a sendto() call, as you would for UDP sockets.
		   
		   If you have a known amount of data to send that you can send in
		   a single function call, then you should use one single sendto()
		   call with the MSG_EOF flag set, as in this example. This is the
		   preferred way to do it, and gives best performance.

		   If you absolutely need to loop then use a sequence like

		    sendto(,,,0,,);
		    while(!done) {
		     send(,,,0);
		    }
		    send(,,,MSG_EOF);

		   this means set the MSG_EOF flag in the *last* send() call only.

		   MSG_EOF performs an implicit shutdown() for one direction of the
		   link, improving performance because the shutdown() can be
		   piggy-backed on data packets, i.e. no additional packets are
		   needed for a shutdown() or CloseSocket() later.
		   
		   However *do not* use MSG_EOF if you want to re-use your
		   connection for subsequent requests (e.g. "persistent TCP
		   connections" in HTTP-1.1). */

		if(sendto(sockfd,REQUEST,strlen(REQUEST),MSG_EOF,(struct sockaddr *)&sin,
		 sizeof(sin))!=strlen(REQUEST)) {
			if((err=Errno())==ENOTCONN) {
			 	/* T/TCP failed. Try ordinary TCP */
				dottcp=0;
			} else {
				fprintf(stderr,"sendto: error %d\n",err);
				exit(10);
			}
		}
	}
	/* ---- end of T/TCP stuff */
	
	if(!dottcp) {
		if(connect(sockfd,(struct sockaddr *)&sin,sizeof(sin))<0) {
			fprintf(stderr,"connect: error %d\n",Errno());
			exit(10);
		}
		if(send(sockfd,REQUEST,strlen(REQUEST),0)!=strlen(REQUEST)) {
			fprintf(stderr,"send: error %d\n",Errno());
			exit(10);
		}
	}
	get_response(sockfd,buf,256);
	puts(buf);
	CloseSocket(sockfd);
}
