2 // Copyright (C) 2008, 2009, 2010, 2011, 2012 Free Software Foundation, Inc.
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 3 of the License, or
7 // (at your option) any later version.
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "gnashconfig.h"
32 #if defined(WIN32) || defined(_WIN32)
33 # define LIBLTDL_DLL_IMPORT 1
47 #include "dsodefs.h" //For DSOEXPORT.
50 #include "diskstream.h"
56 #include "rtmp_server.h"
57 #include "http_server.h"
59 using namespace gnash
;
61 using namespace boost
;
66 map
<int, Handler
*> DSOEXPORT handlers
;
68 // The user config for Cygnal is loaded and parsed here:
69 static CRcInitFile
& crcfile
= CRcInitFile::getDefaultInstance();
72 :_streams(1), // note that stream 0 is reserved by the system.
73 // _diskstreams(new gnash::DiskStream[STREAMS_BLOCK]),
76 // GNASH_REPORT_FUNCTION;
77 // reserve memory for the vector as it makes vector operations
83 // GNASH_REPORT_FUNCTION;
87 Handler::sync(int /* in_fd */)
89 // GNASH_REPORT_FUNCTION;
95 Handler::addClient(int fd
, Network::protocols_supported_e proto
)
97 // GNASH_REPORT_FUNCTION;
99 std::lock_guard
<std::mutex
> lock(_mutex
);
101 log_debug("Adding %d to the client array.", fd
);
107 std::shared_ptr
<HTTPServer
> http(new HTTPServer
);
115 std::shared_ptr
<RTMPServer
> rtmp(new RTMPServer
);
120 case Network::RTMPTS
:
125 log_unimpl(_("Protocol %d for Handler::AddClient()"), proto
);
129 _clients
.push_back(fd
);
130 _protocol
[fd
] = proto
;
132 return _clients
.size();
135 // Parse the first nessages when starting a new message handler,
136 // which is used to determine the name of the resource to
137 // initialize, or load from the cache.
139 Handler::parseFirstRequest(int fd
, gnash::Network::protocols_supported_e proto
)
141 GNASH_REPORT_FUNCTION
;
144 cygnal::Buffer
*buf
= 0;
145 std::lock_guard
<std::mutex
> lock(_mutex
);
153 int ret
= _http
[fd
]->readNet(fd
, buf
);
155 _http
[fd
]->processHeaderFields(buf
);
156 string hostname
, path
;
157 string::size_type pos
= _http
[fd
]->getField("host").find(":", 0);
158 if (pos
!= string::npos
) {
159 hostname
+= _http
[fd
]->getField("host").substr(0, pos
);
161 hostname
+= "localhost";
163 path
= _http
[fd
]->getFilespec();
164 key
= hostname
+ path
;
165 log_debug("HTTP key is: %s", key
);
168 log_error(_("HTTP key couldn't be read!"));
172 size_t bytes
= http
.sniffBytesReady(fd
);
174 buf
= new cygnal::Buffer(bytes
);
178 int ret
= http
.readNet(fd
, buf
);
180 http
.processHeaderFields(buf
);
181 string hostname
, path
;
182 string::size_type pos
= http
.getField("host").find(":", 0);
183 if (pos
!= string::npos
) {
184 hostname
+= http
.getField("host").substr(0, pos
);
186 hostname
+= "localhost";
188 path
= http
.getFilespec();
189 key
= hostname
+ path
;
190 log_debug("HTTP key is: %s", key
);
193 log_error(_("HTTP key couldn't be read!"));
202 // _rtmp[fd]->recvMsg(fd);
206 case Network::RTMPTS
:
211 log_error(_("FD #%d has no protocol handler registered"), fd
);
219 Handler::recvMsg(int fd
)
221 // GNASH_REPORT_FUNCTION;
222 std::lock_guard
<std::mutex
> lock(_mutex
);
224 switch (_protocol
[fd
]) {
229 return _http
[fd
]->recvMsg(fd
);
236 case Network::RTMPTS
:
241 log_error(_("FD #%d has no protocol handler registered"), fd
);
249 Handler::removeClient(int x
)
251 // GNASH_REPORT_FUNCTION;
253 std::lock_guard
<std::mutex
> lock(_mutex
);
255 vector
<int>::iterator it
;
256 for (it
= _clients
.begin(); it
< _clients
.end(); ++it
) {
258 log_debug("Removing %d from the client array.", *it
);
265 Handler::setPlugin(std::shared_ptr
<Handler::cygnal_init_t
> &/* init */)
267 // GNASH_REPORT_FUNCTION;
268 // _plugin.reset(init.get());
272 Handler::setPlugin(Handler::cygnal_io_read_t
/* read_ptr */, Handler::cygnal_io_write_t
/* write_ptr */)
274 // GNASH_REPORT_FUNCTION;
276 _plugin
.reset(new Handler::cygnal_init_t
);
279 std::shared_ptr
<Handler::cygnal_init_t
>
280 Handler::initModule(const std::string
& str
)
282 // GNASH_REPORT_FUNCTION;
289 if (module
[0] == '/') {
294 string
symbol(module
);
296 _pluginsdir
= PLUGINSDIR
;
297 log_security(_("Initializing module: \"%s\" from %s"), symbol
, _pluginsdir
);
299 // Update the list of loaded plugins so we only load them once.
300 if (_plugins
[module
] == 0) {
301 sl
= new SharedLib(module
);
302 lt_dlsetsearchpath(_pluginsdir
.c_str());
304 _plugins
[module
] = sl
;
306 sl
= _plugins
[module
];
309 _plugin
.reset(new Handler::cygnal_init_t
);
312 symbol
.append("_init_func");
313 Handler::cygnal_io_init_t init_symptr
= reinterpret_cast<Handler::cygnal_io_init_t
>
314 (sl
->getInitEntry(symbol
));
316 log_network(_("No %s symbol in plugin"), symbol
);
318 std::shared_ptr
<cygnal_init_t
> info
= init_symptr(_netconnect
);
319 log_network(_("Initialized Plugin: \"%s\": %s"), info
->version
,
323 // Look for the "module"_read_init function we'll use to get data
324 // from the cgi-bin as a dynamically loadable plugin.
326 symbol
.append("_read_func");
328 Handler::cygnal_io_read_t read_symptr
= reinterpret_cast<Handler::cygnal_io_read_t
>
329 (sl
->getInitEntry(symbol
));
332 log_error(_("Couldn't get %s symbol"), symbol
);
337 _plugin
->read_func
= read_symptr
;
339 // Look for the "module"_write_init function we'll use to send data
340 // to the cgi-bin as a dynamically loadable plugin.
342 symbol
.append("_write_func");
343 Handler::cygnal_io_write_t write_symptr
= reinterpret_cast<Handler::cygnal_io_write_t
>
344 (sl
->getInitEntry(symbol
));
347 log_error(_("Couldn't get %s symbol"), symbol
);
352 _plugin
->write_func
= write_symptr
;
358 Handler::writeToPlugin(std::uint8_t *data
, size_t size
)
360 // GNASH_REPORT_FUNCTION;
363 ret
= _plugin
->write_func(data
, size
);
369 std::shared_ptr
<cygnal::Buffer
>
370 Handler::readFromPlugin()
372 // GNASH_REPORT_FUNCTION;
374 std::shared_ptr
<cygnal::Buffer
> buf
;
376 buf
= _plugin
->read_func();
383 Handler::initialized()
385 // GNASH_REPORT_FUNCTION;
387 && (_clients
.size() == 1)
397 // Find a stream in the vector or Disk Streams
398 std::shared_ptr
<gnash::DiskStream
>
399 Handler::findStream(const std::string
&filespec
)
401 // GNASH_REPORT_FUNCTION;
403 for (int i
= 0; i
< _streams
; i
++) {
404 if (_diskstreams
[i
]->getFilespec() == filespec
) {
405 return _diskstreams
[i
];
409 return _diskstreams
[0];
412 // Create a new DiskStream
414 Handler::createStream(double /* transid */)
416 GNASH_REPORT_FUNCTION
;
418 _diskstreams
[_streams
]->setState(DiskStream::CREATED
);
423 // Create a new DiskStream
425 Handler::createStream(double /* transid */, const std::string
&filespec
)
427 GNASH_REPORT_FUNCTION
;
429 if (filespec
.empty()) {
433 _diskstreams
[_streams
]->setState(DiskStream::CREATED
);
434 _diskstreams
[_streams
]->setFilespec(filespec
);
440 Handler::playStream()
442 GNASH_REPORT_FUNCTION
;
444 // _diskstreams[int(streamid)]->setState(DiskStream::PLAY);
450 Handler::playStream(const std::string
&filespec
)
452 GNASH_REPORT_FUNCTION
;
454 std::shared_ptr
<gnash::DiskStream
> ds
= _diskstreams
[_streams
];
456 string fullpath
= crcfile
.getDocumentRoot();
458 fullpath
+= filespec
;
459 log_debug("FILENAME: %s", fullpath
);
461 // gnash::DiskStream &ds = findStream(filespec);
462 if (ds
->getState() == DiskStream::CREATED
) {
463 if (ds
->open(fullpath
)) {
464 ds
->loadToMem(0); // FIXME: load only part of the whole file for now
465 ds
->setState(DiskStream::PLAY
);
473 // Publish a live stream
475 Handler::publishStream()
477 GNASH_REPORT_FUNCTION
;
479 return publishStream("", Handler::LIVE
);
483 Handler::publishStream(const std::string
&/*filespec */, Handler::pub_stream_e
/* op
486 GNASH_REPORT_FUNCTION
;
488 // _diskstreams[int(streamid)]->setState(DiskStream::PUBLISH);
493 // Seek within the RTMP stream
495 Handler::seekStream()
497 GNASH_REPORT_FUNCTION
;
498 // _diskstreams[int(streamid)]->setState(DiskStream::SEEK);
504 Handler::seekStream(int /* offset */)
506 GNASH_REPORT_FUNCTION
;
507 // _diskstreams[int(streamid)]->setState(DiskStream::SEEK);
512 // Pause the RTMP stream
514 Handler::pauseStream(double streamid
)
516 GNASH_REPORT_FUNCTION
;
518 _diskstreams
[int(streamid
)]->setState(DiskStream::PAUSE
);
523 // Pause the RTMP stream
525 Handler::togglePause(double streamid
)
527 GNASH_REPORT_FUNCTION
;
529 if (_diskstreams
[int(streamid
)]->getState() == DiskStream::PAUSE
) {
530 _diskstreams
[int(streamid
)]->setState(DiskStream::PLAY
);
531 } if (_diskstreams
[int(streamid
)]->getState() == DiskStream::PLAY
) {
532 _diskstreams
[int(streamid
)]->setState(DiskStream::PAUSE
);
538 // Resume the paused RTMP stream
540 Handler::resumeStream(double streamid
)
542 GNASH_REPORT_FUNCTION
;
544 togglePause(streamid
);
549 // Close the RTMP stream
551 Handler::closeStream(double streamid
)
553 GNASH_REPORT_FUNCTION
;
555 _diskstreams
[int(streamid
)]->setState(DiskStream::CLOSED
);
560 // Delete the RTMP stream
562 Handler::deleteStream(double streamid
)
564 GNASH_REPORT_FUNCTION
;
566 _diskstreams
[int(streamid
)]->setState(DiskStream::NO_STATE
);
573 // Dump internal data.
577 const char *proto_str
[] = {
589 // GNASH_REPORT_FUNCTION;
590 cerr
<< "Currently there are " <<_clients
.size() << " clients connected."
592 for (size_t i
= 0; i
< _clients
.size(); i
++) {
593 cerr
<< "Client on fd #" << _clients
[i
] << " is using "
594 << proto_str
[_protocol
[i
]] << endl
;
597 cerr
<< "Currently there are " << dec
<<_diskstreams
.size() << " DiskStreams."
599 map
<int, std::shared_ptr
<DiskStream
> >::iterator it
;
600 for (it
= _diskstreams
.begin(); it
!= _diskstreams
.end(); ++it
) {
602 cerr
<< "DiskStream for fd #" << dec
<< it
->first
<< endl
;
609 } // end of gnash namespace
613 // indent-tabs-mode: t