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
2016-12-26 23:23:16 +08:00
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
2002-09-24 06:08:50 +08:00
//
2007-08-30 02:11:09 +08:00
# include <sys/ipc.h>
# include <sys/msg.h>
2018-04-25 01:16:19 +08:00
# include <cinttypes>
2007-08-30 02:11:09 +08:00
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"
2017-04-11 09:52:29 +08:00
# include "zm_monitorstream.h"
2017-06-23 05:58:32 +08:00
# include "zm_eventstream.h"
2002-09-16 17:19:24 +08:00
2016-09-27 08:08:45 +08:00
bool ValidateAccess ( User * user , int mon_id ) {
2016-04-04 22:11:48 +08:00
bool allowed = true ;
2004-12-30 02:03:13 +08:00
2017-07-06 02:10:09 +08:00
if ( mon_id > 0 ) {
2016-04-04 22:11:48 +08:00
if ( user - > getStream ( ) < User : : PERM_VIEW )
allowed = false ;
if ( ! user - > canAccess ( mon_id ) )
allowed = false ;
2016-09-28 21:08:00 +08:00
} else {
2016-04-04 22:11:48 +08:00
if ( user - > getEvents ( ) < User : : PERM_VIEW )
allowed = false ;
}
2017-07-06 02:10:09 +08:00
if ( ! allowed ) {
2018-02-13 18:26:08 +08:00
Error ( " Error, insufficient privileges for requested action user %d %s for monitor %d " ,
user - > Id ( ) , user - > getUsername ( ) , mon_id ) ;
2016-04-04 22:11:48 +08:00
exit ( - 1 ) ;
}
2018-07-05 02:50:47 +08:00
return allowed ;
2004-12-30 02:03:13 +08:00
}
2017-06-23 05:58:32 +08:00
int main ( int argc , const char * argv [ ] ) {
2016-04-04 22:11:48 +08:00
self = argv [ 0 ] ;
2013-10-07 07:37:50 +08:00
2016-04-04 22:11:48 +08:00
srand ( getpid ( ) * time ( 0 ) ) ;
2009-04-15 04:18:57 +08:00
2017-08-24 03:05:44 +08:00
enum { ZMS_UNKNOWN , ZMS_MONITOR , ZMS_EVENT } source = ZMS_UNKNOWN ;
2016-04-04 22:11:48 +08:00
enum { ZMS_JPEG , ZMS_MPEG , ZMS_RAW , ZMS_ZIP , ZMS_SINGLE } mode = ZMS_JPEG ;
char format [ 32 ] = " " ;
int monitor_id = 0 ;
time_t event_time = 0 ;
2018-04-18 01:57:19 +08:00
uint64_t event_id = 0 ;
2016-04-28 21:20:56 +08:00
unsigned int frame_id = 1 ;
2016-04-04 22:11:48 +08:00
unsigned int scale = 100 ;
unsigned int rate = 100 ;
double maxfps = 10.0 ;
unsigned int bitrate = 100000 ;
unsigned int ttl = 0 ;
2018-09-29 00:31:53 +08:00
EventStream : : StreamMode replay = EventStream : : MODE_NONE ;
2017-03-20 23:16:39 +08:00
std : : string username ;
std : : string password ;
2016-04-04 22:11:48 +08:00
char auth [ 64 ] = " " ;
2016-09-27 08:08:45 +08:00
unsigned int connkey = 0 ;
unsigned int playback_buffer = 0 ;
2003-06-09 04:24:52 +08:00
2016-04-04 22:11:48 +08:00
bool nph = false ;
2018-06-01 23:27:53 +08:00
const char * basename = strrchr ( argv [ 0 ] , ' / ' ) ;
if ( basename ) //if we found a / lets skip past it
2016-04-04 22:11:48 +08:00
basename + + ;
else //argv[0] will not always contain the full path, but rather just the script name
basename = argv [ 0 ] ;
const char * nph_prefix = " nph- " ;
2018-06-01 23:27:53 +08:00
if ( basename & & ! strncmp ( basename , nph_prefix , strlen ( nph_prefix ) ) ) {
2016-04-04 22:11:48 +08:00
nph = true ;
}
zmLoadConfig ( ) ;
2004-12-29 00:46:48 +08:00
2018-06-01 23:27:53 +08:00
const char * query = getenv ( " QUERY_STRING " ) ;
2017-07-06 02:10:09 +08:00
if ( query ) {
2018-06-01 23:27:53 +08:00
Debug ( 1 , " Query: %s " , query ) ;
2016-04-04 22:11:48 +08:00
char temp_query [ 1024 ] ;
2018-06-01 23:27:53 +08:00
strncpy ( temp_query , query , sizeof ( temp_query ) ) ;
2016-04-04 22:11:48 +08:00
char * q_ptr = temp_query ;
char * parms [ 16 ] ; // Shouldn't be more than this
int parm_no = 0 ;
2018-06-01 23:27:53 +08:00
while ( ( parm_no < 16 ) & & ( parms [ parm_no ] = strtok ( q_ptr , " & " ) ) ) {
2016-04-04 22:11:48 +08:00
parm_no + + ;
q_ptr = NULL ;
}
2017-07-06 02:10:09 +08:00
for ( int p = 0 ; p < parm_no ; p + + ) {
2018-06-01 23:27:53 +08:00
char * name = strtok ( parms [ p ] , " = " ) ;
char * value = strtok ( NULL , " = " ) ;
2016-09-27 08:08:45 +08:00
if ( ! value )
value = ( char * ) " " ;
2018-06-01 23:27:53 +08:00
if ( ! strcmp ( name , " source " ) ) {
source = ! strcmp ( value , " event " ) ? ZMS_EVENT : ZMS_MONITOR ;
} else if ( ! strcmp ( name , " mode " ) ) {
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 ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " format " ) ) {
2016-04-04 22:11:48 +08:00
strncpy ( format , value , sizeof ( format ) ) ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " monitor " ) ) {
2016-04-04 22:11:48 +08:00
monitor_id = atoi ( value ) ;
2017-08-24 22:13:46 +08:00
if ( source = = ZMS_UNKNOWN )
source = ZMS_MONITOR ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " time " ) ) {
2016-04-04 22:11:48 +08:00
event_time = atoi ( value ) ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " event " ) ) {
2016-04-04 22:11:48 +08:00
event_id = strtoull ( value , ( char * * ) NULL , 10 ) ;
2017-08-24 03:05:44 +08:00
source = ZMS_EVENT ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " frame " ) ) {
2016-04-04 22:11:48 +08:00
frame_id = strtoull ( value , ( char * * ) NULL , 10 ) ;
2017-08-24 03:05:44 +08:00
source = ZMS_EVENT ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " scale " ) ) {
2016-04-04 22:11:48 +08:00
scale = atoi ( value ) ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " rate " ) ) {
2016-04-04 22:11:48 +08:00
rate = atoi ( value ) ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " maxfps " ) ) {
2016-04-04 22:11:48 +08:00
maxfps = atof ( value ) ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " bitrate " ) ) {
2016-04-04 22:11:48 +08:00
bitrate = atoi ( value ) ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " ttl " ) ) {
2016-04-04 22:11:48 +08:00
ttl = atoi ( value ) ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " replay " ) ) {
2018-09-29 00:31:53 +08:00
if ( ! strcmp ( value , " gapless " ) ) {
replay = EventStream : : MODE_ALL_GAPLESS ;
} else if ( ! strcmp ( value , " all " ) ) {
replay = EventStream : : MODE_ALL ;
} else if ( ! strcmp ( value , " none " ) ) {
replay = EventStream : : MODE_NONE ;
} else if ( ! strcmp ( value , " single " ) ) {
replay = EventStream : : MODE_SINGLE ;
} else {
Error ( " Unsupported value %s for replay, defaulting to none " , value ) ;
}
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " connkey " ) ) {
2016-04-04 22:11:48 +08:00
connkey = atoi ( value ) ;
2017-07-06 02:10:09 +08:00
} else if ( ! strcmp ( name , " buffer " ) ) {
2016-04-04 22:11:48 +08:00
playback_buffer = atoi ( value ) ;
2017-07-06 02:10:09 +08:00
} else if ( config . opt_use_auth ) {
if ( strcmp ( config . auth_relay , " none " ) = = 0 ) {
if ( ! strcmp ( name , " user " ) ) {
2017-03-20 23:16:39 +08:00
username = value ;
2016-04-04 22:11:48 +08:00
}
2017-07-06 02:10:09 +08:00
} else {
2016-04-04 22:11:48 +08:00
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
2017-07-06 02:10:09 +08:00
if ( ! strcmp ( name , " auth " ) ) {
2017-12-13 02:42:48 +08:00
strncpy ( auth , value , sizeof ( auth ) - 1 ) ;
2016-04-04 22:11:48 +08:00
}
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
2017-07-06 02:10:09 +08:00
if ( ! strcmp ( name , " user " ) ) {
2017-03-21 03:12:23 +08:00
username = UriDecode ( value ) ;
2016-04-04 22:11:48 +08:00
}
2017-07-06 02:10:09 +08:00
if ( ! strcmp ( name , " pass " ) ) {
2017-03-30 08:07:58 +08:00
password = UriDecode ( value ) ;
Debug ( 1 , " Have %s for password " , password . c_str ( ) ) ;
2016-04-04 22:11:48 +08:00
}
}
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
2017-07-06 03:34:02 +08:00
} // end foreach parm
} // end if query
2002-09-16 17:19:24 +08:00
2017-11-22 12:55:53 +08:00
char log_id_string [ 32 ] = " zms " ;
if ( monitor_id ) {
snprintf ( log_id_string , sizeof ( log_id_string ) , " zms_m%d " , monitor_id ) ;
} else {
2018-04-18 01:57:19 +08:00
snprintf ( log_id_string , sizeof ( log_id_string ) , " zms_e% " PRIu64 , event_id ) ;
2017-11-22 12:55:53 +08:00
}
logInit ( log_id_string ) ;
2017-07-06 02:10:09 +08:00
if ( config . opt_use_auth ) {
2016-04-04 22:11:48 +08:00
User * user = 0 ;
2005-10-20 23:42:41 +08:00
2018-06-01 23:27:53 +08:00
if ( strcmp ( config . auth_relay , " none " ) = = 0 ) {
2017-07-06 02:10:09 +08:00
if ( username . length ( ) ) {
2018-06-01 23:27:53 +08:00
user = zmLoadUser ( username . c_str ( ) ) ;
2016-04-04 22:11:48 +08:00
}
2017-07-06 02:10:09 +08:00
} else {
2016-04-04 22:11:48 +08:00
//if ( strcmp( config.auth_relay, "hashed" ) == 0 )
{
2017-07-06 02:10:09 +08:00
if ( * auth ) {
2018-06-01 23:27:53 +08:00
user = zmLoadAuthUser ( auth , config . auth_hash_ips ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
//else if ( strcmp( config.auth_relay, "plain" ) == 0 )
{
2017-07-06 02:10:09 +08:00
if ( username . length ( ) & & password . length ( ) ) {
2018-06-01 23:27:53 +08:00
user = zmLoadUser ( username . c_str ( ) , password . c_str ( ) ) ;
2007-08-30 02:11:09 +08:00
}
2016-04-04 22:11:48 +08:00
}
}
2017-07-06 02:10:09 +08:00
if ( ! user ) {
2018-06-01 23:27:53 +08:00
Error ( " Unable to authenticate user " ) ;
2016-04-04 22:11:48 +08:00
logTerm ( ) ;
zmDbClose ( ) ;
2018-06-01 23:27:53 +08:00
return - 1 ;
2016-04-04 22:11:48 +08:00
}
2018-06-01 23:27:53 +08:00
ValidateAccess ( user , monitor_id ) ;
} // end if config.opt_use_auth
2002-09-16 17:19:24 +08:00
2017-11-22 12:55:53 +08:00
hwcaps_detect ( ) ;
zmSetDefaultTermHandler ( ) ;
zmSetDefaultDieHandler ( ) ;
2016-04-04 22:11:48 +08:00
setbuf ( stdout , 0 ) ;
2017-07-06 02:10:09 +08:00
if ( nph ) {
2016-04-04 22:11:48 +08:00
fprintf ( stdout , " HTTP/1.0 200 OK \r \n " ) ;
}
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 ) ) ;
2004-03-04 23:05:54 +08:00
2016-04-04 22:11:48 +08:00
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 " ) ;
// 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
2017-07-06 02:10:09 +08:00
if ( source = = ZMS_MONITOR ) {
2016-09-27 08:08:45 +08:00
MonitorStream stream ;
stream . setStreamScale ( scale ) ;
stream . setStreamReplayRate ( rate ) ;
stream . setStreamMaxFPS ( maxfps ) ;
stream . setStreamTTL ( ttl ) ;
stream . setStreamQueue ( connkey ) ;
stream . setStreamBuffer ( playback_buffer ) ;
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
2016-09-27 08:08:45 +08:00
if ( mode = = ZMS_JPEG ) {
stream . setStreamType ( MonitorStream : : STREAM_JPEG ) ;
} else if ( mode = = ZMS_RAW ) {
stream . setStreamType ( MonitorStream : : STREAM_RAW ) ;
2017-07-06 02:10:09 +08:00
} else if ( mode = = ZMS_ZIP ) {
2016-09-27 08:08:45 +08:00
stream . setStreamType ( MonitorStream : : STREAM_ZIP ) ;
2017-07-06 02:10:09 +08:00
} else if ( mode = = ZMS_SINGLE ) {
2016-09-27 08:08:45 +08:00
stream . setStreamType ( MonitorStream : : STREAM_SINGLE ) ;
} else {
2004-03-04 23:05:54 +08:00
# if HAVE_LIBAVCODEC
2016-09-27 08:08:45 +08:00
stream . setStreamFormat ( format ) ;
stream . setStreamBitrate ( bitrate ) ;
stream . setStreamType ( MonitorStream : : STREAM_MPEG ) ;
2004-03-04 23:05:54 +08:00
# else // HAVE_LIBAVCODEC
2016-09-27 08:08:45 +08:00
Error ( " MPEG streaming of '%s' attempted while disabled " , query ) ;
fprintf ( stderr , " MPEG streaming is disabled. \n You should configure with the --with-ffmpeg option and rebuild to use this functionality. \n " ) ;
logTerm ( ) ;
zmDbClose ( ) ;
return ( - 1 ) ;
2004-03-04 23:05:54 +08:00
# endif // HAVE_LIBAVCODEC
2016-09-27 08:08:45 +08:00
}
stream . runStream ( ) ;
} else if ( source = = ZMS_EVENT ) {
if ( ! event_id ) {
Fatal ( " Can't view an event without specifying an event_id. " ) ;
}
2017-08-24 03:05:44 +08:00
Debug ( 3 , " Doing event stream scale(%d) " , scale ) ;
2016-09-27 08:08:45 +08:00
EventStream stream ;
stream . setStreamScale ( scale ) ;
stream . setStreamReplayRate ( rate ) ;
stream . setStreamMaxFPS ( maxfps ) ;
stream . setStreamMode ( replay ) ;
stream . setStreamQueue ( connkey ) ;
if ( monitor_id & & event_time ) {
2018-03-03 10:27:03 +08:00
stream . setStreamStart ( monitor_id , event_time ) ;
2016-09-27 08:08:45 +08:00
} else {
2017-08-24 03:05:44 +08:00
Debug ( 3 , " Setting stream start to frame (%d) " , frame_id ) ;
2018-03-03 10:27:03 +08:00
stream . setStreamStart ( event_id , frame_id ) ;
2016-09-27 08:08:45 +08:00
}
if ( mode = = ZMS_JPEG ) {
stream . setStreamType ( EventStream : : STREAM_JPEG ) ;
} else {
2007-08-30 02:11:09 +08:00
# if HAVE_LIBAVCODEC
2016-09-27 08:08:45 +08:00
stream . setStreamFormat ( format ) ;
stream . setStreamBitrate ( bitrate ) ;
stream . setStreamType ( EventStream : : STREAM_MPEG ) ;
2007-08-30 02:11:09 +08:00
# else // HAVE_LIBAVCODEC
2016-09-27 08:08:45 +08:00
Error ( " MPEG streaming of '%s' attempted while disabled " , query ) ;
fprintf ( stderr , " MPEG streaming is disabled. \n You should ensure the ffmpeg libraries are installed and detected and rebuild to use this functionality. \n " ) ;
logTerm ( ) ;
zmDbClose ( ) ;
return ( - 1 ) ;
2007-08-30 02:11:09 +08:00
# endif // HAVE_LIBAVCODEC
2016-09-27 08:08:45 +08:00
} // end if jpeg or mpeg
stream . runStream ( ) ;
2017-08-24 03:05:44 +08:00
} else {
Error ( " Neither a monitor or event was specified. " ) ;
2016-09-27 08:08:45 +08:00
} // end if monitor or event
2014-11-15 05:17:44 +08:00
2016-09-27 08:08:45 +08:00
logTerm ( ) ;
zmDbClose ( ) ;
2014-11-15 05:17:44 +08:00
2016-09-27 08:08:45 +08:00
return ( 0 ) ;
2002-09-16 17:19:24 +08:00
}