2 * MP3/MPlayer plugin to VDR (C++)
4 * (C) 2001-2006 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"
42 #define CON_TIMEOUT 30*1000 // default timeout (ms) for connect operation
43 #define RW_TIMEOUT 30*1000 // default timeout (ms) for read/write operations
44 #define BUFFERSIZE 128*1024 // default ringbuffer size (bytes) for async read
46 #define NETDOWN_TIMEOUT 30 // timeout (s) for shutting down network
48 const char *netscript=0;
50 #if APIVERSNUM == 10131
51 #error Using this plugin with vdr 1.1.31 is not recommended (may cause high cpu load during streaming)
54 // -----------------------------------------------------------------------------
56 int RunCommand(const char *cmd, const char *State, const char *Name=0)
62 #if APIVERSNUM < 10318
63 asprintf(&tmp,"%s %s \"%s\"",cmd,State,strescape(Name,"\"$"));
65 asprintf(&tmp,"%s %s \"%s\"",cmd,State,*strescape(Name,"\"$"));
67 else asprintf(&tmp,"%s %s",cmd,State);
69 d(printf("run: executing '%s'\n",tmp))
76 // -- cNetScript ---------------------------------------------------------------
78 class cNetScript : public cThread {
83 virtual void Action(void);
93 cNetScript::cNetScript(void)
95 count=0; pending=false;
98 cNetScript::~cNetScript()
100 if(pending) Cancel(0);
103 void cNetScript::Up(void)
107 if(pending) { Cancel(0); pending=false; }
108 RunCommand(netscript,"up");
114 void cNetScript::Down(void)
118 if(--count==0) { Start(); pending=true; }
123 void cNetScript::Action(void)
125 d(printf("net: netscript down delay\n"))
126 sleep(NETDOWN_TIMEOUT);
128 RunCommand(netscript,"down");
132 // -- cNetConnect --------------------------------------------------------------
134 class cNetConnect : public cThread {
137 const char *hostname;
143 virtual void Action(void);
146 cNetConnect(int Fd, const char *Hostname, int Port);
148 int Wait(int timeoutMs);
151 cNetConnect::cNetConnect(int Fd, const char *Hostname, int Port)
160 cNetConnect::~cNetConnect()
165 int cNetConnect::Wait(int timeoutMs)
168 if(!result) conCond.TimedWait(conMutex,timeoutMs);
173 void cNetConnect::Done(int res)
181 void cNetConnect::Action(void)
183 d(printf("net: name lookup %s\n",hostname))
184 struct hostent *hp=gethostbyname(hostname);
186 struct sockaddr_in sin;
187 sin.sin_port=htons(port);
188 sin.sin_family=AF_INET;
189 memcpy((char *)&sin.sin_addr,hp->h_addr,hp->h_length);
190 d(printf("net: connecting to %s:%d\n",hostname,port))
191 if(connect(fd,(struct sockaddr *)&sin,sizeof(sin))==0) {
192 d(printf("net: connected\n"))
195 else { esyslog("connect() failed: %s",strerror(errno)); Done(-1); }
197 else { esyslog("Unknown host '%s'",hostname); Done(-1); }
200 // -- cNet ---------------------------------------------------------------------
202 cNet::cNet(int size, int ConTimeoutMs, int RwTimeoutMs)
203 :cRingBufferLinear(size>0?size:BUFFERSIZE,1,false)
205 fd=-1; deferedErrno=0; count=0;
206 connected=netup=false;
207 rwTimeout =RwTimeoutMs ? RwTimeoutMs :RW_TIMEOUT;
208 conTimeout=ConTimeoutMs ? ConTimeoutMs:CON_TIMEOUT;
209 #if APIVERSNUM >= 10132
219 void cNet::Close(void)
226 if(fd>=0) { close(fd); fd=-1; }
230 void cNet::Disconnect(void)
233 if(netup) { ns.Down(); netup=false; }
236 bool cNet::Connect(const char *hostname, const int port)
239 fd=socket(AF_INET,SOCK_STREAM,0);
242 cNetConnect *con=new cNetConnect(fd,hostname,port);
243 int res=con->Wait(conTimeout);
246 if(fcntl(fd,F_SETFL,O_NONBLOCK)>=0) {
247 deferedErrno=0; connected=true;
251 else esyslog("fnctl() failed: %s",strerror(errno));
253 else if(res==0) esyslog("Connection timed out");
255 else esyslog("socket() failed: %s",strerror(errno));
260 void cNet::CopyFromBuff(unsigned char *dest, int n)
262 memcpy(dest,lineBuff,n);
264 if(count>0) memmove(lineBuff,lineBuff+n,count);
267 int cNet::Gets(char *dest, int len)
269 len--; // let room for trailing zero
273 int r=RingRead(lineBuff,sizeof(lineBuff));
281 while(n<count && n+c<len) {
282 if(lineBuff[n]=='\n') len=0;
285 CopyFromBuff((unsigned char *)dest,n);
292 int cNet::Read(unsigned char *dest, int len)
296 c=count; if(c>len) c=len;
297 CopyFromBuff(dest,c);
300 c=RingRead(dest,len);
305 int cNet::Write(unsigned char *dest, int len)
308 cPoller poll(fd,true);
310 if(poll.Poll(rwTimeout)) {
311 r=write(fd,dest,len);
312 if(r<0 && errno!=EAGAIN) {
313 esyslog("write() failed: %s",strerror(errno));
316 dest+=r; len-=r; t+=r;
318 else { esyslog("Write timed out"); break; }
323 int cNet::Puts(char *dest)
325 return Write((unsigned char *)dest,strlen(dest));
328 int cNet::RingRead(unsigned char *dest, int len)
333 if(!Available() && deferedErrno) {
334 d(printf("net: ringbuffer empty, async read bailed out\n"))
347 void cNet::Action(void)
349 d(printf("net: async read started\n"))
351 cPoller poll(fd,false);
353 if(poll.Poll(rwTimeout)) {
354 unsigned char buff[8192];
355 int r=read(fd,buff,sizeof(buff));
358 do { d+=Put(buff+d,r-d); } while(d<r && connected);
360 else if(r<0 && errno!=EAGAIN) {
362 esyslog("read() failed: %s",strerror(errno));
367 d(printf("EOF from read()\n"))
373 esyslog("Read timed out");