/* * Author: NoMachine * * Copyright (c) 2009, 2012 NoMachine * All rights reserved * * Support functions and system calls' replacements needed to let the * software run on Win32 based operating systems. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. 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. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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 #include #include "sfds.h" #ifndef __MINGW32__ #include #endif extern void debug(const char *fmt,...); extern void debug2(const char *fmt,...); extern void debug3(const char *fmt,...); extern void error(const char *fmt,...); extern void fatal(const char *fmt,...); /* * structure to store real file descriptor and type for sfd */ static struct { int fd; HANDLE handle; sfd_type type; } sfd_map[SFD_MAP_SIZE]; static int sfd_map_init = 0; static int sfd_count = 0; int sfd_start = 0; #ifndef __MINGW32__ void myInvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved) { return; } #endif /* * store real fd in map, detect fd type and return sfd number. */ int allocate_sfd(int fd_or_handle) { int slot = SFD_FD_INVALID; int i; int real_fd; HANDLE real_handle; DWORD handle_type; /* * Init the map once */ if (!sfd_map_init) { sfd_map_init = 1; for (i = 0; i < SFD_MAP_SIZE; ++i) { sfd_map[i].fd = SFD_FD_INVALID; sfd_map[i].type = SFD_TYPE_NONE; } } /* * Find an open slot */ for (i = sfd_start; i < SFD_MAP_SIZE; ++i) { /* * Is this slot open? */ if (sfd_map[i].fd == SFD_FD_INVALID) { slot = i; break; } } /* * Bail if no slot found */ if (slot == SFD_FD_INVALID) { error("ERROR: Too many connections."); return -1; } #if 0 /* * Detect and save real fd and real handle */ int optVal; int optLen = sizeof(int); BOOL bIsSocket = TRUE; HRESULT hr = S_OK; int ret = getsockopt(fd_or_handle, SOL_SOCKET, SO_DEBUG, (char*)&optVal, &optLen); if (ret == SOCKET_ERROR && WSAGetLastError() == WSAENOTSOCK) { bIsSocket = FALSE; } // if (!bIsSocket && fd_or_handle > 600) // bIsSocket = TRUE; if (bIsSocket == TRUE) real_handle = (HANDLE)fd_or_handle; else #endif #ifndef __MINGW32__ _invalid_parameter_handler oldHandler, newHandler; newHandler = myInvalidParameterHandler; oldHandler = _set_invalid_parameter_handler(newHandler); int iPrev = _CrtSetReportMode(_CRT_ASSERT, 0); #endif real_handle = (HANDLE)_get_osfhandle(fd_or_handle); #ifndef __MINGW32__ _set_invalid_parameter_handler(oldHandler); _CrtSetReportMode(_CRT_ASSERT, iPrev); #endif if (real_handle == INVALID_HANDLE_VALUE) { /* * fd_or_handle was a handle, we can try to create a fd for it */ real_handle = (HANDLE) fd_or_handle; real_fd = _open_osfhandle((long) real_handle, 0); } else { /* * fd_or_handle was a fd */ real_fd = fd_or_handle; } debug3("_get_osfhandle() for real_fd [%d] returned [%d]", real_fd, real_handle); /* * Detect and save type */ handle_type = GetFileType(real_handle); debug3("GetFileType() for handle [%d] returned [%d]", real_handle, handle_type); switch (handle_type) { case FILE_TYPE_CHAR: { sfd_map[slot].type = SFD_TYPE_CONSOLE; break; } case FILE_TYPE_PIPE: { int optVal = 0; int optLen = sizeof(optVal); if (getsockopt((SOCKET) real_handle, SOL_SOCKET, SO_ACCEPTCONN, (char *) &optVal, &optLen)) { sfd_map[slot].type = SFD_TYPE_PIPE; } else { sfd_map[slot].type = SFD_TYPE_SOCKET; } break; } case FILE_TYPE_DISK: { sfd_map[slot].type = SFD_TYPE_FD; break; } case FILE_TYPE_UNKNOWN: { error("unknown type for handle [%d]", real_handle); return SFD_FD_INVALID; break; } default: { error("cannot detect a type for handle [%d]", real_handle); return SFD_FD_INVALID; break; } } /* * Save the fd and handle */ sfd_map[slot].fd = (int) real_fd; sfd_map[slot].handle = (HANDLE) real_handle; debug("allocating new sfd, sfd [%i] fd [%i] handle [%d] type [%i]", slot, real_fd, real_handle, sfd_map[slot].type); sfd_count++; /* * Return the slot as the sfd */ return (slot); } /* * For a real fd, get our sfd */ int fd_to_sfd(int real_fd) { int i; int sfds; /* * Walk the list. */ for (i = 0, sfds = 0; i < SFD_MAP_SIZE && sfds < sfd_count; i++) { /* * Increment the count of sfds that we have encountered in our walk, */ if (sfd_map[i].fd != SFD_FD_INVALID) { sfds++; } if (sfd_map[i].fd == real_fd) { return i; } } fatal("cannot convert fd to sfd"); return SFD_FD_INVALID; } /* * For an sfd, get the real descriptor behind it. */ int sfd_to_fd(int sfd) { return sfd_map[sfd].fd; } // set the sfd type to console. GetFileType() in Windows seem to return wrong type for a console returning PIPE (3) in place of CHARTYPE (2) void sfd_set_to_console(int sfd) { sfd_map[sfd].type = SFD_TYPE_CONSOLE; } /* * For an sfd, get the real handle behind it */ HANDLE sfd_to_handle(int sfd) { return sfd_map[sfd].handle; } void sfd_replace(int sfd, HANDLE handle, int type) { //_close(sfd_map[sfd].handle); sfd_map[sfd].handle = handle; sfd_map[sfd].type = type; } /* * For an sfd, get the type */ int get_sfd_type(int sfd) { if(sfd < sizeof(sfd_map) / sizeof(sfd_map[0])) { return sfd_map[sfd].type; } else { return -1; } } /* * Free an sfd from the map. */ void free_sfd(int sfd) { if (sfd_map[sfd].type != SFD_TYPE_NONE && sfd < sizeof(sfd_map) / sizeof(sfd_map[0])) { /* * Blank the slot */ sfd_map[sfd].fd = SFD_FD_INVALID; sfd_map[sfd].handle = (HANDLE) SFD_HANDLE_INVALID; sfd_map[sfd].type = SFD_TYPE_NONE; sfd_count--; } } /* * Check if sfd is file. */ int sfd_is_fd(int sfd) { if (sfd_map[sfd].type == SFD_TYPE_FD) { return 1; } return 0; } /* * Check if sfd is socket. */ int sfd_is_socket(int sfd) { if (sfd_map[sfd].type == SFD_TYPE_SOCKET) { return 1; } return 0; } /* * Check if sfd is pipe. */ int sfd_is_pipe(int sfd) { if (sfd_map[sfd].type == SFD_TYPE_PIPE) { return 1; } return 0; } /* * Check if sfd is console. */ int sfd_is_console(int sfd) { if (sfd_map[sfd].type == SFD_TYPE_CONSOLE) { return 1; } return 0; } /* * Check if sfd is file or console. */ int sfd_is_fd_or_console(int sfd) { if (sfd_is_fd(sfd) || sfd_is_console(sfd)) { return 1; } return 0; } /* * Check if sfd is socket or pipe. */ int sfd_is_socket_or_pipe(int sfd) { if (sfd_is_socket(sfd) || sfd_is_pipe(sfd)) { return 1; } return 0; }