Win32-OpenSSH/contrib/win32/win32compat/sfds.c

404 lines
6.9 KiB
C
Raw Normal View History

/*
* Author: NoMachine <developers@nomachine.com>
*
* 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 <winsock2.h>
#include <io.h>
#include "sfds.h"
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;
/*
* 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;
}
/*
* Detect and save real fd and real handle
*/
real_handle = (HANDLE) _get_osfhandle(fd_or_handle);
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;
}
/*
* 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;
}