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