diff options
Diffstat (limited to 'src/lib/sockio-c.cxx')
-rw-r--r-- | src/lib/sockio-c.cxx | 1307 |
1 files changed, 1307 insertions, 0 deletions
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 <stdio.h> +#include <stdlib.h> + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include <sys/time.h> +#include <string.h> +#include <signal.h> +#ifdef __WIN32__ +# include <winsock2.h> +# include <ws2tcpip.h> +#else +# include <arpa/inet.h> +# include <netdb.h> +#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<num; i++) + *vals++ = get_int(sock); + return 0; +} + +OPENAXIOM_C_EXPORT int +sock_get_ints(int purpose, int *vals, int num) +{ + if (accept_if_needed(purpose) != -1) + return get_ints(purpose_table[purpose], vals, num); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_int(openaxiom_sio *sock,int val) +{ + int ret_val; + ret_val = swrite(sock, byte_address(val), sizeof(int), "send_int"); + if (ret_val == -1) { + return -1; + } + return 0; +} + +OPENAXIOM_C_EXPORT int +sock_send_int(int purpose,int val) +{ + if (accept_if_needed(purpose) != -1) + return send_int(purpose_table[purpose], val); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_ints(openaxiom_sio *sock, const int *vals, int num) +{ + int i; + for(i=0; i<num; i++) + if (send_int(sock, *vals++) == -1) + return -1; + return 0; +} + +OPENAXIOM_C_EXPORT int +sock_send_ints(int purpose, const int *vals, int num) +{ + if (accept_if_needed(purpose) != -1) + return send_ints(purpose_table[purpose], vals, num); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_string_len(openaxiom_sio *sock, const char *str,int len) +{ + int val; + if (len > 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; i<num; i++) + if (send_string(sock, *vals++) == -1) + return -1; + return 0; +} + +OPENAXIOM_C_EXPORT int +sock_send_strings(int purpose, const char**vals, int num) +{ + if (accept_if_needed(purpose) != -1) + return send_strings(purpose_table[purpose], vals, num); + return -1; +} + +OPENAXIOM_C_EXPORT char * +get_string(openaxiom_sio *sock) +{ + int val, len; + char *buf; + len = get_int(sock); + if (len <0) return NULL; + buf = (char*) malloc(len*sizeof(char)); + val = fill_buf(sock, (Byte*) buf, len, "get_string"); + if (val == -1){ + free(buf); + return NULL; + } +#ifdef DEBUG + fprintf(stderr,"get_string: received \"%s\" \n",buf); +#endif + return buf; +} + +OPENAXIOM_C_EXPORT char * +sock_get_string(int purpose) +{ + if (accept_if_needed(purpose) != -1) + return get_string(purpose_table[purpose]); + else return NULL; +} + + +OPENAXIOM_C_EXPORT char * +get_string_buf(openaxiom_sio *sock, char *buf, int buf_len) +{ + int nbytes_read; + int nbytes_to_read; + if(sock->nbytes_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; i<num; i++) + *vals++ = get_string(sock); + return 0; +} + +OPENAXIOM_C_EXPORT int +sock_get_strings(int purpose, char** vals, int num) +{ + if (accept_if_needed(purpose) != -1) + return get_strings(purpose_table[purpose], vals, num); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_float(openaxiom_sio *sock, double num) +{ + int val; + val = swrite(sock, byte_address(num), sizeof(double),"send_float"); + if (val == -1) { + return -1; + } + return 0; +} + +OPENAXIOM_C_EXPORT int +sock_send_float(int purpose, double num) +{ + if (accept_if_needed(purpose) != -1) + return send_float(purpose_table[purpose], num); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_sfloats(openaxiom_sio *sock, const float *vals,int num) +{ + int i; + for(i=0; i<num; i++) + if (send_float(sock, (double) *vals++) == -1) + return -1; + return 0; +} + +OPENAXIOM_C_EXPORT int +sock_send_sfloats(int purpose, const float* vals, int num) +{ + if (accept_if_needed(purpose) != -1) + return send_sfloats(purpose_table[purpose], vals, num); + return -1; +} + +OPENAXIOM_C_EXPORT int +send_floats(openaxiom_sio *sock, const double *vals, int num) +{ + int i; + for(i=0; i<num; i++) + if (send_float(sock, *vals++) == -1) + return -1; + return 0; +} + +OPENAXIOM_C_EXPORT int +sock_send_floats(int purpose, const double *vals, int num) +{ + if (accept_if_needed(purpose) != -1) + return send_floats(purpose_table[purpose], vals, num); + return -1; +} + +OPENAXIOM_C_EXPORT double +get_float(openaxiom_sio *sock) +{ + double num = -1.0; + fill_buf(sock, byte_address(num), sizeof(double), "get_float"); +#ifdef DEBUG + fprintf(stderr,"get_float: received %f\n",num); +#endif + return num; +} + +OPENAXIOM_C_EXPORT double +sock_get_float(int purpose) +{ + if (accept_if_needed(purpose) != -1) + return get_float(purpose_table[purpose]); + else return 0.0; +} + +OPENAXIOM_C_EXPORT int +get_sfloats(openaxiom_sio *sock, float *vals, int num) +{ + int i; + for(i=0; i<num; i++) + *vals++ = (float) get_float(sock); + return 0; +} + + +OPENAXIOM_C_EXPORT int +sock_get_sfloats(int purpose,float * vals, int num) +{ + if (accept_if_needed(purpose) != -1) + return get_sfloats(purpose_table[purpose], vals, num); + return -1; +} + +OPENAXIOM_C_EXPORT int +get_floats(openaxiom_sio *sock,double *vals,int num) +{ + int i; + for(i=0; i<num; i++) + *vals++ = get_float(sock); + return 0; +} + + +OPENAXIOM_C_EXPORT int +sock_get_floats(int purpose, double *vals, int num) +{ + if (accept_if_needed(purpose) != -1) + return get_floats(purpose_table[purpose], vals, num); + return -1; +} + +OPENAXIOM_C_EXPORT int +wait_for_client_kill(openaxiom_sio *sock, int sig) +{ + int ret_val; + switch(sock->purpose) { + 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; i<max_con; i++) { + code = connect(sock->socket, &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; i<max_con; i++) { + code = connect(sock->socket, &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; i<TotalMaxPurposes; i++) { + purpose_table[i] = NULL; + } +} + + +OPENAXIOM_C_EXPORT int +make_server_number() +{ + spad_server_number = oa_getpid(); + return spad_server_number; +} + +OPENAXIOM_C_EXPORT void +close_socket(openaxiom_socket socket_num, const char *name) +{ + oa_close_socket(socket_num); + oa_unlink(name); +} + +OPENAXIOM_C_EXPORT int +make_server_name(char *name, const char* base) +{ + char *num; + if (spad_server_number != -1) { + sprintf(name, "%s%d", base, spad_server_number); + return 0; + } + num = oa_getenv("SPADNUM"); + if (num == NULL) { +/* fprintf(stderr, + "\n(AXIOM Sockets) The AXIOM server number is undefined.\n"); +*/ + return -1; + } + sprintf(name, "%s%s", base, num); + return 0; +} + +static void +init_socks() +{ + FD_ZERO(&socket_mask); + FD_ZERO(&server_mask); + init_purpose_table(); + server.socket = 0; + for (int i=0; i<MaxClients; i++) + clients[i].socket = 0; +} + +/* client Spad server sockets: server is a local domain socket. */ +OPENAXIOM_C_EXPORT int +open_server(const char* server_name) +{ + char *s, name[256]; + + init_socks(); +#ifdef SIGPIPE + bsdSignal(SIGPIPE, sigpipe_handler,RestartSystemCalls); +#endif + if (make_server_name(name, server_name) == -1) + return -2; + /* Next create the local domain socket */ + server.socket = openaxiom_socket_stream_link(OPENAXIOM_AF_LOCAL); + if (is_invalid_socket(&server)) { + perror("opening local server socket"); + server.socket = 0; + return -2; + } else { + server.addr.u_addr.sa_family = OPENAXIOM_AF_LOCAL; + memset(server.addr.u_addr.sa_data, 0, + sizeof(server.addr.u_addr.sa_data)); + strcpy(server.addr.u_addr.sa_data, name); + if (bind(server.socket, &server.addr.u_addr, + sizeof(server.addr.u_addr))) { + perror("binding local server socket"); + server.socket = 0; + return -2; + } + FD_SET(server.socket, &socket_mask); + FD_SET(server.socket, &server_mask); + listen(server.socket, 5); + } + s = oa_getenv("SPADSERVER"); + if (s == NULL) { +/* fprintf(stderr, "Not a spad server system\n"); */ + return -1; + } + return 0; +} + +/* reads a the socket purpose declaration for classification */ +OPENAXIOM_C_EXPORT void +get_socket_type(openaxiom_sio *sock) +{ + sock->pid = 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; + } + } +} + +} |