TTCP/RFC1644 problem

Karim Fodil-Lemelin kfl at xiphos.ca
Tue Feb 10 09:51:17 PST 2004


Hi,
We actively use TTCP and we like it (www.xiplink.com). The problem is 
that it does not behave exactly like in Steven's book.  I have sample 
code if you want to try it. But basically you need to set the NOPUSH 
flag (setsockopt()) before   using sendto() _and_ in the server as 
well.  For short duration connections over satellite links, its very 
useful since it can save one RTT per connections (minimum 600ms) which 
can be very important when dealing with thousands of connections. See 
attachment for example and dumps.  It does have to be used carefully 
(with security concerns), but can still be very useful.

We are currently based on 4.8 and will port to 5.x whenever it becomes 
stable. I for one, would be very happy if FreeBSD continues supporting 
T/TCP.  There are systems and users out there!

Here is the dump:

12:44:01.851882 192.168.27.2.1096 > 192.168.28.2.8908: SFP 
919859592:919859992(400) win 65535 <mss 1460,nop,wscale 
3,opt-20:5000,nop,nop,timestamp 68099116 0,nop,nop,cc 146> (DF)
12:44:01.852185 192.168.28.2.8908 > 192.168.27.2.1096: S 
3400625327:3400625327(0) ack 919859994 win 65535 <mss 1460,nop,wscale 
3,nop,nop,timestamp 68113687 68099116,nop,nop,cc 309,nop,nop,ccecho 146> 
(DF)
12:44:01.852355 192.168.27.2.1096 > 192.168.28.2.8908: . ack 1 win 62640 
<nop,nop,timestamp 68099117 68113687,nop,nop,cc 146> (DF)
12:44:01.852472 192.168.28.2.8908 > 192.168.27.2.1096: . ack 1 win 62500 
<nop,nop,timestamp 68113687 68099117,nop,nop,cc 309> (DF)
12:44:01.852718 192.168.28.2.8908 > 192.168.27.2.1096: F 1:1(0) ack 1 
win 62500 <nop,nop,timestamp 68113687 68099117,nop,nop,cc 309> (DF)
12:44:01.852846 192.168.27.2.1096 > 192.168.28.2.8908: . ack 2 win 62640 
<nop,nop,timestamp 68099117 68113687,nop,nop,cc 146> (DF)

First packet you see the SYN-FIN PUSH, then second packet it gets acked 
(data + SYN + FIN) then the connection closes. BTW don't mind the option 
20 (opt-20) Its our implementation of SCPS-TP.


Karim
Xiphos Technologies.

Andre Oppermann wrote:

>Danny Braniss wrote:
>  
>
>>>I have been the last one fuzz around in the TTCP code areas.  However
>>>there could be problems that were lurking there before in other code
>>>parts (syncache maybe).  TTCP isn't used in production by anyone (AFAIK)
>>>and only minimally tested.
>>>      
>>>
I have to disagree here :)

>>ahh, that's one realy good piece of info so far.
>>this is one more step away from 'don't judge a book by it's cover' ...
>>reading the specs of ttcp, it seemed promising, but i guess it becomes
>>insignificat when the world uses ssl:-)
>>    
>>
>
>There are who like it and there are people who hate it.
>
>  
>
>>>What FreeBSD version are you using?
>>>      
>>>
>>4.8, 4.9 and current.
>>    
>>
>
>In 4.8 and 4.9 is the legacy code.  When it doesn't work between a
>4.x client and server then the TTCP as such is broken.  My changes
>(tcp hostcache) are in 5.2 for the first time.  Before it it's the
>legacy code as well.  I hope I haven't broken TTCP more than it was
>before.
>  
>
>  
>
>>and solaris(but i guess they don't do ttcp) and linux (not yet).
>>    
>>
>
>Linux never will.  They consider TTCP broken by design.  Solaris
>I dont know.
>
>The problem is that TTCP will never make it mainstream or even
>little side stream.  FreeBSD is the only BSD implementing it.
>Removing it would make maintainance of the tcp code a bit easier.
>Yet there are a couple of our FreeBSD folks emotionally attached
>to it (but they do not actively or even passively maintain it).
>
>  
>

-------------- next part --------------
#include "cliserv.h"

int read_stream (int fd, char *ptr, int maxbytes)
{
        int nleft, nread;

        nleft = maxbytes;
        while (nleft > 0) {
                if ((nread = read(fd, ptr, nleft)) < 0)
                        return (nread);         /* error return < 0 */
                else if (nread == 0)
                        break;                  /* EOF, return #bytes read */
                nleft -= nread;
                ptr += nread;
        }
        return (maxbytes - nleft);
}


int main (int argc, char *argv[])
{
	struct sockaddr_in serv, cli;
	char *request;
	int listenfd, sockfd, n, clilen;
	int One = 1;

	if ((listenfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
		printf("socket error\n");
		exit(0);
	}

	memset(&serv, sizeof(serv), 0);
	serv.sin_family = AF_INET;
	serv.sin_port = htons(TCP_SERV_PORT);
	serv.sin_addr.s_addr = htonl(INADDR_ANY); 

	if (bind(listenfd, (SA)&serv, sizeof(serv)) < 0) {
		perror("bind error");
		exit(0);
	}


	if (listen(listenfd, SOMAXCONN) < 0) {
		printf("listen error\n");
		exit(0);
	}


	for(;;) {
		clilen = sizeof(cli);
		printf("waiting for client to connect\n");
		setsockopt(listenfd, IPPROTO_TCP, TCP_NOPUSH, &One, sizeof (One));
		if ((sockfd = accept(listenfd, (SA)&cli, &clilen)) < 0) {
			printf("accept error\n");
			exit(0);
		}

		One = 0;	
		setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &One, sizeof (One));

		if ((n = read(sockfd, request, REQUEST)) < 0) {
			printf("read error\n");
			exit(0);
		}
		printf("%d\n", n);
		close(sockfd);
	}
}
-------------- next part --------------
#include <netdb.h>
#include "cliserv.h"

int read_stream (int fd, char *ptr, int maxbytes)
{
        int nleft, nread;

        nleft = maxbytes;
        while (nleft > 0) {
                if ((nread = read(fd, ptr, nleft)) < 0)
                        return (nread);         /* error return < 0 */
                else if (nread == 0)
                        break;                  /* EOF, return #bytes read */
                nleft -= nread;
                ptr += nread;
        }
        return (maxbytes - nleft);
}

int main (int argc, char *argv[])
{
        struct sockaddr_in serv;
        struct hostent *host;
        char request[REQUEST];
        uint32_t ipAddr;
        int sockfd, n;
	int eof;
	int One = 1;

        if (argc !=3) {
                printf("usage: ttcpcli <IP address or name of server> <EOF>\n");
                exit(0);
        }
	sscanf(argv[2], "%d", &eof);

        if ((sockfd = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
                printf("socket error\n");
                exit(0);
        }

        memset(&serv, sizeof(serv), 0);
        serv.sin_family = AF_INET;
        serv.sin_port = htons(TCP_SERV_PORT);
        if ((ipAddr = inet_addr(argv[1])) != -1) {
                serv.sin_addr.s_addr = ipAddr;
        }
        else if ((host = gethostbyname(argv[1])) != NULL) {
                bcopy((char *)host->h_addr, (char *)&serv.sin_addr, host->h_length);
        }
        else {
                printf("unknown host\n");
                exit(0);
        }

	/* form request */
	strcpy(request, "This is a T/TCP payload");
	setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &One, sizeof (One));

	if (eof) {
		if (sendto (sockfd, request, REQUEST, MSG_EOF, (SA)&serv, sizeof(serv)) != REQUEST) {
			printf("sendto error\n");
			exit(0);
		}
	}
	else {
		if (sendto (sockfd, request, REQUEST, 0, (SA)&serv, sizeof(serv)) != REQUEST) {
                        printf("sendto error\n");
                        exit(0);
                }
	}

        setsockopt(sockfd, IPPROTO_TCP, TCP_NOPUSH, &One, sizeof (One));

	/* Normally we would receive data and do some processing */
	read(sockfd, request, REQUEST);
	exit(0);
}
-------------- next part --------------
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define SA struct sockaddr *
#define REQUEST 400
#define REPLY	400
#define TCP_SERV_PORT 8908



More information about the freebsd-net mailing list