From b56562693a88f88e7c290de9e1dc18d96a0da792 Mon Sep 17 00:00:00 2001 From: Gabriel Dos Reis Date: Mon, 2 Jan 2017 14:03:55 -0800 Subject: Include a native entry point for parsing Boot source files, and for transpiling to Lisp. --- src/lib/Makefile.in | 25 +- src/lib/bsdsignal.c | 65 --- src/lib/bsdsignal.cxx | 65 +++ src/lib/cfuns-c.c | 914 ---------------------------------- src/lib/cfuns-c.cxx | 914 ++++++++++++++++++++++++++++++++++ src/lib/sockio-c.c | 1307 ------------------------------------------------- src/lib/sockio-c.cxx | 1307 +++++++++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 2304 insertions(+), 2293 deletions(-) delete mode 100644 src/lib/bsdsignal.c create mode 100644 src/lib/bsdsignal.cxx delete mode 100644 src/lib/cfuns-c.c create mode 100644 src/lib/cfuns-c.cxx delete mode 100644 src/lib/sockio-c.c create mode 100644 src/lib/sockio-c.cxx (limited to 'src/lib') diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in index 7a8d4609..aeecfabf 100644 --- a/src/lib/Makefile.in +++ b/src/lib/Makefile.in @@ -1,4 +1,4 @@ -# Copyright (C) 2007-2016, Gabriel Dos Reis. +# Copyright (C) 2007-2017, Gabriel Dos Reis. # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -31,7 +31,14 @@ -core_SOURCES = bsdsignal.c cfuns-c.c sockio-c.c +core_SOURCES = \ + bsdsignal.cxx \ + cfuns-c.cxx \ + sockio-c.cxx \ + ../io/std-streams.cxx \ + ../io/InputFragment.cxx \ + ../syntax/token.cxx \ + ../syntax/Parser.cxx terminal_io_SOURCES = cursor.c edin.c fnct_key.c openpty.c prt.c wct.c @@ -52,9 +59,9 @@ unused_SOURCES = emupty.c libopen_axiom_core_SOURCES = $(core_SOURCES) ifeq (@oa_use_libtool_for_shared_lib@,no) -libopen_axiom_core_objects = $(libopen_axiom_core_SOURCES:.c=.$(OBJEXT)) +libopen_axiom_core_objects = $(libopen_axiom_core_SOURCES:.cxx=.$(OBJEXT)) else -libopen_axiom_core_objects = $(libopen_axiom_core_SOURCES:.c=.lo) +libopen_axiom_core_objects = $(libopen_axiom_core_SOURCES:.cxx=.lo) endif libspad_objects = $(libspad_SOURCES:.c=.lo) @@ -67,7 +74,7 @@ subdir = src/lib/ .PHONY: all all-lib .SUFFIXES: -.SUFFIXES: .o .lib .obj .c .h +.SUFFIXES: .o .lib .obj .c .h .cxx all: all-ax @@ -90,14 +97,18 @@ $(oa_target_libdir)/$(oa_shrlib_prefix)open-axiom-core$(SHREXT): \ $(libopen_axiom_core_objects) \ @oa_c_runtime_extra@ -lm -libopen-axiom-core.$(LIBEXT): $(libopen_axiom_core_SOURCES:.c=.lo) - $(LINK) -o $@ $(libopen_axiom_core_SOURCES:.c=.lo) +libopen-axiom-core.$(LIBEXT): $(libopen_axiom_core_SOURCES:.cxx=.lo) + $(LINK) -o $@ $(libopen_axiom_core_SOURCES:.cxx=.lo) libspad.$(LIBEXT): $(libspad_objects) $(LINK) -o $@ $(libspad_objects) .PRECIOUS: %.$(OBJEXT) +%.$(OBJEXT) %.lo: %.cxx $(oa_c_macros_h) + $(COMPILE) $(oa_shrobj_flags) -no-suppress -o $@ $(CFLAGS) \ + $(oa_includes) $(AXIOM_X11_CFLAGS) $< + %.$(OBJEXT) %.lo: %.c $(oa_c_macros_h) $(COMPILE) $(oa_shrobj_flags) -no-suppress -o $@ $(CFLAGS) \ $(oa_includes) $(AXIOM_X11_CFLAGS) $< diff --git a/src/lib/bsdsignal.c b/src/lib/bsdsignal.c deleted file mode 100644 index 07fc6b54..00000000 --- a/src/lib/bsdsignal.c +++ /dev/null @@ -1,65 +0,0 @@ -/* - Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. - All rights reserved. - Copyright (C) 2007-2010, Gabriel Dos Reis. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - - Neither the name of The Numerical ALgorithms Group Ltd. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "openaxiom-c-macros.h" -#include -#include "bsdsignal.h" - -OPENAXIOM_C_EXPORT SignalHandlerFunc -bsdSignal(int sig, SignalHandlerFunc action, int restartSystemCall) -{ -#if HAVE_DECL_SIGACTION - - struct sigaction in,out; - in.sa_handler = action; - /* handler is reinstalled - calls are restarted if restartSystemCall */ -#ifdef SA_RESTART - if(restartSystemCall) in.sa_flags = SA_RESTART; - else in.sa_flags = 0; -#elif defined(SA_INTERRUPT) - if (restartSystemCall) in.sa_flags = 0; - else in.sa_flags = SA_INTERRUPT; -#else - in.sa_flags = 0; -#endif - - return (sigaction(sig, &in, &out) ? (SignalHandlerFunc) -1 : - (SignalHandlerFunc) out.sa_handler); -#else /* !HAVE_DECL_SIGACTION */ - return (SignalHandlerFunc) -1; -#endif /* HAVE_DECL_SIGACTION */ -} - - diff --git a/src/lib/bsdsignal.cxx b/src/lib/bsdsignal.cxx new file mode 100644 index 00000000..07fc6b54 --- /dev/null +++ b/src/lib/bsdsignal.cxx @@ -0,0 +1,65 @@ +/* + Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd. + All rights reserved. + Copyright (C) 2007-2010, Gabriel Dos Reis. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + - Neither the name of The Numerical ALgorithms Group Ltd. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "openaxiom-c-macros.h" +#include +#include "bsdsignal.h" + +OPENAXIOM_C_EXPORT SignalHandlerFunc +bsdSignal(int sig, SignalHandlerFunc action, int restartSystemCall) +{ +#if HAVE_DECL_SIGACTION + + struct sigaction in,out; + in.sa_handler = action; + /* handler is reinstalled - calls are restarted if restartSystemCall */ +#ifdef SA_RESTART + if(restartSystemCall) in.sa_flags = SA_RESTART; + else in.sa_flags = 0; +#elif defined(SA_INTERRUPT) + if (restartSystemCall) in.sa_flags = 0; + else in.sa_flags = SA_INTERRUPT; +#else + in.sa_flags = 0; +#endif + + return (sigaction(sig, &in, &out) ? (SignalHandlerFunc) -1 : + (SignalHandlerFunc) out.sa_handler); +#else /* !HAVE_DECL_SIGACTION */ + return (SignalHandlerFunc) -1; +#endif /* HAVE_DECL_SIGACTION */ +} + + diff --git a/src/lib/cfuns-c.c b/src/lib/cfuns-c.c deleted file mode 100644 index 11c28691..00000000 --- a/src/lib/cfuns-c.c +++ /dev/null @@ -1,914 +0,0 @@ -/* - Copyright (C) 1991-2002, The Numerical Algorithms Group Ltd. - All rights reserved. - - Copyright (C) 2007-2013, Gabriel Dos Reis. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - - Neither the name of The Numerical Algorithms Group Ltd. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#include "openaxiom-c-macros.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -#ifdef OPENAXIOM_MS_WINDOWS_HOST -# include -#else -# include -# include -#endif - -#include "cfuns.h" - -/* Most versions of Windows don't have the POSIX functions getuid(), - geteuid(), getgid(), and getegid(). The following definitions are - approximations, to patch for the deficiencies of Windows - POSIX interface. */ - -#if !HAVE_DECL_GETUID -# define getuid() 0 -#endif - -#if !HAVE_DECL_GETGID -# define getgid() 0 -#endif - -#if !HAVE_DECL_GETEUID -# define geteuid() getuid() -#endif - -#if !HAVE_DECL_GETEGID -# define getegid() getgid() -#endif - -namespace OpenAxiom { - // Make a copy of string data on free store. - static char* - copy_c_str(const std::string& s) { - return strdup(s.c_str()); - } - -OPENAXIOM_C_EXPORT int -addtopath(char *dir) -{ - char *path, *newpath; - - path = oa_getenv("PATH"); - if (path == NULL) - return -1; - - newpath = (char *) malloc(1 + strlen(path) + strlen(dir) + strlen("PATH=:")); - if (newpath == NULL) - return -1; - - sprintf(newpath, "PATH=%s:%s", path, dir); - - return putenv(newpath); -} - - - -/* Returns 1 if `c' designates a path separator, 0 otherwise. */ -static inline int -openaxiom_is_path_separator(char c) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return c == '\\' || c == '/'; -#else - return c == '/'; -#endif -} - -/* - Returns a the dirname of `path'. If `path' has no separator, then - returns ".". The returned value if malloc-allocated. */ - -OPENAXIOM_C_EXPORT char* -oa_dirname(const char* path) -{ - const int n = strlen(path); - const char* mark = path + n; - - if (n == 0) - return strdup("."); - else if (n == 1 && openaxiom_is_path_separator(*path)) - return strdup("/"); - - /* For "/banana/space/", we want "/banana". */ - if (openaxiom_is_path_separator(*--mark)) - --mark; - while (path < mark && !openaxiom_is_path_separator(*mark)) - --mark; - - if (path == mark) - return strdup(openaxiom_is_path_separator(*path) ? "/" : "."); - else { - const int l = mark - path; - char* dir = (char*) malloc(l + 1); - memcpy(dir, path, l); - dir[l] = '\0'; - return dir; - } -} - -/* - * Test whether the path is the name of a directory. Returns 1 if so, 0 if - * not, -1 if it doesn't exist. - */ - - -OPENAXIOM_C_EXPORT int -directoryp(char *path) -{ - struct stat buf; - int code = stat(path, &buf); - - return code == -1 ? -1 : S_ISDIR(buf.st_mode); -} - -OPENAXIOM_C_EXPORT int -make_path_from_file(char *s, char *t) -{ - char *pos = NULL; - char *c; - - /** simply copies the path name from t into s **/ - for (c = t + strlen(t); c != s; c--) - if (*c == '/') { - pos = c; - break; - } - /** Check to see if the path was actually present **/ - if (c == t) { /** No Path, so return the pwd **/ - return (-1); - } - /** now just do the copying **/ - strncpy(s, t, pos - t); - return 1; -} - -/* The functions writeablep() and readablep() determine write and - read access of a file designated by its name. The function - axiom_has_write_access is a sub-routine of writeablep. - - The access is determined based on the POSIX semantics; see - "Advanced Programming in the UNIX Environement", section 4.5. - - 1. If the effective user ID of the process is 0 (the superuser), - access is allowed. This gives the superuser free rein throughout - the entire file system. - - 2. If the effective user ID of the process equals the owner ID of - the file (i.e., the process owns the file), access is allowed - if the appropriate user access permission bit is set. [...] - - 3. If the effective group ID of the process or one of the - supplementary group IDs of the process equals the group ID - of the file, access is allowed if the appropriate - group access permission bit is set. Otherwise, permission - is denied. - - 4. If the appropriate other access permission bit is set, access is - allowed. Otherwise, permission is defined. */ - - -/* Return 1 if the process has write access of file as explained above. - Otherwise, return 0. */ - -static inline int -axiom_has_write_access(const struct stat* file_info) -{ - uid_t effetive_uid = geteuid(); - - if (effetive_uid == 0) - return 1; - - if (effetive_uid == file_info->st_uid) - return (file_info->st_mode & S_IWUSR) ? 1 : 0; - -#ifdef S_IWGRP - if (getegid() == file_info->st_gid) - return (file_info->st_mode & S_IWGRP) ? 1 : 0; -#endif - -#ifdef S_IWOTH - return (file_info->st_mode & S_IWOTH) ? 1 : 0; -#else - return 0; -#endif -} - - -/* Return - -1 if the file designated by PATH is inexistent. - 0 if the file exists but write access is denied. - 1 if the file exists and process has write access. - 2 if the file does not exists but process has write - has write access to the dirname of path. */ - -OPENAXIOM_C_EXPORT int -writeablep(const char *path) -{ - struct stat buf; - int code; - - code = stat(path, &buf); - if (code == -1) { - /* The file does not exist, so check to see if the directory - is writable. */ - char* dir = oa_dirname(path); - code = stat(dir, &buf); - /* FIXME: Work around MinGW/MSYS bug. - The string pointed to by `dir' was strdup'd. According to - the C standard, that means the the string was allocated - by `malloc', therefore can be disposed of by `free'. However, - the MinGW/MSYS port appears to use MS' StrDup as the real - worker. Consequently, the guarantee that the the string can - free'd no longer holds. We have to use MS's LocalFree. */ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - LocalFree(dir); -#else - free(dir); -#endif - return (code == 0) && axiom_has_write_access(&buf) ? 2 : -1; - } - - return axiom_has_write_access(&buf); -} - - -/* Return - -1 if the file designated by PATH is inexistent. - 0 if the file exists but process has no read access. - 1 if the file exists and read access is granted. */ - -OPENAXIOM_C_EXPORT int -readablep(const char *path) -{ - struct stat buf; - int code; - - code = stat(path, &buf); - if (code == -1) - return -1; - - if (geteuid() == buf.st_uid) - return ((buf.st_mode & S_IREAD) != 0); - -#ifdef S_IRGRP - if (getegid() == buf.st_gid) - return ((buf.st_mode & S_IRGRP) != 0); -#endif - -#ifdef S_IROTH - return ((buf.st_mode & S_IROTH) != 0); -#else - return 0; -#endif -} - - - -OPENAXIOM_C_EXPORT long -findString(char *file, char *string) -{ - int nstring, charpos; - FILE *fn; - char buffer[1024]; - - if ((fn = fopen(file, "r")) == NULL) - return -1; - - for (charpos = 0, nstring = strlen(string); - fgets(buffer, sizeof buffer, fn) != NULL; - charpos += strlen(buffer) - ) - if (!strncmp(buffer, string, nstring)) - return charpos; - return -1; - -} - -OPENAXIOM_C_EXPORT int -copyEnvValue(char *varName, char *buffer) -{ - char *s; - - s = oa_getenv(varName); - if (s == NULL) - return 0; - strcpy(buffer, s); - return strlen(s); -} - -/* Return 1 if the file descriptor FD, as viewed by the Core Executable, - is attached to a terminal. */ -OPENAXIOM_C_EXPORT int -std_stream_is_terminal(int fd) -{ - assert(fd > -1 && fd < 3); -#ifdef OPENAXIOM_MS_WINDOWS_HOST - DWORD handle; - switch (fd) { - case 0: handle = STD_INPUT_HANDLE; break; - case 1: handle = STD_OUTPUT_HANDLE; break; - case 2: handle = STD_ERROR_HANDLE; break; - /* Next code is never executed but it makes the compiler happy. */ - default: return 0; - } - /* The MS documentation suggests `GetFileType' for determining - the nature of the file handle. The return value, in our case, - is an over approximation of what we are interested in: Are we - dealing with a stream connected to a terminal? The constant - FILE_TYPE_CHAR characterises character files; in particular - a console terminal, or a printer. There is an undocumented - function `VerifyConsoleIoHandle' to deal precisely with the case - we are interested in. However, while availale in Wine, it is - not available in the MinGW headers. Consequently, we cannot - rely on it for the moment. - So, we may still get garbage out of this function on MS platforms. */ - return GetFileType(GetStdHandle(handle)) == FILE_TYPE_CHAR; -#else - return isatty(fd); -#endif -} - -/* Change the process' curretnt directory. Return zero on success, - and -1 on failure. */ -OPENAXIOM_C_EXPORT int -oa_chdir(const char* path) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return SetCurrentDirectory(path) ? 0 : -1; -#else - return chdir(path); -#endif /* OPENAXIOM_MS_WINDOWS_HOST */ -} - - -/* return true if path is `.' or `..'. */ -static inline int -is_dot_or_dotdot(const char* path) -{ - return strcmp(path, ".") == 0 || strcmp(path, "..") == 0; -} - -/* Remove a directory entry. Files are removed, directories are - recursively walked and removed. - Return 0 on success, and -1 on falure. - In practice, OpenAxiom does not remove directories with - non-trivial recursive structues. */ -OPENAXIOM_C_EXPORT int -oa_unlink(const char* path) -{ - const char* curdir; - int status = -1; -#ifdef OPENAXIOM_MS_WINDOWS_HOST - WIN32_FIND_DATA findData; - HANDLE walkHandle; - - if (is_dot_or_dotdot(path)) - return -1; - - walkHandle = FindFirstFile(path, &findData); - if (walkHandle == INVALID_HANDLE_VALUE) - return -1; - - /* Remember where we are so we can return back properly. */ - curdir = oa_getcwd(); - - do { - if (is_dot_or_dotdot(findData.cFileName)) - continue; - if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { - if ((status = oa_chdir(findData.cFileName)) < 0) - goto sortie; - if ((status = oa_unlink("*")) < 0) - goto sortie; - if ((status = oa_chdir("..")) < 0) - goto sortie; - if(!RemoveDirectory(findData.cFileName)) { - status = -1; - goto sortie; - } - } - else if (!DeleteFile(findData.cFileName)) { - status = -1; - goto sortie; - } - status = 0; - } while (FindNextFile(walkHandle, &findData)); - if (!FindClose(walkHandle)) { - status = -1; - goto sortie; - } -#else - struct stat pathstat; - DIR* dir; - struct dirent* entry; - - /* Don't ever try to remove `.' or `..'. */ - if (is_dot_or_dotdot(path)) - return -1; - - if (stat(path, &pathstat) < 0) - return -1; - - /* handle non directories first. */ - if (!S_ISDIR(pathstat.st_mode)) - return unlink(path); - - /* change into the path so that we don't have to form full - pathnames. */ - curdir = oa_getcwd(); - if ((dir = opendir(path)) == NULL || oa_chdir(path) < 0) - goto sortie; - - while (errno = 0, (entry = readdir(dir)) != NULL) { - struct stat s; - if (is_dot_or_dotdot(entry->d_name)) - continue; - if ((status = stat(entry->d_name, &s)) < 0) - goto sortie; - if (S_ISDIR(s.st_mode)) { - if ((status = oa_unlink(entry->d_name)) < 0) - goto sortie; - } - else if ((status = unlink(entry->d_name)) < 0) - goto sortie; - } - if (errno != 0) { - status = -1; - goto sortie; - } - - /* Now, get one level up, and remove the empty directory. */ - if (oa_chdir("..") < 0 || closedir(dir) < 0 || rmdir(path) < 0) - status = -1; - else - status = 0; -#endif /* OPENAXIOM_MS_WINDOWS_HOST */ - - sortie: - oa_chdir(curdir); - free((char*) curdir); - return status; -} - -OPENAXIOM_C_EXPORT const char* -oa_acquire_temporary_pathname() { -#if OPENAXIOM_MS_WINDOWS_HOST - char buf[MAX_PATH]; - const char* tmpdir = oa_get_tmpdir(); - auto n = GetTempFileName(tmpdir, "oa-", random() % SHRT_MAX, buf); - /* tmpdir was malloc()ed when OPENAXIOM_MS_WINDOWS_HOST. */ - free(const_cast(tmpdir)); - if (n == 0) { - perror("oa_acquire_temporary_pathname"); - exit(1); - } - return strdup(buf); -#elif HAVE_DECL_MKTEMP - return mktemp(copy_c_str(std::string{ oa_get_tmpdir() } + "/oa-XXXXXX")); -#elif HAVE_DECL_TEMPNAM - return tempnam(oa_get_tmpdir(), "oa-"); -#else - return copy_c_str("oa-" + std::to_string(random())); -#endif -} - -OPENAXIOM_C_EXPORT void -oa_release_temporary_pathname(const char* s) -{ - free(const_cast(s)); // yuck! -} - -/* Rename a file or directory. */ -OPENAXIOM_C_EXPORT int -oa_rename(const char* old_path, const char* new_path) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return MoveFile(old_path, new_path) ? 0 : -1; -#else - return rename(old_path, new_path); -#endif -} - -/* Create a new directory named `path'. Return 0 on success, - and -1 on failure. */ -OPENAXIOM_C_EXPORT int -oa_mkdir(const char* path) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return CreateDirectory(path, NULL) ? 0 : -1; -#else -# define DIRECTORY_PERM ((S_IRWXU|S_IRWXG|S_IRWXO) & ~(S_IWGRP|S_IWOTH)) - return mkdir (path, DIRECTORY_PERM); -# undef DIRECTORY_PERM -#endif -} - -/* Run a shell command. Effectively forward to C's system(). */ -OPENAXIOM_C_EXPORT int -oa_system(const char* cmd) -{ - return system(cmd); -} - -OPENAXIOM_C_EXPORT int -oa_getpid(void) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return GetCurrentProcessId(); -#else - return getpid(); -#endif -} - -/* Concatenate two strings and return a pointer to the - newly allocate resulting string. */ -OPENAXIOM_C_EXPORT const char* -oa_concatenate_string(const char* lhs, const char* rhs) -{ - if (lhs == NULL) - return rhs; - else if (rhs == NULL) - return lhs; - else { - const int lhs_length = strlen(lhs); - char* result = (char*) malloc(lhs_length + strlen(rhs) + 1); - strcpy(result, lhs); - strcpy(result + lhs_length, rhs); - return result; - } -} - -/* Return a string object that is the result of catenating the strings - designated by `left' and `right'. */ -OPENAXIOM_C_EXPORT const char* -oa_strcat(const char* left, const char* right) -{ - int left_size = strlen(left); - int right_size = strlen(right); - int size = left_size + right_size; - char* buffer = (char*) malloc(size + 1); - - memcpy(buffer, left, left_size); - memcpy(buffer + left_size, right, right_size); - buffer[size] = '\0'; - return buffer; -} - -/* Return the value of an environment variable. */ -OPENAXIOM_C_EXPORT char* -oa_getenv(const char* var) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST -#define BUFSIZE 128 - char* buf = (char*) malloc(BUFSIZE); - int len = GetEnvironmentVariable(var, buf, BUFSIZE); - if (len == 0) { - free(buf); - return NULL; - } - else if (len > BUFSIZE) { - buf = (char*) realloc(buf,len); - len = GetEnvironmentVariable(var, buf, len); - if (len == 0) { - free(buf); - return NULL; - } - } - return buf; -#else - return getenv(var); -#endif -} - -/* Set the value of environment variable VAR to VAL. - Return 1 on success, and 0 otherwise. */ -OPENAXIOM_C_EXPORT int -oa_setenv(const char* var, const char* val) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return SetEnvironmentVariable(var, val); -#elif HAVE_DECL_SETENV - return !setenv(var, val, true); -#else - const int var_length = strlen(var); - const int val_length = strlen(val); - char* str = (char*) malloc(var_length + 1 + val_length + 1); - strcpy(str, var); - str[var_length] = '='; - strcpy(str + var_length + 1, val); - str[var_length + 1 + val_length] = '\0'; - return !putenv(str); -#endif -} - - -OPENAXIOM_C_EXPORT char* -oa_getcwd(void) -{ - size_t bufsz = 256; - char* buf = (char*) malloc(bufsz); -#ifdef OPENAXIOM_MS_WINDOWS_HOST - DWORD n = GetCurrentDirectory(bufsz, buf); - if (n == 0) { - perror("oa_getcwd"); - exit(-1); - } - else if (n > bufsz) { - buf = (char*) realloc(buf,n); - if (GetCurrentDirectory(n, buf) != n) { - perror("oa_getcwd"); - exit(-1); - } - } - return buf; -#else /* OPENAXIOM_MS_WINDOWS_HOST */ - errno = 0; - while (getcwd(buf,bufsz) == 0) { - if (errno == ERANGE) { - errno = 0; - bufsz *= 2; - buf = (char*) realloc(buf, bufsz); - } - else { - perror("oa_getcwd"); - exit(-1); - } - } - return buf; -#endif -} - -OPENAXIOM_C_EXPORT int -oa_access_file_for_read(const char* path) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES ? -1 : 1; -#else - return access(path, R_OK); -#endif -} - - -OPENAXIOM_C_EXPORT const char* -oa_get_tmpdir(void) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - char* buf; - /* First, probe. */ - int bufsz = GetTempPath(0, NULL); - if (bufsz == 0) { - perror("oa_get_tmpdir"); - exit(1); - } - else { - int new_size; - buf = (char*) malloc(bufsz + 1); - new_size = GetTempPath(bufsz, buf); - if(new_size == 0 || new_size >= bufsz) { - perror("oa_get_tmpdir"); - free(buf); - exit(1); - } - buf[new_size] = '\0'; - } - return buf; -#else - return "/tmp"; -#endif -} - - -OPENAXIOM_C_EXPORT int -oa_copy_file(const char* src, const char* dst) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - return CopyFile(src,dst, /* bFailIfExists = */ 0) ? 0 : -1; -#else -#define OA_BUFSZ 512 -#define OA_DEFAULT_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) - char buf[OA_BUFSZ]; - int src_fd; - int dst_fd; - int count; - if((src_fd = open(src, O_RDONLY)) < 0) - return -1; - if ((dst_fd = creat(dst, OA_DEFAULT_MODE)) < 0) { - close(src_fd); - return -1; - } - - while ((count = read(src_fd, buf, OA_BUFSZ)) > 0) - if (write(dst_fd, buf, count) != count) - break; - -#undef OA_DEFAULT_MODE -#undef OA_BUFSZ - return (close(dst_fd) < 0 || close(src_fd) < 0 || count < 0) ? -1 : 0; -#endif -} - - -OPENAXIOM_C_EXPORT double -plus_infinity(void ) -{ -#ifdef INFINITY - return INFINITY; -#else - /* This must be a curious platform. */ - volatile double zero = 0.0; - return 1.0 / zero; /* If it traps, well, it traps. */ -#endif -} - -OPENAXIOM_C_EXPORT double -minus_infinity(void) -{ - return -plus_infinity(); -} - -OPENAXIOM_C_EXPORT double -quiet_double_NaN(void) -{ -#ifdef NAN - return NAN; -#else - return sqrt(-1.0); /* Just pick one. */ -#endif -} - - -OPENAXIOM_C_EXPORT Byteorder -oa_get_host_byteorder(void) -{ -#ifdef WORDS_BIGENDIAN - return Byteorder::big; -#else - return Byteorder::little; -#endif -} - - -OPENAXIOM_C_EXPORT void -oa_allocate_process_argv(Process* proc, int argc) -{ - proc->argc = argc; - proc->argv = (char**) malloc((1 + argc) * sizeof (char*)); - proc->argv[argc] = NULL; -} - -OPENAXIOM_C_EXPORT int -oa_spawn(Process* proc, SpawnFlags flags) -{ -#ifdef OPENAXIOM_MS_WINDOWS_HOST - const char* path = NULL; - char* cmd_line = NULL; - int curpos = strlen(proc->argv[0]); - int cmd_line_length = curpos; - int i; - PROCESS_INFORMATION proc_info; - STARTUPINFO startup_info = { 0 }; - DWORD status; - - for (i = 0; i < proc->argc; ++i) - cmd_line_length += 1 + strlen(proc->argv[i]); - - cmd_line = (char*) malloc(cmd_line_length + 1); - strcpy(cmd_line, proc->argv[0]); - for (i = 0; i < proc->argc; ++i) { - cmd_line[curpos++] = ' '; - strcpy(cmd_line + curpos, proc->argv[i]); - curpos += strlen(proc->argv[i]); - } - cmd_line[curpos] = '\0'; - - if ((flags & SpawnFlags::search_path) == 0) - path = proc->argv[0]; - - if(CreateProcess(/* lpApplicationName */ path, - /* lpCommandLine */ cmd_line, - /* lpProcessAttributes */ NULL, - /* lpThreadAttributes */ NULL, - /* bInheritHandles */ TRUE, - /* dwCreationFlags */ 0, - /* lpEnvironment */ NULL, - /* lpCurrentDirectory */ NULL, - /* lpstartupInfo */ &startup_info, - /* lpProcessInformation */ &proc_info) == 0) { - fprintf(stderr, "oa_spawn: error %lu\n", GetLastError()); - return proc->id = -1; - } - proc->id = proc_info.dwProcessId; - if ((flags & SpawnFlags::replace) == 0) - return proc->id; - WaitForSingleObject(proc_info.hProcess, INFINITE); - GetExitCodeProcess(proc_info.hProcess, &status); - CloseHandle(proc_info.hThread); - CloseHandle(proc_info.hProcess); - return status; - -#else - proc->id = 0; - if ((flags & SpawnFlags::replace) == 0) - proc->id = fork(); - if (proc->id == 0) { - if (flags & SpawnFlags::search_path) - execvp(proc->argv[0], proc->argv); - else - execv(proc->argv[0], proc->argv); - perror(strerror(errno)); - /* Don't keep useless clones around. */ - if ((flags & SpawnFlags::replace) == 0) - exit(-1); - } - return proc->id; -#endif -} - -OPENAXIOM_C_EXPORT char* -oa_substr(const char* str, const size_t begin, const size_t end) -{ - char* substring; - int len; - - if (str == NULL || strlen(str) == 0 || - strlen(str) < begin || end >= strlen(str) || begin > end) - return NULL; - - len = (end - begin) + 2; - substring = (char*) malloc(len * sizeof(char)); - memset(substring,'\0',len); - memcpy(substring, str+begin, len-1); - - return substring; -} - -OPENAXIOM_C_EXPORT char** -oa_split(const char* sequence, const char* delimiter, int* size) -{ - int sequence_length = 0, newsize = 0; - char* token; - char** tokens = NULL; - char* sequence_copy; - - sequence_length = strlen(sequence); - sequence_copy = (char*) malloc((sequence_length + 1) * sizeof(char*)); - strcpy(sequence_copy,sequence); - sequence_copy[sequence_length] = '\0'; - - token = strtok(sequence_copy, delimiter); - while (token != NULL) { - - tokens = (char**) realloc(tokens,(newsize + 1) * sizeof(char*)); - tokens[newsize] = token; - newsize++; - token = strtok (NULL, delimiter); - } - - *size = newsize; - - return tokens; -} - -} diff --git a/src/lib/cfuns-c.cxx b/src/lib/cfuns-c.cxx new file mode 100644 index 00000000..11c28691 --- /dev/null +++ b/src/lib/cfuns-c.cxx @@ -0,0 +1,914 @@ +/* + Copyright (C) 1991-2002, The Numerical Algorithms Group Ltd. + All rights reserved. + + Copyright (C) 2007-2013, Gabriel Dos Reis. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + - Neither the name of The Numerical Algorithms Group Ltd. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#include "openaxiom-c-macros.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#ifdef OPENAXIOM_MS_WINDOWS_HOST +# include +#else +# include +# include +#endif + +#include "cfuns.h" + +/* Most versions of Windows don't have the POSIX functions getuid(), + geteuid(), getgid(), and getegid(). The following definitions are + approximations, to patch for the deficiencies of Windows + POSIX interface. */ + +#if !HAVE_DECL_GETUID +# define getuid() 0 +#endif + +#if !HAVE_DECL_GETGID +# define getgid() 0 +#endif + +#if !HAVE_DECL_GETEUID +# define geteuid() getuid() +#endif + +#if !HAVE_DECL_GETEGID +# define getegid() getgid() +#endif + +namespace OpenAxiom { + // Make a copy of string data on free store. + static char* + copy_c_str(const std::string& s) { + return strdup(s.c_str()); + } + +OPENAXIOM_C_EXPORT int +addtopath(char *dir) +{ + char *path, *newpath; + + path = oa_getenv("PATH"); + if (path == NULL) + return -1; + + newpath = (char *) malloc(1 + strlen(path) + strlen(dir) + strlen("PATH=:")); + if (newpath == NULL) + return -1; + + sprintf(newpath, "PATH=%s:%s", path, dir); + + return putenv(newpath); +} + + + +/* Returns 1 if `c' designates a path separator, 0 otherwise. */ +static inline int +openaxiom_is_path_separator(char c) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return c == '\\' || c == '/'; +#else + return c == '/'; +#endif +} + +/* + Returns a the dirname of `path'. If `path' has no separator, then + returns ".". The returned value if malloc-allocated. */ + +OPENAXIOM_C_EXPORT char* +oa_dirname(const char* path) +{ + const int n = strlen(path); + const char* mark = path + n; + + if (n == 0) + return strdup("."); + else if (n == 1 && openaxiom_is_path_separator(*path)) + return strdup("/"); + + /* For "/banana/space/", we want "/banana". */ + if (openaxiom_is_path_separator(*--mark)) + --mark; + while (path < mark && !openaxiom_is_path_separator(*mark)) + --mark; + + if (path == mark) + return strdup(openaxiom_is_path_separator(*path) ? "/" : "."); + else { + const int l = mark - path; + char* dir = (char*) malloc(l + 1); + memcpy(dir, path, l); + dir[l] = '\0'; + return dir; + } +} + +/* + * Test whether the path is the name of a directory. Returns 1 if so, 0 if + * not, -1 if it doesn't exist. + */ + + +OPENAXIOM_C_EXPORT int +directoryp(char *path) +{ + struct stat buf; + int code = stat(path, &buf); + + return code == -1 ? -1 : S_ISDIR(buf.st_mode); +} + +OPENAXIOM_C_EXPORT int +make_path_from_file(char *s, char *t) +{ + char *pos = NULL; + char *c; + + /** simply copies the path name from t into s **/ + for (c = t + strlen(t); c != s; c--) + if (*c == '/') { + pos = c; + break; + } + /** Check to see if the path was actually present **/ + if (c == t) { /** No Path, so return the pwd **/ + return (-1); + } + /** now just do the copying **/ + strncpy(s, t, pos - t); + return 1; +} + +/* The functions writeablep() and readablep() determine write and + read access of a file designated by its name. The function + axiom_has_write_access is a sub-routine of writeablep. + + The access is determined based on the POSIX semantics; see + "Advanced Programming in the UNIX Environement", section 4.5. + + 1. If the effective user ID of the process is 0 (the superuser), + access is allowed. This gives the superuser free rein throughout + the entire file system. + + 2. If the effective user ID of the process equals the owner ID of + the file (i.e., the process owns the file), access is allowed + if the appropriate user access permission bit is set. [...] + + 3. If the effective group ID of the process or one of the + supplementary group IDs of the process equals the group ID + of the file, access is allowed if the appropriate + group access permission bit is set. Otherwise, permission + is denied. + + 4. If the appropriate other access permission bit is set, access is + allowed. Otherwise, permission is defined. */ + + +/* Return 1 if the process has write access of file as explained above. + Otherwise, return 0. */ + +static inline int +axiom_has_write_access(const struct stat* file_info) +{ + uid_t effetive_uid = geteuid(); + + if (effetive_uid == 0) + return 1; + + if (effetive_uid == file_info->st_uid) + return (file_info->st_mode & S_IWUSR) ? 1 : 0; + +#ifdef S_IWGRP + if (getegid() == file_info->st_gid) + return (file_info->st_mode & S_IWGRP) ? 1 : 0; +#endif + +#ifdef S_IWOTH + return (file_info->st_mode & S_IWOTH) ? 1 : 0; +#else + return 0; +#endif +} + + +/* Return + -1 if the file designated by PATH is inexistent. + 0 if the file exists but write access is denied. + 1 if the file exists and process has write access. + 2 if the file does not exists but process has write + has write access to the dirname of path. */ + +OPENAXIOM_C_EXPORT int +writeablep(const char *path) +{ + struct stat buf; + int code; + + code = stat(path, &buf); + if (code == -1) { + /* The file does not exist, so check to see if the directory + is writable. */ + char* dir = oa_dirname(path); + code = stat(dir, &buf); + /* FIXME: Work around MinGW/MSYS bug. + The string pointed to by `dir' was strdup'd. According to + the C standard, that means the the string was allocated + by `malloc', therefore can be disposed of by `free'. However, + the MinGW/MSYS port appears to use MS' StrDup as the real + worker. Consequently, the guarantee that the the string can + free'd no longer holds. We have to use MS's LocalFree. */ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + LocalFree(dir); +#else + free(dir); +#endif + return (code == 0) && axiom_has_write_access(&buf) ? 2 : -1; + } + + return axiom_has_write_access(&buf); +} + + +/* Return + -1 if the file designated by PATH is inexistent. + 0 if the file exists but process has no read access. + 1 if the file exists and read access is granted. */ + +OPENAXIOM_C_EXPORT int +readablep(const char *path) +{ + struct stat buf; + int code; + + code = stat(path, &buf); + if (code == -1) + return -1; + + if (geteuid() == buf.st_uid) + return ((buf.st_mode & S_IREAD) != 0); + +#ifdef S_IRGRP + if (getegid() == buf.st_gid) + return ((buf.st_mode & S_IRGRP) != 0); +#endif + +#ifdef S_IROTH + return ((buf.st_mode & S_IROTH) != 0); +#else + return 0; +#endif +} + + + +OPENAXIOM_C_EXPORT long +findString(char *file, char *string) +{ + int nstring, charpos; + FILE *fn; + char buffer[1024]; + + if ((fn = fopen(file, "r")) == NULL) + return -1; + + for (charpos = 0, nstring = strlen(string); + fgets(buffer, sizeof buffer, fn) != NULL; + charpos += strlen(buffer) + ) + if (!strncmp(buffer, string, nstring)) + return charpos; + return -1; + +} + +OPENAXIOM_C_EXPORT int +copyEnvValue(char *varName, char *buffer) +{ + char *s; + + s = oa_getenv(varName); + if (s == NULL) + return 0; + strcpy(buffer, s); + return strlen(s); +} + +/* Return 1 if the file descriptor FD, as viewed by the Core Executable, + is attached to a terminal. */ +OPENAXIOM_C_EXPORT int +std_stream_is_terminal(int fd) +{ + assert(fd > -1 && fd < 3); +#ifdef OPENAXIOM_MS_WINDOWS_HOST + DWORD handle; + switch (fd) { + case 0: handle = STD_INPUT_HANDLE; break; + case 1: handle = STD_OUTPUT_HANDLE; break; + case 2: handle = STD_ERROR_HANDLE; break; + /* Next code is never executed but it makes the compiler happy. */ + default: return 0; + } + /* The MS documentation suggests `GetFileType' for determining + the nature of the file handle. The return value, in our case, + is an over approximation of what we are interested in: Are we + dealing with a stream connected to a terminal? The constant + FILE_TYPE_CHAR characterises character files; in particular + a console terminal, or a printer. There is an undocumented + function `VerifyConsoleIoHandle' to deal precisely with the case + we are interested in. However, while availale in Wine, it is + not available in the MinGW headers. Consequently, we cannot + rely on it for the moment. + So, we may still get garbage out of this function on MS platforms. */ + return GetFileType(GetStdHandle(handle)) == FILE_TYPE_CHAR; +#else + return isatty(fd); +#endif +} + +/* Change the process' curretnt directory. Return zero on success, + and -1 on failure. */ +OPENAXIOM_C_EXPORT int +oa_chdir(const char* path) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return SetCurrentDirectory(path) ? 0 : -1; +#else + return chdir(path); +#endif /* OPENAXIOM_MS_WINDOWS_HOST */ +} + + +/* return true if path is `.' or `..'. */ +static inline int +is_dot_or_dotdot(const char* path) +{ + return strcmp(path, ".") == 0 || strcmp(path, "..") == 0; +} + +/* Remove a directory entry. Files are removed, directories are + recursively walked and removed. + Return 0 on success, and -1 on falure. + In practice, OpenAxiom does not remove directories with + non-trivial recursive structues. */ +OPENAXIOM_C_EXPORT int +oa_unlink(const char* path) +{ + const char* curdir; + int status = -1; +#ifdef OPENAXIOM_MS_WINDOWS_HOST + WIN32_FIND_DATA findData; + HANDLE walkHandle; + + if (is_dot_or_dotdot(path)) + return -1; + + walkHandle = FindFirstFile(path, &findData); + if (walkHandle == INVALID_HANDLE_VALUE) + return -1; + + /* Remember where we are so we can return back properly. */ + curdir = oa_getcwd(); + + do { + if (is_dot_or_dotdot(findData.cFileName)) + continue; + if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + if ((status = oa_chdir(findData.cFileName)) < 0) + goto sortie; + if ((status = oa_unlink("*")) < 0) + goto sortie; + if ((status = oa_chdir("..")) < 0) + goto sortie; + if(!RemoveDirectory(findData.cFileName)) { + status = -1; + goto sortie; + } + } + else if (!DeleteFile(findData.cFileName)) { + status = -1; + goto sortie; + } + status = 0; + } while (FindNextFile(walkHandle, &findData)); + if (!FindClose(walkHandle)) { + status = -1; + goto sortie; + } +#else + struct stat pathstat; + DIR* dir; + struct dirent* entry; + + /* Don't ever try to remove `.' or `..'. */ + if (is_dot_or_dotdot(path)) + return -1; + + if (stat(path, &pathstat) < 0) + return -1; + + /* handle non directories first. */ + if (!S_ISDIR(pathstat.st_mode)) + return unlink(path); + + /* change into the path so that we don't have to form full + pathnames. */ + curdir = oa_getcwd(); + if ((dir = opendir(path)) == NULL || oa_chdir(path) < 0) + goto sortie; + + while (errno = 0, (entry = readdir(dir)) != NULL) { + struct stat s; + if (is_dot_or_dotdot(entry->d_name)) + continue; + if ((status = stat(entry->d_name, &s)) < 0) + goto sortie; + if (S_ISDIR(s.st_mode)) { + if ((status = oa_unlink(entry->d_name)) < 0) + goto sortie; + } + else if ((status = unlink(entry->d_name)) < 0) + goto sortie; + } + if (errno != 0) { + status = -1; + goto sortie; + } + + /* Now, get one level up, and remove the empty directory. */ + if (oa_chdir("..") < 0 || closedir(dir) < 0 || rmdir(path) < 0) + status = -1; + else + status = 0; +#endif /* OPENAXIOM_MS_WINDOWS_HOST */ + + sortie: + oa_chdir(curdir); + free((char*) curdir); + return status; +} + +OPENAXIOM_C_EXPORT const char* +oa_acquire_temporary_pathname() { +#if OPENAXIOM_MS_WINDOWS_HOST + char buf[MAX_PATH]; + const char* tmpdir = oa_get_tmpdir(); + auto n = GetTempFileName(tmpdir, "oa-", random() % SHRT_MAX, buf); + /* tmpdir was malloc()ed when OPENAXIOM_MS_WINDOWS_HOST. */ + free(const_cast(tmpdir)); + if (n == 0) { + perror("oa_acquire_temporary_pathname"); + exit(1); + } + return strdup(buf); +#elif HAVE_DECL_MKTEMP + return mktemp(copy_c_str(std::string{ oa_get_tmpdir() } + "/oa-XXXXXX")); +#elif HAVE_DECL_TEMPNAM + return tempnam(oa_get_tmpdir(), "oa-"); +#else + return copy_c_str("oa-" + std::to_string(random())); +#endif +} + +OPENAXIOM_C_EXPORT void +oa_release_temporary_pathname(const char* s) +{ + free(const_cast(s)); // yuck! +} + +/* Rename a file or directory. */ +OPENAXIOM_C_EXPORT int +oa_rename(const char* old_path, const char* new_path) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return MoveFile(old_path, new_path) ? 0 : -1; +#else + return rename(old_path, new_path); +#endif +} + +/* Create a new directory named `path'. Return 0 on success, + and -1 on failure. */ +OPENAXIOM_C_EXPORT int +oa_mkdir(const char* path) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return CreateDirectory(path, NULL) ? 0 : -1; +#else +# define DIRECTORY_PERM ((S_IRWXU|S_IRWXG|S_IRWXO) & ~(S_IWGRP|S_IWOTH)) + return mkdir (path, DIRECTORY_PERM); +# undef DIRECTORY_PERM +#endif +} + +/* Run a shell command. Effectively forward to C's system(). */ +OPENAXIOM_C_EXPORT int +oa_system(const char* cmd) +{ + return system(cmd); +} + +OPENAXIOM_C_EXPORT int +oa_getpid(void) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return GetCurrentProcessId(); +#else + return getpid(); +#endif +} + +/* Concatenate two strings and return a pointer to the + newly allocate resulting string. */ +OPENAXIOM_C_EXPORT const char* +oa_concatenate_string(const char* lhs, const char* rhs) +{ + if (lhs == NULL) + return rhs; + else if (rhs == NULL) + return lhs; + else { + const int lhs_length = strlen(lhs); + char* result = (char*) malloc(lhs_length + strlen(rhs) + 1); + strcpy(result, lhs); + strcpy(result + lhs_length, rhs); + return result; + } +} + +/* Return a string object that is the result of catenating the strings + designated by `left' and `right'. */ +OPENAXIOM_C_EXPORT const char* +oa_strcat(const char* left, const char* right) +{ + int left_size = strlen(left); + int right_size = strlen(right); + int size = left_size + right_size; + char* buffer = (char*) malloc(size + 1); + + memcpy(buffer, left, left_size); + memcpy(buffer + left_size, right, right_size); + buffer[size] = '\0'; + return buffer; +} + +/* Return the value of an environment variable. */ +OPENAXIOM_C_EXPORT char* +oa_getenv(const char* var) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST +#define BUFSIZE 128 + char* buf = (char*) malloc(BUFSIZE); + int len = GetEnvironmentVariable(var, buf, BUFSIZE); + if (len == 0) { + free(buf); + return NULL; + } + else if (len > BUFSIZE) { + buf = (char*) realloc(buf,len); + len = GetEnvironmentVariable(var, buf, len); + if (len == 0) { + free(buf); + return NULL; + } + } + return buf; +#else + return getenv(var); +#endif +} + +/* Set the value of environment variable VAR to VAL. + Return 1 on success, and 0 otherwise. */ +OPENAXIOM_C_EXPORT int +oa_setenv(const char* var, const char* val) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return SetEnvironmentVariable(var, val); +#elif HAVE_DECL_SETENV + return !setenv(var, val, true); +#else + const int var_length = strlen(var); + const int val_length = strlen(val); + char* str = (char*) malloc(var_length + 1 + val_length + 1); + strcpy(str, var); + str[var_length] = '='; + strcpy(str + var_length + 1, val); + str[var_length + 1 + val_length] = '\0'; + return !putenv(str); +#endif +} + + +OPENAXIOM_C_EXPORT char* +oa_getcwd(void) +{ + size_t bufsz = 256; + char* buf = (char*) malloc(bufsz); +#ifdef OPENAXIOM_MS_WINDOWS_HOST + DWORD n = GetCurrentDirectory(bufsz, buf); + if (n == 0) { + perror("oa_getcwd"); + exit(-1); + } + else if (n > bufsz) { + buf = (char*) realloc(buf,n); + if (GetCurrentDirectory(n, buf) != n) { + perror("oa_getcwd"); + exit(-1); + } + } + return buf; +#else /* OPENAXIOM_MS_WINDOWS_HOST */ + errno = 0; + while (getcwd(buf,bufsz) == 0) { + if (errno == ERANGE) { + errno = 0; + bufsz *= 2; + buf = (char*) realloc(buf, bufsz); + } + else { + perror("oa_getcwd"); + exit(-1); + } + } + return buf; +#endif +} + +OPENAXIOM_C_EXPORT int +oa_access_file_for_read(const char* path) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return GetFileAttributes(path) == INVALID_FILE_ATTRIBUTES ? -1 : 1; +#else + return access(path, R_OK); +#endif +} + + +OPENAXIOM_C_EXPORT const char* +oa_get_tmpdir(void) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + char* buf; + /* First, probe. */ + int bufsz = GetTempPath(0, NULL); + if (bufsz == 0) { + perror("oa_get_tmpdir"); + exit(1); + } + else { + int new_size; + buf = (char*) malloc(bufsz + 1); + new_size = GetTempPath(bufsz, buf); + if(new_size == 0 || new_size >= bufsz) { + perror("oa_get_tmpdir"); + free(buf); + exit(1); + } + buf[new_size] = '\0'; + } + return buf; +#else + return "/tmp"; +#endif +} + + +OPENAXIOM_C_EXPORT int +oa_copy_file(const char* src, const char* dst) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + return CopyFile(src,dst, /* bFailIfExists = */ 0) ? 0 : -1; +#else +#define OA_BUFSZ 512 +#define OA_DEFAULT_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH) + char buf[OA_BUFSZ]; + int src_fd; + int dst_fd; + int count; + if((src_fd = open(src, O_RDONLY)) < 0) + return -1; + if ((dst_fd = creat(dst, OA_DEFAULT_MODE)) < 0) { + close(src_fd); + return -1; + } + + while ((count = read(src_fd, buf, OA_BUFSZ)) > 0) + if (write(dst_fd, buf, count) != count) + break; + +#undef OA_DEFAULT_MODE +#undef OA_BUFSZ + return (close(dst_fd) < 0 || close(src_fd) < 0 || count < 0) ? -1 : 0; +#endif +} + + +OPENAXIOM_C_EXPORT double +plus_infinity(void ) +{ +#ifdef INFINITY + return INFINITY; +#else + /* This must be a curious platform. */ + volatile double zero = 0.0; + return 1.0 / zero; /* If it traps, well, it traps. */ +#endif +} + +OPENAXIOM_C_EXPORT double +minus_infinity(void) +{ + return -plus_infinity(); +} + +OPENAXIOM_C_EXPORT double +quiet_double_NaN(void) +{ +#ifdef NAN + return NAN; +#else + return sqrt(-1.0); /* Just pick one. */ +#endif +} + + +OPENAXIOM_C_EXPORT Byteorder +oa_get_host_byteorder(void) +{ +#ifdef WORDS_BIGENDIAN + return Byteorder::big; +#else + return Byteorder::little; +#endif +} + + +OPENAXIOM_C_EXPORT void +oa_allocate_process_argv(Process* proc, int argc) +{ + proc->argc = argc; + proc->argv = (char**) malloc((1 + argc) * sizeof (char*)); + proc->argv[argc] = NULL; +} + +OPENAXIOM_C_EXPORT int +oa_spawn(Process* proc, SpawnFlags flags) +{ +#ifdef OPENAXIOM_MS_WINDOWS_HOST + const char* path = NULL; + char* cmd_line = NULL; + int curpos = strlen(proc->argv[0]); + int cmd_line_length = curpos; + int i; + PROCESS_INFORMATION proc_info; + STARTUPINFO startup_info = { 0 }; + DWORD status; + + for (i = 0; i < proc->argc; ++i) + cmd_line_length += 1 + strlen(proc->argv[i]); + + cmd_line = (char*) malloc(cmd_line_length + 1); + strcpy(cmd_line, proc->argv[0]); + for (i = 0; i < proc->argc; ++i) { + cmd_line[curpos++] = ' '; + strcpy(cmd_line + curpos, proc->argv[i]); + curpos += strlen(proc->argv[i]); + } + cmd_line[curpos] = '\0'; + + if ((flags & SpawnFlags::search_path) == 0) + path = proc->argv[0]; + + if(CreateProcess(/* lpApplicationName */ path, + /* lpCommandLine */ cmd_line, + /* lpProcessAttributes */ NULL, + /* lpThreadAttributes */ NULL, + /* bInheritHandles */ TRUE, + /* dwCreationFlags */ 0, + /* lpEnvironment */ NULL, + /* lpCurrentDirectory */ NULL, + /* lpstartupInfo */ &startup_info, + /* lpProcessInformation */ &proc_info) == 0) { + fprintf(stderr, "oa_spawn: error %lu\n", GetLastError()); + return proc->id = -1; + } + proc->id = proc_info.dwProcessId; + if ((flags & SpawnFlags::replace) == 0) + return proc->id; + WaitForSingleObject(proc_info.hProcess, INFINITE); + GetExitCodeProcess(proc_info.hProcess, &status); + CloseHandle(proc_info.hThread); + CloseHandle(proc_info.hProcess); + return status; + +#else + proc->id = 0; + if ((flags & SpawnFlags::replace) == 0) + proc->id = fork(); + if (proc->id == 0) { + if (flags & SpawnFlags::search_path) + execvp(proc->argv[0], proc->argv); + else + execv(proc->argv[0], proc->argv); + perror(strerror(errno)); + /* Don't keep useless clones around. */ + if ((flags & SpawnFlags::replace) == 0) + exit(-1); + } + return proc->id; +#endif +} + +OPENAXIOM_C_EXPORT char* +oa_substr(const char* str, const size_t begin, const size_t end) +{ + char* substring; + int len; + + if (str == NULL || strlen(str) == 0 || + strlen(str) < begin || end >= strlen(str) || begin > end) + return NULL; + + len = (end - begin) + 2; + substring = (char*) malloc(len * sizeof(char)); + memset(substring,'\0',len); + memcpy(substring, str+begin, len-1); + + return substring; +} + +OPENAXIOM_C_EXPORT char** +oa_split(const char* sequence, const char* delimiter, int* size) +{ + int sequence_length = 0, newsize = 0; + char* token; + char** tokens = NULL; + char* sequence_copy; + + sequence_length = strlen(sequence); + sequence_copy = (char*) malloc((sequence_length + 1) * sizeof(char*)); + strcpy(sequence_copy,sequence); + sequence_copy[sequence_length] = '\0'; + + token = strtok(sequence_copy, delimiter); + while (token != NULL) { + + tokens = (char**) realloc(tokens,(newsize + 1) * sizeof(char*)); + tokens[newsize] = token; + newsize++; + token = strtok (NULL, delimiter); + } + + *size = newsize; + + return tokens; +} + +} diff --git a/src/lib/sockio-c.c b/src/lib/sockio-c.c deleted file mode 100644 index 24b8f475..00000000 --- a/src/lib/sockio-c.c +++ /dev/null @@ -1,1307 +0,0 @@ -/* - Copyright (c) 1991-2002, The Numerical Algorithms Group Ltd. - All rights reserved. - Copyright (C) 2007-2013, Gabriel Dos Reis. - All rights reserved. - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - - - Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - - Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. - - - Neither the name of The Numerical ALgorithms Group Ltd. nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER - OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -/* socket i/o primitives */ - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#ifdef __WIN32__ -# include -# include -#else -# include -# include -#endif - -#include "cfuns.h" -#include "sockio.h" -#include "com.h" -#include "bsdsignal.h" -#include "sockio.h" - -namespace OpenAxiom { - -#define TotalMaxPurposes 50 -#define MaxServerNumbers 100 -#define accept_if_needed(purpose) \ - ( purpose_table[purpose] == NULL ? sock_accept_connection(purpose) : 1 ) - -/* Note that the name AF_LOCAL is more portable than AF_UNIX, but MingW - implementation and Windows documentation don't always agree. */ - -#if HAVE_AF_LOCAL -# define OPENAXIOM_AF_LOCAL AF_LOCAL -#elif HAVE_AF_UNIX -# define OPENAXIOM_AF_LOCAL AF_UNIX -#else -# error "needs one of AF_LOCAL or AF_UNIX" -#endif - - -/* socket description of spad clients */ -openaxiom_sio clients[MaxClients]; - -/* Local socket for server */ -openaxiom_sio server; - -/* table of dedicated socket types */ -openaxiom_sio *purpose_table[TotalMaxPurposes]; - -/* bit mask of active sockets */ -fd_set socket_mask; - -/* bit mask of server sockets */ -fd_set server_mask; - -/* used to identify closed socket on SIGPIPE */ -int socket_closed; - -/* spad server number used in sman */ -int spad_server_number = -1; - - -/* Non zero if the host system module support for socket is activated. - This is needed only for MS platforms. */ -static int openaxiom_socket_module_loaded = 0; - -#ifdef __WIN32__ -/* Windows require some handshaking with the WinSock DLL before - we can even think about talking about sockets. */ - -static void -openaxiom_unload_socket_module() -{ - WSACleanup(); - openaxiom_socket_module_loaded = 0; -} -#endif - - -static void -openaxiom_load_socket_module() -{ - if (!openaxiom_socket_module_loaded) { -#ifdef __WIN32__ - WSADATA wsaData; - - /* Request version 2.0 of WinSock DLL. */ - if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { - perror("could not find suitable WinSock DLL."); - exit(WSAGetLastError()); - } - - atexit(&openaxiom_unload_socket_module); - - if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { - perror("could not find suitable WinSock DLL."); - exit(WSAGetLastError()); - } -#endif - } - openaxiom_socket_module_loaded = 1; -} - - -/* Convert an IP address from presentation (string or ascii form) - to numeric form. The result is stored in the last argument. - Success is indicated by a return value 0; failure is -1. */ -OPENAXIOM_C_EXPORT int -oa_inet_pton(const char* addr, int prot, Byte* bytes) -{ - openaxiom_load_socket_module(); - switch (prot) { - case 4: { -#ifdef __WIN32__ - unsigned long inet_val = inet_addr(addr); - if (inet_val == INADDR_NONE || inet_val == INADDR_ANY) - return -1; - memcpy(bytes, &inet_val, 4); - return 0; -#else - struct in_addr inet_val; - if (inet_aton(addr, &inet_val) != 0) { - memcpy(bytes, &inet_val, 4); - return 0; - } - return -1; -#endif - } - default: - return -1; - } -} - -/* Resolve a hostname to its IP address. On success return 0, - otherwise -1. */ -OPENAXIOM_C_EXPORT int -oa_get_host_address(const char* n, int prot, Byte* bytes) -{ - struct hostent* h; - openaxiom_load_socket_module(); - h = gethostbyname(n); - if (h == 0) - return -1; - - if (h->h_length != prot) - /* Protocol mismatch. */ - return -1; - memcpy(bytes, h->h_addr_list[0], prot); - return 0; -} - - -/* Get a socket identifier to a local server. We take whatever protocol - is the default for the address family in the SOCK_STREAM type. */ -static inline openaxiom_socket -openaxiom_socket_stream_link(int family) -{ - openaxiom_load_socket_module(); - return socket(family, SOCK_STREAM, 0); -} - - -/* Returns 1 if SOCKET is an invalid socket. Otherwise return 0. */ - -static inline int -openaxiom_socket_is_invalid(openaxiom_socket sock) -{ -#ifdef __WIN32__ - return sock == INVALID_SOCKET; -#else - return sock < 0; -#endif -} - -static inline int -is_invalid_socket(const openaxiom_sio* s) -{ - return openaxiom_socket_is_invalid(s->socket); -} - -/* Returns 1 if SOCKET is a valid socket. Otherwise return 0. */ - -static inline int -is_valid_socket(const openaxiom_sio* s) -{ -#ifdef __WIN32__ - return s->socket != INVALID_SOCKET; -#else - return s->socket > 0; -#endif -} - - -/* Because a socket on Windows platform is a not just a simple file - descriptor as it is in the Unix world, it is invalid to use - a socket identifier as argument for read(), or close, or - any other file descriptor function. Furthermore, Windows - requires cleanup. */ - -OPENAXIOM_C_EXPORT void -oa_close_socket(openaxiom_socket s) -{ -#ifdef __WIN32__ - shutdown(s, SD_BOTH); - closesocket(s); -#else - close(s); -#endif -} - -/* Local IPC Socket: - On POSIX systems, this is just the Local IPC Socket. - On Windows, we Windows Named Pipes. - - Please, remember that Windows Named Pipes are closer to - Unix Domain Sockets than they are to Unix Named Pipes. They - ae full duplex communication links, supporting regular - file I/O operations. */ - -OPENAXIOM_C_EXPORT openaxiom_filedesc -oa_open_local_client_stream_socket(const char* path) -{ -#ifdef __WIN32__ -# define NAMED_PIPE_PREFIX "\\\\.\\pipe" - char* pipename; - HANDLE handle; - - pipename = (char *) malloc(sizeof NAMED_PIPE_PREFIX + strlen(path)); - strcpy(pipename, NAMED_PIPE_PREFIX); - strcat(pipename, path); - - /* Try to open only an existing named pipe. */ - while (1) { - handle = CreateFile(/* lpFileName */ pipename, - /* dwDesiredAccess */ GENERIC_READ | GENERIC_WRITE, - /* dwSharedMode */ 0, - /* lpSecurityAttributes */ NULL, - /* dwCreationDisposition */ OPEN_EXISTING, - /* dwFlagsAttributes */ 0, - /* hTemplateFile */ NULL); - - if (handle != INVALID_HANDLE_VALUE) - return handle; - - if (GetLastError() != ERROR_PIPE_BUSY - || !WaitNamedPipe(pipename, NMPWAIT_WAIT_FOREVER)) - return INVALID_HANDLE_VALUE; - } -# undef NAMED_PIPE_PREFIX -#else - int sock = socket(AF_UNIX, SOCK_STREAM, 0); - struct sockaddr_un addr; - if (sock < 0) - return -1; - - memset(&addr, 0, sizeof addr); - addr.sun_family = OPENAXIOM_AF_LOCAL; - strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); - if (connect(sock, (struct sockaddr*)&addr, sizeof addr) < 0) { - close(sock); - return -1; - } - return sock; -#endif -} - -OPENAXIOM_C_EXPORT int -oa_filedesc_read(openaxiom_filedesc desc, Byte* buf, int size) -{ -#ifdef __WIN32__ - DWORD count = -1; - if (ReadFile(/* hFile */ desc, - /* lpBuffer */ buf, - /* nNumberOfBytesToRead */ size, - /* lpNumberOfBytesRead */ &count, - /* lpOverlapped */ NULL)) - return count; - return -1; -#else - return read(desc, buf, size); -#endif -} - -OPENAXIOM_C_EXPORT int -oa_filedesc_write(openaxiom_filedesc desc, const Byte* buf, int size) -{ -#ifdef __WIN32__ - DWORD count = -1; - if (WriteFile(/* hFile */ desc, - /* lpBuffer */ buf, - /* nNumberOfBytesToWrite */ size, - /* lpNumberOfBytesWritten */ &count, - /* lpOverlapped */ NULL)) - return count; - return -1; -#else - return write(desc, buf, size); -#endif -} - -OPENAXIOM_C_EXPORT int -oa_filedesc_close(openaxiom_filedesc desc) -{ -#ifdef __WIN32__ - return CloseHandle(desc) ? 0 : -1; -#else - return close(desc); -#endif -} - -/* IP sockets. -*/ - -OPENAXIOM_C_EXPORT openaxiom_socket -oa_connect_ip_port_stream(const Byte* addr, int prot, openaxiom_port port) -{ - struct sockaddr_in server; - openaxiom_socket sock; - /* IP6 is not yet supported. */ - if (prot != 4) - return OPENAXIOM_INVALID_SOCKET; - - sock = openaxiom_socket_stream_link(AF_INET); - if (openaxiom_socket_is_invalid(sock)) - return OPENAXIOM_INVALID_SOCKET; - - memset(&server, 0, sizeof server); - server.sin_family = AF_INET; - memcpy(&server.sin_addr, addr, prot); - server.sin_port = htons(port); - if (connect(sock, (struct sockaddr*)&server, sizeof server) < 0) { - oa_close_socket(sock); - return OPENAXIOM_INVALID_SOCKET; - } - return sock; -} - -/* It is idiomatic in the Unix/POSIX world to use the standard - read() and write() functions on sockets. However, in the Windows - world, that is invalid. Consequently, portability suggests that - we restrict ourselves to the POSIX standard functions recv() and - send(). */ - - -/* Read some bytes of data into buffer `buf' with capacity `size'. - On failure, return -1; otherwise return the number of bytes - actually read. */ - -OPENAXIOM_C_EXPORT int -oa_socket_read(openaxiom_socket sock, Byte* buf, int size) -{ - return recv(sock, (char*) buf, size, 0); -} - -/* Attempt to read a byte from scoket `sock'. - On failure, return -1; otherwise the actual byte read. */ - -OPENAXIOM_C_EXPORT int -oa_socket_read_byte(openaxiom_socket sock) -{ - Byte byte; - if(oa_socket_read(sock, &byte, 1) < 1) - return -1; - return byte; -} - - -/* Send `size' bytes of data contained in `buf' to the socket `sock'. - Return -1 on failured; the number of actualy write bytes on success. */ - -OPENAXIOM_C_EXPORT int -oa_socket_write(openaxiom_socket sock, const Byte* buf, int size) -{ - return send(sock, (const char*) buf, size, 0); -} - -/* Send one byte to socket `sock'. */ -OPENAXIOM_C_EXPORT int -oa_socket_write_byte(openaxiom_socket sock, Byte byte) -{ - return oa_socket_write(sock, &byte, 1) < 1 ? -1 : byte; -} - - -/* Return 1 is the last call was cancelled. */ - -static inline int -openaxiom_syscall_was_cancelled() -{ -#ifdef __WIN32__ - return WSAGetLastError() == WSAEINTR; -#else - return errno == EINTR; -#endif -} - -/* Return 1 is last connect() was refused. */ - -static inline int -openaxiom_connection_refused() -{ -#ifdef __WIN32__ - return WSAGetLastError() == WSAECONNREFUSED; -#else - return errno == ECONNREFUSED; -#endif -} - - -OPENAXIOM_C_EXPORT void -sigpipe_handler(int sig) -{ - socket_closed = 1; -} - -OPENAXIOM_C_EXPORT int -wait_for_client_read(openaxiom_sio *sock, Byte* buf, int buf_size, - const char* msg) -{ - int ret_val; - switch(sock->purpose) { - case SessionManager: - case ViewportServer: - sock_accept_connection(sock->purpose); - ret_val = sread(purpose_table[sock->purpose], buf, buf_size, msg); - sock->socket = 0; - return ret_val; - default: - sock->socket = 0; - return -1; - } -} - -OPENAXIOM_C_EXPORT int -wait_for_client_write(openaxiom_sio* sock, const Byte* buf, - int buf_size, const char* msg) -{ - int ret_val; - switch(sock->purpose) { - case SessionManager: - case ViewportServer: - sock_accept_connection(sock->purpose); - ret_val = swrite(purpose_table[sock->purpose], buf, buf_size, msg); - sock->socket = 0; - return ret_val; - default: - sock->socket = 0; - return -1; - } -} - -OPENAXIOM_C_EXPORT int -sread(openaxiom_sio* sock, Byte* buf, int buf_size, const char *msg) -{ - int ret_val; - char err_msg[256]; - errno = 0; - do { - ret_val = oa_socket_read(sock->socket, buf, buf_size); - } while (ret_val == -1 && openaxiom_syscall_was_cancelled()); - if (ret_val == 0) { - FD_CLR(sock->socket, &socket_mask); - purpose_table[sock->purpose] = NULL; - oa_close_socket(sock->socket); - return wait_for_client_read(sock, buf, buf_size, msg); - } - if (ret_val == -1) { - if (msg) { - sprintf(err_msg, "reading: %s", msg); - perror(err_msg); - } - return -1; - } - return ret_val; -} - -OPENAXIOM_C_EXPORT int -swrite(openaxiom_sio* sock, const Byte* buf, int buf_size, - const char* msg) -{ - int ret_val; - char err_msg[256]; - errno = 0; - socket_closed = 0; - ret_val = oa_socket_write(sock->socket, buf, buf_size); - if (ret_val == -1) { - if (socket_closed) { - FD_CLR(sock->socket, &socket_mask); - purpose_table[sock->purpose] = NULL; - /* printf(" closing socket %d\n", sock->socket); */ - oa_close_socket(sock->socket); - return wait_for_client_write(sock, buf, buf_size, msg); - } else { - if (msg) { - sprintf(err_msg, "writing: %s", msg); - perror(err_msg); - } - return -1; - } - } - return ret_val; -} - -OPENAXIOM_C_EXPORT int -sselect(int n,fd_set *rd, fd_set *wr, fd_set *ex, void *timeout) -{ - int ret_val; - do { - ret_val = select(n, rd, wr, ex, (struct timeval *) timeout); - } while (ret_val == -1 && openaxiom_syscall_was_cancelled()); - return ret_val; -} - -OPENAXIOM_C_EXPORT int -fill_buf(openaxiom_sio *sock, Byte* buf, int len, const char* msg) -{ - int bytes = 0, ret_val; - while(bytes < len) { - ret_val = sread(sock, buf + bytes, len - bytes, msg); - if (ret_val == -1) return -1; - bytes += ret_val; - } - return bytes; -} - -OPENAXIOM_C_EXPORT int -get_int(openaxiom_sio *sock) -{ - int val = -1, len; - len = fill_buf(sock, byte_address(val), sizeof(int), "get_int"); - if (len != sizeof(int)) { -#ifdef DEBUG - fprintf(stderr,"get_int: caught error\n",val); -#endif - return -1; - } -#ifdef DEBUG - fprintf(stderr,"get_int: received %d\n",val); -#endif - return val; -} - -OPENAXIOM_C_EXPORT int -sock_get_int(int purpose) -{ - if (accept_if_needed(purpose) != -1) - return get_int(purpose_table[purpose]); - else return -1; -} - -OPENAXIOM_C_EXPORT int -get_ints(openaxiom_sio *sock, int *vals, int num) -{ - int i; - for(i=0; i 1023) { - char *buf; - buf = (char*) malloc(len+1); - strncpy(buf,str,len); - buf[len]='\0'; - send_int(sock,len+1); - val = swrite(sock, (const Byte*) buf, len+1, "send_string_len"); - free(buf); - } else { - static char buf[1024]; - strncpy(buf, str, len); - buf[len] = '\0'; - send_int(sock, len+1); - val = swrite(sock, (const Byte*) buf, len+1, "send_string_len"); - } - if (val == -1) { - return val; - } - return 0; -} - -OPENAXIOM_C_EXPORT int -send_string(openaxiom_sio* sock, const char* str) -{ - int val, len = strlen(str); - send_int(sock, len+1); - val = swrite(sock, (const Byte*) str, len+1, "send_string"); - if (val == -1) { - return -1; - } - return 0; -} - - -OPENAXIOM_C_EXPORT int -sock_send_string(int purpose, const char *str) -{ - if (accept_if_needed(purpose) != -1) - return send_string(purpose_table[purpose], str); - return -1; -} - -OPENAXIOM_C_EXPORT int -sock_send_string_len(int purpose, const char* str, int len) -{ - if (accept_if_needed(purpose) != -1) - return send_string_len(purpose_table[purpose], str, len); - return -1; -} - -OPENAXIOM_C_EXPORT int -send_strings(openaxiom_sio *sock, const char** vals, int num) -{ - int i; - for(i=0; inbytes_pending == 0) - sock->nbytes_pending = get_int(sock); - nbytes_to_read = sock->nbytes_pending > buf_len - ? buf_len - : sock->nbytes_pending; - nbytes_read = fill_buf(sock, (Byte*)buf, nbytes_to_read, - "get_string_buf"); - if (nbytes_read == -1) { - sock->nbytes_pending = 0; - return NULL; - } - sock->nbytes_pending -= nbytes_read; - return sock->nbytes_pending == 0 ? NULL : buf; -} - -OPENAXIOM_C_EXPORT char * -sock_get_string_buf(int purpose, char* buf, int buf_len) -{ - if (accept_if_needed(purpose) != -1) - return get_string_buf(purpose_table[purpose], buf, buf_len); - return NULL; -} - -OPENAXIOM_C_EXPORT int -get_strings(openaxiom_sio *sock, char** vals,int num) -{ - int i; - for(i=0; ipurpose) { - case SessionManager: - case ViewportServer: - sock_accept_connection(sock->purpose); - ret_val = send_signal(purpose_table[sock->purpose], sig); - sock->socket = 0; - return ret_val; - default: - sock->socket = 0; - return -1; - } -} - - -OPENAXIOM_C_EXPORT int -sock_get_remote_fd(int purpose) -{ - if (accept_if_needed(purpose) != -1) - return purpose_table[purpose]->remote; - return -1; -} - -OPENAXIOM_C_EXPORT int -send_signal(openaxiom_sio *sock, int sig) -{ - int ret_val; -#if HAVE_DECL_KILL - ret_val = kill(sock->pid, sig); -#else - ret_val = raise(sig); -#endif - if (ret_val == -1 && errno == ESRCH) { - FD_CLR(sock->socket, &socket_mask); - purpose_table[sock->purpose] = NULL; -/* printf(" closing socket %d\n", sock->socket); */ - oa_close_socket(sock->socket); - return wait_for_client_kill(sock, sig); - } - return ret_val; -} - -OPENAXIOM_C_EXPORT int -sock_send_signal(int purpose,int sig) -{ - if (accept_if_needed(purpose) != -1) - return send_signal(purpose_table[purpose], sig); - return -1; -} - -OPENAXIOM_C_EXPORT int -send_wakeup(openaxiom_sio *sock) -{ -#ifdef SIGUSR1 - return send_signal(sock, SIGUSR1); -#else - return -1; -#endif -} - -OPENAXIOM_C_EXPORT int -sock_send_wakeup(int purpose) -{ - if (accept_if_needed(purpose) != -1) - return send_wakeup(purpose_table[purpose]); - return -1; -} - -OPENAXIOM_C_EXPORT openaxiom_sio * -connect_to_local_server_new(const char *server_name, int purpose, int time_out) -{ - int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1; - openaxiom_sio *sock; - char name[256]; - - make_server_name(name, server_name); - sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1); - if (sock == NULL) { - perror("allocating socket space"); - return NULL; - } - - sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); - if (is_invalid_socket(sock)) { - perror("opening client socket"); - free(sock); - return NULL; - } - - memset(server.addr.u_addr.sa_data, 0, - sizeof(server.addr.u_addr.sa_data)); - sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; - strcpy(sock->addr.u_addr.sa_data, name); - for(i=0; isocket, &sock->addr.u_addr, - sizeof(sock->addr.u_addr)); - if (code == -1) { - if (errno != ENOENT && !openaxiom_connection_refused()) { - perror("connecting server stream socket"); - return NULL; - } else { - if (i != max_con - 1) - openaxiom_sleep(1); - continue; - } - } else break; - } - - if (code == -1) { - return NULL; - } - - send_int(sock, oa_getpid()); - send_int(sock, purpose); - send_int(sock, sock->socket); - sock->pid = get_int(sock); - sock->remote = get_int(sock); - return sock; -} - -OPENAXIOM_C_EXPORT openaxiom_sio * -connect_to_local_server(const char *server_name, int purpose, int time_out) -{ - int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1; - openaxiom_sio *sock; - char name[256]; - - make_server_name(name, server_name); - sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1); - if (sock == NULL) { - perror("allocating socket space"); - return NULL; - } - - sock->purpose = purpose; - /* create the socket */ - sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); - if (is_invalid_socket(sock)) { - perror("opening client socket"); - free(sock); - return NULL; - } - /* connect socket using name specified in command line */ - memset(server.addr.u_addr.sa_data, 0, - sizeof(server.addr.u_addr.sa_data)); - sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; - strcpy(sock->addr.u_addr.sa_data, name); - for(i=0; isocket, &sock->addr.u_addr, - sizeof(sock->addr.u_addr)); - if (code == -1) { - if (errno != ENOENT && !openaxiom_connection_refused()) { - perror("connecting server stream socket"); - return NULL; - } else { - if (i != max_con - 1) - openaxiom_sleep(1); - continue; - } - } else break; - } - if (code == -1) { - return NULL; - } - send_int(sock, oa_getpid()); - send_int(sock, sock->purpose); - send_int(sock, sock->socket); - sock->pid = get_int(sock); -/* fprintf(stderr, "Got int form socket\n"); */ - sock->remote = get_int(sock); - return sock; -} - -/* act as terminal session for sock connected to stdin and stdout of another - process */ -OPENAXIOM_C_EXPORT void -remote_stdio(openaxiom_sio *sock) -{ - char buf[1024]; - fd_set rd; - int len; - while (1) { - FD_ZERO(&rd); - FD_SET(sock->socket,&rd); - FD_SET(0, &rd); - len = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL); - if (len == -1) { - perror("stdio select"); - return; - } - if (FD_ISSET(0, &rd)) { - fgets(buf,1024,stdin); - len = strlen(buf); - swrite(sock, byte_address(buf), len, "remote_stdio::write"); - } - if (FD_ISSET(sock->socket, &rd)) { - len = sread(sock, byte_address(buf), 1024, "remote_stdio::read"); - if (len == -1) - return; - else { - *(buf + len) = '\0'; - fputs(buf, stdout); - fflush(stdout); - } - } - } -} - -/* initialize the table of dedicated sockets */ -static void -init_purpose_table() -{ - int i; - for(i=0; ipid = get_int(sock); - sock->purpose = get_int(sock); - sock->remote = get_int(sock); - send_int(sock, oa_getpid()); - send_int(sock, sock->socket); - purpose_table[sock->purpose] = sock; -} - -OPENAXIOM_C_EXPORT int -accept_connection() -{ - int client = 0; - while (client < MaxClients && clients[client].socket != 0) - ++client; - if (client == MaxClients) { - printf("Ran out of client openaxiom_sio structures\n"); - return -1; - } - clients[client].socket = accept(server.socket, 0, 0); - if (is_invalid_socket(&clients[client])) { - perror("accept_connection"); - clients[client].socket = 0; - return -1; - } - FD_SET(clients[client].socket, &socket_mask); - get_socket_type(&clients[client]); - return clients[client].purpose; -} - -OPENAXIOM_C_EXPORT int -sock_accept_connection(int purpose) -{ - fd_set rd; - int ret_val, p; - if (oa_getenv("SPADNUM") == NULL) return -1; - while (1) { - rd = server_mask; - ret_val = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL); - if (ret_val == -1) { - perror ("Select"); - return -1; - } - if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) { - p = accept_connection(); - if (p == purpose) return 1; - } - } -} - -/* Socket I/O selection called from the BOOT serverLoop function */ - -OPENAXIOM_C_EXPORT int -server_switch() -{ - int ret_val, cmd = 0; - fd_set rd, wr, ex, fds_mask; - FD_ZERO(&rd); - FD_ZERO(&wr); - FD_ZERO(&ex); - fds_mask = server_mask; - cmd = 0; - if (purpose_table[SessionManager] != NULL) { - FD_SET(0, &fds_mask); - FD_SET(purpose_table[SessionManager]->socket, &fds_mask); - } - while (1) { - do { - if (purpose_table[MenuServer] != NULL) { - FD_SET(purpose_table[MenuServer]->socket, &fds_mask); - } - rd = fds_mask; - ret_val = select(FD_SETSIZE, &rd, 0, 0, 0); - if (ret_val == -1) { - /* perror ("Select in switch"); */ - return -1; - } - if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) - accept_connection(); - } while (purpose_table[SessionManager] == NULL); - FD_SET(purpose_table[SessionManager]->socket, &fds_mask); - if (FD_ISSET(purpose_table[SessionManager]->socket, &rd)) { - cmd = get_int(purpose_table[SessionManager]); - return cmd; - } - if (FD_ISSET(0, &rd)) { - return CallInterp; - } - if (purpose_table[MenuServer] != NULL && - (FD_ISSET(purpose_table[MenuServer]->socket, &rd))) { - cmd = get_int(purpose_table[MenuServer]); - return cmd; - } - } -} - -} diff --git a/src/lib/sockio-c.cxx b/src/lib/sockio-c.cxx new file mode 100644 index 00000000..24b8f475 --- /dev/null +++ b/src/lib/sockio-c.cxx @@ -0,0 +1,1307 @@ +/* + Copyright (c) 1991-2002, The Numerical Algorithms Group Ltd. + All rights reserved. + Copyright (C) 2007-2013, Gabriel Dos Reis. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + - Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + - Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + - Neither the name of The Numerical ALgorithms Group Ltd. nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS + IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER + OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +/* socket i/o primitives */ + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#ifdef __WIN32__ +# include +# include +#else +# include +# include +#endif + +#include "cfuns.h" +#include "sockio.h" +#include "com.h" +#include "bsdsignal.h" +#include "sockio.h" + +namespace OpenAxiom { + +#define TotalMaxPurposes 50 +#define MaxServerNumbers 100 +#define accept_if_needed(purpose) \ + ( purpose_table[purpose] == NULL ? sock_accept_connection(purpose) : 1 ) + +/* Note that the name AF_LOCAL is more portable than AF_UNIX, but MingW + implementation and Windows documentation don't always agree. */ + +#if HAVE_AF_LOCAL +# define OPENAXIOM_AF_LOCAL AF_LOCAL +#elif HAVE_AF_UNIX +# define OPENAXIOM_AF_LOCAL AF_UNIX +#else +# error "needs one of AF_LOCAL or AF_UNIX" +#endif + + +/* socket description of spad clients */ +openaxiom_sio clients[MaxClients]; + +/* Local socket for server */ +openaxiom_sio server; + +/* table of dedicated socket types */ +openaxiom_sio *purpose_table[TotalMaxPurposes]; + +/* bit mask of active sockets */ +fd_set socket_mask; + +/* bit mask of server sockets */ +fd_set server_mask; + +/* used to identify closed socket on SIGPIPE */ +int socket_closed; + +/* spad server number used in sman */ +int spad_server_number = -1; + + +/* Non zero if the host system module support for socket is activated. + This is needed only for MS platforms. */ +static int openaxiom_socket_module_loaded = 0; + +#ifdef __WIN32__ +/* Windows require some handshaking with the WinSock DLL before + we can even think about talking about sockets. */ + +static void +openaxiom_unload_socket_module() +{ + WSACleanup(); + openaxiom_socket_module_loaded = 0; +} +#endif + + +static void +openaxiom_load_socket_module() +{ + if (!openaxiom_socket_module_loaded) { +#ifdef __WIN32__ + WSADATA wsaData; + + /* Request version 2.0 of WinSock DLL. */ + if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0) { + perror("could not find suitable WinSock DLL."); + exit(WSAGetLastError()); + } + + atexit(&openaxiom_unload_socket_module); + + if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { + perror("could not find suitable WinSock DLL."); + exit(WSAGetLastError()); + } +#endif + } + openaxiom_socket_module_loaded = 1; +} + + +/* Convert an IP address from presentation (string or ascii form) + to numeric form. The result is stored in the last argument. + Success is indicated by a return value 0; failure is -1. */ +OPENAXIOM_C_EXPORT int +oa_inet_pton(const char* addr, int prot, Byte* bytes) +{ + openaxiom_load_socket_module(); + switch (prot) { + case 4: { +#ifdef __WIN32__ + unsigned long inet_val = inet_addr(addr); + if (inet_val == INADDR_NONE || inet_val == INADDR_ANY) + return -1; + memcpy(bytes, &inet_val, 4); + return 0; +#else + struct in_addr inet_val; + if (inet_aton(addr, &inet_val) != 0) { + memcpy(bytes, &inet_val, 4); + return 0; + } + return -1; +#endif + } + default: + return -1; + } +} + +/* Resolve a hostname to its IP address. On success return 0, + otherwise -1. */ +OPENAXIOM_C_EXPORT int +oa_get_host_address(const char* n, int prot, Byte* bytes) +{ + struct hostent* h; + openaxiom_load_socket_module(); + h = gethostbyname(n); + if (h == 0) + return -1; + + if (h->h_length != prot) + /* Protocol mismatch. */ + return -1; + memcpy(bytes, h->h_addr_list[0], prot); + return 0; +} + + +/* Get a socket identifier to a local server. We take whatever protocol + is the default for the address family in the SOCK_STREAM type. */ +static inline openaxiom_socket +openaxiom_socket_stream_link(int family) +{ + openaxiom_load_socket_module(); + return socket(family, SOCK_STREAM, 0); +} + + +/* Returns 1 if SOCKET is an invalid socket. Otherwise return 0. */ + +static inline int +openaxiom_socket_is_invalid(openaxiom_socket sock) +{ +#ifdef __WIN32__ + return sock == INVALID_SOCKET; +#else + return sock < 0; +#endif +} + +static inline int +is_invalid_socket(const openaxiom_sio* s) +{ + return openaxiom_socket_is_invalid(s->socket); +} + +/* Returns 1 if SOCKET is a valid socket. Otherwise return 0. */ + +static inline int +is_valid_socket(const openaxiom_sio* s) +{ +#ifdef __WIN32__ + return s->socket != INVALID_SOCKET; +#else + return s->socket > 0; +#endif +} + + +/* Because a socket on Windows platform is a not just a simple file + descriptor as it is in the Unix world, it is invalid to use + a socket identifier as argument for read(), or close, or + any other file descriptor function. Furthermore, Windows + requires cleanup. */ + +OPENAXIOM_C_EXPORT void +oa_close_socket(openaxiom_socket s) +{ +#ifdef __WIN32__ + shutdown(s, SD_BOTH); + closesocket(s); +#else + close(s); +#endif +} + +/* Local IPC Socket: + On POSIX systems, this is just the Local IPC Socket. + On Windows, we Windows Named Pipes. + + Please, remember that Windows Named Pipes are closer to + Unix Domain Sockets than they are to Unix Named Pipes. They + ae full duplex communication links, supporting regular + file I/O operations. */ + +OPENAXIOM_C_EXPORT openaxiom_filedesc +oa_open_local_client_stream_socket(const char* path) +{ +#ifdef __WIN32__ +# define NAMED_PIPE_PREFIX "\\\\.\\pipe" + char* pipename; + HANDLE handle; + + pipename = (char *) malloc(sizeof NAMED_PIPE_PREFIX + strlen(path)); + strcpy(pipename, NAMED_PIPE_PREFIX); + strcat(pipename, path); + + /* Try to open only an existing named pipe. */ + while (1) { + handle = CreateFile(/* lpFileName */ pipename, + /* dwDesiredAccess */ GENERIC_READ | GENERIC_WRITE, + /* dwSharedMode */ 0, + /* lpSecurityAttributes */ NULL, + /* dwCreationDisposition */ OPEN_EXISTING, + /* dwFlagsAttributes */ 0, + /* hTemplateFile */ NULL); + + if (handle != INVALID_HANDLE_VALUE) + return handle; + + if (GetLastError() != ERROR_PIPE_BUSY + || !WaitNamedPipe(pipename, NMPWAIT_WAIT_FOREVER)) + return INVALID_HANDLE_VALUE; + } +# undef NAMED_PIPE_PREFIX +#else + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + struct sockaddr_un addr; + if (sock < 0) + return -1; + + memset(&addr, 0, sizeof addr); + addr.sun_family = OPENAXIOM_AF_LOCAL; + strncpy(addr.sun_path, path, sizeof(addr.sun_path) - 1); + if (connect(sock, (struct sockaddr*)&addr, sizeof addr) < 0) { + close(sock); + return -1; + } + return sock; +#endif +} + +OPENAXIOM_C_EXPORT int +oa_filedesc_read(openaxiom_filedesc desc, Byte* buf, int size) +{ +#ifdef __WIN32__ + DWORD count = -1; + if (ReadFile(/* hFile */ desc, + /* lpBuffer */ buf, + /* nNumberOfBytesToRead */ size, + /* lpNumberOfBytesRead */ &count, + /* lpOverlapped */ NULL)) + return count; + return -1; +#else + return read(desc, buf, size); +#endif +} + +OPENAXIOM_C_EXPORT int +oa_filedesc_write(openaxiom_filedesc desc, const Byte* buf, int size) +{ +#ifdef __WIN32__ + DWORD count = -1; + if (WriteFile(/* hFile */ desc, + /* lpBuffer */ buf, + /* nNumberOfBytesToWrite */ size, + /* lpNumberOfBytesWritten */ &count, + /* lpOverlapped */ NULL)) + return count; + return -1; +#else + return write(desc, buf, size); +#endif +} + +OPENAXIOM_C_EXPORT int +oa_filedesc_close(openaxiom_filedesc desc) +{ +#ifdef __WIN32__ + return CloseHandle(desc) ? 0 : -1; +#else + return close(desc); +#endif +} + +/* IP sockets. +*/ + +OPENAXIOM_C_EXPORT openaxiom_socket +oa_connect_ip_port_stream(const Byte* addr, int prot, openaxiom_port port) +{ + struct sockaddr_in server; + openaxiom_socket sock; + /* IP6 is not yet supported. */ + if (prot != 4) + return OPENAXIOM_INVALID_SOCKET; + + sock = openaxiom_socket_stream_link(AF_INET); + if (openaxiom_socket_is_invalid(sock)) + return OPENAXIOM_INVALID_SOCKET; + + memset(&server, 0, sizeof server); + server.sin_family = AF_INET; + memcpy(&server.sin_addr, addr, prot); + server.sin_port = htons(port); + if (connect(sock, (struct sockaddr*)&server, sizeof server) < 0) { + oa_close_socket(sock); + return OPENAXIOM_INVALID_SOCKET; + } + return sock; +} + +/* It is idiomatic in the Unix/POSIX world to use the standard + read() and write() functions on sockets. However, in the Windows + world, that is invalid. Consequently, portability suggests that + we restrict ourselves to the POSIX standard functions recv() and + send(). */ + + +/* Read some bytes of data into buffer `buf' with capacity `size'. + On failure, return -1; otherwise return the number of bytes + actually read. */ + +OPENAXIOM_C_EXPORT int +oa_socket_read(openaxiom_socket sock, Byte* buf, int size) +{ + return recv(sock, (char*) buf, size, 0); +} + +/* Attempt to read a byte from scoket `sock'. + On failure, return -1; otherwise the actual byte read. */ + +OPENAXIOM_C_EXPORT int +oa_socket_read_byte(openaxiom_socket sock) +{ + Byte byte; + if(oa_socket_read(sock, &byte, 1) < 1) + return -1; + return byte; +} + + +/* Send `size' bytes of data contained in `buf' to the socket `sock'. + Return -1 on failured; the number of actualy write bytes on success. */ + +OPENAXIOM_C_EXPORT int +oa_socket_write(openaxiom_socket sock, const Byte* buf, int size) +{ + return send(sock, (const char*) buf, size, 0); +} + +/* Send one byte to socket `sock'. */ +OPENAXIOM_C_EXPORT int +oa_socket_write_byte(openaxiom_socket sock, Byte byte) +{ + return oa_socket_write(sock, &byte, 1) < 1 ? -1 : byte; +} + + +/* Return 1 is the last call was cancelled. */ + +static inline int +openaxiom_syscall_was_cancelled() +{ +#ifdef __WIN32__ + return WSAGetLastError() == WSAEINTR; +#else + return errno == EINTR; +#endif +} + +/* Return 1 is last connect() was refused. */ + +static inline int +openaxiom_connection_refused() +{ +#ifdef __WIN32__ + return WSAGetLastError() == WSAECONNREFUSED; +#else + return errno == ECONNREFUSED; +#endif +} + + +OPENAXIOM_C_EXPORT void +sigpipe_handler(int sig) +{ + socket_closed = 1; +} + +OPENAXIOM_C_EXPORT int +wait_for_client_read(openaxiom_sio *sock, Byte* buf, int buf_size, + const char* msg) +{ + int ret_val; + switch(sock->purpose) { + case SessionManager: + case ViewportServer: + sock_accept_connection(sock->purpose); + ret_val = sread(purpose_table[sock->purpose], buf, buf_size, msg); + sock->socket = 0; + return ret_val; + default: + sock->socket = 0; + return -1; + } +} + +OPENAXIOM_C_EXPORT int +wait_for_client_write(openaxiom_sio* sock, const Byte* buf, + int buf_size, const char* msg) +{ + int ret_val; + switch(sock->purpose) { + case SessionManager: + case ViewportServer: + sock_accept_connection(sock->purpose); + ret_val = swrite(purpose_table[sock->purpose], buf, buf_size, msg); + sock->socket = 0; + return ret_val; + default: + sock->socket = 0; + return -1; + } +} + +OPENAXIOM_C_EXPORT int +sread(openaxiom_sio* sock, Byte* buf, int buf_size, const char *msg) +{ + int ret_val; + char err_msg[256]; + errno = 0; + do { + ret_val = oa_socket_read(sock->socket, buf, buf_size); + } while (ret_val == -1 && openaxiom_syscall_was_cancelled()); + if (ret_val == 0) { + FD_CLR(sock->socket, &socket_mask); + purpose_table[sock->purpose] = NULL; + oa_close_socket(sock->socket); + return wait_for_client_read(sock, buf, buf_size, msg); + } + if (ret_val == -1) { + if (msg) { + sprintf(err_msg, "reading: %s", msg); + perror(err_msg); + } + return -1; + } + return ret_val; +} + +OPENAXIOM_C_EXPORT int +swrite(openaxiom_sio* sock, const Byte* buf, int buf_size, + const char* msg) +{ + int ret_val; + char err_msg[256]; + errno = 0; + socket_closed = 0; + ret_val = oa_socket_write(sock->socket, buf, buf_size); + if (ret_val == -1) { + if (socket_closed) { + FD_CLR(sock->socket, &socket_mask); + purpose_table[sock->purpose] = NULL; + /* printf(" closing socket %d\n", sock->socket); */ + oa_close_socket(sock->socket); + return wait_for_client_write(sock, buf, buf_size, msg); + } else { + if (msg) { + sprintf(err_msg, "writing: %s", msg); + perror(err_msg); + } + return -1; + } + } + return ret_val; +} + +OPENAXIOM_C_EXPORT int +sselect(int n,fd_set *rd, fd_set *wr, fd_set *ex, void *timeout) +{ + int ret_val; + do { + ret_val = select(n, rd, wr, ex, (struct timeval *) timeout); + } while (ret_val == -1 && openaxiom_syscall_was_cancelled()); + return ret_val; +} + +OPENAXIOM_C_EXPORT int +fill_buf(openaxiom_sio *sock, Byte* buf, int len, const char* msg) +{ + int bytes = 0, ret_val; + while(bytes < len) { + ret_val = sread(sock, buf + bytes, len - bytes, msg); + if (ret_val == -1) return -1; + bytes += ret_val; + } + return bytes; +} + +OPENAXIOM_C_EXPORT int +get_int(openaxiom_sio *sock) +{ + int val = -1, len; + len = fill_buf(sock, byte_address(val), sizeof(int), "get_int"); + if (len != sizeof(int)) { +#ifdef DEBUG + fprintf(stderr,"get_int: caught error\n",val); +#endif + return -1; + } +#ifdef DEBUG + fprintf(stderr,"get_int: received %d\n",val); +#endif + return val; +} + +OPENAXIOM_C_EXPORT int +sock_get_int(int purpose) +{ + if (accept_if_needed(purpose) != -1) + return get_int(purpose_table[purpose]); + else return -1; +} + +OPENAXIOM_C_EXPORT int +get_ints(openaxiom_sio *sock, int *vals, int num) +{ + int i; + for(i=0; i 1023) { + char *buf; + buf = (char*) malloc(len+1); + strncpy(buf,str,len); + buf[len]='\0'; + send_int(sock,len+1); + val = swrite(sock, (const Byte*) buf, len+1, "send_string_len"); + free(buf); + } else { + static char buf[1024]; + strncpy(buf, str, len); + buf[len] = '\0'; + send_int(sock, len+1); + val = swrite(sock, (const Byte*) buf, len+1, "send_string_len"); + } + if (val == -1) { + return val; + } + return 0; +} + +OPENAXIOM_C_EXPORT int +send_string(openaxiom_sio* sock, const char* str) +{ + int val, len = strlen(str); + send_int(sock, len+1); + val = swrite(sock, (const Byte*) str, len+1, "send_string"); + if (val == -1) { + return -1; + } + return 0; +} + + +OPENAXIOM_C_EXPORT int +sock_send_string(int purpose, const char *str) +{ + if (accept_if_needed(purpose) != -1) + return send_string(purpose_table[purpose], str); + return -1; +} + +OPENAXIOM_C_EXPORT int +sock_send_string_len(int purpose, const char* str, int len) +{ + if (accept_if_needed(purpose) != -1) + return send_string_len(purpose_table[purpose], str, len); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_strings(openaxiom_sio *sock, const char** vals, int num) +{ + int i; + for(i=0; inbytes_pending == 0) + sock->nbytes_pending = get_int(sock); + nbytes_to_read = sock->nbytes_pending > buf_len + ? buf_len + : sock->nbytes_pending; + nbytes_read = fill_buf(sock, (Byte*)buf, nbytes_to_read, + "get_string_buf"); + if (nbytes_read == -1) { + sock->nbytes_pending = 0; + return NULL; + } + sock->nbytes_pending -= nbytes_read; + return sock->nbytes_pending == 0 ? NULL : buf; +} + +OPENAXIOM_C_EXPORT char * +sock_get_string_buf(int purpose, char* buf, int buf_len) +{ + if (accept_if_needed(purpose) != -1) + return get_string_buf(purpose_table[purpose], buf, buf_len); + return NULL; +} + +OPENAXIOM_C_EXPORT int +get_strings(openaxiom_sio *sock, char** vals,int num) +{ + int i; + for(i=0; ipurpose) { + case SessionManager: + case ViewportServer: + sock_accept_connection(sock->purpose); + ret_val = send_signal(purpose_table[sock->purpose], sig); + sock->socket = 0; + return ret_val; + default: + sock->socket = 0; + return -1; + } +} + + +OPENAXIOM_C_EXPORT int +sock_get_remote_fd(int purpose) +{ + if (accept_if_needed(purpose) != -1) + return purpose_table[purpose]->remote; + return -1; +} + +OPENAXIOM_C_EXPORT int +send_signal(openaxiom_sio *sock, int sig) +{ + int ret_val; +#if HAVE_DECL_KILL + ret_val = kill(sock->pid, sig); +#else + ret_val = raise(sig); +#endif + if (ret_val == -1 && errno == ESRCH) { + FD_CLR(sock->socket, &socket_mask); + purpose_table[sock->purpose] = NULL; +/* printf(" closing socket %d\n", sock->socket); */ + oa_close_socket(sock->socket); + return wait_for_client_kill(sock, sig); + } + return ret_val; +} + +OPENAXIOM_C_EXPORT int +sock_send_signal(int purpose,int sig) +{ + if (accept_if_needed(purpose) != -1) + return send_signal(purpose_table[purpose], sig); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_wakeup(openaxiom_sio *sock) +{ +#ifdef SIGUSR1 + return send_signal(sock, SIGUSR1); +#else + return -1; +#endif +} + +OPENAXIOM_C_EXPORT int +sock_send_wakeup(int purpose) +{ + if (accept_if_needed(purpose) != -1) + return send_wakeup(purpose_table[purpose]); + return -1; +} + +OPENAXIOM_C_EXPORT openaxiom_sio * +connect_to_local_server_new(const char *server_name, int purpose, int time_out) +{ + int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1; + openaxiom_sio *sock; + char name[256]; + + make_server_name(name, server_name); + sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1); + if (sock == NULL) { + perror("allocating socket space"); + return NULL; + } + + sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); + if (is_invalid_socket(sock)) { + perror("opening client socket"); + free(sock); + return NULL; + } + + memset(server.addr.u_addr.sa_data, 0, + sizeof(server.addr.u_addr.sa_data)); + sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; + strcpy(sock->addr.u_addr.sa_data, name); + for(i=0; isocket, &sock->addr.u_addr, + sizeof(sock->addr.u_addr)); + if (code == -1) { + if (errno != ENOENT && !openaxiom_connection_refused()) { + perror("connecting server stream socket"); + return NULL; + } else { + if (i != max_con - 1) + openaxiom_sleep(1); + continue; + } + } else break; + } + + if (code == -1) { + return NULL; + } + + send_int(sock, oa_getpid()); + send_int(sock, purpose); + send_int(sock, sock->socket); + sock->pid = get_int(sock); + sock->remote = get_int(sock); + return sock; +} + +OPENAXIOM_C_EXPORT openaxiom_sio * +connect_to_local_server(const char *server_name, int purpose, int time_out) +{ + int max_con=(time_out == 0 ? 1000000 : time_out), i, code=-1; + openaxiom_sio *sock; + char name[256]; + + make_server_name(name, server_name); + sock = (openaxiom_sio *) calloc(sizeof(openaxiom_sio), 1); + if (sock == NULL) { + perror("allocating socket space"); + return NULL; + } + + sock->purpose = purpose; + /* create the socket */ + sock->socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); + if (is_invalid_socket(sock)) { + perror("opening client socket"); + free(sock); + return NULL; + } + /* connect socket using name specified in command line */ + memset(server.addr.u_addr.sa_data, 0, + sizeof(server.addr.u_addr.sa_data)); + sock->addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; + strcpy(sock->addr.u_addr.sa_data, name); + for(i=0; isocket, &sock->addr.u_addr, + sizeof(sock->addr.u_addr)); + if (code == -1) { + if (errno != ENOENT && !openaxiom_connection_refused()) { + perror("connecting server stream socket"); + return NULL; + } else { + if (i != max_con - 1) + openaxiom_sleep(1); + continue; + } + } else break; + } + if (code == -1) { + return NULL; + } + send_int(sock, oa_getpid()); + send_int(sock, sock->purpose); + send_int(sock, sock->socket); + sock->pid = get_int(sock); +/* fprintf(stderr, "Got int form socket\n"); */ + sock->remote = get_int(sock); + return sock; +} + +/* act as terminal session for sock connected to stdin and stdout of another + process */ +OPENAXIOM_C_EXPORT void +remote_stdio(openaxiom_sio *sock) +{ + char buf[1024]; + fd_set rd; + int len; + while (1) { + FD_ZERO(&rd); + FD_SET(sock->socket,&rd); + FD_SET(0, &rd); + len = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL); + if (len == -1) { + perror("stdio select"); + return; + } + if (FD_ISSET(0, &rd)) { + fgets(buf,1024,stdin); + len = strlen(buf); + swrite(sock, byte_address(buf), len, "remote_stdio::write"); + } + if (FD_ISSET(sock->socket, &rd)) { + len = sread(sock, byte_address(buf), 1024, "remote_stdio::read"); + if (len == -1) + return; + else { + *(buf + len) = '\0'; + fputs(buf, stdout); + fflush(stdout); + } + } + } +} + +/* initialize the table of dedicated sockets */ +static void +init_purpose_table() +{ + int i; + for(i=0; ipid = get_int(sock); + sock->purpose = get_int(sock); + sock->remote = get_int(sock); + send_int(sock, oa_getpid()); + send_int(sock, sock->socket); + purpose_table[sock->purpose] = sock; +} + +OPENAXIOM_C_EXPORT int +accept_connection() +{ + int client = 0; + while (client < MaxClients && clients[client].socket != 0) + ++client; + if (client == MaxClients) { + printf("Ran out of client openaxiom_sio structures\n"); + return -1; + } + clients[client].socket = accept(server.socket, 0, 0); + if (is_invalid_socket(&clients[client])) { + perror("accept_connection"); + clients[client].socket = 0; + return -1; + } + FD_SET(clients[client].socket, &socket_mask); + get_socket_type(&clients[client]); + return clients[client].purpose; +} + +OPENAXIOM_C_EXPORT int +sock_accept_connection(int purpose) +{ + fd_set rd; + int ret_val, p; + if (oa_getenv("SPADNUM") == NULL) return -1; + while (1) { + rd = server_mask; + ret_val = sselect(FD_SETSIZE, &rd, nullptr, nullptr, NULL); + if (ret_val == -1) { + perror ("Select"); + return -1; + } + if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) { + p = accept_connection(); + if (p == purpose) return 1; + } + } +} + +/* Socket I/O selection called from the BOOT serverLoop function */ + +OPENAXIOM_C_EXPORT int +server_switch() +{ + int ret_val, cmd = 0; + fd_set rd, wr, ex, fds_mask; + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + fds_mask = server_mask; + cmd = 0; + if (purpose_table[SessionManager] != NULL) { + FD_SET(0, &fds_mask); + FD_SET(purpose_table[SessionManager]->socket, &fds_mask); + } + while (1) { + do { + if (purpose_table[MenuServer] != NULL) { + FD_SET(purpose_table[MenuServer]->socket, &fds_mask); + } + rd = fds_mask; + ret_val = select(FD_SETSIZE, &rd, 0, 0, 0); + if (ret_val == -1) { + /* perror ("Select in switch"); */ + return -1; + } + if (is_valid_socket(&server) && FD_ISSET(server.socket, &rd)) + accept_connection(); + } while (purpose_table[SessionManager] == NULL); + FD_SET(purpose_table[SessionManager]->socket, &fds_mask); + if (FD_ISSET(purpose_table[SessionManager]->socket, &rd)) { + cmd = get_int(purpose_table[SessionManager]); + return cmd; + } + if (FD_ISSET(0, &rd)) { + return CallInterp; + } + if (purpose_table[MenuServer] != NULL && + (FD_ISSET(purpose_table[MenuServer]->socket, &rd))) { + cmd = get_int(purpose_table[MenuServer]); + return cmd; + } + } +} + +} -- cgit v1.2.3