<commit_before>// bdls_osutil.cpp                                                    -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bdls_osutil.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bdls_osutil_cpp, "$Id$ $CSID$")

#include <bdls_processutil.h>

#include <bslmf_assert.h>
#include <bsls_platform.h>

#include <bsl_cstring.h>

#ifdef BSLS_PLATFORM_OS_WINDOWS
# undef u_VISTA_OR_LATER
# if 6 <= BSLS_PLATFORM_OS_VER_MAJOR
#   define u_VISTA_OR_LATER 1
# endif

# include <bdlsb_fixedmemoutstreambuf.h>
# include <windows.h>
# ifdef u_VISTA_OR_LATER
#   include <bsl_limits.h>
#   include "VersionHelpers.h"
# else
#   include <process.h>
# endif
#else
# include <unistd.h>
# include <sys/utsname.h>
#endif

namespace BloombergLP {

                            // --------------------
                            // struct bdls::OsUtil
                            // --------------------

// CLASS METHODS
#ifdef BSLS_PLATFORM_OS_WINDOWS

namespace bdls {
int OsUtil::getOsInfo(bsl::string *osName,
                      bsl::string *osVersion,
                      bsl::string *osPatch)
{
    BSLS_ASSERT(osName);
    BSLS_ASSERT(osVersion);
    BSLS_ASSERT(osPatch);

    *osName = "Windows";

#ifdef u_VISTA_OR_LATER
    // On Windows, 'WORD' means a 16-bit unsigned int.

    WORD major = 0;
    WORD minor = 0;
    WORD servicePackMajor = 0;

    const WORD maxWord = bsl::numeric_limits<WORD>::max();

    while (IsWindowsVersionOrGreater(major, minor, servicePackMajor)) {
        if (major >= maxWord) {
            return -1;                                                // RETURN
        }
        ++major;
    }
    --major;
    while (IsWindowsVersionOrGreater(major, minor, servicePackMajor)) {
        if (minor >= maxWord) {
            return -1;                                                // RETURN
        }
        ++minor;
    }
    --minor;
    while (IsWindowsVersionOrGreater(major, minor, servicePackMajor)) {
        if (servicePackMajor >= maxWord) {
            return -1;                                                // RETURN
        }
        ++servicePackMajor;
    }
    --servicePackMajor;

    // Os version

    // We want to do this with a minimum of allocations.  Both an
    // 'ostringstream' and 'sprintf' would allocate memory, so we us a
    // 'bdlsb::FixedMemOutStreamBuf"

    char buf[256];
    bdlsb::FixedMemOutStreamBuf sb(buf, sizeof(buf));
    bsl::ostream ostr(&sb);

    ostr << major << '.' << minor << bsl::ends;
    *osVersion = buf;

    // Service pack number

    sb.pubsetbuf(buf, sizeof(buf));
    buf[0] = 0;

    if (servicePackMajor) {
        // Note that we are incapable of detecting any 'servicePackMinor'
        // version other than 0.  But it seems rational that if Microsoft had
        // any plans for non-zero 'servicePackMinor' version at or after
        // Vista, they would have made 'IsWindowsVersionOrGreater' take 4 args
        // instead of 3.

        ostr << "Service Pack " << servicePackMajor << ".0" << bsl::ends;
    }

    *osPatch = buf;

#else

    OSVERSIONINFOEX osvi;

    bsl::memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
        return -1;
    }

    // Os version

    // We want to do this with a minimum of allocations.  Both an
    // 'ostringstream' and 'sprintf' would allocate memory, so we us a
    // 'bdlsb::FixedMemOutStreamBuf"

    char buf[256];
    bdlsb::FixedMemOutStreamBuf sb(buf, sizeof(buf));
    bsl::ostream ostr(&sb);

    ostr << osvi.dwMajorVersion << '.' << osvi.dwMinorVersion << bsl::ends;
    *osVersion = buf;

    sb.pubsetbuf(buf, sizeof(buf));
    buf[0] = 0;

    // Service pack number

    if (osvi.wServicePackMajor) {
        ostr << "Service Pack " << osvi.wServicePackMajor << '.'
             << osvi.wServicePackMinor << bsl::ends;
    }
    *osPatch = buf;

#endif

    return 0;
}
}  // close package namespace

#elif defined(BSLS_PLATFORM_OS_UNIX)

namespace bdls {
int OsUtil::getOsInfo(bsl::string *osName,
                      bsl::string *osVersion,
                      bsl::string *osPatch)
{
    BSLS_ASSERT(osName);
    BSLS_ASSERT(osVersion);
    BSLS_ASSERT(osPatch);

    struct utsname unameInfo;
    if (-1 == uname(&unameInfo)) {
        return -1;                                                    // RETURN
    }
    *osName = unameInfo.sysname;
    *osVersion = unameInfo.release;
    *osPatch = unameInfo.version;
    return 0;
}
}  // close package namespace

#else

BSLMF_ASSERT("Unsupported operating system", false);

#endif
}  // close enterprise namespace

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<commit_msg>bdls_osutil.t.cpp: local macro all upper case, not #undef'ed before define<commit_after>// bdls_osutil.cpp                                                    -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bdls_osutil.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bdls_osutil_cpp, "$Id$ $CSID$")

#include <bdls_processutil.h>

#include <bslmf_assert.h>
#include <bsls_platform.h>

#include <bsl_cstring.h>

#ifdef BSLS_PLATFORM_OS_WINDOWS
# include <bdlsb_fixedmemoutstreambuf.h>
# include <windows.h>

# define   U_VISTA_OR_LATER 0
# if 6 <= BSLS_PLATFORM_OS_VER_MAJOR
#   undef  U_VISTA_OR_LATER
#   define U_VISTA_OR_LATER 1
# endif
# if 0 != U_VISTA_OR_LATER
#   include <bsl_limits.h>
#   include "VersionHelpers.h"
# else
#   include <process.h>
# endif
#else
# include <unistd.h>
# include <sys/utsname.h>
#endif

namespace BloombergLP {

                            // --------------------
                            // struct bdls::OsUtil
                            // --------------------

// CLASS METHODS
#ifdef BSLS_PLATFORM_OS_WINDOWS

namespace bdls {
int OsUtil::getOsInfo(bsl::string *osName,
                      bsl::string *osVersion,
                      bsl::string *osPatch)
{
    BSLS_ASSERT(osName);
    BSLS_ASSERT(osVersion);
    BSLS_ASSERT(osPatch);

    *osName = "Windows";

#if 0 != U_VISTA_OR_LATER
    // On Windows, 'WORD' means a 16-bit unsigned int.

    WORD major = 0;
    WORD minor = 0;
    WORD servicePackMajor = 0;

    const WORD maxWord = bsl::numeric_limits<WORD>::max();

    while (IsWindowsVersionOrGreater(major, minor, servicePackMajor)) {
        if (major >= maxWord) {
            return -1;                                                // RETURN
        }
        ++major;
    }
    --major;
    while (IsWindowsVersionOrGreater(major, minor, servicePackMajor)) {
        if (minor >= maxWord) {
            return -1;                                                // RETURN
        }
        ++minor;
    }
    --minor;
    while (IsWindowsVersionOrGreater(major, minor, servicePackMajor)) {
        if (servicePackMajor >= maxWord) {
            return -1;                                                // RETURN
        }
        ++servicePackMajor;
    }
    --servicePackMajor;

    // Os version

    // We want to do this with a minimum of allocations.  Both an
    // 'ostringstream' and 'sprintf' would allocate memory, so we us a
    // 'bdlsb::FixedMemOutStreamBuf"

    char buf[256];
    bdlsb::FixedMemOutStreamBuf sb(buf, sizeof(buf));
    bsl::ostream ostr(&sb);

    ostr << major << '.' << minor << bsl::ends;
    *osVersion = buf;

    // Service pack number

    sb.pubsetbuf(buf, sizeof(buf));
    buf[0] = 0;

    if (servicePackMajor) {
        // Note that we are incapable of detecting any 'servicePackMinor'
        // version other than 0.  But it seems rational that if Microsoft had
        // any plans for non-zero 'servicePackMinor' version at or after
        // Vista, they would have made 'IsWindowsVersionOrGreater' take 4 args
        // instead of 3.

        ostr << "Service Pack " << servicePackMajor << ".0" << bsl::ends;
    }

    *osPatch = buf;

#else

    OSVERSIONINFOEX osvi;

    bsl::memset(&osvi, 0, sizeof(OSVERSIONINFOEX));
    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);

    if (!GetVersionEx((OSVERSIONINFO *)&osvi)) {
        return -1;
    }

    // Os version

    // We want to do this with a minimum of allocations.  Both an
    // 'ostringstream' and 'sprintf' would allocate memory, so we us a
    // 'bdlsb::FixedMemOutStreamBuf"

    char buf[256];
    bdlsb::FixedMemOutStreamBuf sb(buf, sizeof(buf));
    bsl::ostream ostr(&sb);

    ostr << osvi.dwMajorVersion << '.' << osvi.dwMinorVersion << bsl::ends;
    *osVersion = buf;

    sb.pubsetbuf(buf, sizeof(buf));
    buf[0] = 0;

    // Service pack number

    if (osvi.wServicePackMajor) {
        ostr << "Service Pack " << osvi.wServicePackMajor << '.'
             << osvi.wServicePackMinor << bsl::ends;
    }
    *osPatch = buf;

#endif

    return 0;
}
}  // close package namespace

#elif defined(BSLS_PLATFORM_OS_UNIX)

namespace bdls {
int OsUtil::getOsInfo(bsl::string *osName,
                      bsl::string *osVersion,
                      bsl::string *osPatch)
{
    BSLS_ASSERT(osName);
    BSLS_ASSERT(osVersion);
    BSLS_ASSERT(osPatch);

    struct utsname unameInfo;
    if (-1 == uname(&unameInfo)) {
        return -1;                                                    // RETURN
    }
    *osName = unameInfo.sysname;
    *osVersion = unameInfo.release;
    *osPatch = unameInfo.version;
    return 0;
}
}  // close package namespace

#else

BSLMF_ASSERT("Unsupported operating system", false);

#endif
}  // close enterprise namespace

// ----------------------------------------------------------------------------
// Copyright 2015 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
<|endoftext|>


<commit_before>#include "condor_common.h"
#include "_condor_fix_resource.h"
#include <iostream.h>
#include <time.h>

#ifndef WIN32
#include <netinet/in.h>
#include <sys/param.h>
#endif  // ifndef WIN32

#include "condor_classad.h"
#include "condor_parser.h"
#include "sched.h"
#include "condor_status.h"
#include "manager.h"
#include "condor_debug.h"
#include "condor_config.h"
#include "condor_network.h"
#include "internet.h"
#include "fdprintf.h"
#include "condor_io.h"
#include "condor_attributes.h"

#include "../condor_daemon_core.V6/condor_daemon_core.h"

#include "condor_collector.h"
#include "collector_engine.h"
#include "HashTable.h"
#include "hashkey.h"

#include "condor_uid.h"

// about self
static char *_FileName_ = __FILE__;		// used by EXCEPT
char* mySubSystem = "COLLECTOR";		// used by Daemon Core

// variables from the config file
char *Log;
char *CollectorLog;
char *CondorAdministrator;
char *CondorDevelopers;
int   MaxCollectorLog;
int   ClientTimeout;
int   QueryTimeout;
int   MachineUpdateInterval;
int	  MasterCheckInterval;

// the heart of the collector ...
CollectorEngine collector;

// misc functions
#ifndef WIN32
extern	   void initializeReporter (void);
#endif
extern "C" int  SetSyscalls () {return 0;}
extern     void initializeParams();

// misc external variables
extern int errno;

// internal function prototypes
void houseKeeper(void);
int receive_update(Service*, int, Stream*);
int receive_query(Service*, int, Stream*);
void process_query(AdTypes, ClassAd &, Stream *);
int sigint_handler(Service*, int);
int sighup_handler(Service*, int);
#ifndef WIN32
void sigpipe_handler();
void unixsigint_handler();
void unixsighup_handler();
#endif

void usage(char* name)
{
	dprintf(D_ALWAYS,"Usage: %s [-f] [-b] [-t] [-p <port>]\n",name );
	exit( 1 );
}

// main initialization code... the real main() is in DaemonCore
main_init(int argc, char *argv[])
{
	char** ptr;

	// handle collector-specific command line args
	if(argc > 1)
	{
		usage(argv[0]);
	}
	for(ptr = argv + 1; *ptr; ptr++)
	{
		if(ptr[0][0] != '-')
		{
			usage(argv[0]);
		}
		switch(ptr[0][1])
		{
		// place collector-specific command line args here
		default:
			usage(argv[0]);
		}
	}

	// read in various parameters from condor_config
    initializeParams ();

    // install signal handlers
	daemonCore->Register_Signal(DC_SIGINT,"SIGINT",(SignalHandler)sigint_handler,"sigint_handler()");

#ifndef WIN32
	install_sig_handler (SIGINT, unixsigint_handler);
#endif	// of ifndef WIN32

#ifndef WIN32
	// setup routine to report to condor developers
	initializeReporter ();
#endif

	// install command handlers for queries
	daemonCore->Register_Command(QUERY_STARTD_ADS,"QUERY_STARTD_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);
	daemonCore->Register_Command(QUERY_STARTD_ADS,"QUERY_STARTD_PVT__ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);
	daemonCore->Register_Command(QUERY_SCHEDD_ADS,"QUERY_SCHEDD_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);
	daemonCore->Register_Command(QUERY_MASTER_ADS,"QUERY_MASTER_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);
	daemonCore->Register_Command(QUERY_CKPT_SRVR_ADS,"QUERY_CKPT_SRVR_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);

	// install command handlers for updates
	daemonCore->Register_Command(UPDATE_STARTD_AD,"UPDATE_STARTD_AD",
		(CommandHandler)receive_update,"receive_update",NULL,WRITE);
	daemonCore->Register_Command(UPDATE_SCHEDD_AD,"UPDATE_SCHEDD_AD",
		(CommandHandler)receive_update,"receive_update",NULL,WRITE);
	daemonCore->Register_Command(UPDATE_MASTER_AD,"UPDATE_MASTER_AD",
		(CommandHandler)receive_update,"receive_update",NULL,WRITE);
	daemonCore->Register_Command(UPDATE_CKPT_SRVR_AD,"UPDATE_CKPT_SRVR_AD",
		(CommandHandler)receive_update,"receive_update",NULL,WRITE);

	// set up housekeeper
	if (!collector.scheduleHousekeeper(MachineUpdateInterval))
	{
		EXCEPT ("Could not initialize housekeeper");
	}

	// set up routine to check on masters
	if (!collector.scheduleDownMasterCheck (MasterCheckInterval))
	{
		EXCEPT ("Could not initialize master check routine");
	}

	// set up so that private ads from startds are collected as well
	collector.wantStartdPrivateAds (true);

	return TRUE;
}

int
receive_query(Service* s, int command, Stream* sock)
{
    struct sockaddr_in *from;
	AdTypes whichAds;
	ClassAd ad;

	from = sock->endpoint();

	sock->decode();
	sock->timeout(ClientTimeout);
    if (!ad.get((Stream &)*sock) || !sock->eom())
    {
        dprintf(D_ALWAYS,"Failed to receive query on TCP: aborting\n");
        return FALSE;
    }

    // cancel timeout --- collector engine sets up its own timeout for
    // collecting further information
    sock->timeout(0);

    switch (command)
    {
	  case QUERY_STARTD_ADS:
		dprintf (D_ALWAYS, "Got QUERY_STARTD_ADS\n");
		whichAds = STARTD_AD;
		break;

	  case QUERY_SCHEDD_ADS:
		dprintf (D_ALWAYS, "Got QUERY_SCHEDD_ADS\n");
		whichAds = SCHEDD_AD;
		break;

	  case QUERY_MASTER_ADS:
		dprintf (D_ALWAYS, "Got QUERY_MASTER_ADS\n");
		whichAds = MASTER_AD;
		break;

	  case QUERY_CKPT_SRVR_ADS:
		dprintf (D_ALWAYS, "Got QUERY_CKPT_SRVR_ADS\n");
		whichAds = CKPT_SRVR_AD;
		break;

	  case QUERY_STARTD_PVT_ADS:
		dprintf (D_ALWAYS, "Got QUERY_STARTD_PVT_ADS\n");
		whichAds = STARTD_PVT_AD;
		break;

	  default:
		dprintf(D_ALWAYS,"Unknown command %d in process_query()\n", command);
		whichAds = (AdTypes) -1;
    }

    if (whichAds != (AdTypes) -1)
		process_query (whichAds, ad, sock);

    // all done; let daemon core will clean up connection
	return TRUE;
}

int
receive_update(Service *s, int command, Stream* sock)
{
    int	insert;
	sockaddr_in *from;
	ClassAd *ad;

	// TCP commands should not allow for classad updates.  In fact the collector
	// will not collect on TCP to discourage use of TCP for classad updates.
	if ( sock->type() == Stream::reli_sock ) {
		// update via tcp; sorry buddy, use udp or you're outa here!
		dprintf(D_ALWAYS,"Received UPDATE command via TCP; ignored\n");
		// let daemon core clean up the socket
		return TRUE;
	}

	// get endpoint
	from = sock->endpoint();

    // process the given command
	if (!(ad = collector.collect (command,(Sock*)sock,from,insert)))
	{
		if (insert == -2)
		{
			// this should never happen assuming we never register QUERY
			// commands with daemon core, but it cannot hurt to check...
			dprintf (D_ALWAYS,"Got QUERY command (%d); not supported for UDP\n",
						command);
		}
	}

	// let daemon core clean up the socket
	return TRUE;
}

static ClassAd *__query__;
static Stream *__sock__;
static int __numAds__;
static int __failed__;

int
query_scanFunc (ClassAd *ad)
{
    int more = 1;

    if ((*ad) >= (*__query__))
    {
        if (!__sock__->code(more) || !ad->put(*__sock__))
        {
            dprintf (D_ALWAYS,
                    "Error sending query result to client -- aborting\n");
            return 0;
        }
        __numAds__++;
    }

    return 1;
}

void
process_query (AdTypes whichAds, ClassAd &query, Stream *sock)
{
	int		more;

	// here we set up a network timeout of a longer duration
	sock->timeout(QueryTimeout);

	// set up for hashtable scan
	__query__ = &query;
	__numAds__ = 0;
	__sock__ = sock;
	sock->encode();
	if (!collector.walkHashTable (whichAds, query_scanFunc))
	{
		dprintf (D_ALWAYS, "Error sending query response\n");
	}

	// end of query response ...
	more = 0;
	if (!sock->code(more))
	{
		dprintf (D_ALWAYS, "Error sending EndOfResponse (0) to client\n");
	}

	// flush the output
	if (!sock->end_of_message())
	{
		dprintf (D_ALWAYS, "Error flushing CEDAR socket\n");
	}

	dprintf (D_ALWAYS, "(Sent %d ads in response to query)\n", __numAds__);
}

#ifndef WIN32
int 	__mailer__;

int
reportScanFunc (ClassAd *ad)
{
	char buffer[2048];
	int	 x;

	if (!ad->LookupString (ATTR_NAME, buffer)) return 0;
	fdprintf (__mailer__, "%15s", buffer);

	if (!ad->LookupString (ATTR_ARCH, buffer)) return 0;
	fdprintf (__mailer__, "%8s", buffer);

	if (!ad->LookupString (ATTR_OPSYS, buffer)) return 0;
	fdprintf (__mailer__, "%14s", buffer);

	if (!ad->LookupInteger (ATTR_MIPS, x)) x = -1;
	fdprintf (__mailer__, "%4d", x);

	if (!ad->LookupInteger (ATTR_KFLOPS, x)) x = -1;
	fdprintf (__mailer__, "%7d", x);

	if (!ad->LookupString (ATTR_STATE, buffer)) return 0;
	fdprintf (__mailer__, "%10s\n", buffer);

	return 1;
}

void
reportToDevelopers (void)
{
	char	whoami[128];
	char	buffer[128];

	if (get_machine_name (whoami) == -1) {
		dprintf (D_ALWAYS, "Unable to get_machine_name()\n");
		return;
	}

	sprintf (buffer, "Condor Collector (%s):  Monthly report\n", whoami);
	if ((__mailer__ = email (buffer, CondorDevelopers)) < 0) {
		dprintf (D_ALWAYS, "Didn't send monthly report (couldn't open url)\n");
		return;
	}

	if (!collector.walkHashTable (STARTD_AD, reportScanFunc)) {
		dprintf (D_ALWAYS, "Error sending monthly report\n");
	}

	close (__mailer__);
	return;
}
#endif  // of ifndef WIN32

// signal handlers ...
int
sigint_handler (Service *s, int sig)
{
    dprintf (D_ALWAYS, "Killed by SIGINT\n");
    exit(0);
	return FALSE;	// never will get here; just to satisfy c++
}

#ifndef WIN32
void
unixsigint_handler ()
{
    dprintf (D_ALWAYS, "Killed by SIGINT\n");
    exit(0);
	return;	// never will get here; just to satisfy c++
}

#endif	// of ifndef WIN32

int
main_config()
{
    initializeParams();
	return TRUE;
}

int
main_shutdown_fast()
{
	exit(0);
	return TRUE;	// to satisfy c++
}

int
main_shutdown_graceful()
{
	exit(0);
	return TRUE;	// to satisfy c++
}

<commit_msg>Made the handler for QUERY_STARTD_PVT_ADS registered with NEGOTIATOR permission.<commit_after>#include "condor_common.h"
#include "_condor_fix_resource.h"
#include <iostream.h>
#include <time.h>

#ifndef WIN32
#include <netinet/in.h>
#include <sys/param.h>
#endif  // ifndef WIN32

#include "condor_classad.h"
#include "condor_parser.h"
#include "sched.h"
#include "condor_status.h"
#include "manager.h"
#include "condor_debug.h"
#include "condor_config.h"
#include "condor_network.h"
#include "internet.h"
#include "fdprintf.h"
#include "condor_io.h"
#include "condor_attributes.h"

#include "../condor_daemon_core.V6/condor_daemon_core.h"

#include "condor_collector.h"
#include "collector_engine.h"
#include "HashTable.h"
#include "hashkey.h"

#include "condor_uid.h"

// about self
static char *_FileName_ = __FILE__;		// used by EXCEPT
char* mySubSystem = "COLLECTOR";		// used by Daemon Core

// variables from the config file
char *Log;
char *CollectorLog;
char *CondorAdministrator;
char *CondorDevelopers;
int   MaxCollectorLog;
int   ClientTimeout;
int   QueryTimeout;
int   MachineUpdateInterval;
int	  MasterCheckInterval;

// the heart of the collector ...
CollectorEngine collector;

// misc functions
#ifndef WIN32
extern	   void initializeReporter (void);
#endif
extern "C" int  SetSyscalls () {return 0;}
extern     void initializeParams();

// misc external variables
extern int errno;

// internal function prototypes
void houseKeeper(void);
int receive_update(Service*, int, Stream*);
int receive_query(Service*, int, Stream*);
void process_query(AdTypes, ClassAd &, Stream *);
int sigint_handler(Service*, int);
int sighup_handler(Service*, int);
#ifndef WIN32
void sigpipe_handler();
void unixsigint_handler();
void unixsighup_handler();
#endif

void usage(char* name)
{
	dprintf(D_ALWAYS,"Usage: %s [-f] [-b] [-t] [-p <port>]\n",name );
	exit( 1 );
}

// main initialization code... the real main() is in DaemonCore
main_init(int argc, char *argv[])
{
	char** ptr;

	// handle collector-specific command line args
	if(argc > 1)
	{
		usage(argv[0]);
	}
	for(ptr = argv + 1; *ptr; ptr++)
	{
		if(ptr[0][0] != '-')
		{
			usage(argv[0]);
		}
		switch(ptr[0][1])
		{
		// place collector-specific command line args here
		default:
			usage(argv[0]);
		}
	}

	// read in various parameters from condor_config
    initializeParams ();

    // install signal handlers
	daemonCore->Register_Signal(DC_SIGINT,"SIGINT",(SignalHandler)sigint_handler,"sigint_handler()");

#ifndef WIN32
	install_sig_handler (SIGINT, unixsigint_handler);
#endif	// of ifndef WIN32

#ifndef WIN32
	// setup routine to report to condor developers
	initializeReporter ();
#endif

	// install command handlers for queries
	daemonCore->Register_Command(QUERY_STARTD_ADS,"QUERY_STARTD_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);
	daemonCore->Register_Command(QUERY_STARTD_PVT_ADS,"QUERY_STARTD_PVT_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,NEGOTIATOR);
	daemonCore->Register_Command(QUERY_SCHEDD_ADS,"QUERY_SCHEDD_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);
	daemonCore->Register_Command(QUERY_MASTER_ADS,"QUERY_MASTER_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);
	daemonCore->Register_Command(QUERY_CKPT_SRVR_ADS,"QUERY_CKPT_SRVR_ADS",
		(CommandHandler)receive_query,"receive_query",NULL,READ);

	// install command handlers for updates
	daemonCore->Register_Command(UPDATE_STARTD_AD,"UPDATE_STARTD_AD",
		(CommandHandler)receive_update,"receive_update",NULL,WRITE);
	daemonCore->Register_Command(UPDATE_SCHEDD_AD,"UPDATE_SCHEDD_AD",
		(CommandHandler)receive_update,"receive_update",NULL,WRITE);
	daemonCore->Register_Command(UPDATE_MASTER_AD,"UPDATE_MASTER_AD",
		(CommandHandler)receive_update,"receive_update",NULL,WRITE);
	daemonCore->Register_Command(UPDATE_CKPT_SRVR_AD,"UPDATE_CKPT_SRVR_AD",
		(CommandHandler)receive_update,"receive_update",NULL,WRITE);

	// set up housekeeper
	if (!collector.scheduleHousekeeper(MachineUpdateInterval))
	{
		EXCEPT ("Could not initialize housekeeper");
	}

	// set up routine to check on masters
	if (!collector.scheduleDownMasterCheck (MasterCheckInterval))
	{
		EXCEPT ("Could not initialize master check routine");
	}

	// set up so that private ads from startds are collected as well
	collector.wantStartdPrivateAds (true);

	return TRUE;
}

int
receive_query(Service* s, int command, Stream* sock)
{
    struct sockaddr_in *from;
	AdTypes whichAds;
	ClassAd ad;

	from = sock->endpoint();

	sock->decode();
	sock->timeout(ClientTimeout);
    if (!ad.get((Stream &)*sock) || !sock->eom())
    {
        dprintf(D_ALWAYS,"Failed to receive query on TCP: aborting\n");
        return FALSE;
    }

    // cancel timeout --- collector engine sets up its own timeout for
    // collecting further information
    sock->timeout(0);

    switch (command)
    {
	  case QUERY_STARTD_ADS:
		dprintf (D_ALWAYS, "Got QUERY_STARTD_ADS\n");
		whichAds = STARTD_AD;
		break;

	  case QUERY_SCHEDD_ADS:
		dprintf (D_ALWAYS, "Got QUERY_SCHEDD_ADS\n");
		whichAds = SCHEDD_AD;
		break;

	  case QUERY_MASTER_ADS:
		dprintf (D_ALWAYS, "Got QUERY_MASTER_ADS\n");
		whichAds = MASTER_AD;
		break;

	  case QUERY_CKPT_SRVR_ADS:
		dprintf (D_ALWAYS, "Got QUERY_CKPT_SRVR_ADS\n");
		whichAds = CKPT_SRVR_AD;
		break;

	  case QUERY_STARTD_PVT_ADS:
		dprintf (D_ALWAYS, "Got QUERY_STARTD_PVT_ADS\n");
		whichAds = STARTD_PVT_AD;
		break;

	  default:
		dprintf(D_ALWAYS,"Unknown command %d in process_query()\n", command);
		whichAds = (AdTypes) -1;
    }

    if (whichAds != (AdTypes) -1)
		process_query (whichAds, ad, sock);

    // all done; let daemon core will clean up connection
	return TRUE;
}

int
receive_update(Service *s, int command, Stream* sock)
{
    int	insert;
	sockaddr_in *from;
	ClassAd *ad;

	// TCP commands should not allow for classad updates.  In fact the collector
	// will not collect on TCP to discourage use of TCP for classad updates.
	if ( sock->type() == Stream::reli_sock ) {
		// update via tcp; sorry buddy, use udp or you're outa here!
		dprintf(D_ALWAYS,"Received UPDATE command via TCP; ignored\n");
		// let daemon core clean up the socket
		return TRUE;
	}

	// get endpoint
	from = sock->endpoint();

    // process the given command
	if (!(ad = collector.collect (command,(Sock*)sock,from,insert)))
	{
		if (insert == -2)
		{
			// this should never happen assuming we never register QUERY
			// commands with daemon core, but it cannot hurt to check...
			dprintf (D_ALWAYS,"Got QUERY command (%d); not supported for UDP\n",
						command);
		}
	}

	// let daemon core clean up the socket
	return TRUE;
}

static ClassAd *__query__;
static Stream *__sock__;
static int __numAds__;
static int __failed__;

int
query_scanFunc (ClassAd *ad)
{
    int more = 1;

    if ((*ad) >= (*__query__))
    {
        if (!__sock__->code(more) || !ad->put(*__sock__))
        {
            dprintf (D_ALWAYS,
                    "Error sending query result to client -- aborting\n");
            return 0;
        }
        __numAds__++;
    }

    return 1;
}

void
process_query (AdTypes whichAds, ClassAd &query, Stream *sock)
{
	int		more;

	// here we set up a network timeout of a longer duration
	sock->timeout(QueryTimeout);

	// set up for hashtable scan
	__query__ = &query;
	__numAds__ = 0;
	__sock__ = sock;
	sock->encode();
	if (!collector.walkHashTable (whichAds, query_scanFunc))
	{
		dprintf (D_ALWAYS, "Error sending query response\n");
	}

	// end of query response ...
	more = 0;
	if (!sock->code(more))
	{
		dprintf (D_ALWAYS, "Error sending EndOfResponse (0) to client\n");
	}

	// flush the output
	if (!sock->end_of_message())
	{
		dprintf (D_ALWAYS, "Error flushing CEDAR socket\n");
	}

	dprintf (D_ALWAYS, "(Sent %d ads in response to query)\n", __numAds__);
}

#ifndef WIN32
int 	__mailer__;

int
reportScanFunc (ClassAd *ad)
{
	char buffer[2048];
	int	 x;

	if (!ad->LookupString (ATTR_NAME, buffer)) return 0;
	fdprintf (__mailer__, "%15s", buffer);

	if (!ad->LookupString (ATTR_ARCH, buffer)) return 0;
	fdprintf (__mailer__, "%8s", buffer);

	if (!ad->LookupString (ATTR_OPSYS, buffer)) return 0;
	fdprintf (__mailer__, "%14s", buffer);

	if (!ad->LookupInteger (ATTR_MIPS, x)) x = -1;
	fdprintf (__mailer__, "%4d", x);

	if (!ad->LookupInteger (ATTR_KFLOPS, x)) x = -1;
	fdprintf (__mailer__, "%7d", x);

	if (!ad->LookupString (ATTR_STATE, buffer)) return 0;
	fdprintf (__mailer__, "%10s\n", buffer);

	return 1;
}

void
reportToDevelopers (void)
{
	char	whoami[128];
	char	buffer[128];

	if (get_machine_name (whoami) == -1) {
		dprintf (D_ALWAYS, "Unable to get_machine_name()\n");
		return;
	}

	sprintf (buffer, "Condor Collector (%s):  Monthly report\n", whoami);
	if ((__mailer__ = email (buffer, CondorDevelopers)) < 0) {
		dprintf (D_ALWAYS, "Didn't send monthly report (couldn't open url)\n");
		return;
	}

	if (!collector.walkHashTable (STARTD_AD, reportScanFunc)) {
		dprintf (D_ALWAYS, "Error sending monthly report\n");
	}

	close (__mailer__);
	return;
}
#endif  // of ifndef WIN32

// signal handlers ...
int
sigint_handler (Service *s, int sig)
{
    dprintf (D_ALWAYS, "Killed by SIGINT\n");
    exit(0);
	return FALSE;	// never will get here; just to satisfy c++
}

#ifndef WIN32
void
unixsigint_handler ()
{
    dprintf (D_ALWAYS, "Killed by SIGINT\n");
    exit(0);
	return;	// never will get here; just to satisfy c++
}

#endif	// of ifndef WIN32

int
main_config()
{
    initializeParams();
	return TRUE;
}

int
main_shutdown_fast()
{
	exit(0);
	return TRUE;	// to satisfy c++
}

int
main_shutdown_graceful()
{
	exit(0);
	return TRUE;	// to satisfy c++
}

<|endoftext|>


<commit_before>#ifndef INCLUDE_AL_COLOR_HPP
#define INCLUDE_AL_COLOR_HPP

/*
 *  AlloSphere Research Group / Media Arts & Technology, UCSB, 2009
 */

/*
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "allocore/system/pstdint.h"

namespace al{

struct Color;
struct Colori;
struct HSV;

/// Color represented by red, green, blue, and alpha components
struct Color{

	union{
		struct{
			float r;			///< Red component in [0, 1]
			float g;			///< Green component in [0, 1]
			float b;			///< Blue component in [0, 1]
			float a;			///< Alpha component in [0, 1]
		};
		float components[4];	///< RGBA component vector
	};

	/// @param[in] r			red component
	/// @param[in] g			green component
	/// @param[in] b			blue component
	/// @param[in] a			alpha component
	Color(float r, float g, float b, float a=1.f)
	:	r(r), g(g), b(b), a(a){}

	/// @param[in] gray			red/green/blue components
	/// @param[in] a			alpha component
	Color(float gray=1.f, float a=1.f)
	:	r(gray), g(gray), b(gray), a(a){}

	/// @param[in] c	RGBA color to convert from
	Color(const Colori& c){ *this = c; }

	/// @param[in] hsv			HSV value
	/// @param[in] a			alpha component
	Color(const HSV& hsv, float a=1.f)
	:	a(a)
	{	*this = hsv; }

	/// Set color component at index with no bounds checking
	float& operator[](int i){ return components[i]; }

	/// Get color component at index with no bounds checking
	const float& operator[](int i) const { return components[i]; }

	/// Set RGB from another color and alpha from argument
	Color& set(const Color& c, float al){ a=al; return set(c.r,c.g,c.b); }

	/// Set RGBA components
	Color& set(float re, float gr, float bl, float al){ a=al; return set(re,gr,bl); }

	/// Set RGB components
	Color& set(float re, float gr, float bl){ r=re; g=gr; b=bl; return *this; }

	/// Set from gray value
	Color& set(float v){ return set(v,v,v); }

	/// Set from gray value and alpha
	Color& set(float v, float al){ return set(v,v,v,a); }

	/// Set from an array of RGBA components
	template <class T>
	Color& set(const T* rgba){ return set(rgba[0],rgba[1],rgba[2],rgba[3]); }

	/// Set components from tightly packed RGBA array
	template <class Array4>
	Color& operator= (const Array4& v){ return set(v[0], v[1], v[2], v[3]); }

	/// Set from gray value
	Color& operator= (float v){ return set(v); }
	Color& operator= (double v){ return set(v); }

	/// Set components from integer color
	Color& operator= (const Colori& v);

	/// Set RGB components from HSV
	Color& operator= (const HSV& v);

	/// Return true if all components are equal, false otherwise
	bool operator ==(const Color& v) const { return v.r==r && v.g==g && v.b==b && v.a==a; }

	/// Return true if components are not equal, false otherwise
	bool operator !=(const Color& v) const { return !(*this == v); }

	Color& operator+= (const Color& v){ return set(r+v.r, g+v.g, b+v.b, a+v.a); }
	Color& operator-= (const Color& v){ return set(r-v.r, g-v.g, b-v.b, a-v.a); }
	Color& operator*= (const Color& v){ return set(r*v.r, g*v.g, b*v.b, a*v.a); }
	Color& operator/= (const Color& v){ return set(r/v.r, g/v.g, b/v.b, a/v.a); }
	Color& operator+= (float v){ return set(r+v, g+v, b+v, a+v); }
	Color& operator-= (float v){ return set(r-v, g-v, b-v, a-v); }
	Color& operator*= (float v){ return set(r*v, g*v, b*v, a*v); }
	Color& operator/= (float v){ return set(r/v, g/v, b/v, a/v); }

	Color operator- () const { return Color(-r,-g,-b,-a); }
	Color operator+ (const Color& v) const { return Color(*this)+=v; }
	Color operator- (const Color& v) const { return Color(*this)-=v; }
	Color operator* (const Color& v) const { return Color(*this)*=v; }
	Color operator/ (const Color& v) const { return Color(*this)/=v; }
	Color operator+ (float v) const { return Color(*this)+=v; }
	Color operator- (float v) const { return Color(*this)-=v; }
	Color operator* (float v) const { return Color(*this)*=v; }
	Color operator/ (float v) const { return Color(*this)/=v; }

	/// Returns nearest black or white color
	Color blackAndWhite() const { return Color(luminance()>0.5f?1.f:0.f); }

	/// Clamp all components into [0,1] range
	Color& clamp(){
		r<0.f ? r=0.f : (r>1.f ? r=1.f : 0);
		g<0.f ? g=0.f : (g>1.f ? g=1.f : 0);
		b<0.f ? b=0.f : (b>1.f ? b=1.f : 0);
		a<0.f ? a=0.f : (a>1.f ? a=1.f : 0);
		return *this;
	}

	/// Returns inverted color
	Color inverse() const { return Color(1.f-r, 1.f-g, 1.f-b, a); }

	/// Invert RGB components
	Color& invert(){ return set(1.f-r, 1.f-g, 1.f-b); }

	/// Returns luminance value
	float luminance() const { return r*0.3f+g*0.59f+b*0.11f; }

	/// Returns self linearly mixed with another color (0 = none)
	Color mix(const Color& c, float amt=0.5f) const {
		return (c-*this)*amt + *this;
	}

private:
	float tof(uint8_t v){ return float(v)/255.f; }
};

/// Color represented by red, green, blue, and alpha components packed into 32-bit integer

/// The component accessor methods operate exclusively with integer types. To
/// convert to and from floating point values in the interval [0, 1], use the
/// overloaded assignment (=) operators.
struct Colori {

	union{
		struct{
			uint8_t r;			///< Red component in [0, 255]
			uint8_t g;			///< Green component in [0, 255]
			uint8_t b;			///< Blue component in [0, 255]
			uint8_t a;			///< Alpha component in [0, 255]
		};
		uint8_t components[4];	///< RGBA component vector
		uint32_t rgba;			///< RGBA components packed into 32-bit integer
	};

	/// @param[in] r			red component
	/// @param[in] g			green component
	/// @param[in] b			blue component
	/// @param[in] a			alpha component
	Colori(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
	:	r(r), g(g), b(b), a(a){}

	/// @param[in] gray			red/green/blue components
	/// @param[in] a			alpha component
	Colori(uint8_t gray=255, uint8_t a=255)
	:	r(gray), g(gray), b(gray), a(a){}

	/// @param[in] c			RGBA color to convert from
	Colori(const Color& c){ *this = c; }

	/// @param[in] hsv			HSV value
	/// @param[in] a			alpha component
	Colori(const HSV& hsv, float a=1.f)
	:	a(toi(a))
	{	*this = hsv; }

	/// Set color component at index with no bounds checking
	uint8_t& operator[](int i){ return components[i]; }

	/// Get color component at index with no bounds checking
	const uint8_t& operator[](int i) const { return components[i]; }

	/// Set from floating-point color
	Colori& operator= (const Color& c){
		r=toi(c.r); g=toi(c.g); b=toi(c.b); a=toi(c.a); return *this; }

	/// Set RGB components from HSV
	Colori& operator= (const HSV& v){ *this = Color(v); return *this; }

	/// Set RGB components
	Colori& set(uint8_t re, uint8_t gr, uint8_t bl){
		r=re; g=gr; b=bl; return *this; }

	/// Set RGBA components
	Colori& set(uint8_t re, uint8_t gr, uint8_t bl, uint8_t al){
		a=al; return set(re,gr,bl); }

	/// Set from gray value
	Colori& set(uint8_t v){ return set(v,v,v); }

	/// Set from gray value and alpha
	Colori& set(uint8_t v, uint8_t al){ return set(v,al); }

private:
	uint8_t toi(float v){ return uint8_t(v*255.f); }
};

/// Color represented by hue, saturation, and value
struct HSV{

	union{
		struct{
			float h;			///< Hue component in [0, 1]
			float s;			///< Saturation component in [0, 1]
			float v;			///< Value component in [0, 1]
		};
		float components[3];	///< HSV component vector
	};

	/// @param[in] h	hue
	/// @param[in] s	saturation
	/// @param[in] v	value
	HSV(float h=0, float s=1, float v=1): h(h), s(s), v(v){}

	/// @param[in] c	RGB color to convert from
	HSV(const Color& c){ *this = c; }

	/// @param[in] c	RGB color to convert from
	HSV(const Colori& c){ *this = c; }

	/// @param[in] hsv		3-vector of hsv components
	template<class T>
	HSV(T * hsv): h(hsv[0]), s(hsv[1]), v(hsv[2]){}

	/// Set from RGB color
	HSV& operator= (const Color& c);

	/// Set from RGB color
	HSV& operator= (const Colori& c){ return *this = Color(c); }

	/// Rotate hue in interval [0, 1)
	HSV& rotateHue(float dh){ h += dh; return wrapHue(); }

	/// Wrap hue value into valid interval [0, 1)
	HSV& wrapHue(){
		if(h>1){ h -= int(h); }
		else if(h<0){ h -= int(h)-1; }
		return *this;
	}
};

// Implementation --------------------------------------------------------------

inline Color operator + (float s, const Color& c){ return  c+s; }
inline Color operator - (float s, const Color& c){ return -c+s; }
inline Color operator * (float s, const Color& c){ return  c*s; }
inline Color operator / (float s, const Color& c){ return Color(s/c.r, s/c.g, s/c.b, s/c.a); }

inline Color& Color::operator= (const Colori& v){
		r=tof(v.r); g=tof(v.g); b=tof(v.b); a=tof(v.a); return *this; }

} // al::

#endif
<commit_msg>Header info update<commit_after>#ifndef INCLUDE_AL_COLOR_HPP
#define INCLUDE_AL_COLOR_HPP

/*	Allocore --
	Multimedia / virtual environment application class library

	Copyright (C) 2009. AlloSphere Research Group, Media Arts & Technology, UCSB.
	Copyright (C) 2006-2008. The Regents of the University of California (REGENTS).
	All Rights Reserved.

	Permission to use, copy, modify, distribute, and distribute modified versions
	of this software and its documentation without fee and without a signed
	licensing agreement, is hereby granted, provided that the above copyright
	notice, the list of contributors, this paragraph and the following two paragraphs
	appear in all copies, modifications, and distributions.

	IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
	SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
	OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
	BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

	REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
	THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
	PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
	HEREUNDER IS PROVIDED "AS IS". REGENTS HAS  NO OBLIGATION TO PROVIDE
	MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

	File description:
	RGBA and HSV color classes

	File author(s):
	Lance Putnam, 2010, putnam.lance@gmail.com
*/

#include "allocore/system/pstdint.h"

namespace al{

struct Color;
struct Colori;
struct HSV;

/// Color represented by red, green, blue, and alpha components
struct Color{

	union{
		struct{
			float r;			///< Red component in [0, 1]
			float g;			///< Green component in [0, 1]
			float b;			///< Blue component in [0, 1]
			float a;			///< Alpha component in [0, 1]
		};
		float components[4];	///< RGBA component vector
	};

	/// @param[in] r			red component
	/// @param[in] g			green component
	/// @param[in] b			blue component
	/// @param[in] a			alpha component
	Color(float r, float g, float b, float a=1.f)
	:	r(r), g(g), b(b), a(a){}

	/// @param[in] gray			red/green/blue components
	/// @param[in] a			alpha component
	Color(float gray=1.f, float a=1.f)
	:	r(gray), g(gray), b(gray), a(a){}

	/// @param[in] c	RGBA color to convert from
	Color(const Colori& c){ *this = c; }

	/// @param[in] hsv			HSV value
	/// @param[in] a			alpha component
	Color(const HSV& hsv, float a=1.f)
	:	a(a)
	{	*this = hsv; }

	/// Set color component at index with no bounds checking
	float& operator[](int i){ return components[i]; }

	/// Get color component at index with no bounds checking
	const float& operator[](int i) const { return components[i]; }

	/// Set RGB from another color and alpha from argument
	Color& set(const Color& c, float al){ a=al; return set(c.r,c.g,c.b); }

	/// Set RGBA components
	Color& set(float re, float gr, float bl, float al){ a=al; return set(re,gr,bl); }

	/// Set RGB components
	Color& set(float re, float gr, float bl){ r=re; g=gr; b=bl; return *this; }

	/// Set from gray value
	Color& set(float v){ return set(v,v,v); }

	/// Set from gray value and alpha
	Color& set(float v, float al){ return set(v,v,v,a); }

	/// Set from an array of RGBA components
	template <class T>
	Color& set(const T* rgba){ return set(rgba[0],rgba[1],rgba[2],rgba[3]); }

	/// Set components from tightly packed RGBA array
	template <class Array4>
	Color& operator= (const Array4& v){ return set(v[0], v[1], v[2], v[3]); }

	/// Set from gray value
	Color& operator= (float v){ return set(v); }
	Color& operator= (double v){ return set(v); }

	/// Set components from integer color
	Color& operator= (const Colori& v);

	/// Set RGB components from HSV
	Color& operator= (const HSV& v);

	/// Return true if all components are equal, false otherwise
	bool operator ==(const Color& v) const { return v.r==r && v.g==g && v.b==b && v.a==a; }

	/// Return true if components are not equal, false otherwise
	bool operator !=(const Color& v) const { return !(*this == v); }

	Color& operator+= (const Color& v){ return set(r+v.r, g+v.g, b+v.b, a+v.a); }
	Color& operator-= (const Color& v){ return set(r-v.r, g-v.g, b-v.b, a-v.a); }
	Color& operator*= (const Color& v){ return set(r*v.r, g*v.g, b*v.b, a*v.a); }
	Color& operator/= (const Color& v){ return set(r/v.r, g/v.g, b/v.b, a/v.a); }
	Color& operator+= (float v){ return set(r+v, g+v, b+v, a+v); }
	Color& operator-= (float v){ return set(r-v, g-v, b-v, a-v); }
	Color& operator*= (float v){ return set(r*v, g*v, b*v, a*v); }
	Color& operator/= (float v){ return set(r/v, g/v, b/v, a/v); }

	Color operator- () const { return Color(-r,-g,-b,-a); }
	Color operator+ (const Color& v) const { return Color(*this)+=v; }
	Color operator- (const Color& v) const { return Color(*this)-=v; }
	Color operator* (const Color& v) const { return Color(*this)*=v; }
	Color operator/ (const Color& v) const { return Color(*this)/=v; }
	Color operator+ (float v) const { return Color(*this)+=v; }
	Color operator- (float v) const { return Color(*this)-=v; }
	Color operator* (float v) const { return Color(*this)*=v; }
	Color operator/ (float v) const { return Color(*this)/=v; }

	/// Returns nearest black or white color
	Color blackAndWhite() const { return Color(luminance()>0.5f?1.f:0.f); }

	/// Clamp all components into [0,1] range
	Color& clamp(){
		r<0.f ? r=0.f : (r>1.f ? r=1.f : 0);
		g<0.f ? g=0.f : (g>1.f ? g=1.f : 0);
		b<0.f ? b=0.f : (b>1.f ? b=1.f : 0);
		a<0.f ? a=0.f : (a>1.f ? a=1.f : 0);
		return *this;
	}

	/// Returns inverted color
	Color inverse() const { return Color(1.f-r, 1.f-g, 1.f-b, a); }

	/// Invert RGB components
	Color& invert(){ return set(1.f-r, 1.f-g, 1.f-b); }

	/// Returns luminance value
	float luminance() const { return r*0.3f+g*0.59f+b*0.11f; }

	/// Returns self linearly mixed with another color (0 = none)
	Color mix(const Color& c, float amt=0.5f) const {
		return (c-*this)*amt + *this;
	}

private:
	float tof(uint8_t v){ return float(v)/255.f; }
};

/// Color represented by red, green, blue, and alpha components packed into 32-bit integer

/// The component accessor methods operate exclusively with integer types. To
/// convert to and from floating point values in the interval [0, 1], use the
/// overloaded assignment (=) operators.
struct Colori {

	union{
		struct{
			uint8_t r;			///< Red component in [0, 255]
			uint8_t g;			///< Green component in [0, 255]
			uint8_t b;			///< Blue component in [0, 255]
			uint8_t a;			///< Alpha component in [0, 255]
		};
		uint8_t components[4];	///< RGBA component vector
		uint32_t rgba;			///< RGBA components packed into 32-bit integer
	};

	/// @param[in] r			red component
	/// @param[in] g			green component
	/// @param[in] b			blue component
	/// @param[in] a			alpha component
	Colori(uint8_t r, uint8_t g, uint8_t b, uint8_t a=255)
	:	r(r), g(g), b(b), a(a){}

	/// @param[in] gray			red/green/blue components
	/// @param[in] a			alpha component
	Colori(uint8_t gray=255, uint8_t a=255)
	:	r(gray), g(gray), b(gray), a(a){}

	/// @param[in] c			RGBA color to convert from
	Colori(const Color& c){ *this = c; }

	/// @param[in] hsv			HSV value
	/// @param[in] a			alpha component
	Colori(const HSV& hsv, float a=1.f)
	:	a(toi(a))
	{	*this = hsv; }

	/// Set color component at index with no bounds checking
	uint8_t& operator[](int i){ return components[i]; }

	/// Get color component at index with no bounds checking
	const uint8_t& operator[](int i) const { return components[i]; }

	/// Set from floating-point color
	Colori& operator= (const Color& c){
		r=toi(c.r); g=toi(c.g); b=toi(c.b); a=toi(c.a); return *this; }

	/// Set RGB components from HSV
	Colori& operator= (const HSV& v){ *this = Color(v); return *this; }

	/// Set RGB components
	Colori& set(uint8_t re, uint8_t gr, uint8_t bl){
		r=re; g=gr; b=bl; return *this; }

	/// Set RGBA components
	Colori& set(uint8_t re, uint8_t gr, uint8_t bl, uint8_t al){
		a=al; return set(re,gr,bl); }

	/// Set from gray value
	Colori& set(uint8_t v){ return set(v,v,v); }

	/// Set from gray value and alpha
	Colori& set(uint8_t v, uint8_t al){ return set(v,al); }

private:
	uint8_t toi(float v){ return uint8_t(v*255.f); }
};

/// Color represented by hue, saturation, and value
struct HSV{

	union{
		struct{
			float h;			///< Hue component in [0, 1]
			float s;			///< Saturation component in [0, 1]
			float v;			///< Value component in [0, 1]
		};
		float components[3];	///< HSV component vector
	};

	/// @param[in] h	hue
	/// @param[in] s	saturation
	/// @param[in] v	value
	HSV(float h=0, float s=1, float v=1): h(h), s(s), v(v){}

	/// @param[in] c	RGB color to convert from
	HSV(const Color& c){ *this = c; }

	/// @param[in] c	RGB color to convert from
	HSV(const Colori& c){ *this = c; }

	/// @param[in] hsv		3-vector of hsv components
	template<class T>
	HSV(T * hsv): h(hsv[0]), s(hsv[1]), v(hsv[2]){}

	/// Set from RGB color
	HSV& operator= (const Color& c);

	/// Set from RGB color
	HSV& operator= (const Colori& c){ return *this = Color(c); }

	/// Rotate hue in interval [0, 1)
	HSV& rotateHue(float dh){ h += dh; return wrapHue(); }

	/// Wrap hue value into valid interval [0, 1)
	HSV& wrapHue(){
		if(h>1){ h -= int(h); }
		else if(h<0){ h -= int(h)-1; }
		return *this;
	}
};

// Implementation --------------------------------------------------------------

inline Color operator + (float s, const Color& c){ return  c+s; }
inline Color operator - (float s, const Color& c){ return -c+s; }
inline Color operator * (float s, const Color& c){ return  c*s; }
inline Color operator / (float s, const Color& c){ return Color(s/c.r, s/c.g, s/c.b, s/c.a); }

inline Color& Color::operator= (const Colori& v){
		r=tof(v.r); g=tof(v.g); b=tof(v.b); a=tof(v.a); return *this; }

} // al::

#endif
<|endoftext|>


<commit_before>#include <Python.h>
#include <structmember.h>

#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-global.h>
#include <poppler/cpp/poppler-page.h>

#include <string>
#include <vector>

static PyObject* PdftotextError;

typedef struct {
    PyObject_HEAD
    int page_count;
    PyObject* data;
    poppler::document* doc;
} PDF;

static void PDF_clear(PDF* self) {
    self->page_count = 0;
    delete self->doc;
    self->doc = NULL;
    Py_CLEAR(self->data);
}

static int PDF_load_data(PDF* self, PyObject* file) {
    #if PY_MAJOR_VERSION >= 3
    self->data = PyObject_CallMethod(file, "read", NULL);
    #else
    self->data = PyObject_CallMethod(file, (char*)"read", NULL);
    #endif
    if (self->data == NULL) {
        return -1;
    }
    return 0;
}

static int PDF_create_doc(PDF* self) {
    Py_ssize_t len;
    char* buf;

    if (PyBytes_AsStringAndSize(self->data, &buf, &len) < 0) {
        return -1;
    }
    self->doc = poppler::document::load_from_raw_data(buf, len);
    if (self->doc == NULL) {
        PyErr_Format(PdftotextError, "Poppler error creating document");
        return -1;
    }
    return 0;
}

static int PDF_unlock(PDF* self, char* password) {
    if (self->doc->unlock(std::string(password), std::string(password))) {
        PyErr_Format(PdftotextError, "Failed to unlock document");
        return -1;
    }
    return 0;
}

static int PDF_init(PDF* self, PyObject* args, PyObject* kwds) {
    PyObject* pdf_file;
    char* password = (char*)"";
    static char* kwlist[] = {(char*)"pdf_file", (char*)"password", NULL};

    PDF_clear(self);

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s", kwlist, &pdf_file, &password)) {
        goto error;
    }
    if (PDF_load_data(self, pdf_file) < 0) {
        goto error;
    }
    if (PDF_create_doc(self) < 0) {
        goto error;
    }
    if (PDF_unlock(self, password) < 0) {
        goto error;
    }

    self->page_count = self->doc->pages();
    return 0;

error:
    PDF_clear(self);
    return -1;
}

static void PDF_dealloc(PDF* self) {
    PDF_clear(self);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject* PDF_read_page(PDF* self, int page_number) {
    const poppler::page* page;
    std::vector<char> page_utf8;

    page = self->doc->create_page(page_number);
    if (page == NULL) {
        return PyErr_Format(PdftotextError, "Poppler error creating page");
    }
    page_utf8 = page->text().to_utf8();
    delete page;
    return PyUnicode_DecodeUTF8(page_utf8.data(), page_utf8.size(), NULL);
}

static Py_ssize_t PDF_len(PyObject* obj) {
    PDF* self = (PDF*)obj;
    return self->page_count;
}

static PyObject* PDF_getitem(PyObject* obj, Py_ssize_t i) {
    PDF* self = (PDF*)obj;

    if (i < 0 || i >= self->page_count) {
        return PyErr_Format(PyExc_IndexError, "Index out of range");
    }
    return PDF_read_page(self, i);
}

static PySequenceMethods PDF_sequence_methods = {
    PDF_len,      // sq_length (__len__)
    0,            // sq_concat
    0,            // sq_repeat
    PDF_getitem,  // sq_item (__getitem__)
};

static PyTypeObject PDFType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "pdftotext.PDF",                                   // tp_name
    sizeof(PDF),                                       // tp_basicsize
    0,                                                 // tp_itemsize
    (destructor)PDF_dealloc,                           // tp_dealloc
    0,                                                 // tp_print
    0,                                                 // tp_getattr
    0,                                                 // tp_setattr
    0,                                                 // tp_reserved
    0,                                                 // tp_repr
    0,                                                 // tp_as_number
    &PDF_sequence_methods,                             // tp_as_sequence
    0,                                                 // tp_as_mapping
    0,                                                 // tp_hash
    0,                                                 // tp_call
    0,                                                 // tp_str
    0,                                                 // tp_getattro
    0,                                                 // tp_setattro
    0,                                                 // tp_as_buffer
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,          // tp_flags
    "PDF(pdf_file, password="") -> new PDF document",  // tp_doc
    0,                                                 // tp_traverse
    0,                                                 // tp_clear
    0,                                                 // tp_richcompare
    0,                                                 // tp_weaklistoffset
    0,                                                 // tp_iter
    0,                                                 // tp_iternext
    0,                                                 // tp_methods
    0,                                                 // tp_members
    0,                                                 // tp_getset
    0,                                                 // tp_base
    0,                                                 // tp_dict
    0,                                                 // tp_descr_get
    0,                                                 // tp_descr_set
    0,                                                 // tp_dictoffset
    (initproc)PDF_init,                                // tp_init
};

#if POPPLER_CPP_AT_LEAST_0_30_0
static void do_nothing(const std::string&, void*) {}
#endif

#if PY_MAJOR_VERSION >= 3
static PyModuleDef pdftotextmodule = {
    PyModuleDef_HEAD_INIT,
    "pdftotext",
    "Simple PDF text extraction.",
};

PyMODINIT_FUNC PyInit_pdftotext() {
    PyObject* module;

    PDFType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&PDFType) < 0) {
        return NULL;
    }

    module = PyModule_Create(&pdftotextmodule);
    if (module == NULL) {
        return NULL;
    }

    Py_INCREF(&PDFType);
    PyModule_AddObject(module, "PDF", (PyObject*)&PDFType);

    PdftotextError = PyErr_NewExceptionWithDoc(
        "pdftotext.Error", "PDF error.", NULL, NULL);
    Py_INCREF(PdftotextError);
    PyModule_AddObject(module, "Error", PdftotextError);

    #if POPPLER_CPP_AT_LEAST_0_30_0
    poppler::set_debug_error_function(do_nothing, NULL);
    #endif

    return module;
}
#else
static PyMethodDef module_methods[] = {
    {NULL},  // Sentinel
};

PyMODINIT_FUNC initpdftotext() {
    PyObject* module;

    PDFType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&PDFType) < 0) {
        return;
    }

    module = Py_InitModule3(
        "pdftotext", module_methods, "Simple PDF text extraction.");
    if (module == NULL) {
        return;
    }

    Py_INCREF(&PDFType);
    PyModule_AddObject(module, "PDF", (PyObject*)&PDFType);

    PdftotextError = PyErr_NewExceptionWithDoc(
        (char*)"pdftotext.Error", (char*)"PDF error.", NULL, NULL);
    Py_INCREF(PdftotextError);
    PyModule_AddObject(module, "Error", PdftotextError);

    #if POPPLER_CPP_AT_LEAST_0_30_0
    poppler::set_debug_error_function(do_nothing, NULL);
    #endif
}
#endif
<commit_msg>Use NULL methods in Py_InitModule3<commit_after>#include <Python.h>
#include <structmember.h>

#include <poppler/cpp/poppler-document.h>
#include <poppler/cpp/poppler-global.h>
#include <poppler/cpp/poppler-page.h>

#include <string>
#include <vector>

static PyObject* PdftotextError;

typedef struct {
    PyObject_HEAD
    int page_count;
    PyObject* data;
    poppler::document* doc;
} PDF;

static void PDF_clear(PDF* self) {
    self->page_count = 0;
    delete self->doc;
    self->doc = NULL;
    Py_CLEAR(self->data);
}

static int PDF_load_data(PDF* self, PyObject* file) {
    #if PY_MAJOR_VERSION >= 3
    self->data = PyObject_CallMethod(file, "read", NULL);
    #else
    self->data = PyObject_CallMethod(file, (char*)"read", NULL);
    #endif
    if (self->data == NULL) {
        return -1;
    }
    return 0;
}

static int PDF_create_doc(PDF* self) {
    Py_ssize_t len;
    char* buf;

    if (PyBytes_AsStringAndSize(self->data, &buf, &len) < 0) {
        return -1;
    }
    self->doc = poppler::document::load_from_raw_data(buf, len);
    if (self->doc == NULL) {
        PyErr_Format(PdftotextError, "Poppler error creating document");
        return -1;
    }
    return 0;
}

static int PDF_unlock(PDF* self, char* password) {
    if (self->doc->unlock(std::string(password), std::string(password))) {
        PyErr_Format(PdftotextError, "Failed to unlock document");
        return -1;
    }
    return 0;
}

static int PDF_init(PDF* self, PyObject* args, PyObject* kwds) {
    PyObject* pdf_file;
    char* password = (char*)"";
    static char* kwlist[] = {(char*)"pdf_file", (char*)"password", NULL};

    PDF_clear(self);

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s", kwlist, &pdf_file, &password)) {
        goto error;
    }
    if (PDF_load_data(self, pdf_file) < 0) {
        goto error;
    }
    if (PDF_create_doc(self) < 0) {
        goto error;
    }
    if (PDF_unlock(self, password) < 0) {
        goto error;
    }

    self->page_count = self->doc->pages();
    return 0;

error:
    PDF_clear(self);
    return -1;
}

static void PDF_dealloc(PDF* self) {
    PDF_clear(self);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject* PDF_read_page(PDF* self, int page_number) {
    const poppler::page* page;
    std::vector<char> page_utf8;

    page = self->doc->create_page(page_number);
    if (page == NULL) {
        return PyErr_Format(PdftotextError, "Poppler error creating page");
    }
    page_utf8 = page->text().to_utf8();
    delete page;
    return PyUnicode_DecodeUTF8(page_utf8.data(), page_utf8.size(), NULL);
}

static Py_ssize_t PDF_len(PyObject* obj) {
    PDF* self = (PDF*)obj;
    return self->page_count;
}

static PyObject* PDF_getitem(PyObject* obj, Py_ssize_t i) {
    PDF* self = (PDF*)obj;

    if (i < 0 || i >= self->page_count) {
        return PyErr_Format(PyExc_IndexError, "Index out of range");
    }
    return PDF_read_page(self, i);
}

static PySequenceMethods PDF_sequence_methods = {
    PDF_len,      // sq_length (__len__)
    0,            // sq_concat
    0,            // sq_repeat
    PDF_getitem,  // sq_item (__getitem__)
};

static PyTypeObject PDFType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "pdftotext.PDF",                                   // tp_name
    sizeof(PDF),                                       // tp_basicsize
    0,                                                 // tp_itemsize
    (destructor)PDF_dealloc,                           // tp_dealloc
    0,                                                 // tp_print
    0,                                                 // tp_getattr
    0,                                                 // tp_setattr
    0,                                                 // tp_reserved
    0,                                                 // tp_repr
    0,                                                 // tp_as_number
    &PDF_sequence_methods,                             // tp_as_sequence
    0,                                                 // tp_as_mapping
    0,                                                 // tp_hash
    0,                                                 // tp_call
    0,                                                 // tp_str
    0,                                                 // tp_getattro
    0,                                                 // tp_setattro
    0,                                                 // tp_as_buffer
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,          // tp_flags
    "PDF(pdf_file, password="") -> new PDF document",  // tp_doc
    0,                                                 // tp_traverse
    0,                                                 // tp_clear
    0,                                                 // tp_richcompare
    0,                                                 // tp_weaklistoffset
    0,                                                 // tp_iter
    0,                                                 // tp_iternext
    0,                                                 // tp_methods
    0,                                                 // tp_members
    0,                                                 // tp_getset
    0,                                                 // tp_base
    0,                                                 // tp_dict
    0,                                                 // tp_descr_get
    0,                                                 // tp_descr_set
    0,                                                 // tp_dictoffset
    (initproc)PDF_init,                                // tp_init
};

#if POPPLER_CPP_AT_LEAST_0_30_0
static void do_nothing(const std::string&, void*) {}
#endif

#if PY_MAJOR_VERSION >= 3
static PyModuleDef pdftotextmodule = {
    PyModuleDef_HEAD_INIT,
    "pdftotext",
    "Simple PDF text extraction.",
};

PyMODINIT_FUNC PyInit_pdftotext() {
    PyObject* module;

    PDFType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&PDFType) < 0) {
        return NULL;
    }

    module = PyModule_Create(&pdftotextmodule);
    if (module == NULL) {
        return NULL;
    }

    Py_INCREF(&PDFType);
    PyModule_AddObject(module, "PDF", (PyObject*)&PDFType);

    PdftotextError = PyErr_NewExceptionWithDoc(
        "pdftotext.Error", "PDF error.", NULL, NULL);
    Py_INCREF(PdftotextError);
    PyModule_AddObject(module, "Error", PdftotextError);

    #if POPPLER_CPP_AT_LEAST_0_30_0
    poppler::set_debug_error_function(do_nothing, NULL);
    #endif

    return module;
}
#else
PyMODINIT_FUNC initpdftotext() {
    PyObject* module;

    PDFType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&PDFType) < 0) {
        return;
    }

    module = Py_InitModule3("pdftotext", NULL, "Simple PDF text extraction.");
    if (module == NULL) {
        return;
    }

    Py_INCREF(&PDFType);
    PyModule_AddObject(module, "PDF", (PyObject*)&PDFType);

    PdftotextError = PyErr_NewExceptionWithDoc(
        (char*)"pdftotext.Error", (char*)"PDF error.", NULL, NULL);
    Py_INCREF(PdftotextError);
    PyModule_AddObject(module, "Error", PdftotextError);

    #if POPPLER_CPP_AT_LEAST_0_30_0
    poppler::set_debug_error_function(do_nothing, NULL);
    #endif
}
#endif
<|endoftext|>


<commit_before>/*
 * GwtFileHandler.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/gwt/GwtFileHandler.hpp>

#include <boost/regex.hpp>

#include <core/FilePath.hpp>
#include <core/system/System.hpp>
#include <core/http/Request.hpp>
#include <core/http/Response.hpp>

namespace core {
namespace gwt {

namespace {

FilePath requestedFile(const std::string& wwwLocalPath,
                       const std::string& relativePath)
{
   // ensure that this path does not start with /
   if (relativePath.find('/') == 0)
      return FilePath();

   // ensure that this path does not contain ..
   if (relativePath.find("..") != std::string::npos)
      return FilePath();

#ifndef _WIN32

   // calculate "real" wwwPath
   FilePath wwwRealPath;
   Error error = core::system::realPath(wwwLocalPath, &wwwRealPath);
   if (error)
   {
      LOG_ERROR(error);
      return FilePath();
   }

   // calculate "real" requested path
   FilePath realRequestedPath;
   FilePath requestedPath = wwwRealPath.complete(relativePath);
   error = core::system::realPath(requestedPath.absolutePath(),
                                  &realRequestedPath);
   if (error)
   {
      error.addProperty("requested-path", relativePath);
      LOG_ERROR(error);
      return FilePath();
   }

   // validate that the requested path falls within the www path
   if ( (realRequestedPath != wwwRealPath) &&
        realRequestedPath.relativePath(wwwRealPath).empty() )
   {
      LOG_WARNING_MESSAGE("Non www-local-path URI requested: " +
                          relativePath);
      return FilePath();
   }

   // return the path
   return realRequestedPath;

#else

   // just complete the path straight away on Win32
   return FilePath(wwwLocalPath).complete(relativePath);

#endif

}

void handleFileRequest(const std::string& wwwLocalPath,
                       const std::string& baseUri,
                       core::http::UriFilterFunction mainPageFilter,
                       const http::Request& request,
                       http::Response* pResponse)
{
   // get the uri and strip the query string
   std::string uri = request.uri();
   std::size_t pos = uri.find("?");
   if (pos != std::string::npos)
      uri.erase(pos);

   // request for one-character short of root location redirects to root
   if (uri == baseUri.substr(0, baseUri.size()-1))
   {
      pResponse->setMovedPermanently(request, baseUri);
      return;
   }

   // request for a URI not within our location scope
   if (uri.find(baseUri) != 0)
   {
      pResponse->setError(http::status::NotFound,
                          request.uri() + " not found");
      return;
   }

   // auto-append index.htm to request for root location
   const char * const kIndexFile = "index.htm";
   if (uri == baseUri)
      uri += kIndexFile;

   // if this is main page and we have a filter then then give it a crack
   // at the request
   std::string mainPage = baseUri + kIndexFile;
   if (uri == mainPage)
   {
      // run filter if we have one
      if (mainPageFilter)
      {
         // if the filter returns false it means we should stop processing
         if (!mainPageFilter(request, pResponse))
            return ;
      }

		// set chrome frame compatible
		pResponse->setChromeFrameCompatible(request);
   }

   // get the requested file
   std::string relativePath = uri.substr(baseUri.length());
   FilePath filePath = requestedFile(wwwLocalPath, relativePath);
   if (filePath.empty())
   {
      pResponse->setError(http::status::NotFound,
                          request.uri() + " not found");
      return;
   }

   // case: files designated to be cached "forever"
   if (regex_match(uri, boost::regex(".*\\.cache\\..*")))
   {
      pResponse->setCacheForeverHeaders();
      pResponse->setFile(filePath, request);
   }

   // case: files designated to never be cached
   else if (regex_match(uri, boost::regex(".*\\.nocache\\..*")))
   {
      pResponse->setNoCacheHeaders();
      pResponse->setFile(filePath, request);
   }

   // case: normal cacheable file
   else
   {
      // since these are application components we force revalidation
      pResponse->setCacheWithRevalidationHeaders();
      pResponse->setCacheableFile(filePath, request);
   }

}

} // anonymous namespace

http::UriHandlerFunction fileHandlerFunction(
                                       const std::string& wwwLocalPath,
                                       const std::string& baseUri,
                                       http::UriFilterFunction mainPageFilter)
{
   return boost::bind(handleFileRequest,
                      wwwLocalPath,
                      baseUri,
                      mainPageFilter,
                      _1,
                      _2);
}

} // namespace gwt
} // namespace core

<commit_msg>don't log realPath error if it is file not found<commit_after>/*
 * GwtFileHandler.cpp
 *
 * Copyright (C) 2009-11 by RStudio, Inc.
 *
 * This program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */

#include <core/gwt/GwtFileHandler.hpp>

#include <boost/regex.hpp>

#include <core/FilePath.hpp>
#include <core/system/System.hpp>
#include <core/http/Request.hpp>
#include <core/http/Response.hpp>

namespace core {
namespace gwt {

namespace {

FilePath requestedFile(const std::string& wwwLocalPath,
                       const std::string& relativePath)
{
   // ensure that this path does not start with /
   if (relativePath.find('/') == 0)
      return FilePath();

   // ensure that this path does not contain ..
   if (relativePath.find("..") != std::string::npos)
      return FilePath();

#ifndef _WIN32

   // calculate "real" wwwPath
   FilePath wwwRealPath;
   Error error = core::system::realPath(wwwLocalPath, &wwwRealPath);
   if (error)
   {
      LOG_ERROR(error);
      return FilePath();
   }

   // calculate "real" requested path
   FilePath realRequestedPath;
   FilePath requestedPath = wwwRealPath.complete(relativePath);
   error = core::system::realPath(requestedPath.absolutePath(),
                                  &realRequestedPath);
   if (error)
   {
      // log if this isn't file not found
      if (error.code() != boost::system::errc::no_such_file_or_directory)
      {
         error.addProperty("requested-path", relativePath);
         LOG_ERROR(error);
      }
      return FilePath();
   }

   // validate that the requested path falls within the www path
   if ( (realRequestedPath != wwwRealPath) &&
        realRequestedPath.relativePath(wwwRealPath).empty() )
   {
      LOG_WARNING_MESSAGE("Non www-local-path URI requested: " +
                          relativePath);
      return FilePath();
   }

   // return the path
   return realRequestedPath;

#else

   // just complete the path straight away on Win32
   return FilePath(wwwLocalPath).complete(relativePath);

#endif

}

void handleFileRequest(const std::string& wwwLocalPath,
                       const std::string& baseUri,
                       core::http::UriFilterFunction mainPageFilter,
                       const http::Request& request,
                       http::Response* pResponse)
{
   // get the uri and strip the query string
   std::string uri = request.uri();
   std::size_t pos = uri.find("?");
   if (pos != std::string::npos)
      uri.erase(pos);

   // request for one-character short of root location redirects to root
   if (uri == baseUri.substr(0, baseUri.size()-1))
   {
      pResponse->setMovedPermanently(request, baseUri);
      return;
   }

   // request for a URI not within our location scope
   if (uri.find(baseUri) != 0)
   {
      pResponse->setError(http::status::NotFound,
                          request.uri() + " not found");
      return;
   }

   // auto-append index.htm to request for root location
   const char * const kIndexFile = "index.htm";
   if (uri == baseUri)
      uri += kIndexFile;

   // if this is main page and we have a filter then then give it a crack
   // at the request
   std::string mainPage = baseUri + kIndexFile;
   if (uri == mainPage)
   {
      // run filter if we have one
      if (mainPageFilter)
      {
         // if the filter returns false it means we should stop processing
         if (!mainPageFilter(request, pResponse))
            return ;
      }

		// set chrome frame compatible
		pResponse->setChromeFrameCompatible(request);
   }

   // get the requested file
   std::string relativePath = uri.substr(baseUri.length());
   FilePath filePath = requestedFile(wwwLocalPath, relativePath);
   if (filePath.empty())
   {
      pResponse->setError(http::status::NotFound,
                          request.uri() + " not found");
      return;
   }

   // case: files designated to be cached "forever"
   if (regex_match(uri, boost::regex(".*\\.cache\\..*")))
   {
      pResponse->setCacheForeverHeaders();
      pResponse->setFile(filePath, request);
   }

   // case: files designated to never be cached
   else if (regex_match(uri, boost::regex(".*\\.nocache\\..*")))
   {
      pResponse->setNoCacheHeaders();
      pResponse->setFile(filePath, request);
   }

   // case: normal cacheable file
   else
   {
      // since these are application components we force revalidation
      pResponse->setCacheWithRevalidationHeaders();
      pResponse->setCacheableFile(filePath, request);
   }

}

} // anonymous namespace

http::UriHandlerFunction fileHandlerFunction(
                                       const std::string& wwwLocalPath,
                                       const std::string& baseUri,
                                       http::UriFilterFunction mainPageFilter)
{
   return boost::bind(handleFileRequest,
                      wwwLocalPath,
                      baseUri,
                      mainPageFilter,
                      _1,
                      _2);
}

} // namespace gwt
} // namespace core

<|endoftext|>