⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 unixdmon.cpp

📁 mini http server,可以集成嵌入到程序中,实现简单的web功能
💻 CPP
📖 第 1 页 / 共 2 页
字号:
				{ iFlags |= FLG_RDATA; }
			else
				{ return 0; };
			}
        else if ( !PIUtil_stricmp( KEY_CONF_RLIMITFSIZE, pVariable ) )
			{
			if ( AddResourceLimit( RLIMIT_FSIZE, "RLIMIT_FSIZE", pValue,
				&tRFSize ) )
				{ iFlags |= FLG_RFSIZE; }
			else
				{ return 0; };
			}
        else if ( !PIUtil_stricmp( KEY_CONF_USER, pVariable ) )
			{
			if ( !GetUid( pValue ) )
				{ return 0; };
			}
        else if ( !PIUtil_stricmp( KEY_CONF_GROUP, pVariable ) )
			{
			if ( !GetGid( pValue ) )
				{ return 0; };
			}
        else if ( !PIUtil_stricmp( KEY_CONF_PIDFILE, pVariable ) )
            {
			ofstream ofs( pValue );
			if ( ofs.good() )
				{
				ofs << ::getpid() << endl;
				}
			else
				{
				PILog_addMessage( PIObject_getDB( pObject ),
					PIObject_getConfigurationDB( pObject ), PILOG_ERROR,
					"%sUNIXDaemon: Unable to open PID file: '%s'",
					pWhere, pValue );
				return 0;
				};
			}
        else if ( !PIUtil_stricmp( KEY_CONF_LOCKFILENAME, pVariable ) )
			{
			const char *pTmp = tempnam( 0, "Pi3" );
			assert( pTmp );
			pLockFileName = PIUtil_strdup( pTmp );

			/* ---
			--- */
			assert( pValue );
			assert( pLockFileName );
			ofstream ofs( pValue );
			if ( ofs.good() ) {
				ofs << pLockFileName << endl;
				pMainLockFileName = PIUtil_strdup( pValue );
				}
			else
				{
				PILog_addMessage( PIObject_getDB( pObject ),
					PIObject_getConfigurationDB( pObject ), PILOG_ERROR,
					"UNIXDaemon: Could not write lockfile name '%s' \
into specified file '%s'.", pLockFileName, pValue );
				*pLockFileName = '\0';
				return 0;
				};
			}
		else
			{
			PILog_addMessage( PIObject_getDB( pObject ),
				PIObject_getConfigurationDB( pObject ), PILOG_ERROR,
				"%sUNIXDaemon: Unknown parameter '%s'", pWhere, pVariable );
			};
#endif

		return 1;
		};

	/* --- --- */
    static int ParameterFn( void *pData, const char *pVar, const char *pVal,
		const char *pWhere )
        {
        assert( pData );
        return ((UNIXDaemon *)pData)->Parameter( pVar, pVal, pWhere );
        };

public:
	/* --- --- */
	UNIXDaemon( PIObject *pTheObject, int iArgc, const char *ppArgv[] )
	:	pObject( pTheObject ),
		pServerObject( 0 ),
		iOK( 0 ),
		pMessage( 0 )
#if POSIX
		, iFlags( 0 ),
		tId( (uid_t)-1 ),
		tGid( (gid_t)-1 ),
		iNumberOfProcesses( 5 ),	/* if this is changed then change the
									documentation above */
		pProcessIds( 0 ),
		pMainLockFileName( 0 ),
		pLockFileName( 0 ),
		tParentPid( ::getpid() )
		{
		if ( !PIObject_readParameters( pObject, iArgc, ppArgv, ParameterFn,
			this ) )
			{ return; };

		/* --- Generate lockfile ? --- */
		if ( pLockFileName )
			{
			if ( !GenerateLockFile() )
				{ return; };
			};

		pProcessIds = new pid_t[iNumberOfProcesses];
		if ( !pProcessIds )
			{ return; };

		memset( pProcessIds, 0, sizeof( pid_t ) * iNumberOfProcesses );
#else
		{
		if ( !PIObject_readParameters( pObject, iArgc, ppArgv, ParameterFn,
			this ) )
			{ return; };
#endif

		/* --- load up the server object --- */
		pServerObject = PIObject_loadEx( pObject, KEY_CONF_SERVEROBJECT );
		if ( !pServerObject )
			{ return; };
		iOK = 1;
		};

	/* --- --- */
	virtual ~UNIXDaemon()
		{
#if POSIX
		/* ---
		These cleanup tasks shutdown the server cleanly, this is not
		something that should happen when a child process exists, so
		return if this is a child process.
		We can determine if this is a child process by comparing the
		the current process id to tParentPid, the process id when
		this object was constructed and before any fork's.	
		--- */
		if ( ::getpid()!=tParentPid )
			{ return; };

		int i;

		/* --- kill child processes --- */
		if ( pProcessIds )
			{
			for( i=0; i<iNumberOfProcesses; i++ )	
				{
				if ( pProcessIds[i] )
					{
					::kill( pProcessIds[i], SIGTERM );
					};
				};
			};

		/* ---
		NOTE: maybe wait for notification that processes have died
		--- */

		/* --- remove the file containing the lockfile name --- */
		if ( pMainLockFileName && *pMainLockFileName )
			{ ::unlink( pMainLockFileName ); };
		if ( pMainLockFileName )
			{ PIUtil_free( pMainLockFileName ); };

		/* --- remove the lockfile --- */
		if ( pLockFileName && *pLockFileName )
			{ ::unlink( pLockFileName ); };
		if ( pLockFileName )
			{ PIUtil_free( pLockFileName ); };
		delete [] pProcessIds;
#endif
		PIObject_delete( pServerObject, 0, 0 );
		if ( pMessage ) { PIUtil_free( pMessage ); };
		};

#if POSIX
	/* --- signal handler --- */
	static void SignalHandler( int iSignal )
		{
		switch( iSignal )
			{
			case SIGTERM:
				exit( 0 );
				break;

			default:;
			};
		};

	/* --- child function --- */
	int ChildMain( int iArgc, const char *ppArgv[] )
		{
		/* --- ignore SIGINT --- */
		signal( SIGINT, SIG_IGN );

		/* --- quick exit on sigterm, don't bother freeing memory --- */
		signal( SIGTERM, SignalHandler );

		/* --- make sure we don't kill any siblings --- */
		memset( pProcessIds, 0, sizeof( pid_t ) * iNumberOfProcesses );

		/* --- set resource limits --- */
		if ( iFlags & FLG_RCORE )
			{
			if ( !SetRLimit( RLIMIT_CORE, &tRCore, "RLIMIT_CORE" ) )
				{ return PIAPI_ABORT; };
			};
		if ( iFlags & FLG_RCPU )
			{
			if ( !SetRLimit( RLIMIT_CPU, &tRCPU, "RLIMIT_CPU" ) )
				{ return PIAPI_ABORT; };
			};
		if ( iFlags & FLG_RDATA )
			{
			if ( !SetRLimit( RLIMIT_DATA, &tRData, "RLIMIT_DATA" ) )
				{ return PIAPI_ABORT; };
			};
		if ( iFlags & FLG_RFSIZE )
			{
			if ( !SetRLimit( RLIMIT_FSIZE, &tRFSize, "RLIMIT_FSIZE" ) )
				{ return PIAPI_ABORT; };
			};

#if RUN_MAIN_AS_ROOT
		/*
		** Change the effective user and group ids
		*/
		/* --- group id --- */
		if ( iFlags & FLG_GID )
			{
			if ( ::setgid( tGid )==-1 )
				{
				Cerr() << "Could not set group id to '" << tGid <<
					"' error code is " << errno << endl;
				return PIAPI_ABORT;
				};
			};

		/* --- user id --- */
		if ( iFlags & FLG_UID )
			{
			if ( ::setuid( tId )==-1 )
				{
				Cerr() << "Could not set user id to '" << tId <<
					"' error code is " << errno << endl;
				return PIAPI_ABORT;
				};
			};
#endif

		int iRet = PILogic_execute( pServerObject, iArgc, ppArgv );

		/* ---
		If there was an error write out details
		--- */
		if ( iRet )
			{
	        Cerr() << "Error(s) during child execution:-" << endl;
			PILog_writeDiagnostics( PIObject_getDB( pObject ), PILOG_ALL, 0 );
			cout.flush();
			cerr.flush();
			};

		return 0;
		}; 
#endif

	/* --- --- */
	int DoExecute( int iArgc, const char *ppArgv[] )
		{
		/* --- Write start message? --- */
		if ( pMessage )
			{
			cout << pMessage << endl;
			};
#if	!POSIX
		return PILogic_execute( pServerObject, iArgc, ppArgv );
#else
		assert( pProcessIds );

#if !RUN_MAIN_AS_ROOT
		/*
		** Change the effective user and group ids
		*/
		/* --- group id --- */
		if ( iFlags & FLG_GID )
			{
			if ( ::setgid( tGid )==-1 )
				{
				Cerr() << "Could not set group id to '" << tGid <<
					"' error code is " << errno << endl;
				return PIAPI_ERROR;
				};
			};

		/* --- user id --- */
		if ( iFlags & FLG_UID )
			{
			if ( ::setuid( tId )==-1 )
				{
				Cerr() << "Could not set user id to '" << tId <<
					"' error code is " << errno << endl;
				return PIAPI_ABORT;
				};
			};
#endif

		int iCurrentNumberOfChildren = 0;

		for(;;)
			{
			/* --- create new child processes --- */
			while( iCurrentNumberOfChildren<iNumberOfProcesses )
				{
#if 0
/*
** LATER, XXX
**
** This is obselete
*/
				/* ---
				If a lockfile was created then before forking
				check that the lockfile still exists, a child
				may have removed it in an attempt to stop the server 
				because of a tight fork() loop caused by a problem with
				the lockfile
				--- */
				struct stat tStat;
				if ( pLockFileName && stat( pLockFileName, &tStat )==-1 )
					{
					Cerr() << "**" << endl;
					Cerr() << "** Lockfile '" << pLockFileName <<
						"' does not exist, aborting daemon." << endl;
					Cerr() << "**" << endl;
					Cerr() << "** This typically indicates a serious error in \
child process execution." << endl;
					Cerr() << "**" << endl;
					return PIAPI_ABORT;
					};
#endif

				int iChildPid = ::fork();
				switch( iChildPid )
					{
					case -1:
						/* --- assume this is EAGAIN for tables full --- */
						sleep( 5 );		/* extremely sophisticated response */
						break;

					case 0:
						if ( ChildMain( iArgc, ppArgv )==PIAPI_ABORT )
							{
							/* --- Abort the server --- */
							if ( pLockFileName )
								{ ::unlink( pLockFileName ); };
							};
						return PIAPI_COMPLETED;

					default:
						/* ---
						this is the parent, record this new child.
						--- */
						{
						iCurrentNumberOfChildren++;
						assert( iCurrentNumberOfChildren <=
							iNumberOfProcesses );
						int i=0;
						for(i=0; i<iNumberOfProcesses; i++ )
							{
							if ( pProcessIds[i]==0 )
								{
								pProcessIds[i] = iChildPid;
								break;
								};
							};
						assert( i<iNumberOfProcesses );
						};
					};	/* --- switch on fork --- */
				}; /* --- loop while we have not reached max.# processes --- */ 

			/* ---
			Before we can create another process we must wait for one
			to die
			--- */
			for(;;)
				{
				int iStatus;
				pid_t tPid = ::wait( &iStatus );
				if ( tPid==-1 )
					{
					if ( errno!=EINTR )
						{
						/* --- signal caught, exit --- */
						Cerr() << "Unknown error from wait(): " << errno
							<< endl;
						};
					return PIAPI_COMPLETED;
					}
				else
					{
					/* ---
					if this child process did not exit normally, then
					log a message 
					--- */
					if ( !(WIFEXITED(iStatus)) )
						{
						Cerr() << "Child process " << tPid <<
							" did not exit normally, status: " << iStatus
							<< endl;
						};

					/* --- mark this process as reaped --- */
					int iProcessSlot = -1;	/* slot of exitted process */
					for(int i=0; i<iNumberOfProcesses; i++ )
						{
						if ( pProcessIds[i]==tPid )
							{
							iProcessSlot = i;
							pProcessIds[i] = 0;
							break;
							};
						};
					if ( iProcessSlot==-1 )
						{
						/* --- 
						This is not a child process we know about. This
						could happen if a restart occurred (via SIGHUP) and
						child processes from a previous iteration are 
						signalling.

						In this case ignore the signal
						---- */
						}	
					else
						{
						/* ----
						One of the current children has died, decrement the
						child process count and break to allow a new one
						to be created
						--- */
						iCurrentNumberOfChildren--;
						break;
						};
					};
				};
			};

		return PIAPI_COMPLETED;
#endif	/* POSIX */
		};
	
	/* --- --- */
	int Execute( int iArgc, const char *ppArgv[] )
		{
		int iRet = DoExecute( iArgc, ppArgv );
		switch( iRet )
			{
			case PIAPI_COMPLETED:
				break;


			case PIAPI_ABORT:
				CONFIG_ERR( pObject, "UNIXDaemon: A critical error occurred." );
				break;

			default:
				CONFIG_ERR( pObject, "UNIXDaemon: An error occurred." );
			};
		return iRet;
		};

	/* --- --- */
	inline int IsOK()		{ return iOK; };
};

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_onClassLoad( PIClass_LoadAction eLoad, void * )
{
	switch( eLoad )
		{
		case STARTUP:
		default:;
		};

	return PIAPI_COMPLETED;
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_constructor( PIObject *pObj, int iArgc,
		const char *ppArgv[] )
{
	UNIXDaemon *pUNIXDaemon = new UNIXDaemon( pObj, iArgc, ppArgv );
	if (!( pUNIXDaemon && pUNIXDaemon->IsOK() ))
		{
		delete pUNIXDaemon;
		return PIAPI_ERROR;
		};
	PIObject_setUserData( pObj, pUNIXDaemon );
	return PIAPI_COMPLETED;
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_copyConstructor( PIObject *, int, const char *[] )
{
	/* --- this class doesn't support copy construction --- */
	return PIAPI_ERROR;	
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_execute( PIObject *pObj, int iArgc, 
	const char *ppArgv[] )
{
	if ( !pObj ) return PIAPI_ERROR;
	return ((UNIXDaemon *)PIObject_getUserData(pObj))->Execute( iArgc, ppArgv );
}

/*____________________________________________________________________________*\
 *
 Function:
 Synopsis:
 Description:
\*____________________________________________________________________________*/
PUBLIC_PIAPI int UNIXDaemon_destructor( PIObject *pObj, int, const char *[] )
{
	delete (UNIXDaemon *)PIObject_getUserData( pObj );
	return PIAPI_COMPLETED;
}

#if 0
/*___+++CNF_BEGIN+++___*/
	<Class>
		Name UNIXDaemonClass
		Type LogicExtension
		Library Server
		OnClassLoad UNIXDaemon_onClassLoad
		Constructor UNIXDaemon_constructor
		CopyConstructor UNIXDaemon_copyConstructor
		Destructor UNIXDaemon_destructor
		Execute UNIXDaemon_execute
	</Class>

	<Object>
		Name UNIXDaemon
		Class UNIXDaemonClass
	</Object>

/*___+++CNF_END+++___*/
#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -