changeset 22855:d258dd05e0ab

Move netstream.c out of its single-file subdirectory.
author diego
date Sun, 01 Apr 2007 09:39:32 +0000
parents 404750261cfc
children 27db9ffe00a5
files TOOLS/Makefile TOOLS/netstream.c TOOLS/netstream/Makefile TOOLS/netstream/netstream.c
diffstat 4 files changed, 432 insertions(+), 445 deletions(-) [+]
line wrap: on
line diff
--- a/TOOLS/Makefile	Sun Apr 01 09:28:04 2007 +0000
+++ b/TOOLS/Makefile	Sun Apr 01 09:39:32 2007 +0000
@@ -48,6 +48,26 @@
 %.so.6.0: %.o
 	ld -shared -o $@ $< -ldl -lc
 
+# FIXME: netstream linking is a mess that should be fixed properly some day.
+# It does not work with either GUI, LIVE555, libavformat, cdparanoia enabled.
+NETSTREAM_DEPS = ../libmpdemux/libmpdemux.a \
+                 ../stream/stream.a \
+                 ../dvdread/libdvdread.a \
+                 ../libdvdcss/libdvdcss.a \
+                 ../libavutil/libavutil.a \
+                 ../m_option.o \
+                 ../m_struct.o \
+                 ../mp_msg.o \
+                 ../osdep/libosdep.a \
+                 -ltermcap -lm \
+
+ifeq ($(TARGET_WIN32),yes)
+NETSTREAM_DEPS += -lwsock32
+endif
+
+netstream: $(NETSTREAM_DEPS)
+	$(CC) -o $@ netstream.o $^
+
 clean distclean:
 	rm -f $(OBJS)
 	rm -f fastmem-* fastmem2-* fastmemcpybench
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/TOOLS/netstream.c	Sun Apr 01 09:39:32 2007 +0000
@@ -0,0 +1,412 @@
+/*
+ *  netstream.c
+ *
+ *	Copyright (C) Alban Bedel - 04/2003
+ *
+ *  This file is part of MPlayer, a free movie player.
+ *	
+ *  MPlayer is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *   
+ *  MPlayer is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *   
+ *  You should have received a copy of the GNU General Public License
+ *  along with MPlayer; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/types.h>
+
+#include "config.h"
+
+#ifndef HAVE_WINSOCK2
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#else
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+
+#include "stream/stream.h"
+#include "libmpdemux/demuxer.h"
+#include "mp_msg.h"
+#include "libavutil/common.h"
+#include "mpbswap.h"
+
+/// Netstream packets def and some helpers
+#include "stream/netstream.h"
+
+
+//Set some standard variables
+char* dvdsub_lang=NULL;
+char* audio_lang=NULL;
+int sub_justify=0;
+int identify=0;
+int dvdsub_id=0;
+int audio_id=0;
+int video_id=0;
+void af_fmt2str() {};
+
+#ifdef __MINGW32__
+#define usleep sleep
+void strsep() {};
+#endif
+
+static unsigned short int port = 10000;
+
+typedef struct client_st client_t;
+struct client_st {
+  int fd;
+  stream_t* stream;
+  client_t* next;
+  client_t* prev;
+};
+
+static int write_error(int fd,char* msg) {
+  int len = strlen(msg) + 1;
+  return write_packet(fd,NET_STREAM_ERROR,msg,len);
+}
+
+static int net_stream_open(client_t* cl,char* url) {
+  int file_format=DEMUXER_TYPE_UNKNOWN;
+  mp_net_stream_opened_t ret;
+
+  if(cl->stream) {
+    if(!write_error(cl->fd,"A stream is currently opened\n"))
+      return 0;
+    return 1;
+  }
+
+  mp_msg(MSGT_NETST,MSGL_V,"Open stream %s\n",url);
+  cl->stream = open_stream(url,NULL,&file_format);
+  if(!cl->stream) {
+    if(!write_error(cl->fd,"Open failed\n"))
+      return 0;
+    return 1;
+  }
+  stream_reset(cl->stream);
+  stream_seek(cl->stream,cl->stream->start_pos);
+  ret.file_format = file_format;
+  ret.flags = cl->stream->flags;
+  ret.sector_size = cl->stream->sector_size;
+  ret.start_pos = cl->stream->start_pos;
+  ret.end_pos = cl->stream->end_pos;
+  net_stream_opened_2_me(&ret);
+
+  if(!write_packet(cl->fd,NET_STREAM_OK,(char*)&ret,sizeof(mp_net_stream_opened_t)))
+    return 0;
+  return 1;
+}
+
+static int net_stream_fill_buffer(client_t* cl,uint16_t max_len) {
+  int r;
+  mp_net_stream_packet_t *pack;
+  
+  if(!cl->stream) {
+    if(!write_error(cl->fd,"No stream is currently opened\n"))
+      return 0;
+    return 1;
+  }
+  if(max_len == 0) {
+    if(!write_error(cl->fd,"Fill buffer called with 0 lenght\n"))
+      return 0;
+    return 1;
+  }
+  pack = malloc(max_len + sizeof(mp_net_stream_packet_t));
+  pack->cmd = NET_STREAM_OK;
+  r = stream_read(cl->stream,pack->data,max_len);
+  pack->len = le2me_16(r + sizeof(mp_net_stream_packet_t));
+  if(!net_write(cl->fd,(char*)pack,le2me_16(pack->len))) {
+    free(pack);
+    return 0;
+  }
+  free(pack);
+  return 1;
+}
+
+static int net_stream_seek(client_t* cl, uint64_t pos) {
+  
+  if(!cl->stream) {
+    if(!write_error(cl->fd,"No stream is currently opened\n"))
+      return 0;
+    return 1;
+  }
+
+  if(!stream_seek(cl->stream,(off_t)pos)) {
+    if(!write_error(cl->fd,"Seek failed\n"))
+      return 0;
+    return 1;
+  }
+  if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
+    return 0;
+  return 1;
+}
+
+static int net_stream_reset(client_t* cl) {
+  if(!cl->stream) {
+    if(!write_error(cl->fd,"No stream is currently opened\n"))
+      return 0;
+    return 1;
+  }
+  stream_reset(cl->stream);
+  if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
+    return 0;
+  return 1;
+}
+
+static int net_stream_close(client_t* cl) {
+  if(!cl->stream) {
+    if(!write_error(cl->fd,"No stream is currently opened\n"))
+      return 0;
+    return 1;
+  }
+
+  free_stream(cl->stream);
+  cl->stream = NULL;
+
+  if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
+    return 0;
+  return 1;
+}
+
+int handle_client(client_t* cl,mp_net_stream_packet_t* pack) {
+
+  if(!pack)
+    return 0;
+ 
+  switch(pack->cmd) {
+  case NET_STREAM_OPEN:
+    if(((char*)pack)[pack->len-1] != '\0') {
+      mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid open packet\n");
+      return 0;
+    }
+    return net_stream_open(cl,pack->data);
+  case NET_STREAM_FILL_BUFFER:
+    if(pack->len != sizeof(mp_net_stream_packet_t) + 2) {
+      mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
+      return 0;
+    }
+    return net_stream_fill_buffer(cl,le2me_16(*((uint16_t*)pack->data)));
+  case NET_STREAM_SEEK:
+    if(pack->len != sizeof(mp_net_stream_packet_t) + 8) {
+      mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
+      return 0;
+    }
+    return net_stream_seek(cl,le2me_64(*((uint64_t*)pack->data)));
+  case NET_STREAM_RESET:
+    return net_stream_reset(cl);
+  case NET_STREAM_CLOSE:
+    if(pack->len != sizeof(mp_net_stream_packet_t)){
+      mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
+      return 0;
+    }
+    return net_stream_close(cl);
+  default:
+    mp_msg(MSGT_NETST,MSGL_WARN,"Got unknown command %d\n",pack->cmd);
+    if(!write_error(cl->fd,"Unknown command\n"))
+      return 0;
+  }
+  return 0;
+}
+
+static client_t* add_client(client_t *head,int fd) {
+  client_t *new = calloc(1,sizeof(client_t));
+  new->fd = fd;
+  if(!head) return new;
+  new->next = head;
+  head->prev = new;
+  return new;
+}
+
+static int make_fd_set(fd_set* fds, client_t** _cl, int listen) {
+  int max_fd = listen;
+  client_t *cl = *_cl;
+  FD_ZERO(fds);
+  FD_SET(listen,fds);
+  while(cl) {
+    // Remove this client
+    if(cl->fd < 0) {
+      client_t* f = cl;
+      if(cl->prev) cl->prev->next = cl->next;
+      if(cl->next) cl->next->prev = cl->prev;
+      if(cl->stream) free_stream(cl->stream);
+      if(!cl->prev) // Remove the head
+	*_cl = cl->next;
+      cl = cl->next;  
+      free(f);
+      continue;
+    }
+    FD_SET(cl->fd,fds);
+    if(cl->fd > max_fd) max_fd = cl->fd;
+    cl = cl->next;
+  }
+  return max_fd+1;
+}
+
+/// Hack to 'cleanly' exit
+static int run_server = 1;
+
+void exit_sig(int sig) {
+  static int count = 0;
+  sig++; // gcc warning
+  count++;
+  if(count==3) exit(1);
+  if(count > 3)
+#ifdef __MINGW32__
+    WSACleanup();
+#else
+    kill(getpid(),SIGKILL);
+#endif
+  run_server = 0;
+}
+
+static int main_loop(int listen_fd) {
+  client_t *clients = NULL,*iter;
+  fd_set fds;
+
+  signal(SIGTERM,exit_sig); // kill
+#ifndef __MINGW32__
+  signal(SIGHUP,exit_sig);  // kill -HUP  /  xterm closed
+  signal(SIGINT,exit_sig);  // Interrupt from keyboard
+  signal(SIGQUIT,exit_sig); // Quit from keyboard
+#endif 
+
+  while(run_server) {
+    int sel_n = make_fd_set(&fds,&clients,listen_fd);
+    int n = select(sel_n,&fds,NULL,NULL,NULL);
+    if(n < 0) {
+      if(errno == EINTR)
+	continue;
+      mp_msg(MSGT_NETST,MSGL_FATAL,"Select error: %s\n",strerror(errno));
+      return 1;
+    }
+    // New connection
+    if(FD_ISSET(listen_fd,&fds)) {
+      struct sockaddr_in addr;
+      socklen_t slen = sizeof(struct sockaddr_in);
+      int client_fd = accept(listen_fd,(struct sockaddr*)&addr,&slen);
+      if(client_fd < 0) {
+	mp_msg(MSGT_NETST,MSGL_ERR,"accept failed: %s\n",strerror(errno));
+	continue;
+      }
+      mp_msg(MSGT_NETST,MSGL_V,"New client from %s\n",inet_ntoa(addr.sin_addr));
+      clients = add_client(clients,client_fd);
+      if(n == 1) continue;
+    }
+    // Look for the clients
+    for(iter = clients ; iter ; iter = iter->next) {
+      mp_net_stream_packet_t* pack;
+      if(!FD_ISSET(iter->fd,&fds)) continue;
+      pack = read_packet(iter->fd);
+      if(!pack) {
+	close(iter->fd);
+	iter->fd = -1;
+	continue;
+      }
+      if(!handle_client(iter,pack)) {
+	close(iter->fd);
+	iter->fd = -1;
+      }
+      free(pack);
+    }
+  }
+  mp_msg(MSGT_NETST,MSGL_INFO,"Exit ....\n");
+  close(listen_fd);
+#ifdef __MINGW32__
+  WSACleanup();
+#endif
+  while(clients) {
+    client_t* f = clients;
+    if(f->stream) free_stream(f->stream);
+    if(f->fd > 0) close(f->fd);
+    free(f);
+    clients = clients->next;
+  }
+  return 0;
+}
+
+int main(int argc, char** argv) {
+  int listen_fd;
+  struct sockaddr_in addr;
+
+  mp_msg_init();
+  //  mp_msg_set_level(verbose+MSGL_STATUS);
+  
+#ifdef __MINGW32__
+  WSADATA wsaData;
+  WSAStartup(MAKEWORD(1,1), &wsaData);
+#endif
+  listen_fd = socket(AF_INET, SOCK_STREAM, 0);
+  if(listen_fd < 0) {
+    mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to create listen_fd: %s\n",strerror(errno));
+    return -1;
+  }
+  memset(&addr,0,sizeof(struct sockaddr));
+  addr.sin_addr.s_addr = INADDR_ANY;
+  addr.sin_port = htons(port);
+  addr.sin_family = AF_INET;
+  if(bind(listen_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr))) {
+    mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to bind listen socket: %s\n",strerror(errno));
+    return -1;
+  }
+  
+
+  if(listen(listen_fd,1)) {
+    mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to turn the socket in listen state: %s\n",strerror(errno));
+    return -1;
+  }
+  return main_loop(listen_fd);
+}
+
+
+
+//---- For libmpdemux
+
+float stream_cache_seek_min_percent=50.0;
+float stream_cache_min_percent=20.0;
+
+#include <libmpdemux/demuxer.h>
+#include <libmpdemux/stheader.h>
+
+// audio stream skip/resync functions requires only for seeking.
+// (they should be implemented in the audio codec layer)
+void skip_audio_frame(sh_audio_t *sh_audio){
+  sh_audio=NULL;
+}
+void resync_audio_stream(sh_audio_t *sh_audio){
+  sh_audio=NULL;
+}
+
+int mp_input_check_interrupt(int time){
+    if(time) usleep(time);
+    return 0;
+}
+
+// for libdvdread:
+#include "get_path.c"
+
+int stream_cache_size=0;
+
+// for demux_ogg:
+void* vo_sub=NULL;
+int vo_osd_changed(int new_value){ new_value++; return 0;}
+int   subcc_enabled=0;
+
+float sub_fps=0;
+int sub_utf8=0;
+int   suboverlap_enabled = 1;
+float sub_delay=0;
+
+//---------------
--- a/TOOLS/netstream/Makefile	Sun Apr 01 09:28:04 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,33 +0,0 @@
-
-MPROOT=../..
-
-include $(MPROOT)/config.mak
-
-CFLAGS  = $(OPTFLAGS) -I$(MPROOT)
-
-all: netstream
-
-# FIXME: linking is a mess that should be fixed properly some day
-# it does not work with either GUI, LIVE555, libavformat, cdparanoia enabled
-DEPS = $(MPROOT)/libmpdemux/libmpdemux.a \
-	$(MPROOT)/stream/stream.a \
-	$(MPROOT)/dvdread/libdvdread.a \
-	$(MPROOT)/libdvdcss/libdvdcss.a \
-	$(MPROOT)/libavutil/libavutil.a \
-	$(MPROOT)/m_option.o \
-	$(MPROOT)/m_struct.o \
-	$(MPROOT)/mp_msg.o \
-	$(MPROOT)/osdep/libosdep.a \
-	-ltermcap -lm \
-
-ifeq ($(TARGET_WIN32),yes)
-DEPS += -lwsock32
-endif
-
-netstream: $(DEPS)
-	$(CC) -o $@ netstream.o $^
-
-clean:
-	rm -f *.o *.a *~
-
-.PHONY: all clean
--- a/TOOLS/netstream/netstream.c	Sun Apr 01 09:28:04 2007 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,412 +0,0 @@
-/*
- *  netstream.c
- *
- *	Copyright (C) Alban Bedel - 04/2003
- *
- *  This file is part of MPlayer, a free movie player.
- *	
- *  MPlayer is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2, or (at your option)
- *  any later version.
- *   
- *  MPlayer is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *   
- *  You should have received a copy of the GNU General Public License
- *  along with MPlayer; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <errno.h>
-#include <signal.h>
-#include <sys/types.h>
-
-#include "config.h"
-
-#ifndef HAVE_WINSOCK2
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#else
-#include <winsock2.h>
-#include <ws2tcpip.h>
-#endif
-
-#include "stream/stream.h"
-#include "libmpdemux/demuxer.h"
-#include "mp_msg.h"
-#include "libavutil/common.h"
-#include "mpbswap.h"
-
-/// Netstream packets def and some helpers
-#include "stream/netstream.h"
-
-
-//Set some standard variables
-char* dvdsub_lang=NULL;
-char* audio_lang=NULL;
-int sub_justify=0;
-int identify=0;
-int dvdsub_id=0;
-int audio_id=0;
-int video_id=0;
-void af_fmt2str() {};
-
-#ifdef __MINGW32__
-#define usleep sleep
-void strsep() {};
-#endif
-
-static unsigned short int port = 10000;
-
-typedef struct client_st client_t;
-struct client_st {
-  int fd;
-  stream_t* stream;
-  client_t* next;
-  client_t* prev;
-};
-
-static int write_error(int fd,char* msg) {
-  int len = strlen(msg) + 1;
-  return write_packet(fd,NET_STREAM_ERROR,msg,len);
-}
-
-static int net_stream_open(client_t* cl,char* url) {
-  int file_format=DEMUXER_TYPE_UNKNOWN;
-  mp_net_stream_opened_t ret;
-
-  if(cl->stream) {
-    if(!write_error(cl->fd,"A stream is currently opened\n"))
-      return 0;
-    return 1;
-  }
-
-  mp_msg(MSGT_NETST,MSGL_V,"Open stream %s\n",url);
-  cl->stream = open_stream(url,NULL,&file_format);
-  if(!cl->stream) {
-    if(!write_error(cl->fd,"Open failed\n"))
-      return 0;
-    return 1;
-  }
-  stream_reset(cl->stream);
-  stream_seek(cl->stream,cl->stream->start_pos);
-  ret.file_format = file_format;
-  ret.flags = cl->stream->flags;
-  ret.sector_size = cl->stream->sector_size;
-  ret.start_pos = cl->stream->start_pos;
-  ret.end_pos = cl->stream->end_pos;
-  net_stream_opened_2_me(&ret);
-
-  if(!write_packet(cl->fd,NET_STREAM_OK,(char*)&ret,sizeof(mp_net_stream_opened_t)))
-    return 0;
-  return 1;
-}
-
-static int net_stream_fill_buffer(client_t* cl,uint16_t max_len) {
-  int r;
-  mp_net_stream_packet_t *pack;
-  
-  if(!cl->stream) {
-    if(!write_error(cl->fd,"No stream is currently opened\n"))
-      return 0;
-    return 1;
-  }
-  if(max_len == 0) {
-    if(!write_error(cl->fd,"Fill buffer called with 0 lenght\n"))
-      return 0;
-    return 1;
-  }
-  pack = malloc(max_len + sizeof(mp_net_stream_packet_t));
-  pack->cmd = NET_STREAM_OK;
-  r = stream_read(cl->stream,pack->data,max_len);
-  pack->len = le2me_16(r + sizeof(mp_net_stream_packet_t));
-  if(!net_write(cl->fd,(char*)pack,le2me_16(pack->len))) {
-    free(pack);
-    return 0;
-  }
-  free(pack);
-  return 1;
-}
-
-static int net_stream_seek(client_t* cl, uint64_t pos) {
-  
-  if(!cl->stream) {
-    if(!write_error(cl->fd,"No stream is currently opened\n"))
-      return 0;
-    return 1;
-  }
-
-  if(!stream_seek(cl->stream,(off_t)pos)) {
-    if(!write_error(cl->fd,"Seek failed\n"))
-      return 0;
-    return 1;
-  }
-  if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
-    return 0;
-  return 1;
-}
-
-static int net_stream_reset(client_t* cl) {
-  if(!cl->stream) {
-    if(!write_error(cl->fd,"No stream is currently opened\n"))
-      return 0;
-    return 1;
-  }
-  stream_reset(cl->stream);
-  if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
-    return 0;
-  return 1;
-}
-
-static int net_stream_close(client_t* cl) {
-  if(!cl->stream) {
-    if(!write_error(cl->fd,"No stream is currently opened\n"))
-      return 0;
-    return 1;
-  }
-
-  free_stream(cl->stream);
-  cl->stream = NULL;
-
-  if(!write_packet(cl->fd,NET_STREAM_OK,NULL,0))
-    return 0;
-  return 1;
-}
-
-int handle_client(client_t* cl,mp_net_stream_packet_t* pack) {
-
-  if(!pack)
-    return 0;
- 
-  switch(pack->cmd) {
-  case NET_STREAM_OPEN:
-    if(((char*)pack)[pack->len-1] != '\0') {
-      mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid open packet\n");
-      return 0;
-    }
-    return net_stream_open(cl,pack->data);
-  case NET_STREAM_FILL_BUFFER:
-    if(pack->len != sizeof(mp_net_stream_packet_t) + 2) {
-      mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
-      return 0;
-    }
-    return net_stream_fill_buffer(cl,le2me_16(*((uint16_t*)pack->data)));
-  case NET_STREAM_SEEK:
-    if(pack->len != sizeof(mp_net_stream_packet_t) + 8) {
-      mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
-      return 0;
-    }
-    return net_stream_seek(cl,le2me_64(*((uint64_t*)pack->data)));
-  case NET_STREAM_RESET:
-    return net_stream_reset(cl);
-  case NET_STREAM_CLOSE:
-    if(pack->len != sizeof(mp_net_stream_packet_t)){
-      mp_msg(MSGT_NETST,MSGL_WARN,"Got invalid fill buffer packet\n");
-      return 0;
-    }
-    return net_stream_close(cl);
-  default:
-    mp_msg(MSGT_NETST,MSGL_WARN,"Got unknown command %d\n",pack->cmd);
-    if(!write_error(cl->fd,"Unknown command\n"))
-      return 0;
-  }
-  return 0;
-}
-
-static client_t* add_client(client_t *head,int fd) {
-  client_t *new = calloc(1,sizeof(client_t));
-  new->fd = fd;
-  if(!head) return new;
-  new->next = head;
-  head->prev = new;
-  return new;
-}
-
-static int make_fd_set(fd_set* fds, client_t** _cl, int listen) {
-  int max_fd = listen;
-  client_t *cl = *_cl;
-  FD_ZERO(fds);
-  FD_SET(listen,fds);
-  while(cl) {
-    // Remove this client
-    if(cl->fd < 0) {
-      client_t* f = cl;
-      if(cl->prev) cl->prev->next = cl->next;
-      if(cl->next) cl->next->prev = cl->prev;
-      if(cl->stream) free_stream(cl->stream);
-      if(!cl->prev) // Remove the head
-	*_cl = cl->next;
-      cl = cl->next;  
-      free(f);
-      continue;
-    }
-    FD_SET(cl->fd,fds);
-    if(cl->fd > max_fd) max_fd = cl->fd;
-    cl = cl->next;
-  }
-  return max_fd+1;
-}
-
-/// Hack to 'cleanly' exit
-static int run_server = 1;
-
-void exit_sig(int sig) {
-  static int count = 0;
-  sig++; // gcc warning
-  count++;
-  if(count==3) exit(1);
-  if(count > 3)
-#ifdef __MINGW32__
-    WSACleanup();
-#else
-    kill(getpid(),SIGKILL);
-#endif
-  run_server = 0;
-}
-
-static int main_loop(int listen_fd) {
-  client_t *clients = NULL,*iter;
-  fd_set fds;
-
-  signal(SIGTERM,exit_sig); // kill
-#ifndef __MINGW32__
-  signal(SIGHUP,exit_sig);  // kill -HUP  /  xterm closed
-  signal(SIGINT,exit_sig);  // Interrupt from keyboard
-  signal(SIGQUIT,exit_sig); // Quit from keyboard
-#endif 
-
-  while(run_server) {
-    int sel_n = make_fd_set(&fds,&clients,listen_fd);
-    int n = select(sel_n,&fds,NULL,NULL,NULL);
-    if(n < 0) {
-      if(errno == EINTR)
-	continue;
-      mp_msg(MSGT_NETST,MSGL_FATAL,"Select error: %s\n",strerror(errno));
-      return 1;
-    }
-    // New connection
-    if(FD_ISSET(listen_fd,&fds)) {
-      struct sockaddr_in addr;
-      socklen_t slen = sizeof(struct sockaddr_in);
-      int client_fd = accept(listen_fd,(struct sockaddr*)&addr,&slen);
-      if(client_fd < 0) {
-	mp_msg(MSGT_NETST,MSGL_ERR,"accept failed: %s\n",strerror(errno));
-	continue;
-      }
-      mp_msg(MSGT_NETST,MSGL_V,"New client from %s\n",inet_ntoa(addr.sin_addr));
-      clients = add_client(clients,client_fd);
-      if(n == 1) continue;
-    }
-    // Look for the clients
-    for(iter = clients ; iter ; iter = iter->next) {
-      mp_net_stream_packet_t* pack;
-      if(!FD_ISSET(iter->fd,&fds)) continue;
-      pack = read_packet(iter->fd);
-      if(!pack) {
-	close(iter->fd);
-	iter->fd = -1;
-	continue;
-      }
-      if(!handle_client(iter,pack)) {
-	close(iter->fd);
-	iter->fd = -1;
-      }
-      free(pack);
-    }
-  }
-  mp_msg(MSGT_NETST,MSGL_INFO,"Exit ....\n");
-  close(listen_fd);
-#ifdef __MINGW32__
-  WSACleanup();
-#endif
-  while(clients) {
-    client_t* f = clients;
-    if(f->stream) free_stream(f->stream);
-    if(f->fd > 0) close(f->fd);
-    free(f);
-    clients = clients->next;
-  }
-  return 0;
-}
-
-int main(int argc, char** argv) {
-  int listen_fd;
-  struct sockaddr_in addr;
-
-  mp_msg_init();
-  //  mp_msg_set_level(verbose+MSGL_STATUS);
-  
-#ifdef __MINGW32__
-  WSADATA wsaData;
-  WSAStartup(MAKEWORD(1,1), &wsaData);
-#endif
-  listen_fd = socket(AF_INET, SOCK_STREAM, 0);
-  if(listen_fd < 0) {
-    mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to create listen_fd: %s\n",strerror(errno));
-    return -1;
-  }
-  memset(&addr,0,sizeof(struct sockaddr));
-  addr.sin_addr.s_addr = INADDR_ANY;
-  addr.sin_port = htons(port);
-  addr.sin_family = AF_INET;
-  if(bind(listen_fd,(struct sockaddr*)&addr,sizeof(struct sockaddr))) {
-    mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to bind listen socket: %s\n",strerror(errno));
-    return -1;
-  }
-  
-
-  if(listen(listen_fd,1)) {
-    mp_msg(MSGT_NETST,MSGL_FATAL,"Failed to turn the socket in listen state: %s\n",strerror(errno));
-    return -1;
-  }
-  return main_loop(listen_fd);
-}
-
-
-
-//---- For libmpdemux
-
-float stream_cache_seek_min_percent=50.0;
-float stream_cache_min_percent=20.0;
-
-#include <libmpdemux/demuxer.h>
-#include <libmpdemux/stheader.h>
-
-// audio stream skip/resync functions requires only for seeking.
-// (they should be implemented in the audio codec layer)
-void skip_audio_frame(sh_audio_t *sh_audio){
-  sh_audio=NULL;
-}
-void resync_audio_stream(sh_audio_t *sh_audio){
-  sh_audio=NULL;
-}
-
-int mp_input_check_interrupt(int time){
-    if(time) usleep(time);
-    return 0;
-}
-
-// for libdvdread:
-#include "get_path.c"
-
-int stream_cache_size=0;
-
-// for demux_ogg:
-void* vo_sub=NULL;
-int vo_osd_changed(int new_value){ new_value++; return 0;}
-int   subcc_enabled=0;
-
-float sub_fps=0;
-int sub_utf8=0;
-int   suboverlap_enabled = 1;
-float sub_delay=0;
-
-//---------------