diff options
Diffstat (limited to 'ACE/bin/LabVIEW_RT/labview_test_controller/labview_test_controller.cpp')
-rw-r--r-- | ACE/bin/LabVIEW_RT/labview_test_controller/labview_test_controller.cpp | 599 |
1 files changed, 0 insertions, 599 deletions
diff --git a/ACE/bin/LabVIEW_RT/labview_test_controller/labview_test_controller.cpp b/ACE/bin/LabVIEW_RT/labview_test_controller/labview_test_controller.cpp deleted file mode 100644 index 728c847121c..00000000000 --- a/ACE/bin/LabVIEW_RT/labview_test_controller/labview_test_controller.cpp +++ /dev/null @@ -1,599 +0,0 @@ -// $Id$ -// -// Defines the entry point for the LabVIEW RT test controller DLL application. -// This DLL is loaded at system boot by LabVIEW RT. The controller waits for -// TCP connections from the ACE+TAO test scripts. The test scripts will direct -// operation of the tests via commands sent over TCP. In order to be ready for -// connections without intervention via VI, the initial load will spawn a -// thread that sets up the listening socket. - -#include "stdafx.h" -#include <errno.h> -#include <fcntl.h> -#include <io.h> -#include <memory.h> -#include <process.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> - -#include <Winsock2.h> - -// NULL is the documented way to check DLL handles, and this is plain -// Windows code, not ACE, so we stick to the Microsoft way... -// FUZZ: disable check_for_NULL - -// This is plain Windows code, not ACE. Therefore we disable -// the check for ACE_OS -// FUZZ: disable check_for_lack_ACE_OS - -// TEST_FUNC is the prototype for the called test's main entrypoint. It's -// the normal C main. -typedef int (*TEST_FUNC) (int argc, char *argv[]); - -// Thread entrypoints -static unsigned int __stdcall test_control (void *param); -static unsigned int __stdcall peer_svc (void *peer_p); -static unsigned int __stdcall run_test (void *test_p); - -static const char *format_errmsg (unsigned int errcode, const char *prefix); - -// Logging information -static const char *LogName = "acetao.log"; -static HANDLE logf = INVALID_HANDLE_VALUE; - -BOOL APIENTRY DllMain( HANDLE hModule, - DWORD ul_reason_for_call, - LPVOID lpReserved - ) -{ - if (ul_reason_for_call == DLL_PROCESS_ATTACH) - { - return (0 != _beginthreadex (0, // security - 8 * 1024, // stack size - test_control, // entrypoint - 0, // param - 0, // creation flags - 0)); // ptr to thread id - } - - return TRUE; -} - -class Test -{ -public: - Test () : dll_handle_ (NULL), - thr_handle_ (0), - entry_ (0), - running_ (false), - status_ (-1) - {} - ~Test (); - - HANDLE handle (void) { return this->thr_handle_; } - int run (void); - const char *start (const char *name); - bool status (int *exit_status); - int wait (void); - void kill (void); - - // Clean up remnants of a test run. - void cleanup (void); - -private: - HMODULE dll_handle_; - HANDLE thr_handle_; - TEST_FUNC entry_; - bool running_; - int status_; - enum { CMDLINE_LEN = 1024, ARGV_SIZE = 100 }; - char name_[CMDLINE_LEN]; - char cmdline_[CMDLINE_LEN]; - int argc_; - char *argv_[ARGV_SIZE]; -}; - -class Peer -{ -public: - Peer (SOCKET h) : handle_ (h) {} - - // Run the Peer's session; intended to be called from a new thread devoted - // to this peer's session. - int svc (void); - -private: - Peer () {}; - - // Process command input from socket. - int command (void); - - // Send a reply string to the peer. - int reply (const char *msg); - - SOCKET handle_; - Test test_; -}; - -// Run a peer session; assume there's a thread for each session, so this -// object has all it needs for context located in 'this' object, and it can -// block at any point as long as one remembers that there is one or more -// test threads running and some attention must be paid to the encapsulated -// socket handle over which this object receives control commands from the -// host test driver. -int -Peer::svc (void) -{ - // Read commands until EOF (peer closed) or protocol error - while (0 == this->command ()) - ; - closesocket (this->handle_); - this->handle_ = INVALID_SOCKET; - return 0; -} - -int -Peer::command (void) -{ - // The protocol exchanges with the peer are execpted to be lock-step - // request-reply command lines, so we can make assumptions about a complete - // line being available to make life easier. - const int MAX_RECV = 1024; - char line[MAX_RECV], *p; - p = &line[0]; - int count = 0, len = 0; - while ((count = recv (this->handle_, p, MAX_RECV - len, 0)) > 0) - { - p[count] = '\0'; - len += count; - p += count; - char *nl; - if ((nl = strchr (line, '\n')) == 0) - continue; - - // At this point we have a 0-terminated string with a newline ending - // the command line. Break out and process the command. - break; - } - if (count <= 0) - return -1; // Relay closed/error socket to caller - - char *cmd = strtok (line, "\t \n\r"); - if (cmd == 0) - { - char err[1024]; - sprintf (err, "Can't parse input: %s\n", line); - this->reply (err); - return -1; - } - // Which command is it? These commands are known: - // - // run <test-dll> [args] - // Run test in the named test-dll; respond with "OK" or an error string. - // status - // If test still running return "RUNNING" else return exit status. - // wait - // Wait for test to exit; return "OK" - // kill - // Kill the thread with the most recent test; return "OK". - // snaplog - // Take a snapshot of the current stdout/stderr log to a new file - // name and reset the stdout/stderr log. - if (strcmp ("run", cmd) == 0) - { - char *test = strtok (0, "\t \n\r"); - if (test == 0) - { - this->reply ("Malformed run command\n"); - return -1; - } - // start() pulls apart the rest of the command line... - const char *errmsg = this->test_.start (test); - if (errmsg == 0) - this->reply ("OK\n"); - else - this->reply (errmsg); - } - else if (strcmp ("status", cmd) == 0) - { - int status; - if (this->test_.status (&status)) - { - char retvalmsg[64]; - sprintf (retvalmsg, "%d\n", status); - this->reply (retvalmsg); - } - else - this->reply ("RUNNING\n"); - } - else if (strcmp ("wait", cmd) == 0) - { - int status = this->test_.wait (); - char retvalmsg[64]; - sprintf (retvalmsg, "%d\n", status); - this->reply (retvalmsg); - } - else if (strcmp ("kill", cmd) == 0) - { - // Killing things is bad... say we can't and the host should reboot us. - this->reply ("NO - please reboot me\n"); - } - else if (strcmp ("waitforfile", cmd) == 0) - { - char *name = strtok (0, "\t \n\r"); - if (name == 0) - { - this->reply ("Malformed waitforfile command\n"); - return -1; - } - char *secs_s = strtok (0, "\t \n\r"); - int secs = 0; - if (secs_s == 0 || (secs = atoi (secs_s)) <= 0) - { - this->reply ("Malformed waitforfile command\n"); - return -1; - } - struct _stat info; - const char *msg = 0; - bool found = false; - while (secs > 0) - { - if (_stat (name, &info) == -1) // No file yet - { - if (errno != ENOENT) - { - // Something more serious than no file yet; bail out. - msg = format_errmsg (errno, name); - break; - } - } - else - { - if (info.st_size > 0) - { - found = true; - break; - } - } - // Either no file yet, or it's there but with no content yet. - Sleep (1 * 1000); // arg is in msec - --secs; - } - if (found) - this->reply ("OK\n"); - else if (secs == 0) - this->reply ("TIMEOUT\n"); - else - this->reply (msg); - } - else if (strcmp ("snaplog", cmd) == 0) - { - if (logf == INVALID_HANDLE_VALUE) - { - this->reply ("NONE\n"); - } - else - { - CloseHandle (logf); - if (0 == rename (LogName, "snapshot.txt")) - { - char abspath[1024]; - if (_fullpath (abspath, "snapshot.txt", 1024)) - { - strcat (abspath, "\n"); - this->reply (abspath); - } - else - { - // Last ditch effort to get a name back to the client - this->reply ("\\ni-rt\\system\\snapshot.txt\n"); - } - } - else - { - this->reply ("NONE\n"); - } - // Reset stdout/stderr to a new file - logf = CreateFile (LogName, - FILE_ALL_ACCESS, - FILE_SHARE_READ, - 0, // security - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - 0); - SetStdHandle (STD_OUTPUT_HANDLE, logf); - SetStdHandle (STD_ERROR_HANDLE, logf); - } - } - else - { - this->reply ("Unrecognized command\n"); - return -1; - } - return 0; -} - -int -Peer::reply (const char *msg) -{ - int len = (int)strlen (msg); // size_t -> int - return send (this->handle_, msg, len, 0) > 0 ? 0 : -1; -} - -Test::~Test () -{ - this->cleanup (); -} - -int -Test::run (void) -{ - this->running_ = true; - this->status_ = (this->entry_) (this->argc_, this->argv_); - this->running_ = false; - // It's possible to cleanup() here; however, that would introduce a race - // with start() following beginthreadex(). So do all the cleanup on user - // action - either getting status, waiting, killing, or running another - // test. Or, terminating the connection. - return 0; -} - -const char * -Test::start (const char *name) -{ - if (this->running_) - return "Already running\n"; - - const char *msg = 0; - - // Reset test status to not inadvertantly report a previous test. - this->status_ = -1; - this->cleanup (); // Resets cmdline_, argc_, argv_ - - // The command line is part-way through being tokenized by strtok(). It - // left off after the program name. Anything remaining are the command - // line arguments for the program. Pick off whatever is there, copy it - // to the cmdline_ array and fill in argc_/argv_ for the eventual run. - strcpy (this->name_, name); - this->argv_[0] = this->name_; - this->argc_ = 1; - size_t cmdchars = 0; - for (char *token = strtok (0, "\t \n\r"); - token != 0 && (cmdchars + strlen (token) + 1) < CMDLINE_LEN; - token = strtok (0, "\t \n\r")) - { - // We have a new token and it will fit in cmdline_. Copy it to the - // next spot in cmdline_, add it to argv_/argc_ then update cmdchars - // to account for the copied-in token and its nul terminator. - strcpy (&this->cmdline_[cmdchars], token); - this->argv_[this->argc_] = &this->cmdline_[cmdchars]; - ++this->argc_; - cmdchars += (strlen (token) + 1); - } - char libspec[1024]; - sprintf (libspec, "%s.dll", name); - if ((this->dll_handle_ = LoadLibrary (libspec)) == NULL) - return format_errmsg (GetLastError (), libspec); - - this->entry_ = (TEST_FUNC) GetProcAddress (this->dll_handle_, "main"); - if (this->entry_ == NULL) - { - msg = format_errmsg (GetLastError (), "main"); - this->cleanup (); - return msg; - } - else - { - unsigned int thread_id; /* unused */ - uintptr_t h = _beginthreadex (0, // security - 1024 * 1024, // stack size - run_test, // entrypoint - (void *)this, // arglist - 0, // initflag - &thread_id); // thread ID - this->thr_handle_ = (HANDLE) h; - if (h == 0) // Test thread may have access to thr_handle_ - { - msg = format_errmsg (GetLastError (), "spawn"); - this->cleanup (); - return msg; - } - } - return 0; -} - -bool -Test::status (int *exit_status) -{ - if (this->running_) - return false; // still running - - *exit_status = this->status_; - this->cleanup (); - return true; -} - -int -Test::wait (void) -{ - WaitForSingleObject (this->thr_handle_, INFINITE); - if (!this->running_) - this->cleanup (); - return this->status_; -} - -void -Test::kill (void) -{ - TerminateThread (this->thr_handle_, -1); - this->cleanup (); - this->running_ = false; - this->status_ = -1; -} - -// Clean up remnants of a test run. -void -Test::cleanup (void) -{ - if (this->dll_handle_ != NULL) - { - FreeLibrary (this->dll_handle_); - this->dll_handle_ = NULL; - } - if (this->thr_handle_ != 0) - { - CloseHandle (this->thr_handle_); - this->thr_handle_ = 0; - } - this->entry_ = 0; - this->argc_ = 0; - for (int i = 0; i < ARGV_SIZE; ++i) - this->argv_[i] = 0; - memset (this->cmdline_, 0, CMDLINE_LEN); -} - -static unsigned int __stdcall -test_control (void * /* param */) -{ - // cd to ace dir?? (can this be an env variable?) - - // redirect stdout/stderr to a file - logf = CreateFile (LogName, - FILE_ALL_ACCESS, - FILE_SHARE_READ, - 0, // security - OPEN_ALWAYS, // Don't crush a previous one - FILE_ATTRIBUTE_NORMAL, - 0); - if (logf == INVALID_HANDLE_VALUE) - perror (LogName); - else - { - SetFilePointer (logf, 0, 0, FILE_END); // Append new content - SetStdHandle (STD_OUTPUT_HANDLE, logf); - SetStdHandle (STD_ERROR_HANDLE, logf); - } - - WORD want; - WSADATA offer; - want = MAKEWORD (2, 2); - if (0 != WSAStartup (want, &offer)) - { - perror ("WSAStartup"); - CloseHandle (logf); - return WSAGetLastError (); - } - - // listen on port 8888 (can I set an env variable for this?) - SOCKET acceptor = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP); - sockaddr_in listen_addr; - memset (&listen_addr, 0, sizeof (listen_addr)); - listen_addr.sin_family = AF_INET; - listen_addr.sin_addr.s_addr = INADDR_ANY; - listen_addr.sin_port = htons (8888); - if (SOCKET_ERROR == bind (acceptor, - (struct sockaddr *)&listen_addr, - sizeof (listen_addr))) - { - perror ("bind"); - } - else - { - listen (acceptor, 10); - SOCKET peer; - while ((peer = accept (acceptor, 0, 0)) != INVALID_SOCKET) - { - Peer *p = new Peer (peer); - if (p == 0) - { - perror ("Out of memory"); - closesocket (peer); - peer = INVALID_SOCKET; - continue; - } - if (0 == _beginthreadex (0, // security - 64 * 1024, // stack size - peer_svc, // entrypoint - (void *)p, // param - 0, // creation flags - 0)) // ptr to thread id - { - perror ("beginthreadex peer"); - closesocket (peer); - delete p; - } - p = 0; - peer = INVALID_SOCKET; - } - perror ("accept"); - } - - closesocket (acceptor); - WSACleanup (); - return 0; -} - -// Entrypoint for thread that's spawned to run a peer's session. Direct -// control to the peer class. -static unsigned int __stdcall -peer_svc (void *peer_p) -{ - Peer *p = (Peer *)peer_p; - DWORD status = p->svc (); - delete p; - return status; -} - -// Entrypoint for the thread spawned to run a test. The thread arg is the -// Test * - call back to the test's run() method; return the test exit code -// as the thread's return value. -static unsigned int __stdcall -run_test (void *test_p) -{ - Test *t = (Test *)test_p; - return t->run (); -} - -// Format a Windows system or Winsock error message given an error code. -static const char * -format_errmsg (unsigned int errcode, const char *prefix) -{ - static const size_t errmsgsize = 1024; - static char errmsg[errmsgsize]; - - sprintf (errmsg, "%s: ", prefix); - size_t len = strlen (errmsg); - char *next = &errmsg[len]; - size_t max_fmt = errmsgsize - len; - if (0 != FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - 0, - errcode, - 0, // Use default language - next, - (DWORD)max_fmt, - 0)) - { - strcat (errmsg, "\n"); - return errmsg; - } - - errno = errcode; - char *msg = _strerror (prefix); - sprintf (errmsg, "err %d: %s", errcode, msg); - return errmsg; -} - -#ifdef TEST_RUNNER_EXPORTS -#define TEST_RUNNER_API __declspec(dllexport) -#else -#define TEST_RUNNER_API __declspec(dllimport) -#endif - -__declspec(dllexport) int test_entry(void) -{ - return 0; -} |