I'm pretty sure this is a kernel problem
1. small socket send/receive buffers result in data not being transferred
2. I was playing with socket buffers using setsockopt() and SO_SNDBUF
and SO_RCVBUF (see small attached programs), I found that given small
enough buffers, data would stop being sent, although more was available.
I suspect what is happening is that one of the buffers fills, stops
accepting data, but doesn't reenable it when there's room again.
When I use netstat I find the buffer on the send side full, and the
buffer on the receive end empty.
This behaviour may depend on the speed of the system, on mine I can
usually get it to happen with buffer sizes around 100, especially if the
side sending data has a larger buffer.
I've tested this on a couple of machines running a 2.2 kernel, and one
running a 2.4 kernel.
3. Keywords: Networking, TCP, kernel
4. Kernel version (output of /proc/version):
Linux version 2.4.0 (root@viola) (gcc version egcs-2.91.66
19990314/Linux (egcs-1.1.2 release)) #2 Thu Jan 25 19:56:28 NZDT 2001
6. Attached at the end are two C++ programs (though they could as easily
have been C),
fakefeed - run first, acts as a server that just keeps sending data on a
connection.
fakesim - run second, connects to fake feed, and outputs what's received.
They both take as parameters a port number, and a buffer size.
e.g. fakefeed 8001 500
fakesim 8001 100
7.1. output of ver_linux script:
-- Versions installed: (if some fields are empty or look
-- unusual then possibly you have very old versions)
Linux viola 2.4.0 #2 Thu Jan 25 19:56:28 NZDT 2001 i586 unknown
Kernel modules 2.4.0
Gnu C egcs-2.91.66
Gnu Make 3.77
Binutils 2.9.1.0.25
Linux C Library 2.1.2
Dynamic linker ldd: version 1.9.9
Procps 2.0.2
Mount 2.9v
Net-tools 1.52
Kbd 0.99
Sh-utils 1.16
Modules Loaded ppp_deflate ipt_state ipt_MASQUERADE
iptable_filter ip_nat_ftp iptable_nat ip_conntrack ip_tables de4x5
v_midi opl3 mpu401 sb sb_lib uart401 sound bsd_comp ppp_async
7.2 output of /proc/cpuinfo
processor
: 0
vendor_id
: GenuineIntel
cpu family : 5
model
: 4
model name : Pentium MMX
stepping
: 4
cpu MHz : 167.049
fdiv_bug
: no
hlt_bug
: no
f00f_bug
: yes
coma_bug
: no
fpu
: yes
fpu_exception
: yes
cpuid level : 1
wp
: yes
flags
: fpu vme de pse tsc msr mce cx8 mmx
bogomips
: 333.41
7.3 output of /proc/modules
ppp_deflate 40912 0 (autoclean)
ipt_state 800 2 (autoclean)
ipt_MASQUERADE 1312 1 (autoclean)
iptable_filter 1856 0 (autoclean) (unused)
ip_nat_ftp 3440 0 (unused)
iptable_nat 12608 1 [ipt_MASQUERADE ip_nat_ftp]
ip_conntrack 12992 2 [ipt_state ipt_MASQUERADE ip_nat_ftp
iptable_nat]
ip_tables 10656 6 [ipt_state ipt_MASQUERADE
iptable_filter iptable_nat]
de4x5 42496 1
v_midi 5264 0 (unused)
opl3 11792 0 (unused)
mpu401 18960 0 (unused)
sb 6656 0 (unused)
sb_lib 34352 0 [sb]
uart401 6416 0 [sb_lib]
sound 57280 0 [v_midi opl3 mpu401 sb_lib uart401]
bsd_comp 4160 0
ppp_async 6464 1
Thanks
--
bits and peace
Nicholas Daley <mailto:[EMAIL PROTECTED]>
insert :-)=s as appropriate
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <iostream.h>
int openList(int port) {
int fd=-1;
sockaddr_in sa;
fd=socket(PF_INET, SOCK_STREAM, 0);
if(fd<0) return -1;
sa.sin_family=AF_INET;
sa.sin_port=htons(port);
sa.sin_addr.s_addr=htonl(INADDR_ANY);
int s=1;
setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,&s,sizeof(s));
if(bind(fd,(struct sockaddr*)&sa,sizeof(sa))<0) {
shutdown(fd,2);
fd=-1;
return fd;
};
if(listen(fd,1)<0) {
shutdown(fd,2);
fd=-1;
return fd;
};
return fd;
};
int main(int argc, char** argv) {
int listener=openList(argc>1?atoi(argv[1]):8001);
int stream=accept(listener,NULL,NULL);
size_t s;
s=argc>2?atoi(argv[2]):3000;
setsockopt(stream,SOL_SOCKET,SO_RCVBUF,&s,sizeof(s));
setsockopt(stream,SOL_SOCKET,SO_SNDBUF,&s,sizeof(s));
close(listener);
char buff[200];
long long sent=0;
for(int i=1;i;i++) {
sprintf(buff,"%d\n",i);
int writeres=write(stream,buff,strlen(buff));
if(writeres<0) { cerr<<"Write error "<<writeres<<','<<errno<<"\a\n";break;}
if(writeres==0) { cerr<<"Write EOF\a\n";break;}
if(writeres!=strlen(buff)) {cerr <<"Didn't finish writing\a\n";break;}
cerr<<buff<<" Total bytes sent="<<(sent+=writeres)<<endl;
}
};
#include <stdlib.h>
#include <errno.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
#include <iostream.h>
typedef double sk_time;
int openCon(const char* hostname, int port) {
int fd=-1;
sockaddr_in sa;
hostent *he;
fd=socket(PF_INET, SOCK_STREAM, 0);
if(fd<0) return -1;
sa.sin_family=AF_INET;
sa.sin_port=htons(port);
he=gethostbyname(hostname);
if(he==NULL) return fd=-1;
sa.sin_addr=*(struct in_addr*) he->h_addr;
if(connect(fd,(struct sockaddr*) &sa, sizeof(sa))<0) return fd=-1;
return fd;
}
int main(int argc, char** argv) {
int tracestream=openCon("localhost",argc>1?atoi(argv[1]):8001);
size_t s;
s=argc>2?atoi(argv[2]):3000;
setsockopt(tracestream,SOL_SOCKET,SO_RCVBUF,&s,sizeof(s));
setsockopt(tracestream,SOL_SOCKET,SO_SNDBUF,&s,sizeof(s));
while(1) {
char c;
if(read(tracestream,&c,1)<=0) break;
cerr<<c;
}
close(tracestream);
};