From d72d6c5fb3d3b3b2f4d38808c4cb2c6cd4113df2 Mon Sep 17 00:00:00 2001 From: leslie Date: Fri, 4 Sep 2009 19:49:07 +0800 Subject: [PATCH] increase robustness of network code --- misc.h | 2 ++ network.c | 68 +++++++++++++++++++++++++++++++++++++------------------ 2 files changed, 48 insertions(+), 22 deletions(-) diff --git a/misc.h b/misc.h index 3207e9c..d038b10 100644 --- a/misc.h +++ b/misc.h @@ -38,6 +38,8 @@ #define AUTOARRAY(type,size) (type *)alloca(sizeof(type)*(size)) #define AUTOMEM(size) (unsigned char *)alloca(size) +#define LOOP_EINTR(xx) ({ int _r; do { _r=(xx); } while(_r<0 && errno==EINTR); _r; }) + // ---------------------------------------------------------------- #define DEV_DVB_FRONTEND "frontend" diff --git a/network.c b/network.c index 5cd8621..1a319f7 100644 --- a/network.c +++ b/network.c @@ -212,7 +212,7 @@ bool cNetSocket::Connect(const char *Hostname, int Port, int timeout) if(!quietlog) PRINTF(L_CORE_NET,"connecting to %s:%d/%s (%d.%d.%d.%d)", hostname,port,udp?"udp":"tcp", (socketAddr.sin_addr.s_addr>> 0)&0xff,(socketAddr.sin_addr.s_addr>> 8)&0xff,(socketAddr.sin_addr.s_addr>>16)&0xff,(socketAddr.sin_addr.s_addr>>24)&0xff); - if(connect(sd,(struct sockaddr *)&socketAddr,sizeof(socketAddr))==0) + if(LOOP_EINTR(connect(sd,(struct sockaddr *)&socketAddr,sizeof(socketAddr)))==0) connected=true; else if(errno==EINPROGRESS) { if(Select(false,timeout)>0) { @@ -253,7 +253,7 @@ bool cNetSocket::Bind(const char *Hostname, int Port) if(!quietlog) PRINTF(L_CORE_NET,"socket: binding to %s:%d/%s (%d.%d.%d.%d)", hostname,port,udp?"udp":"tcp", (socketAddr.sin_addr.s_addr>> 0)&0xff,(socketAddr.sin_addr.s_addr>> 8)&0xff,(socketAddr.sin_addr.s_addr>>16)&0xff,(socketAddr.sin_addr.s_addr>>24)&0xff); - if(bind(sd,(struct sockaddr *)&socketAddr,sizeof(socketAddr))==0) { + if(LOOP_EINTR(bind(sd,(struct sockaddr *)&socketAddr,sizeof(socketAddr)))==0) { connected=true; Activity(); Unlock(); return true; @@ -284,17 +284,28 @@ void cNetSocket::Flush(void) } } +// len>0 : read available bytes, up to len +// len<0 : block read len bytes or fail int cNetSocket::Read(unsigned char *data, int len, int timeout) { cMutexLock lock(this); if(timeout<0) timeout=rwTimeout; - int r=Select(true,timeout); + bool fullread=false; + if(len<0) { len=-len; fullread=true; } + int cnt=0, r; + do { + r=Select(true,timeout); + if(r>0) { + r=LOOP_EINTR(read(sd,data,len)); + if(r<0) PRINTF(L_GEN_ERROR,"socket: read failed: %s",strerror(errno)); + else if(r>0) cnt+=r; + } + } while(r>0 && cnt0) { - r=read(sd,data,len); - if(r<0) PRINTF(L_GEN_ERROR,"socket: read failed: %s",strerror(errno)); - else if(r>0) HEXDUMP(L_CORE_NETDATA,data,r,"network read"); + HEXDUMP(L_CORE_NETDATA,data,cnt,"network read"); + return cnt; } - Activity(); return r; } @@ -302,13 +313,20 @@ int cNetSocket::Write(const unsigned char *data, int len, int timeout) { cMutexLock lock(this); if(timeout<0) timeout=rwTimeout; - int r=Select(false,timeout); + int cnt=0, r; + do { + r=Select(false,timeout); + if(r>0) { + r=LOOP_EINTR(write(sd,data+cnt,len-cnt)); + if(r<0) PRINTF(L_GEN_ERROR,"socket: write failed: %s",strerror(errno)); + else if(r>0) cnt+=r; + } + } while(r>0 && cnt0) { - r=write(sd,data,len); - if(r<0) PRINTF(L_GEN_ERROR,"socket: write failed: %s",strerror(errno)); - else if(r>0) HEXDUMP(L_CORE_NETDATA,data,r,"network write"); + HEXDUMP(L_CORE_NETDATA,data,cnt,"network write"); + return cnt; } - Activity(); return r; } @@ -316,17 +334,23 @@ int cNetSocket::SendTo(const char *Host, int Port, const unsigned char *data, in { cMutexLock lock(this); if(timeout<0) timeout=rwTimeout; - int r=Select(false,timeout); - if(r>0) { - struct sockaddr_in saddr; - if(GetAddr(&saddr,Host,Port)) { - r=sendto(sd,data,len,0,(struct sockaddr *)&saddr,sizeof(saddr)); - if(r<0) PRINTF(L_GEN_ERROR,"socket: sendto %d.%d.%d.%d:%d failed: %s",(saddr.sin_addr.s_addr>> 0)&0xff,(saddr.sin_addr.s_addr>> 8)&0xff,(saddr.sin_addr.s_addr>>16)&0xff,(saddr.sin_addr.s_addr>>24)&0xff,Port,strerror(errno)); - else if(r>0) HEXDUMP(L_CORE_NETDATA,data,r,"network sendto %d.%d.%d.%d:%d",(saddr.sin_addr.s_addr>> 0)&0xff,(saddr.sin_addr.s_addr>> 8)&0xff,(saddr.sin_addr.s_addr>>16)&0xff,(saddr.sin_addr.s_addr>>24)&0xff,Port); - } - else r=-1; + int cnt=0, r=-1; + struct sockaddr_in saddr; + if(GetAddr(&saddr,Host,Port)) { + do { + r=Select(false,timeout); + if(r>0) { + r=LOOP_EINTR(sendto(sd,data,len,0,(struct sockaddr *)&saddr,sizeof(saddr))); + if(r<0) PRINTF(L_GEN_ERROR,"socket: sendto %d.%d.%d.%d:%d failed: %s",(saddr.sin_addr.s_addr>> 0)&0xff,(saddr.sin_addr.s_addr>> 8)&0xff,(saddr.sin_addr.s_addr>>16)&0xff,(saddr.sin_addr.s_addr>>24)&0xff,Port,strerror(errno)); + else if(r>0) cnt+=r; + } + } while(r>0 && cnt0) { + HEXDUMP(L_CORE_NETDATA,data,cnt,"network sendto %d.%d.%d.%d:%d",(saddr.sin_addr.s_addr>> 0)&0xff,(saddr.sin_addr.s_addr>> 8)&0xff,(saddr.sin_addr.s_addr>>16)&0xff,(saddr.sin_addr.s_addr>>24)&0xff,Port); + return cnt; + } return r; } @@ -338,7 +362,7 @@ int cNetSocket::Select(bool forRead, int timeout) struct timeval tv; if(timeout&MSTIMEOUT) { tv.tv_sec=0; tv.tv_usec=(timeout&~MSTIMEOUT)*1000; } else { tv.tv_sec=timeout; tv.tv_usec=0; } - int r=select(sd+1,forRead ? &fds:0,forRead ? 0:&fds,0,&tv); + int r=LOOP_EINTR(select(sd+1,forRead ? &fds:0,forRead ? 0:&fds,0,&tv)); if(r>0) return 1; else if(r<0) { PRINTF(L_GEN_ERROR,"socket: select failed: %s",strerror(errno)); -- 2.39.5