Article delegate-en/2947 of [1-5169] on the server localhost:119
  upper oldest olders older1 this newer1 newers latest
[Top/Up] [oldest] - [Older+chunk] - [Newer+chunk] - [newest + Check]
Newsgroups: mail-lists.delegate-en

[DeleGate-En] Re: delegate tcp handshake over persistent connection?
19 May 2005 23:32:53 GMT (Yutaka Sato)
The DeleGate Project

Hi Tom,

In message <_A2922@delegate-en.ML_> on 04/25/05(09:06:48)
you Tom Hansen <> wrote:
 |Hi, I'm using delegate to try to setup a persistent connection(Pcon) over a
 |delayed link for improved performance. The quick question is can delegate be
 |setup to send data on initial connection establishment? 

No it has not.
But now, SockMux protocol has been extended to be able to do so :)

Reducing the overhead by repetitive hand-shakes for TCP connections
was the very motivation to make such an application-level multiplexer
like "ThruWay", which was superseded by SockMux later.

ThruWay was intended to speed-up HTTP connections, but it was not used
so because Keep-Alive in HTTP/1.1 deployed swiftly, and the RTTs over
the world have been improved.

But now, as networks have become diverse, it seems that we still have
(new) networks with slow RTTs, and HTTP and non-HTTP implementations
which need to be saved out of such situation.

It was in my TODO list in DeleGate/9 to improve the implementation of
SockMux to make the band-width wider.  But before thinking about it,
inspired by your request, I decided to refine the response time on the

 |Detailed question, using the example tcprelay as a guide:
 |hostX% delegated SERVER=sockmux://hostY:9000 PORT=hostX:4567
 |hostY% delegated SERVER=sockmux -PhostY:9000 DEST=hostY:3128
 |still in place. As far as 3way handshake is concerned, delegate at least in
 |this configuration, is only slightly faster by 1 trip. How I'd like it to
 |operate is for the local client connections to be spoofed but also connection
 |establishment through the Pcon only happen with first data, 2way handshake with

The sub-protocols to establish a connection and send data on it,
on a SockMux persistent channel is like this:

   client ---- CONNECT X:* s:p ---> server [s:p]
          <--- CONNECTED X:Y   ----
          ---- SEND X:Y [req1] --->
          ---- SEND X:Y [req2] --->
          <--- SEND X:Y [res1] ----
          <--- SEND X:Y [res2] ----
          <--- SEND X:Y [res3] ----
          <--- CLOSE X:Y       ----

After a connection is established, the peer is identified with an
ID number (Y) and the ID number is used to send data.
So it requires one trip (CONNECT / CONNECTED) before sending the
first data.

Firstly, I thought to introduce generic "SEND X:*" which does not
specify the destination.  But it might make the protocol a little
more complex.  So I extended CONNECT and CONNECTED message to be
able to have initial data.  It is realized with very small extension
like the enclosed patch.  When a socket, right after it is connected
to a client or a server, has data ready to be read (polled for 1
milli-second), it is sent with CONNECT/CONNECTED message like this.

   client ---- CONNECT X:* s:p [req1] ---> server [s:p]
          <--- CONNECTED X:Y [res1]   ----
          ---- SEND X:Y [req1]        --->
          <--- SEND X:Y [res2]        ----
          <--- SEND X:Y [res3]        ----
          <--- CLOSE X:Y              ----

When a request is smaller than 480 bytes or so, the response is got
in one round trip as you expected like this:

   client ---- CONNECT X:* s:p [req1] ---> server [s:p]
          <--- CONNECTED X:Y [res1]   ----
          <--- SEND X:Y [res2]        ----
          <--- SEND X:Y [res3]        ----
          <--- CLOSE X:Y              ----

 |There appears to be a dizzying array of modes and options to delegate and I'm
 |hoping what I'm looking already works in delegate but in a different
 |configuration than I'm using. Maybe instead of a generic tcp relay perhaps
 |using a HTTP specifc mode or using a master configuration to indicate a
 |delegate to delegate relay and use some intra-delegate connection optimization.
 |If it helps, the use is exactly as in this example, it's being used to
 |accelerate a delayed link for a browser and HTTP proxy(squid). 

Bundling parallel-connections generated by a HTTP browser into a single
persistent connection to HTTP proxy/server might be effective too.

I enabled the feature in SockMux by default, and introduced a new option
to disable it as this:


Preliminary testing to compare the response times with and without this
option shows that the feature makes significant improvement for the first
HTTP request/response on a network where the RTT is not so short.
I uploaded the modified version as 9.0.3-pre1 at

  D G   Yutaka Sato <>
 ( - )  National Institute of Advanced Industrial Science and Technology
_<   >_ 1-1-4 Umezono, Tsukuba, Ibaraki, 305-8568 Japan
Do the more with the less -- B. Fuller

diff -cr delegate9.0.2/src/sox.c delegate9.0.3-pre1/src/sox.c
*** delegate9.0.2/src/sox.c	Wed Apr 27 22:46:42 2005
--- delegate9.0.3-pre1/src/sox.c	Fri May 20 05:43:28 2005
*** 616,621 ****
--- 616,661 ----
  	return ival;
+ static int SOX_WAITINIT = 1; /* wait the initial data ready (in milli-sec.) */
+ /*
+  * initial data which is ready at the begining of a connection is sent
+  * with a CONNECT request or a CONNECTED response packet
+  */
+ static void get_conndata(Agent *Apn,Packet *pack){
+ 	int len;
+ 	int pcc;
+ 	if( 0 < PollIn(Apn->a_sock,SOX_WAITINIT) ){
+ 		len = strlen(pack->p_data);
+ 		pcc = recv(Apn->a_sock,pack->p_data+len+1,PWSIZE-len-1,0);
+ 		if( 0 < pcc ){
+ 			PK_setLeng(pack,len+1+pcc);
+ 			Trace("CONNECT+DATA send %d (%d)",pcc,PK_Leng(pack));
+ 		}
+ 	}
+ }
+ static void put_conndata(Packet *pack,int clsock)
+ {	int wcc;
+ 	int pcc = 0;
+ 	int len;
+ 	const char *peek;
+ 	len = strlen(pack->p_data);
+ 	if( len+1 < PK_Leng(pack) ){
+ 		pcc = PK_Leng(pack) - len - 1;
+ 		peek = pack->p_data+len+1;
+ 	}
+ 	if( pcc <= 0 )
+ 		return;
+ 	wcc = send(clsock,peek,pcc,0);
+ 	Trace("CONNECT+DATA recv %d / %d (%d)",pcc,wcc,PK_Leng(pack));
+ 	if( wcc != pcc ){
+ 		/* this is assumed to succeed immediately */
+ 		daemonlog("F","SOX CONNECT+DATA failed %d/%d\n",pcc,wcc);
+ 	}
+ }
   * CONNECT N.bufsize A.client A.clientif
*** 625,630 ****
--- 665,671 ----
  	sprintf(pair,"%d %s %s",MAXBUFSIZE,remote,local);
+ 	get_conndata(Apn,pack);
  static void get_CONNECT(Packet *pack,PVStr(remote),PVStr(local))
  {	int bsiz;
*** 1965,1970 ****
--- 2006,2012 ----
  			goto SOXCLOSE;
  		if( 0 <= clsock ){
+ 			put_conndata(pack,clsock);
  			Apn = newAgent(sox,PK_Said(pack),clsock,SOX_CONNECTED);
*** 1990,1995 ****
--- 2032,2038 ----
  		Trace("CONNed< L#%d <- R#%d[%s]",
  		if( ApR ){
+ 			put_conndata(pack,ApR->a_sock);
  			ApR->a_Xaid = PK_Said(pack);
  			ApR->a_stat = SOX_CONNECTED;
  			Qfdset = 0;

  admin search upper oldest olders older1 this newer1 newers latest
[Top/Up] [oldest] - [Older+chunk] - [Newer+chunk] - [newest + Check]