2 * MP3/MPlayer plugin to VDR (C++)
4 * (C) 2001-2009 Stefan Huelswitt <s.huelswitt@gmx.de>
6 * This code is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This code is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
26 #include <sys/types.h>
31 #include <sys/socket.h>
32 #include <netinet/in.h>
33 #include <arpa/inet.h>
36 #include <vdr/tools.h>
39 #include "setup-mp3.h"
43 #define CON_TIMEOUT 30*1000 // default timeout (ms) for connect operation
44 #define RW_TIMEOUT 30*1000 // default timeout (ms) for read/write operations
45 #define BUFFERSIZE 128*1024 // default ringbuffer size (bytes) for async read
47 #define NETDOWN_TIMEOUT 30 // timeout (s) for shutting down network
49 const char *netscript=0;
51 // -----------------------------------------------------------------------------
53 int RunCommand(const char *cmd, const char *State, const char *Name=0)
58 if(Name) tmp=aprintf("%s %s \"%s\"",cmd,State,*strescape(Name,"\"$"));
59 else tmp=aprintf("%s %s",cmd,State);
61 d(printf("run: executing '%s'\n",tmp))
68 // -- cNetScript ---------------------------------------------------------------
70 class cNetScript : public cThread {
75 virtual void Action(void);
85 cNetScript::cNetScript(void)
87 count=0; pending=false;
90 cNetScript::~cNetScript()
92 if(pending) Cancel(0);
95 void cNetScript::Up(void)
99 if(pending) { Cancel(0); pending=false; }
100 RunCommand(netscript,"up");
106 void cNetScript::Down(void)
110 if(--count==0) { Start(); pending=true; }
115 void cNetScript::Action(void)
117 d(printf("net: netscript down delay\n"))
118 sleep(NETDOWN_TIMEOUT);
120 RunCommand(netscript,"down");
124 // -- cNetConnect --------------------------------------------------------------
126 class cNetConnect : public cThread {
129 const char *hostname;
135 virtual void Action(void);
138 cNetConnect(int Fd, const char *Hostname, int Port);
140 int Wait(int timeoutMs);
143 cNetConnect::cNetConnect(int Fd, const char *Hostname, int Port)
152 cNetConnect::~cNetConnect()
157 int cNetConnect::Wait(int timeoutMs)
160 if(!result) conCond.TimedWait(conMutex,timeoutMs);
165 void cNetConnect::Done(int res)
173 void cNetConnect::Action(void)
175 d(printf("net: name lookup %s\n",hostname))
176 struct hostent *hp=gethostbyname(hostname);
178 struct sockaddr_in sin;
179 sin.sin_port=htons(port);
180 sin.sin_family=AF_INET;
181 memcpy((char *)&sin.sin_addr,hp->h_addr,hp->h_length);
182 d(printf("net: connecting to %s:%d\n",hostname,port))
183 if(connect(fd,(struct sockaddr *)&sin,sizeof(sin))==0) {
184 d(printf("net: connected\n"))
187 else { esyslog("connect() failed: %s",strerror(errno)); Done(-1); }
189 else { esyslog("Unknown host '%s'",hostname); Done(-1); }
192 // -- cNet ---------------------------------------------------------------------
194 cNet::cNet(int size, int ConTimeoutMs, int RwTimeoutMs)
195 :cRingBufferLinear(size>0?size:BUFFERSIZE,1,false)
197 fd=-1; deferedErrno=0; count=0;
198 connected=netup=false;
199 rwTimeout =RwTimeoutMs ? RwTimeoutMs :RW_TIMEOUT;
200 conTimeout=ConTimeoutMs ? ConTimeoutMs:CON_TIMEOUT;
209 void cNet::Close(void)
216 if(fd>=0) { close(fd); fd=-1; }
220 void cNet::Disconnect(void)
223 if(netup) { ns.Down(); netup=false; }
226 bool cNet::Connect(const char *hostname, const int port)
229 fd=socket(AF_INET,SOCK_STREAM,0);
232 cNetConnect *con=new cNetConnect(fd,hostname,port);
233 int res=con->Wait(conTimeout);
236 if(fcntl(fd,F_SETFL,O_NONBLOCK)>=0) {
237 deferedErrno=0; connected=true;
241 else esyslog("fnctl() failed: %s",strerror(errno));
243 else if(res==0) esyslog("Connection timed out");
245 else esyslog("socket() failed: %s",strerror(errno));
250 void cNet::CopyFromBuff(unsigned char *dest, int n)
252 memcpy(dest,lineBuff,n);
254 if(count>0) memmove(lineBuff,lineBuff+n,count);
257 int cNet::Gets(char *dest, int len)
259 len--; // let room for trailing zero
263 int r=RingRead(lineBuff,sizeof(lineBuff));
271 while(n<count && n+c<len) {
272 if(lineBuff[n]=='\n') len=0;
275 CopyFromBuff((unsigned char *)dest,n);
282 int cNet::Read(unsigned char *dest, int len)
286 c=count; if(c>len) c=len;
287 CopyFromBuff(dest,c);
290 c=RingRead(dest,len);
295 int cNet::Write(unsigned char *dest, int len)
298 cPoller poll(fd,true);
300 if(poll.Poll(rwTimeout)) {
301 r=write(fd,dest,len);
302 if(r<0 && errno!=EAGAIN) {
303 esyslog("write() failed: %s",strerror(errno));
306 dest+=r; len-=r; t+=r;
308 else { esyslog("Write timed out"); break; }
313 int cNet::Puts(char *dest)
315 return Write((unsigned char *)dest,strlen(dest));
318 int cNet::RingRead(unsigned char *dest, int len)
323 if(!Available() && deferedErrno) {
324 d(printf("net: ringbuffer empty, async read bailed out\n"))
337 void cNet::Action(void)
339 d(printf("net: async read started\n"))
341 cPoller poll(fd,false);
343 if(poll.Poll(rwTimeout)) {
344 unsigned char buff[8192];
345 int r=read(fd,buff,sizeof(buff));
348 do { d+=Put(buff+d,r-d); } while(d<r && connected);
350 else if(r<0 && errno!=EAGAIN) {
352 esyslog("read() failed: %s",strerror(errno));
357 d(printf("EOF from read()\n"))
363 esyslog("Read timed out");