new files

This commit is contained in:
David Rose 2009-09-17 22:53:34 +00:00
parent 54c3e34f6e
commit 8cf47fea92
3 changed files with 501 additions and 0 deletions

View File

@ -0,0 +1,14 @@
// Filename: p3dAuthSession.I
// Created by: drose (17Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////

View File

@ -0,0 +1,404 @@
// Filename: P3DAuthSession.cxx
// Created by: drose (17Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "p3dAuthSession.h"
#include "p3dInstance.h"
#include "p3dInstanceManager.h"
#include "p3dMultifileReader.h"
#include "p3d_plugin_config.h"
#include "mkdir_complete.h"
#include <ctype.h>
#ifndef _WIN32
#include <fcntl.h>
#include <sys/wait.h>
#include <sys/select.h>
#include <signal.h>
#include <dlfcn.h>
#endif
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DAuthSession::
P3DAuthSession(P3DInstance *inst) :
_inst(inst)
{
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_p3dcert_started = false;
_p3dcert_running = false;
_started_wait_thread = false;
INIT_THREAD(_wait_thread);
// Write the cert chain to a temporary file.
_cert_filename = new P3DTemporaryFile(".crt");
string filename = _cert_filename->get_filename();
FILE *fp = fopen(filename.c_str(), "w");
if (fp == NULL) {
nout << "Couldn't write temporary file\n";
return;
}
if (inst->_mf_reader.get_num_signatures() > 0) {
const P3DMultifileReader::CertChain &cert_chain =
inst->_mf_reader.get_signature(0);
if (cert_chain.size() > 0) {
// Save the cert_dir, this is where the p3dcert program will
// need to write the cert when it is approved.
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_cert_dir = inst_mgr->get_cert_dir(cert_chain[0]._cert);
}
P3DMultifileReader::CertChain::const_iterator ci;
for (ci = cert_chain.begin(); ci != cert_chain.end(); ++ci) {
X509 *c = (*ci)._cert;
PEM_write_X509(fp, c);
}
}
fclose(fp);
start_p3dcert();
}
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::Destructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
P3DAuthSession::
~P3DAuthSession() {
shutdown(false);
if (_cert_filename != NULL) {
delete _cert_filename;
}
}
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::shutdown
// Access: Public
// Description: Terminates the session by killing the subprocess.
////////////////////////////////////////////////////////////////////
void P3DAuthSession::
shutdown(bool send_message) {
if (!send_message) {
// If we're not to send the instance the shutdown message as a
// result of this, then clear the _inst pointer now.
_inst = NULL;
}
if (_p3dcert_started) {
nout << "Killing p3dcert process\n";
#ifdef _WIN32
TerminateProcess(_p3dcert_handle, 2);
CloseHandle(_p3dcert_handle);
#else // _WIN32
kill(_p3dcert_pid, SIGKILL);
#endif // _WIN32
_p3dcert_running = false;
_p3dcert_started = false;
}
// Now that the process has stopped, the thread should stop itself
// quickly too.
join_wait_thread();
// We're no longer bound to any particular instance.
_inst = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::start_p3dcert
// Access: Private
// Description: Starts the p3dcert program running in a child
// process.
////////////////////////////////////////////////////////////////////
void P3DAuthSession::
start_p3dcert() {
if (_p3dcert_started) {
// Already started.
return;
}
if (_inst->_p3dcert_package == NULL) {
nout << "Couldn't start Python: no p3dcert package.\n";
return;
}
P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
_start_dir = inst_mgr->get_root_dir() + "/start";
string root_dir = _inst->_p3dcert_package->get_package_dir();
mkdir_complete(_start_dir, nout);
_p3dcert_exe = root_dir + "/p3dcert";
#ifdef _WIN32
_p3dcert_exe += ".exe";
#endif
// Populate the new process' environment.
_env = string();
// These are the enviroment variables we forward from the current
// environment, if they are set.
const char *keep[] = {
"TMP", "TEMP", "HOME", "USER",
#ifdef _WIN32
"SYSTEMROOT", "USERPROFILE", "COMSPEC",
#endif
#ifdef HAVE_X11
"DISPLAY",
#endif
NULL
};
for (int ki = 0; keep[ki] != NULL; ++ki) {
char *value = getenv(keep[ki]);
if (value != NULL) {
_env += keep[ki];
_env += "=";
_env += value;
_env += '\0';
}
}
// Define some new environment variables.
_env += "PATH=";
_env += root_dir;
_env += '\0';
_env += "LD_LIBRARY_PATH=";
_env += root_dir;
_env += '\0';
_env += "DYLD_LIBRARY_PATH=";
_env += root_dir;
_env += '\0';
_env += "P3DCERT_ROOT=";
_env += root_dir;
_env += '\0';
nout << "Attempting to start p3dcert from " << _p3dcert_exe << "\n";
bool started_p3dcert = false;
#ifdef _WIN32
_p3dcert_handle = win_create_process();
started_p3dcert = (_p3dcert_handle != INVALID_HANDLE_VALUE);
#else
_p3dcert_pid = posix_create_process();
started_p3dcert = (_p3dcert_pid > 0);
#endif
if (!started_p3dcert) {
nout << "Failed to create process.\n";
return;
}
_p3dcert_started = true;
_p3dcert_running = true;
spawn_wait_thread();
}
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::spawn_wait_thread
// Access: Private
// Description: Starts the wait thread. This thread is responsible
// for waiting for the process to finish, and notifying
// the instance when it does.
////////////////////////////////////////////////////////////////////
void P3DAuthSession::
spawn_wait_thread() {
SPAWN_THREAD(_wait_thread, wt_thread_run, this);
_started_wait_thread = true;
}
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::join_wait_thread
// Access: Private
// Description: Waits for the wait thread to stop.
////////////////////////////////////////////////////////////////////
void P3DAuthSession::
join_wait_thread() {
if (!_started_wait_thread) {
return;
}
JOIN_THREAD(_wait_thread);
_started_wait_thread = false;
}
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::wt_thread_run
// Access: Private
// Description: The main function for the wait thread.
////////////////////////////////////////////////////////////////////
void P3DAuthSession::
wt_thread_run() {
// All we do here is wait for the process to terminate.
nout << "wt_thread_run in " << this << " beginning\n";
#ifdef _WIN32
DWORD result = WaitForSingleObject(_p3dcert_handle, INFINITE);
if (result != 0) {
nout << "Wait for process failed: " << GetLastError() << "\n";
}
nout << "p3dcert process has successfully stopped.\n";
#else
int status;
pid_t result = waitpid(_p3dcert_pid, &status, WNOHANG);
if (result == -1) {
perror("waitpid");
break;
}
nout << "p3dcert process has successfully stopped.\n";
if (WIFEXITED(status)) {
nout << " exited normally, status = "
<< WEXITSTATUS(status) << "\n";
} else if (WIFSIGNALED(status)) {
nout << " signalled by " << WTERMSIG(status) << ", core = "
<< WCOREDUMP(status) << "\n";
} else if (WIFSTOPPED(status)) {
nout << " stopped by " << WSTOPSIG(status) << "\n";
}
#endif // _WIN32
// Notify the instance that we're done.
P3DInstance *inst = _inst;
if (inst != NULL) {
inst->auth_finished_sub_thread();
}
nout << "Exiting wt_thread_run in " << this << "\n";
}
#ifdef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::win_create_process
// Access: Private
// Description: Creates a sub-process to run _p3dcert_exe, with
// the appropriate command-line arguments, and the
// environment string defined in _env.
//
// Returns the handle to the created process on success,
// or INVALID_HANDLE_VALUE on falure.
////////////////////////////////////////////////////////////////////
HANDLE P3DAuthSession::
win_create_process() {
// Make sure we see an error dialog if there is a missing DLL.
SetErrorMode(0);
STARTUPINFO startup_info;
ZeroMemory(&startup_info, sizeof(STARTUPINFO));
startup_info.cb = sizeof(startup_info);
// Make sure the initial window is *shown* for this graphical app.
startup_info.wShowWindow = SW_SHOW;
startup_info.dwFlags |= STARTF_USESHOWWINDOW;
const char *start_dir_cstr = _start_dir.c_str();
// Construct the command-line string, containing the quoted
// command-line arguments.
ostringstream stream;
stream << "\"" << _p3dcert_exe << "\" \""
<< _cert_filename->get_filename() << "\" \""
<< _cert_dir << "\"";
// I'm not sure why CreateProcess wants a non-const char pointer for
// its command-line string, but I'm not taking chances. It gets a
// non-const char array that it can modify.
string command_line_str = stream.str();
nout << "command is: " << command_line_str << "\n";
char *command_line = new char[command_line_str.size() + 1];
strcpy(command_line, command_line_str.c_str());
PROCESS_INFORMATION process_info;
BOOL result = CreateProcess
(_p3dcert_exe.c_str(), command_line, NULL, NULL, TRUE, 0,
(void *)_env.c_str(), start_dir_cstr,
&startup_info, &process_info);
bool started_program = (result != 0);
delete[] command_line;
if (!started_program) {
return INVALID_HANDLE_VALUE;
}
CloseHandle(process_info.hThread);
return process_info.hProcess;
}
#endif // _WIN32
#ifndef _WIN32
////////////////////////////////////////////////////////////////////
// Function: P3DAuthSession::posix_create_process
// Access: Private
// Description: Creates a sub-process to run _p3dcert_exe, with
// the appropriate command-line arguments, and the
// environment string defined in _env.
//
// Returns the pid of the created process on success, or
// -1 on falure.
////////////////////////////////////////////////////////////////////
int P3DAuthSession::
posix_create_process() {
// Fork and exec.
pid_t child = fork();
if (child < 0) {
perror("fork");
return -1;
}
if (child == 0) {
// Here we are in the child process.
if (chdir(_start_dir.c_str()) < 0) {
nout << "Could not chdir to " << _start_dir << "\n";
// This is a warning, not an error. We don't actually care
// that much about the starting directory.
}
// build up an array of char strings for the environment.
vector<const char *> ptrs;
size_t p = 0;
size_t zero = _env.find('\0', p);
while (zero != string::npos) {
ptrs.push_back(_env.data() + p);
p = zero + 1;
zero = _env.find('\0', p);
}
ptrs.push_back((char *)NULL);
execle(_p3dcert_exe.c_str(), _p3dcert_exe.c_str(),
_cert_filename->get_filename().c_str(), _cert_dir.c_str(),
(char *)0, &ptrs[0]);
nout << "Failed to exec " << _p3dcert_exe << "\n";
_exit(1);
}
return child;
}
#endif // _WIN32

View File

@ -0,0 +1,83 @@
// Filename: P3DAuthSession.h
// Created by: drose (17Sep09)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#ifndef P3DAUTHSESSION_H
#define P3DAUTHSESSION_H
#include "p3d_plugin_common.h"
#include "p3dPackage.h"
#include "get_tinyxml.h"
#include "p3dTemporaryFile.h"
#include "p3dReferenceCount.h"
class P3DInstance;
////////////////////////////////////////////////////////////////////
// Class : P3DAuthSession
// Description : This is an instance of a p3dcert program running in a
// subprocess. There's no communication with the
// process, or none of that complicated stuff the
// P3DSession has to do; all we do here is fire off the
// process, then wait for it to exit.
////////////////////////////////////////////////////////////////////
class P3DAuthSession : public P3DReferenceCount {
public:
P3DAuthSession(P3DInstance *inst);
~P3DAuthSession();
void shutdown(bool send_message);
private:
void start_p3dcert();
void spawn_wait_thread();
void join_wait_thread();
private:
// These methods run only within the read thread.
THREAD_CALLBACK_DECLARATION(P3DAuthSession, wt_thread_run);
void wt_thread_run();
#ifdef _WIN32
HANDLE win_create_process();
#else
int posix_create_process();
#endif
private:
P3DInstance *_inst;
string _start_dir;
// This information is passed to create_process().
P3DTemporaryFile *_cert_filename;
string _cert_dir;
string _p3dcert_exe;
string _env;
#ifdef _WIN32
HANDLE _p3dcert_handle;
#else
int _p3dcert_pid;
#endif
bool _p3dcert_started;
bool _p3dcert_running;
// The remaining members are manipulated by or for the read thread.
bool _started_wait_thread;
THREAD _wait_thread;
};
#include "P3DAuthSession.I"
#endif