2002-09-24 06:08:50 +08:00
//
2002-12-10 21:21:41 +08:00
// ZoneMinder Streaming Server, $Date$, $Revision$
2008-07-25 17:33:23 +08:00
// Copyright (C) 2001-2008 Philip Coombes
2002-09-24 06:08:50 +08:00
//
// This program 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
// of the License, or (at your option) any later version.
//
// This program 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 this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
2007-08-30 02:11:09 +08:00
# include <sys/ipc.h>
# include <sys/msg.h>
2002-09-16 17:19:24 +08:00
# include "zm.h"
2003-03-26 20:00:16 +08:00
# include "zm_db.h"
2005-01-19 09:50:24 +08:00
# include "zm_user.h"
2006-04-05 20:22:27 +08:00
# include "zm_signal.h"
2003-03-26 20:00:16 +08:00
# include "zm_monitor.h"
2002-09-16 17:19:24 +08:00
2005-01-19 09:50:24 +08:00
bool ValidateAccess ( User * user , int mon_id )
2004-12-30 02:03:13 +08:00
{
2005-01-19 09:50:24 +08:00
bool allowed = true ;
2004-12-30 02:03:13 +08:00
2005-01-19 09:50:24 +08:00
if ( mon_id > 0 )
2004-12-30 02:03:13 +08:00
{
2005-01-19 09:50:24 +08:00
if ( user - > getStream ( ) < User : : PERM_VIEW )
allowed = false ;
if ( ! user - > canAccess ( mon_id ) )
allowed = false ;
2004-12-30 02:03:13 +08:00
}
else
{
2005-01-19 09:50:24 +08:00
if ( user - > getEvents ( ) < User : : PERM_VIEW )
allowed = false ;
2004-12-30 02:03:13 +08:00
}
2005-01-19 09:50:24 +08:00
if ( ! allowed )
2004-12-30 02:03:13 +08:00
{
2008-07-14 22:43:47 +08:00
Error ( " Error, insufficient privileges for requested action " ) ;
2005-01-19 09:50:24 +08:00
exit ( - 1 ) ;
2004-12-30 02:03:13 +08:00
}
2005-01-19 09:50:24 +08:00
return ( allowed ) ;
2004-12-30 02:03:13 +08:00
}
2004-03-15 02:16:15 +08:00
int main ( int argc , const char * argv [ ] )
2002-09-16 17:19:24 +08:00
{
2013-10-07 07:37:50 +08:00
self = argv [ 0 ] ;
srand ( getpid ( ) * time ( 0 ) ) ;
2009-04-15 04:18:57 +08:00
2007-08-30 02:11:09 +08:00
enum { ZMS_MONITOR , ZMS_EVENT } source = ZMS_MONITOR ;
2007-09-18 22:01:25 +08:00
enum { ZMS_JPEG , ZMS_MPEG , ZMS_RAW , ZMS_ZIP , ZMS_SINGLE } mode = ZMS_JPEG ;
2004-03-04 23:05:54 +08:00
char format [ 32 ] = " " ;
2007-08-30 02:11:09 +08:00
int monitor_id = 0 ;
time_t event_time = 0 ;
int event_id = 0 ;
int frame_id = 1 ;
2004-02-16 03:47:23 +08:00
unsigned int scale = 100 ;
2004-03-15 17:37:21 +08:00
unsigned int rate = 100 ;
2009-04-03 20:10:54 +08:00
double maxfps = 10.0 ;
2004-03-15 17:37:21 +08:00
unsigned int bitrate = 100000 ;
2003-03-21 18:53:55 +08:00
unsigned int ttl = 0 ;
2007-11-21 01:06:45 +08:00
EventStream : : StreamMode replay = EventStream : : MODE_SINGLE ;
2005-01-19 09:50:24 +08:00
char username [ 64 ] = " " ;
char password [ 64 ] = " " ;
2004-12-30 02:03:13 +08:00
char auth [ 64 ] = " " ;
2007-08-30 02:11:09 +08:00
unsigned int connkey = 0 ;
2008-10-30 07:08:21 +08:00
unsigned int playback_buffer = 0 ;
2003-06-09 04:24:52 +08:00
2004-03-15 02:16:15 +08:00
bool nph = false ;
const char * basename = strrchr ( argv [ 0 ] , ' / ' ) ;
2009-05-26 02:03:46 +08:00
if ( basename ) //if we found a / lets skip past it
basename + + ;
else //argv[0] will not always contain the full path, but rather just the script name
basename = argv [ 0 ] ;
2004-03-15 02:16:15 +08:00
const char * nph_prefix = " nph- " ;
2009-05-26 02:03:46 +08:00
if ( basename & & ! strncmp ( basename , nph_prefix , strlen ( nph_prefix ) ) )
2004-03-15 02:16:15 +08:00
{
nph = true ;
}
2004-12-29 00:46:48 +08:00
zmLoadConfig ( ) ;
2011-06-21 17:19:10 +08:00
logInit ( " zms " ) ;
2011-09-08 00:07:23 +08:00
ssedetect ( ) ;
2011-06-21 17:19:10 +08:00
2006-04-05 20:22:27 +08:00
zmSetDefaultTermHandler ( ) ;
zmSetDefaultDieHandler ( ) ;
2002-09-16 17:19:24 +08:00
const char * query = getenv ( " QUERY_STRING " ) ;
if ( query )
{
2008-07-14 22:43:47 +08:00
Debug ( 1 , " Query: %s " , query ) ;
2004-03-04 23:05:54 +08:00
char temp_query [ 1024 ] ;
2004-04-20 00:02:17 +08:00
strncpy ( temp_query , query , sizeof ( temp_query ) ) ;
2002-09-16 17:19:24 +08:00
char * q_ptr = temp_query ;
2004-03-04 23:05:54 +08:00
char * parms [ 16 ] ; // Shouldn't be more than this
2002-09-16 17:19:24 +08:00
int parm_no = 0 ;
2004-04-20 00:02:17 +08:00
while ( ( parm_no < 16 ) & & ( parms [ parm_no ] = strtok ( q_ptr , " & " ) ) )
2002-09-16 17:19:24 +08:00
{
parm_no + + ;
q_ptr = NULL ;
}
for ( int p = 0 ; p < parm_no ; p + + )
{
char * name = strtok ( parms [ p ] , " = " ) ;
char * value = strtok ( NULL , " = " ) ;
2007-11-21 01:06:45 +08:00
if ( ! value )
2008-07-25 01:12:39 +08:00
value = ( char * ) " " ;
2007-08-30 02:11:09 +08:00
if ( ! strcmp ( name , " source " ) )
{
source = ! strcmp ( value , " event " ) ? ZMS_EVENT : ZMS_MONITOR ;
}
2007-09-18 22:01:25 +08:00
else if ( ! strcmp ( name , " mode " ) )
2004-04-19 21:03:16 +08:00
{
2007-09-18 22:01:25 +08:00
mode = ! strcmp ( value , " jpeg " ) ? ZMS_JPEG : ZMS_MPEG ;
mode = ! strcmp ( value , " raw " ) ? ZMS_RAW : mode ;
mode = ! strcmp ( value , " zip " ) ? ZMS_ZIP : mode ;
mode = ! strcmp ( value , " single " ) ? ZMS_SINGLE : mode ;
2004-04-19 21:03:16 +08:00
}
2007-08-30 02:11:09 +08:00
else if ( ! strcmp ( name , " format " ) )
strncpy ( format , value , sizeof ( format ) ) ;
2004-03-04 23:05:54 +08:00
else if ( ! strcmp ( name , " monitor " ) )
2007-08-30 02:11:09 +08:00
monitor_id = atoi ( value ) ;
else if ( ! strcmp ( name , " time " ) )
event_time = atoi ( value ) ;
2004-03-04 23:05:54 +08:00
else if ( ! strcmp ( name , " event " ) )
2007-08-30 02:11:09 +08:00
event_id = strtoull ( value , ( char * * ) NULL , 10 ) ;
2006-01-12 23:41:39 +08:00
else if ( ! strcmp ( name , " frame " ) )
2007-08-30 02:11:09 +08:00
frame_id = strtoull ( value , ( char * * ) NULL , 10 ) ;
2003-10-16 17:00:53 +08:00
else if ( ! strcmp ( name , " scale " ) )
scale = atoi ( value ) ;
2004-03-15 17:37:21 +08:00
else if ( ! strcmp ( name , " rate " ) )
rate = atoi ( value ) ;
else if ( ! strcmp ( name , " maxfps " ) )
2009-04-03 20:10:54 +08:00
maxfps = atof ( value ) ;
2004-03-15 17:37:21 +08:00
else if ( ! strcmp ( name , " bitrate " ) )
bitrate = atoi ( value ) ;
2004-03-04 23:05:54 +08:00
else if ( ! strcmp ( name , " ttl " ) )
ttl = atoi ( value ) ;
2007-11-21 01:06:45 +08:00
else if ( ! strcmp ( name , " replay " ) )
{
replay = ! strcmp ( value , " gapless " ) ? EventStream : : MODE_ALL_GAPLESS : EventStream : : MODE_SINGLE ;
replay = ! strcmp ( value , " all " ) ? EventStream : : MODE_ALL : replay ;
}
2007-08-30 02:53:29 +08:00
else if ( ! strcmp ( name , " connkey " ) )
connkey = atoi ( value ) ;
2008-10-30 07:08:21 +08:00
else if ( ! strcmp ( name , " buffer " ) )
playback_buffer = atoi ( value ) ;
2005-05-16 17:27:06 +08:00
else if ( config . opt_use_auth )
2004-12-30 02:03:13 +08:00
{
2006-01-14 21:37:11 +08:00
if ( strcmp ( config . auth_relay , " none " ) = = 0 )
2004-12-30 02:03:13 +08:00
{
2006-01-14 21:37:11 +08:00
if ( ! strcmp ( name , " user " ) )
2005-10-20 23:42:41 +08:00
{
2006-01-14 21:37:11 +08:00
strncpy ( username , value , sizeof ( username ) ) ;
2005-10-20 23:42:41 +08:00
}
2004-12-30 02:03:13 +08:00
}
2006-01-14 21:37:11 +08:00
else
2005-01-19 09:50:24 +08:00
{
2006-01-14 21:37:11 +08:00
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
2005-10-20 23:42:41 +08:00
{
2006-01-14 21:37:11 +08:00
if ( ! strcmp ( name , " auth " ) )
{
strncpy ( auth , value , sizeof ( auth ) ) ;
}
2005-10-20 23:42:41 +08:00
}
2006-01-14 21:37:11 +08:00
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
2005-10-20 23:42:41 +08:00
{
2006-01-14 21:37:11 +08:00
if ( ! strcmp ( name , " user " ) )
{
strncpy ( username , value , sizeof ( username ) ) ;
}
if ( ! strcmp ( name , " pass " ) )
{
strncpy ( password , value , sizeof ( password ) ) ;
}
2005-10-20 23:42:41 +08:00
}
2004-12-30 02:03:13 +08:00
}
}
2002-09-16 17:19:24 +08:00
}
}
2005-05-16 17:27:06 +08:00
if ( config . opt_use_auth )
2005-01-19 09:50:24 +08:00
{
2005-01-27 04:53:55 +08:00
User * user = 0 ;
2005-10-20 23:42:41 +08:00
2006-01-14 21:37:11 +08:00
if ( strcmp ( config . auth_relay , " none " ) = = 0 )
2005-01-27 04:53:55 +08:00
{
2006-01-14 21:37:11 +08:00
if ( * username )
2005-10-20 23:42:41 +08:00
{
2006-01-14 21:37:11 +08:00
user = zmLoadUser ( username ) ;
2005-10-20 23:42:41 +08:00
}
2005-01-27 04:53:55 +08:00
}
2006-01-14 21:37:11 +08:00
else
2005-01-27 04:53:55 +08:00
{
2006-01-14 21:37:11 +08:00
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
if ( * auth )
{
user = zmLoadAuthUser ( auth , config . auth_hash_ips ) ;
}
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
2005-10-20 23:42:41 +08:00
{
2006-01-14 21:37:11 +08:00
if ( * username & & * password )
{
user = zmLoadUser ( username , password ) ;
}
2005-10-20 23:42:41 +08:00
}
2005-01-27 04:53:55 +08:00
}
if ( ! user )
{
2008-07-14 22:43:47 +08:00
Error ( " Unable to authenticate user " ) ;
2014-11-15 05:17:44 +08:00
logTerm ( ) ;
zmDbClose ( ) ;
2005-01-27 04:53:55 +08:00
return ( - 1 ) ;
}
2007-08-30 02:11:09 +08:00
ValidateAccess ( user , monitor_id ) ;
2004-12-30 02:03:13 +08:00
}
2002-09-16 17:19:24 +08:00
2004-03-04 23:05:54 +08:00
setbuf ( stdout , 0 ) ;
2004-03-15 02:16:15 +08:00
if ( nph )
{
fprintf ( stdout , " HTTP/1.0 200 OK \r \n " ) ;
}
2004-03-04 23:05:54 +08:00
fprintf ( stdout , " Server: ZoneMinder Video Server/%s \r \n " , ZM_VERSION ) ;
time_t now = time ( 0 ) ;
char date_string [ 64 ] ;
strftime ( date_string , sizeof ( date_string ) - 1 , " %a, %d %b %Y %H:%M:%S GMT " , gmtime ( & now ) ) ;
fprintf ( stdout , " Expires: Mon, 26 Jul 1997 05:00:00 GMT \r \n " ) ;
fprintf ( stdout , " Last-Modified: %s \r \n " , date_string ) ;
fprintf ( stdout , " Cache-Control: no-store, no-cache, must-revalidate \r \n " ) ;
fprintf ( stdout , " Cache-Control: post-check=0, pre-check=0 \r \n " ) ;
fprintf ( stdout , " Pragma: no-cache \r \n " ) ;
2004-03-23 17:24:13 +08:00
// Removed as causing more problems than it fixed.
//if ( !nph )
//{
//fprintf( stdout, "Content-Length: 0\r\n");
//}
2004-03-04 23:05:54 +08:00
2007-08-30 02:11:09 +08:00
if ( source = = ZMS_MONITOR )
2002-09-16 17:19:24 +08:00
{
2007-08-30 02:11:09 +08:00
MonitorStream stream ;
stream . setStreamScale ( scale ) ;
stream . setStreamReplayRate ( rate ) ;
stream . setStreamMaxFPS ( maxfps ) ;
stream . setStreamTTL ( ttl ) ;
stream . setStreamQueue ( connkey ) ;
2008-10-30 07:08:21 +08:00
stream . setStreamBuffer ( playback_buffer ) ;
2015-02-23 05:58:15 +08:00
if ( ! stream . setStreamStart ( monitor_id ) ) {
Error ( " Unable to connect to zmc process for monitor %d " , monitor_id ) ;
fprintf ( stderr , " Unable to connect to zmc process. Please ensure that it is running. " ) ;
logTerm ( ) ;
zmDbClose ( ) ;
return ( - 1 ) ;
}
2002-09-16 17:19:24 +08:00
2007-09-18 22:01:25 +08:00
if ( mode = = ZMS_JPEG )
2007-08-30 02:11:09 +08:00
{
stream . setStreamType ( MonitorStream : : STREAM_JPEG ) ;
}
2007-09-18 22:01:25 +08:00
else if ( mode = = ZMS_RAW )
2003-03-21 18:53:55 +08:00
{
2007-08-30 02:11:09 +08:00
stream . setStreamType ( MonitorStream : : STREAM_RAW ) ;
2003-03-21 18:53:55 +08:00
}
2007-09-18 22:01:25 +08:00
else if ( mode = = ZMS_ZIP )
2004-03-04 23:05:54 +08:00
{
2007-08-30 02:11:09 +08:00
stream . setStreamType ( MonitorStream : : STREAM_ZIP ) ;
2004-03-04 23:05:54 +08:00
}
2007-09-18 22:01:25 +08:00
else if ( mode = = ZMS_SINGLE )
2004-03-04 23:05:54 +08:00
{
2007-08-30 02:11:09 +08:00
stream . setStreamType ( MonitorStream : : STREAM_SINGLE ) ;
}
else
{
2004-03-04 23:05:54 +08:00
# if HAVE_LIBAVCODEC
2007-08-30 02:11:09 +08:00
stream . setStreamFormat ( format ) ;
stream . setStreamBitrate ( bitrate ) ;
stream . setStreamType ( MonitorStream : : STREAM_MPEG ) ;
2004-03-04 23:05:54 +08:00
# else // HAVE_LIBAVCODEC
2008-07-14 22:43:47 +08:00
Error ( " MPEG streaming of '%s' attempted while disabled " , query ) ;
2007-08-30 02:11:09 +08:00
fprintf ( stderr , " MPEG streaming is disabled. \n You should configure with the --with-ffmpeg option and rebuild to use this functionality. \n " ) ;
2014-11-15 05:17:44 +08:00
logTerm ( ) ;
zmDbClose ( ) ;
2007-08-30 02:11:09 +08:00
return ( - 1 ) ;
2004-03-04 23:05:54 +08:00
# endif // HAVE_LIBAVCODEC
2007-08-30 02:11:09 +08:00
}
stream . runStream ( ) ;
2002-09-16 17:19:24 +08:00
}
2007-08-30 02:11:09 +08:00
else if ( source = = ZMS_EVENT )
{
EventStream stream ;
stream . setStreamScale ( scale ) ;
stream . setStreamReplayRate ( rate ) ;
stream . setStreamMaxFPS ( maxfps ) ;
2007-11-21 01:06:45 +08:00
stream . setStreamMode ( replay ) ;
2007-08-30 02:11:09 +08:00
stream . setStreamQueue ( connkey ) ;
if ( monitor_id & & event_time )
{
stream . setStreamStart ( monitor_id , event_time ) ;
}
else
{
stream . setStreamStart ( event_id , frame_id ) ;
}
2007-09-18 22:01:25 +08:00
if ( mode = = ZMS_JPEG )
2007-08-30 02:11:09 +08:00
{
stream . setStreamType ( EventStream : : STREAM_JPEG ) ;
}
else
{
# if HAVE_LIBAVCODEC
stream . setStreamFormat ( format ) ;
stream . setStreamBitrate ( bitrate ) ;
stream . setStreamType ( EventStream : : STREAM_MPEG ) ;
# else // HAVE_LIBAVCODEC
2008-07-14 22:43:47 +08:00
Error ( " MPEG streaming of '%s' attempted while disabled " , query ) ;
2008-10-30 07:08:21 +08:00
fprintf ( stderr , " MPEG streaming is disabled. \n You should ensure the ffmpeg libraries are installed and detected and rebuild to use this functionality. \n " ) ;
2014-11-15 05:17:44 +08:00
logTerm ( ) ;
zmDbClose ( ) ;
2007-08-30 02:11:09 +08:00
return ( - 1 ) ;
# endif // HAVE_LIBAVCODEC
}
stream . runStream ( ) ;
}
2014-11-15 05:17:44 +08:00
logTerm ( ) ;
zmDbClose ( ) ;
2002-10-28 22:33:57 +08:00
return ( 0 ) ;
2002-09-16 17:19:24 +08:00
}