2 * Copyright (C) Alban Bedel - 04/2003
4 * This file is part of MPlayer.
6 * MPlayer is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * MPlayer 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 along
17 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include <sys/types.h>
31 #ifndef HAVE_WINSOCK2_H
32 #include <sys/socket.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
40 #include "stream/stream.h"
41 #include "libmpdemux/demuxer.h"
43 #include "libavutil/common.h"
46 /// Netstream packets def and some helpers
47 #include "stream/stream_netstream.h"
55 char *info_sourceform
;
58 char* out_filename
= NULL
;
59 char* force_fourcc
=NULL
;
60 char* passtmpfile
="divx2pass.log";
62 static unsigned short int port
= 10000;
64 typedef struct client_st client_t
;
72 static int write_error(int fd
,char* msg
) {
73 int len
= strlen(msg
) + 1;
74 return write_packet(fd
,NET_STREAM_ERROR
,msg
,len
);
77 static int net_stream_open(client_t
* cl
,char* url
) {
78 int file_format
=DEMUXER_TYPE_UNKNOWN
;
79 mp_net_stream_opened_t ret
;
82 if(!write_error(cl
->fd
,"A stream is currently opened\n"))
87 mp_msg(MSGT_NETST
,MSGL_V
,"Open stream %s\n",url
);
88 cl
->stream
= open_stream(url
,NULL
,&file_format
);
90 if(!write_error(cl
->fd
,"Open failed\n"))
94 stream_reset(cl
->stream
);
95 stream_seek(cl
->stream
,cl
->stream
->start_pos
);
96 ret
.file_format
= file_format
;
97 ret
.flags
= cl
->stream
->flags
;
98 ret
.sector_size
= cl
->stream
->sector_size
;
99 ret
.start_pos
= cl
->stream
->start_pos
;
100 ret
.end_pos
= cl
->stream
->end_pos
;
101 net_stream_opened_2_me(&ret
);
103 if(!write_packet(cl
->fd
,NET_STREAM_OK
,(char*)&ret
,sizeof(mp_net_stream_opened_t
)))
108 static int net_stream_fill_buffer(client_t
* cl
,uint16_t max_len
) {
110 mp_net_stream_packet_t
*pack
;
113 if(!write_error(cl
->fd
,"No stream is currently opened\n"))
118 if(!write_error(cl
->fd
,"Fill buffer called with 0 length\n"))
122 pack
= malloc(max_len
+ sizeof(mp_net_stream_packet_t
));
123 pack
->cmd
= NET_STREAM_OK
;
124 r
= stream_read(cl
->stream
,pack
->data
,max_len
);
125 pack
->len
= le2me_16(r
+ sizeof(mp_net_stream_packet_t
));
126 if(!net_write(cl
->fd
,(char*)pack
,le2me_16(pack
->len
))) {
134 static int net_stream_seek(client_t
* cl
, uint64_t pos
) {
137 if(!write_error(cl
->fd
,"No stream is currently opened\n"))
142 if(!stream_seek(cl
->stream
,(off_t
)pos
)) {
143 if(!write_error(cl
->fd
,"Seek failed\n"))
147 if(!write_packet(cl
->fd
,NET_STREAM_OK
,NULL
,0))
152 static int net_stream_reset(client_t
* cl
) {
154 if(!write_error(cl
->fd
,"No stream is currently opened\n"))
158 stream_reset(cl
->stream
);
159 if(!write_packet(cl
->fd
,NET_STREAM_OK
,NULL
,0))
164 static int net_stream_close(client_t
* cl
) {
166 if(!write_error(cl
->fd
,"No stream is currently opened\n"))
171 free_stream(cl
->stream
);
174 if(!write_packet(cl
->fd
,NET_STREAM_OK
,NULL
,0))
179 static int handle_client(client_t
* cl
,mp_net_stream_packet_t
* pack
) {
185 case NET_STREAM_OPEN
:
186 if(((char*)pack
)[pack
->len
-1] != '\0') {
187 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got invalid open packet\n");
190 return net_stream_open(cl
,pack
->data
);
191 case NET_STREAM_FILL_BUFFER
:
192 if(pack
->len
!= sizeof(mp_net_stream_packet_t
) + 2) {
193 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got invalid fill buffer packet\n");
196 return net_stream_fill_buffer(cl
,le2me_16(*((uint16_t*)pack
->data
)));
197 case NET_STREAM_SEEK
:
198 if(pack
->len
!= sizeof(mp_net_stream_packet_t
) + 8) {
199 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got invalid fill buffer packet\n");
202 return net_stream_seek(cl
,le2me_64(*((uint64_t*)pack
->data
)));
203 case NET_STREAM_RESET
:
204 return net_stream_reset(cl
);
205 case NET_STREAM_CLOSE
:
206 if(pack
->len
!= sizeof(mp_net_stream_packet_t
)){
207 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got invalid fill buffer packet\n");
210 return net_stream_close(cl
);
212 mp_msg(MSGT_NETST
,MSGL_WARN
,"Got unknown command %d\n",pack
->cmd
);
213 if(!write_error(cl
->fd
,"Unknown command\n"))
219 static client_t
* add_client(client_t
*head
,int fd
) {
220 client_t
*new = calloc(1,sizeof(client_t
));
222 if(!head
) return new;
228 static int make_fd_set(fd_set
* fds
, client_t
** _cl
, int listen
) {
234 // Remove this client
237 if(cl
->prev
) cl
->prev
->next
= cl
->next
;
238 if(cl
->next
) cl
->next
->prev
= cl
->prev
;
239 if(cl
->stream
) free_stream(cl
->stream
);
240 if(!cl
->prev
) // Remove the head
247 if(cl
->fd
> max_fd
) max_fd
= cl
->fd
;
253 /// Hack to 'cleanly' exit
254 static int run_server
= 1;
256 void exit_sig(int sig
) {
257 static int count
= 0;
258 sig
++; // gcc warning
260 if(count
==3) exit(1);
265 kill(getpid(),SIGKILL
);
270 static int main_loop(int listen_fd
) {
271 client_t
*clients
= NULL
,*iter
;
274 signal(SIGTERM
,exit_sig
); // kill
276 signal(SIGHUP
,exit_sig
); // kill -HUP / xterm closed
277 signal(SIGINT
,exit_sig
); // Interrupt from keyboard
278 signal(SIGQUIT
,exit_sig
); // Quit from keyboard
282 int sel_n
= make_fd_set(&fds
,&clients
,listen_fd
);
283 int n
= select(sel_n
,&fds
,NULL
,NULL
,NULL
);
287 mp_msg(MSGT_NETST
,MSGL_FATAL
,"Select error: %s\n",strerror(errno
));
291 if(FD_ISSET(listen_fd
,&fds
)) {
292 struct sockaddr_in addr
;
293 socklen_t slen
= sizeof(struct sockaddr_in
);
294 int client_fd
= accept(listen_fd
,(struct sockaddr
*)&addr
,&slen
);
296 mp_msg(MSGT_NETST
,MSGL_ERR
,"accept failed: %s\n",strerror(errno
));
299 mp_msg(MSGT_NETST
,MSGL_V
,"New client from %s\n",inet_ntoa(addr
.sin_addr
));
300 clients
= add_client(clients
,client_fd
);
303 // Look for the clients
304 for(iter
= clients
; iter
; iter
= iter
->next
) {
305 mp_net_stream_packet_t
* pack
;
306 if(!FD_ISSET(iter
->fd
,&fds
)) continue;
307 pack
= read_packet(iter
->fd
);
313 if(!handle_client(iter
,pack
)) {
320 mp_msg(MSGT_NETST
,MSGL_INFO
,"Exit ....\n");
326 client_t
* f
= clients
;
327 if(f
->stream
) free_stream(f
->stream
);
328 if(f
->fd
> 0) close(f
->fd
);
330 clients
= clients
->next
;
337 struct sockaddr_in addr
;
340 // mp_msg_set_level(verbose+MSGL_STATUS);
344 WSAStartup(MAKEWORD(1,1), &wsaData
);
346 listen_fd
= socket(AF_INET
, SOCK_STREAM
, 0);
348 mp_msg(MSGT_NETST
,MSGL_FATAL
,"Failed to create listen_fd: %s\n",strerror(errno
));
351 memset(&addr
,0,sizeof(struct sockaddr
));
352 addr
.sin_addr
.s_addr
= INADDR_ANY
;
353 addr
.sin_port
= htons(port
);
354 addr
.sin_family
= AF_INET
;
355 if(bind(listen_fd
,(struct sockaddr
*)&addr
,sizeof(struct sockaddr
))) {
356 mp_msg(MSGT_NETST
,MSGL_FATAL
,"Failed to bind listen socket: %s\n",strerror(errno
));
361 if(listen(listen_fd
,1)) {
362 mp_msg(MSGT_NETST
,MSGL_FATAL
,"Failed to turn the socket in listen state: %s\n",strerror(errno
));
365 return main_loop(listen_fd
);