|
SASC
DVBSoftCAM
|
00001 /* 00002 * Softcam plugin to VDR (C++) 00003 * 00004 * This code is free software; you can redistribute it and/or 00005 * modify it under the terms of the GNU General Public License 00006 * as published by the Free Software Foundation; either version 2 00007 * of the License, or (at your option) any later version. 00008 * 00009 * This code is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program; if not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html 00018 */ 00019 00020 #include <stdlib.h> 00021 #include <stdio.h> 00022 #include <string.h> 00023 #include <errno.h> 00024 #include <unistd.h> 00025 #include <fcntl.h> 00026 #include <sys/socket.h> 00027 #include <netinet/in.h> 00028 #include <netdb.h> 00029 00030 #include <vdr/thread.h> 00031 #include <vdr/tools.h> 00032 00033 #include "network.h" 00034 #include "misc.h" 00035 #include "log-core.h" 00036 00037 #define DEFAULT_CONNECT_TIMEOUT 20*1000 // ms 00038 #define DEFAULT_READWRITE_TIMEOUT 3*1000 // ms 00039 #define DEFAULT_IDLE_TIMEOUT 120*1000 // ms 00040 00041 // -- cNetWatcher --------------------------------------------------------------- 00042 00043 class cNetWatcher : protected cThread { 00044 private: 00045 cSimpleList<cNetSocket> socks; 00046 protected: 00047 virtual void Action(void); 00048 public: 00049 cNetWatcher(void); 00050 ~cNetWatcher(); 00051 void Up(cNetSocket *so); 00052 void Down(cNetSocket *so); 00053 }; 00054 00055 static cNetWatcher nw; 00056 00057 cNetWatcher::cNetWatcher(void) 00058 :cThread("Netwatcher") 00059 {} 00060 00061 cNetWatcher::~cNetWatcher() 00062 { 00063 Cancel(2); 00064 Lock(); 00065 cNetSocket *so; 00066 while((so=socks.First())) socks.Del(so,false); 00067 Unlock(); 00068 } 00069 00070 void cNetWatcher::Up(cNetSocket *so) 00071 { 00072 Lock(); 00073 socks.Add(so); 00074 if(!Active()) Start(); 00075 Unlock(); 00076 } 00077 00078 void cNetWatcher::Down(cNetSocket *so) 00079 { 00080 Lock(); 00081 socks.Del(so,false); 00082 Unlock(); 00083 } 00084 00085 void cNetWatcher::Action(void) 00086 { 00087 while(Running()) { 00088 sleep(1); 00089 Lock(); 00090 for(cNetSocket *so=socks.First(); so;) { 00091 cNetSocket *next=socks.Next(so); 00092 so->Lock(); 00093 if(so->connected && so->activity.TimedOut()) { 00094 PRINTF(L_CORE_NET,"idle timeout, disconnected %s:%d",so->hostname,so->port); 00095 so->Disconnect(); 00096 } 00097 so->Unlock(); 00098 so=next; 00099 } 00100 Unlock(); 00101 } 00102 } 00103 00104 // -- cNetSocket ------------------------------------------------------------------ 00105 00106 cNetSocket::cNetSocket(void) 00107 { 00108 hostname=0; sd=-1; udp=connected=quietlog=false; 00109 conTimeout=DEFAULT_CONNECT_TIMEOUT; rwTimeout=DEFAULT_READWRITE_TIMEOUT; 00110 idleTimeout=DEFAULT_IDLE_TIMEOUT; 00111 } 00112 00113 cNetSocket::~cNetSocket() 00114 { 00115 Disconnect(); 00116 free(hostname); 00117 } 00118 00119 void cNetSocket::Activity(void) 00120 { 00121 activity.Set(idleTimeout); 00122 } 00123 00124 bool cNetSocket::GetAddr(struct sockaddr_in *saddr, const char *Hostname, int Port) 00125 { 00126 const struct hostent * const hostaddr=gethostbyname(Hostname); 00127 if(hostaddr) { 00128 saddr->sin_family=AF_INET; 00129 saddr->sin_port=htons(Port); 00130 saddr->sin_addr.s_addr=((struct in_addr *)hostaddr->h_addr)->s_addr; 00131 return true; 00132 } 00133 PRINTF(L_GEN_ERROR,"socket: name lookup error for %s",Hostname); 00134 return false; 00135 } 00136 00137 cString cNetSocket::StrError(int err) const 00138 { 00139 char buf[64]; 00140 return strerror_r(err,buf,sizeof(buf)); 00141 } 00142 00143 int cNetSocket::GetSocket(bool Udp) 00144 { 00145 int proto=0; 00146 const struct protoent * const ptrp=getprotobyname(Udp?"udp":"tcp"); 00147 if(ptrp) proto=ptrp->p_proto; 00148 int so; 00149 if((so=socket(PF_INET,Udp?SOCK_DGRAM:SOCK_STREAM,proto))>=0) { 00150 int flgs=fcntl(so,F_GETFL); 00151 if(flgs>=0) { 00152 if(fcntl(so,F_SETFL,flgs|O_NONBLOCK)==0) 00153 return so; 00154 else PRINTF(L_GEN_ERROR,"socket: fcntl SETFL failed: %s",*StrError(errno)); 00155 } 00156 else PRINTF(L_GEN_ERROR,"socket: fcntl GETFL failed: %s",*StrError(errno)); 00157 close(so); 00158 } 00159 else PRINTF(L_GEN_ERROR,"socket: socket failed: %s",*StrError(errno)); 00160 return -1; 00161 } 00162 00163 bool cNetSocket::Connect(const char *Hostname, int Port, int timeout) 00164 { 00165 Lock(); 00166 Disconnect(); 00167 if(Hostname) { 00168 free(hostname); 00169 hostname=strdup(Hostname); port=Port; 00170 } 00171 if(timeout<0) timeout=conTimeout; 00172 struct sockaddr_in socketAddr; 00173 if(GetAddr(&socketAddr,hostname,port) && (sd=GetSocket(udp))>=0) { 00174 if(!quietlog) PRINTF(L_CORE_NET,"connecting to %s:%d/%s (%d.%d.%d.%d)", 00175 hostname,port,udp?"udp":"tcp", 00176 (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); 00177 int r; 00178 do { r=connect(sd,(struct sockaddr *)&socketAddr,sizeof(socketAddr)); } while(r<0 && errno==EINTR); 00179 if(r==0) connected=true; 00180 else if(errno==EINPROGRESS) { 00181 if(Select(false,timeout)>0) { 00182 int r=-1; 00183 unsigned int l=sizeof(r); 00184 if(getsockopt(sd,SOL_SOCKET,SO_ERROR,&r,&l)==0) { 00185 if(r==0) 00186 connected=true; 00187 else PRINTF(L_GEN_ERROR,"socket: connect failed (late): %s",*StrError(r)); 00188 } 00189 else PRINTF(L_GEN_ERROR,"socket: getsockopt failed: %s",*StrError(errno)); 00190 } 00191 else PRINTF(L_GEN_ERROR,"socket: connect timed out"); 00192 } 00193 else PRINTF(L_GEN_ERROR,"socket: connect failed: %s",*StrError(errno)); 00194 00195 if(connected) { Activity(); Unlock(); nw.Up(this); return true; } 00196 } 00197 Unlock(); 00198 Disconnect(); 00199 return false; 00200 } 00201 00202 bool cNetSocket::Bind(const char *Hostname, int Port) 00203 { 00204 Lock(); 00205 Disconnect(); 00206 if(Hostname) { 00207 free(hostname); 00208 hostname=strdup(Hostname); port=Port; 00209 } 00210 struct sockaddr_in socketAddr; 00211 if(GetAddr(&socketAddr,hostname,port) && (sd=GetSocket(udp))>=0) { 00212 if(!quietlog) PRINTF(L_CORE_NET,"socket: binding to %s:%d/%s (%d.%d.%d.%d)", 00213 hostname,port,udp?"udp":"tcp", 00214 (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); 00215 int r; 00216 do { r=bind(sd,(struct sockaddr *)&socketAddr,sizeof(socketAddr)); } while(r<0 && errno==EINTR); 00217 if(r==0) { 00218 connected=true; 00219 Activity(); Unlock(); nw.Up(this); 00220 return true; 00221 } 00222 else PRINTF(L_GEN_ERROR,"socket: bind failed: %s",*StrError(errno)); 00223 } 00224 Unlock(); 00225 Disconnect(); 00226 return false; 00227 } 00228 00229 void cNetSocket::Disconnect(void) 00230 { 00231 nw.Down(this); 00232 cMutexLock lock(this); 00233 if(sd>=0) { close(sd); sd=-1; } 00234 quietlog=connected=false; 00235 } 00236 00237 void cNetSocket::Flush(void) 00238 { 00239 cMutexLock lock(this); 00240 if(sd>=0) { 00241 unsigned char buff[512]; 00242 while(read(sd,buff,sizeof(buff))>0) Activity(); 00243 } 00244 } 00245 00246 // len>0 : block read len bytes or fail 00247 // len<0 : read available bytes up to len 00248 int cNetSocket::Read(unsigned char *data, int len, int timeout) 00249 { 00250 cMutexLock lock(this); 00251 if(timeout<0) timeout=rwTimeout; 00252 bool blockmode=true; 00253 if(len<0) { len=-len; blockmode=false; } 00254 else if(len==0) { 00255 PRINTF(L_GEN_DEBUG,"internal: zero length on socket read"); 00256 errno=EINVAL; 00257 return -1; 00258 } 00259 int cnt=0, r; 00260 cTimeMs tim; 00261 do { 00262 r=timeout; 00263 if(r>0 && blockmode) { r-=tim.Elapsed(); if(r<10) r=10; } 00264 r=Select(true,r); 00265 if(r>0) { 00266 do { r=read(sd,data+cnt,len-cnt); } while(r<0 && errno==EINTR); 00267 if(r<0) PRINTF(L_GEN_ERROR,"socket: read failed: %s",*StrError(errno)); 00268 else if(r>0) cnt+=r; 00269 else { 00270 PRINTF(L_GEN_ERROR,"socket: EOF on read"); 00271 errno=ECONNRESET; 00272 } 00273 } 00274 } while(r>0 && cnt<len && blockmode); 00275 Activity(); 00276 if((!blockmode && cnt>0) || cnt>=len) { 00277 HEXDUMP(L_CORE_NETDATA,data,cnt,"network read"); 00278 return cnt; 00279 } 00280 return -1; 00281 } 00282 00283 int cNetSocket::Write(const unsigned char *data, int len, int timeout) 00284 { 00285 cMutexLock lock(this); 00286 if(timeout<0) timeout=rwTimeout; 00287 int cnt=0, r; 00288 cTimeMs tim; 00289 do { 00290 r=timeout; 00291 if(r>0) { r-=tim.Elapsed(); if(r<10) r=10; } 00292 r=Select(false,r); 00293 if(r>0) { 00294 do { r=write(sd,data+cnt,len-cnt); } while(r<0 && errno==EINTR); 00295 if(r<0) PRINTF(L_GEN_ERROR,"socket: write failed: %s",*StrError(errno)); 00296 else if(r>0) cnt+=r; 00297 } 00298 } while(r>0 && cnt<len); 00299 Activity(); 00300 if(cnt>=len) { 00301 HEXDUMP(L_CORE_NETDATA,data,cnt,"network write"); 00302 return cnt; 00303 } 00304 return -1; 00305 } 00306 00307 int cNetSocket::SendTo(const char *Host, int Port, const unsigned char *data, int len, int timeout) 00308 { 00309 cMutexLock lock(this); 00310 if(timeout<0) timeout=rwTimeout; 00311 int cnt=0, r=-1; 00312 struct sockaddr_in saddr; 00313 if(GetAddr(&saddr,Host,Port)) { 00314 cTimeMs tim; 00315 do { 00316 r=timeout; 00317 if(r>0) { r-=tim.Elapsed(); if(r<10) r=10; } 00318 r=Select(false,r); 00319 if(r>0) { 00320 do { r=sendto(sd,data+cnt,len-cnt,0,(struct sockaddr *)&saddr,sizeof(saddr)); } while(r<0 && errno==EINTR); 00321 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)); 00322 else if(r>0) cnt+=r; 00323 } 00324 } while(r>0 && cnt<len); 00325 } 00326 Activity(); 00327 if(cnt>=len) { 00328 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); 00329 return cnt; 00330 } 00331 return -1; 00332 } 00333 00334 int cNetSocket::Select(bool forRead, int timeout) 00335 { 00336 if(sd>=0) { 00337 fd_set fds; 00338 FD_ZERO(&fds); FD_SET(sd,&fds); 00339 struct timeval tv; 00340 00341 if(timeout>0 && timeout<60) 00342 PRINTF(L_GEN_DEBUG,"socket: internal: small timeout value %d",timeout); 00343 00344 tv.tv_sec=timeout/1000; tv.tv_usec=(timeout%1000)*1000; 00345 int r; 00346 do { r=select(sd+1,forRead ? &fds:0,forRead ? 0:&fds,0,&tv); } while(r<0 && errno==EINTR); 00347 if(r>0) return 1; 00348 else if(r<0) { 00349 PRINTF(L_GEN_ERROR,"socket: select failed: %s",*StrError(errno)); 00350 return -1; 00351 } 00352 else { 00353 if(timeout>0 && !quietlog) PRINTF(L_CORE_NET,"socket: select timed out (%d ms)",timeout); 00354 errno=ETIMEDOUT; 00355 return 0; 00356 } 00357 } 00358 return -1; 00359 }