Messages in this thread | | | Date | Mon, 14 Aug 2000 18:54:45 +0300 | From | Anton Ghiugan <> | Subject | TCP_MAXSEG and getsockopt() |
| |
It looks like getsockopt() function call always returns a default value of zero for MSS parameter (maximum segement size) unless the user has preset it to some different value by calling setsockopt(). Checking with the source code (net/ipv4/tcp_output.c) I have discovered that Linux uses three different variables for MSS (listed below are fragments form comments found in lines 254-274 in the above mentioned source file): - "user_mss is mss set by user by TCP_MAXSEG" - "mss_cache is current effective sending mss" - "mss_clamp is mss negotiated at connection setup. It is minumum of user_mss and mss received with SYN"
As you may guess getsockopt()/setsockopt() when called w/ TCP_MAXSEG operates *only* on the user_mss. While I find perfectly normal for setsockopt() to operate on (that is : modify) user_mss - since the user should be provided w/ a meaning to express what he/she wants the mss to be - I don't find any good reason why getsockopt() should return the same value. At least two reasons makes me belive this is an error: 1. The user program can always remember what value he passed to setsockopt(), if any. Besides of that any system call , including getsockopt()should take longer than a in-memory access in user space. 2. Other implementations of TCP/IP protocol notably SunOS) return correct value. See the source code at the end of this email of a small test application that has been used to verify this assumption.
IMHO getsockopt() should return the value of mss_cache variable. Enclosed is a patch that should modify the kernel in this matter.
---------> CUT HERE <---------------- *** linux/net/ipv4/tcp.c Mon Aug 14 10:52:52 2000 --- - Mon Aug 14 11:01:58 2000 *************** *** 1764,1772 **** len = min(len, sizeof(int)); switch(optname) { case TCP_MAXSEG: ! val = tp->user_mss; break; case TCP_NODELAY: val = (sk->nonagle == 1); break; --- 1764,1772 ---- len = min(len, sizeof(int)); switch(optname) { case TCP_MAXSEG: ! val = tp->mss_cache; break; case TCP_NODELAY: val = (sk->nonagle == 1); break; ---------> CUT HERE <----------------
As promised here it is the source code of the test application that helped me to detect the above bug. The program has been tested on several Linux machines including: 2.2.14-12smp /i686 2.2.16-3 /alpha ---------> CUT HERE <---------------- #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <netinet/tcp.h> int main(int argc, char **argv) {
struct sockaddr_in dest ; unsigned int mss ; socklen_t sl; int s ;
if(argc != 3) { fputs("USAGE: getmss.c <host_ip> <port>\n", stderr) ; return 0 ; }
s = socket(AF_INET, SOCK_STREAM, 0) ; if(s == -1) { perror("socket"); return -1 ; } memset(&dest, 0, sizeof(dest)) ;
dest.sin_family = AF_INET ; dest.sin_addr.s_addr = inet_addr(argv[1]) ; dest.sin_port = htons(atoi(argv[2])); if(connect(s, &dest, sizeof(dest)) == -1) { perror("connect"); close(s) ; return -1 ; }
fprintf(stderr, "Connected to %s on port %s !\n", argv[1], argv[2]);
mss = 0 ; sl = sizeof(mss) ;
if(getsockopt(s, IPPROTO_TCP, TCP_MAXSEG, &mss, &sl) == -1) { perror("getsockopt"); close(s) ; return -1 ; }
fprintf(stdout, "MSS = %u (sizeof(MSS) = %d)\n", mss, sl) ; fflush(stdout) ; close(s) ;
return 0 ; } ---------> CUT HERE <----------------
------------------------------ K Free E-mail http://www.k.ro/ by KappaNet http://www.kappa.ro/
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |