mirror of
https://github.com/PowerShell/Win32-OpenSSH.git
synced 2025-07-04 20:54:52 +02:00
ssh-agent.exe and ssh-add.exe code updated and fixed to work in Windows. For convenience of users, ssh-agent.exe starts a cmd shell with the "SSH_AUTH_SOCK" and "SSH_AGENT_PID" environment variables set. ssh-add.exe can be run immediately from the cmd shell. 'ssh-add -L" and "ssh-add id_rsa" and "ssh-add -d id_rsa" are 3 useful commands to list, add and delete keys from ssh-agent cache.
2953 lines
52 KiB
C
2953 lines
52 KiB
C
/*
|
|
* 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 <errno.h>
|
|
#include <stdio.h>
|
|
#include <fcntl.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#ifndef __MINGW32__
|
|
#include <Crtdbg.h>
|
|
#endif
|
|
|
|
#include "sfds.h"
|
|
|
|
#define FAIL(X) if (X) goto fail
|
|
|
|
#undef DEBUG
|
|
|
|
#ifdef WIN32
|
|
#ifdef DEBUG
|
|
#define DBG_MSG(FMT, ...) debug3(FMT, ## ARGS)
|
|
#else
|
|
#define DBG_MSG(FMT, ...)
|
|
#endif
|
|
#else
|
|
#ifdef DEBUG
|
|
#define DBG_MSG(FMT, ARGS...) debug3(FMT, ## ARGS)
|
|
#else
|
|
#define DBG_MSG(FMT, ARGS...)
|
|
#endif
|
|
#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,...);
|
|
|
|
int glob_itissshclient = 0; // ssh client turns it to 1
|
|
static int winsock_initialized = 0;
|
|
|
|
extern int logfd;
|
|
|
|
static FD_SET debug_sfds;
|
|
static FD_SET crlf_sfds;
|
|
|
|
static fd_set read_sfd_set;
|
|
static fd_set write_sfd_set;
|
|
|
|
#define MAX_THREADS 256
|
|
#define TEST_READ 1
|
|
#define TEST_WRITE 0
|
|
|
|
#define MSG_WAITALL 0x8
|
|
|
|
#ifdef WIN32
|
|
#define STDIN_FILENO 0
|
|
#define STDOUT_FILENO 1
|
|
#define STDERR_FILENO 2
|
|
#endif
|
|
|
|
int PassInputFd = STDIN_FILENO;
|
|
int PassOutputFd = STDOUT_FILENO;
|
|
int PassErrorFd = STDERR_FILENO;
|
|
|
|
/*
|
|
* We store cookies for authorize
|
|
* connections on AF_UNIX sockets here.
|
|
*/
|
|
|
|
struct _SocketCookie
|
|
{
|
|
FILE *f;
|
|
int socket;
|
|
char *cookie;
|
|
} SocketCookieMap[SFD_MAP_SIZE] = {0};
|
|
|
|
DWORD WINAPI selectThread(LPVOID lpParam);
|
|
|
|
typedef struct
|
|
{
|
|
HANDLE thread;
|
|
|
|
DWORD thread_id;
|
|
|
|
HANDLE semaphore1;
|
|
HANDLE semaphore2;
|
|
|
|
int sfd;
|
|
int thread_no;
|
|
int test_type;
|
|
int signaled;
|
|
int exit;
|
|
int exited;
|
|
} thread_data_t, *thread_data_p;
|
|
|
|
static thread_data_p thread_data_set[MAX_THREADS];
|
|
|
|
#define IS_WINSOCK_INITIALIZED() (winsock_initialized != 0)
|
|
|
|
void WSHELPinitialize();
|
|
|
|
/*
|
|
* FIXME. This function forces stopping all socket threads
|
|
* at next select. This workaround nivelates problem with
|
|
* infinite hangs up in below scenario:
|
|
*
|
|
* a) read select start.
|
|
* b) write select start.
|
|
* c) read select ends: SSH2_MSG_CHANNEL_CLOSE received.
|
|
* d) close input channel.
|
|
* e) now write select may never ends.
|
|
*
|
|
* We call this function after (d).
|
|
*/
|
|
|
|
void StopSocketThreads()
|
|
{
|
|
DBG_MSG("-> StopSocketThreads()...");
|
|
|
|
FD_ZERO(&write_sfd_set);
|
|
FD_ZERO(&read_sfd_set);
|
|
|
|
DBG_MSG("<- StopSocketThreads()...");
|
|
}
|
|
|
|
|
|
void read_sfd_set_add(int sfd)
|
|
{
|
|
static int do_init = 1;
|
|
|
|
if (do_init)
|
|
{
|
|
FD_ZERO(&read_sfd_set);
|
|
|
|
do_init = 0;
|
|
}
|
|
|
|
FD_SET((SOCKET) sfd, &read_sfd_set);
|
|
}
|
|
|
|
|
|
void write_sfd_set_add(int sfd)
|
|
{
|
|
static int do_init = 1;
|
|
|
|
if (do_init)
|
|
{
|
|
FD_ZERO(&write_sfd_set);
|
|
|
|
do_init = 0;
|
|
}
|
|
|
|
FD_SET((SOCKET) sfd, &write_sfd_set);
|
|
}
|
|
|
|
|
|
void debug_sfd(int sfd)
|
|
{
|
|
static int do_init = 1;
|
|
|
|
if (do_init)
|
|
{
|
|
FD_ZERO(&debug_sfds);
|
|
|
|
do_init = 0;
|
|
}
|
|
|
|
FD_SET((SOCKET) sfd, &debug_sfds);
|
|
}
|
|
|
|
|
|
void crlf_sfd(int sfd)
|
|
{
|
|
static int do_init = 1;
|
|
|
|
if (do_init)
|
|
{
|
|
FD_ZERO(&crlf_sfds);
|
|
|
|
do_init = 0;
|
|
}
|
|
|
|
FD_SET((SOCKET) sfd, &crlf_sfds);
|
|
}
|
|
|
|
|
|
static int getWSAErrno()
|
|
{
|
|
int wsaerrno = WSAGetLastError();
|
|
|
|
if (wsaerrno == WSAEWOULDBLOCK)
|
|
{
|
|
return EAGAIN;
|
|
}
|
|
|
|
if (wsaerrno == WSAEFAULT)
|
|
{
|
|
return EFAULT;
|
|
}
|
|
|
|
if (wsaerrno == WSAEINVAL)
|
|
{
|
|
return EINVAL;
|
|
}
|
|
|
|
return wsaerrno;
|
|
}
|
|
|
|
|
|
int WSHELPisatty(int sfd)
|
|
{
|
|
int ret;
|
|
|
|
/*
|
|
* We can only do this for console fds.
|
|
*/
|
|
|
|
if (sfd_is_console(sfd) && sfd >= 0)
|
|
{
|
|
//ret = _isatty(sfd_to_fd(sfd));
|
|
|
|
return 1 ; //ret;
|
|
}
|
|
|
|
/*
|
|
* Not a tty.
|
|
*/
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPfstat(int sfd, struct stat *buf)
|
|
{
|
|
int ret;
|
|
|
|
struct _stat tmp;
|
|
|
|
DBG_MSG("WSHELPfstat(sfd = %d, buf = %p)", sfd, buf);
|
|
|
|
ret = _fstat(sfd_to_fd(sfd), &tmp);
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (ret == -1)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("fstat() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
buf -> st_gid = tmp.st_gid;
|
|
buf -> st_atime = tmp.st_atime;
|
|
buf -> st_ctime = tmp.st_ctime;
|
|
buf -> st_dev = tmp.st_dev;
|
|
buf -> st_ino = tmp.st_ino;
|
|
buf -> st_mode = tmp.st_mode;
|
|
buf -> st_mtime = tmp.st_mtime;
|
|
buf -> st_nlink = tmp.st_nlink;
|
|
buf -> st_rdev = tmp.st_rdev;
|
|
buf -> st_size = tmp.st_size;
|
|
buf -> st_uid = tmp.st_uid;
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
FILE* WSHELPfdopen(int sfd, const char *mode)
|
|
{
|
|
FILE* ret;
|
|
|
|
ret = fdopen(sfd_to_fd(sfd), mode);
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (ret == NULL)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("fdopen() returned error, errno [%d]", errno);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int WSHELPpipe(int pfds[2])
|
|
{
|
|
int ret;
|
|
|
|
ret = _pipe(pfds, 1024, _O_BINARY);
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (ret == -1)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("_pipe() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
pfds[0] = allocate_sfd((int)pfds[0]);
|
|
|
|
pfds[1] = allocate_sfd((int)pfds[1]);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int WSHELPdup(int oldsfd)
|
|
{
|
|
int oldfd;
|
|
|
|
int newfd;
|
|
|
|
int newsfd;
|
|
|
|
oldfd = sfd_to_fd(oldsfd);
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Pass through to base layer.
|
|
*/
|
|
|
|
newfd = _dup(oldfd);
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (newfd == -1)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("_dup() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Map the socket.
|
|
*/
|
|
|
|
newsfd = allocate_sfd(newfd);
|
|
|
|
return newsfd;
|
|
}
|
|
|
|
|
|
int WSHELPdup2(int oldsfd, int newsfd)
|
|
{
|
|
int oldfd;
|
|
int newfd;
|
|
|
|
oldfd = sfd_to_fd(oldsfd);
|
|
newfd = sfd_to_fd(newsfd);
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Pass through to base layer.
|
|
*/
|
|
|
|
newfd = _dup2(oldfd, newfd);
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (newfd == -1)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("_dup2() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Map the socket.
|
|
*/
|
|
|
|
newsfd = allocate_sfd(newfd);
|
|
|
|
return newsfd;
|
|
}
|
|
|
|
|
|
int WSHELPopen(const char *pathname, int flags, ...)
|
|
{
|
|
DBG_MSG("WSHELPopen(path = [%s], flags = [%d])", pathname, flags);
|
|
|
|
va_list arguments;
|
|
int newfd;
|
|
int newsfd;
|
|
|
|
va_start(arguments, flags);
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Pass through to base layer.
|
|
*/
|
|
|
|
newfd = _open(pathname, flags, arguments);
|
|
|
|
va_end(arguments);
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (newfd == -1)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("_open() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Map the socket.
|
|
*/
|
|
|
|
newsfd = allocate_sfd(newfd);
|
|
|
|
|
|
return newsfd;
|
|
}
|
|
|
|
|
|
int WSHELPwopen(const wchar_t *pathname, int flags, ...)
|
|
{
|
|
va_list arguments;
|
|
int newfd;
|
|
int newsfd;
|
|
|
|
va_start(arguments, flags);
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Pass through to base layer.
|
|
*/
|
|
|
|
newfd = _wopen(pathname, flags, arguments);
|
|
|
|
va_end(arguments);
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (newfd == -1)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("_wopen() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Map the socket.
|
|
*/
|
|
|
|
newsfd = allocate_sfd(newfd);
|
|
|
|
return newsfd;
|
|
}
|
|
|
|
|
|
int WSHELPcreat(const char *pathname, int mode)
|
|
{
|
|
int newfd;
|
|
int newsfd;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Pass through to base layer.
|
|
*/
|
|
|
|
newfd = _creat(pathname, mode);
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (newfd == -1)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("_creat() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Map the socket.
|
|
*/
|
|
|
|
newsfd = allocate_sfd(newfd);
|
|
|
|
return newsfd;
|
|
}
|
|
|
|
|
|
int WSHELPsocket(int af, int type, int protocol)
|
|
{
|
|
SOCKET sock = -1;
|
|
|
|
int sfd;
|
|
|
|
/*
|
|
* Verify that winsock has been initialized.
|
|
*/
|
|
|
|
if (!IS_WINSOCK_INITIALIZED())
|
|
{
|
|
WSHELPinitialize();
|
|
}
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
switch(af)
|
|
{
|
|
/*
|
|
* AF_UNIX. We emulate unix socket by localhost tcp here.
|
|
*/
|
|
|
|
case AF_UNIX:
|
|
{
|
|
DBG_MSG("Creating AF_UNIX socket...");
|
|
|
|
sock = socket(AF_INET, type, 0);
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* We pass through to base layer as default.
|
|
*/
|
|
|
|
default:
|
|
{
|
|
DBG_MSG("Creating AF_INET socket...");
|
|
|
|
sock = socket(af, type, protocol);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle errors.
|
|
*/
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("socket() returned error, errno [%d]", errno);
|
|
|
|
DBG_MSG("Cannot create socket : errno = %u", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
DBG_MSG("Socket %u created.", sock);
|
|
|
|
/*
|
|
* Map the socket to our fd.
|
|
*/
|
|
|
|
sfd = allocate_sfd((int) sock);
|
|
|
|
return sfd;
|
|
}
|
|
|
|
|
|
int WSHELPsetsockopt(int sfd, int level, int optname, const char* optval, int optlen)
|
|
{
|
|
SOCKET sock;
|
|
|
|
int ret;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = setsockopt(sock, level, optname, optval, optlen);
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("setsockopt() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPgetsockopt(int sfd, int level, int optname, char* optval, int* optlen)
|
|
{
|
|
SOCKET sock;
|
|
|
|
int ret;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = getsockopt(sock, level, optname, optval, optlen);
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("getsockopt() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPgetsockname(int sfd, struct sockaddr* name, int* namelen)
|
|
{
|
|
SOCKET sock;
|
|
|
|
int ret;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = getsockname(sock, name, namelen);
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("getsockname() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPgetpeername(int sfd, struct sockaddr* name, int* namelen)
|
|
{
|
|
SOCKET sock;
|
|
|
|
int ret;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = getpeername(sock, name, namelen);
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("getpeername() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPioctlsocket(int sfd, long cmd, u_long* argp)
|
|
{
|
|
SOCKET sock;
|
|
|
|
int ret;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = ioctlsocket(sock, cmd, argp);
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("ioctlsocket() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPlisten(int sfd, int backlog)
|
|
{
|
|
SOCKET sock;
|
|
|
|
int ret;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = listen(sock, backlog);
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("listen() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPbind(int sfd, const struct sockaddr *name, int namelen)
|
|
{
|
|
SOCKET sock = -1;
|
|
|
|
int ret = SOCKET_ERROR;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
switch(name -> sa_family)
|
|
{
|
|
/*
|
|
* We emulate unix socket here, by tcp socket binded to localhost.
|
|
*/
|
|
|
|
case AF_UNIX:
|
|
{
|
|
int len = 0;
|
|
|
|
unsigned int i = 0;
|
|
|
|
FILE *f = NULL;
|
|
|
|
char cookie[64 + 1] = {0};
|
|
|
|
struct sockaddr_in sin = {0};
|
|
|
|
struct sockaddr_un *unixName = (struct sockaddr_un *) name;
|
|
|
|
/*
|
|
* Bind socket to localhost:0.
|
|
*/
|
|
|
|
DBG_MSG("Binding socket %u to localhost:0...", (unsigned int) sock);
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = 0;
|
|
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
|
|
FAIL(bind(sock, (struct sockaddr *) &sin, sizeof(sin)));
|
|
|
|
/*
|
|
* Retreave local name for socket.
|
|
*/
|
|
|
|
DBG_MSG("Retreaving socket's local name...");
|
|
|
|
len = sizeof(sin);
|
|
|
|
FAIL(getsockname(sock, (struct sockaddr *) &sin, &len));
|
|
|
|
sin.sin_port = ntohs(sin.sin_port);
|
|
|
|
DBG_MSG("family = %u", sin.sin_family);
|
|
DBG_MSG("port = %u", sin.sin_port);
|
|
|
|
/*
|
|
* Check is socket file already exists.
|
|
*/
|
|
|
|
DBG_MSG("Checking is socket file free...");
|
|
|
|
WSASetLastError(WSAEADDRINUSE);
|
|
|
|
f = fopen(unixName -> sun_path, "rt");
|
|
|
|
FAIL(f);
|
|
|
|
/*
|
|
* Create file with retrieved port and cookie.
|
|
* This file emulates unix socket itself.
|
|
*/
|
|
|
|
DBG_MSG("Creating socket file [%s]...", unixName -> sun_path);
|
|
|
|
f = fopen(unixName -> sun_path, "wt+");
|
|
|
|
FAIL(f == NULL);
|
|
|
|
/*
|
|
* Write tcp port to soket file.
|
|
*/
|
|
|
|
fprintf(f, "%d ", sin.sin_port);
|
|
|
|
/*
|
|
* Write 64-byte cookie to socket file.
|
|
* We add port number to rand() to avoid generating the same
|
|
* cookie until next second reached.
|
|
*
|
|
*/
|
|
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
cookie[i] = 33 + (rand() + sin.sin_port) % (128 - 33);
|
|
}
|
|
|
|
cookie[64] = 0;
|
|
|
|
fputs(cookie, f);
|
|
|
|
fflush(f);
|
|
|
|
/*
|
|
* Cache cookie and file handle in SocketCookieMap var.
|
|
*/
|
|
|
|
for (i = 0; i < SFD_MAP_SIZE; i++)
|
|
{
|
|
/*
|
|
* Find first empty row.
|
|
*/
|
|
|
|
if (SocketCookieMap[i].socket == 0)
|
|
{
|
|
SocketCookieMap[i].socket = sock;
|
|
SocketCookieMap[i].cookie = strdup(cookie);
|
|
SocketCookieMap[i].f = f;
|
|
|
|
/*
|
|
for (int i = 0; i < 64; j++)
|
|
{
|
|
printf("%02x ", SocketCookieMap[i].cookie[j]);
|
|
}
|
|
*/
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Clear error.
|
|
*/
|
|
|
|
ret = 0;
|
|
|
|
WSASetLastError(0);
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* As default, we call underlying function.
|
|
*/
|
|
|
|
default:
|
|
{
|
|
ret = bind(sock, name, namelen);
|
|
}
|
|
}
|
|
|
|
fail:
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("bind() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPconnect(int sfd, const struct sockaddr* name, int namelen)
|
|
{
|
|
SOCKET sock = -1;
|
|
|
|
int ret = SOCKET_ERROR;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
switch(name -> sa_family)
|
|
{
|
|
/*
|
|
* We emulate unix socket here, by tcp socket binded to localhost.
|
|
*/
|
|
|
|
case AF_UNIX:
|
|
{
|
|
int len = 0;
|
|
int port = -1;
|
|
|
|
char cookie[64 + 1] = {0};
|
|
|
|
unsigned int i = 0;
|
|
|
|
FILE *f = NULL;
|
|
|
|
struct sockaddr_in sin = {0};
|
|
|
|
struct sockaddr_un *unixName = (struct sockaddr_un *) name;
|
|
|
|
/*
|
|
* Open socket file.
|
|
*/
|
|
|
|
DBG_MSG("Opening socket file [%s] for socket %u...",
|
|
unixName -> sun_path, (unsigned int) sock);
|
|
|
|
f = fopen(unixName -> sun_path, "rt");
|
|
|
|
FAIL(f == NULL);
|
|
|
|
/*
|
|
* Read tcp port and cokie from socket file.
|
|
*/
|
|
|
|
fscanf(f, "%d ", &port);
|
|
fgets(cookie, 64 + 1, f);
|
|
|
|
fclose(f);
|
|
|
|
/*
|
|
* Connect to localhost on given port.
|
|
*/
|
|
|
|
DBG_MSG("Connecting to localhost:%u on socket %u...",
|
|
port, (unsigned int) sock);
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_port = htons(port);
|
|
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
|
|
|
FAIL(connect(sock, (struct sockaddr *) &sin, sizeof(sin)));
|
|
|
|
/*
|
|
* Send authorization cookie.
|
|
* If cookie doesn't match to cookie stored on server side
|
|
* server shutdown connection.
|
|
*/
|
|
|
|
DBG_MSG("Sending authorization cookie...\n");
|
|
|
|
for (i = 0; i < 64; i++)
|
|
{
|
|
DBG_MSG("%02x ", cookie[i]);
|
|
}
|
|
|
|
DBG_MSG("\n");
|
|
|
|
|
|
ret = send(sock, cookie, 64, MSG_DONTROUTE);
|
|
|
|
FAIL(ret != 64);
|
|
|
|
/*
|
|
* Clear error.
|
|
*/
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* As default, we call underlying function.
|
|
*/
|
|
|
|
default:
|
|
{
|
|
/*
|
|
* Call the underlying function as default.
|
|
*/
|
|
|
|
ret = connect(sock, name, namelen);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
fail:
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("connect() returned error, errno [%d]", errno);
|
|
|
|
DBG_MSG("connect() returned error, errno [%d]\n", errno);
|
|
|
|
/*
|
|
* Re-map EAGAIN for connect() semantics.
|
|
*/
|
|
|
|
if (errno == EAGAIN)
|
|
{
|
|
errno = WSAEINPROGRESS;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPshutdown(int sfd, int how)
|
|
{
|
|
SOCKET sock;
|
|
|
|
int ret;
|
|
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = shutdown(sock, how);
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("shutdown() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
int WSHELPaccept(int sfd, struct sockaddr* addr, int* addrlen)
|
|
{
|
|
SOCKET sock;
|
|
|
|
SOCKET new_sock;
|
|
|
|
int new_sfd;
|
|
|
|
int i = 0;
|
|
int j = 0;
|
|
int ret = -1;
|
|
|
|
int expectedFamily = addr -> sa_family;
|
|
|
|
/*
|
|
* Clear errno
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function
|
|
*/
|
|
|
|
new_sock = accept(sock, addr, addrlen);
|
|
|
|
switch(expectedFamily)
|
|
{
|
|
/*
|
|
* Cookie authorization for AF_UNIX.
|
|
*/
|
|
|
|
case AF_UNIX:
|
|
{
|
|
fd_set readsocks;
|
|
|
|
struct timeval timeout = {10, 0};
|
|
|
|
char remoteCookie[64 + 1] = {0};
|
|
|
|
int authorized = 0;
|
|
|
|
/*
|
|
* Retrieave 64-byte authorization cookie from client.
|
|
*/
|
|
|
|
DBG_MSG("Waiting for 64-byte cookie...\n");
|
|
|
|
FD_ZERO(&readsocks);
|
|
FD_SET((SOCKET) new_sock, &readsocks);
|
|
|
|
select(0, &readsocks, NULL, NULL, &timeout);
|
|
|
|
ret = recv(new_sock, remoteCookie, 64, 0);
|
|
|
|
|
|
#ifdef DEBUG
|
|
|
|
DBG_MSG("\nRemoteCookie = [");
|
|
|
|
for (i = 0; remoteCookie[i]; i++)
|
|
{
|
|
DBG_MSG("%02x ", remoteCookie[i]);
|
|
}
|
|
|
|
DBG_MSG("]\n\n");
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Find correct cookie in SocketCookieMap.
|
|
*/
|
|
|
|
for (i = 0; i < SFD_MAP_SIZE; i++)
|
|
{
|
|
/*
|
|
* Find socket.
|
|
*/
|
|
|
|
if (SocketCookieMap[i].socket == sock)
|
|
{
|
|
#ifdef DEBUG
|
|
|
|
DBG_MSG("\nServerCookie = [");
|
|
|
|
for (j = 0; SocketCookieMap[i].cookie[j]; j++)
|
|
{
|
|
DBG_MSG("%02x ", SocketCookieMap[i].cookie[j]);
|
|
}
|
|
|
|
DBG_MSG("]\n\n");
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Compare cookies.
|
|
*/
|
|
|
|
if (strncmp(SocketCookieMap[i].cookie, remoteCookie, 64) == 0)
|
|
{
|
|
authorized = 1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Cookies doesn't match. Shutdown connection.
|
|
*/
|
|
|
|
if (authorized == 0)
|
|
{
|
|
DBG_MSG("ERROR. Accept from unathorized client."
|
|
" I'm going to shutdown connection.\n");
|
|
|
|
shutdown(new_sock, SD_BOTH);
|
|
|
|
new_sock = INVALID_SOCKET;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Handle errors
|
|
*/
|
|
|
|
if (new_sock == INVALID_SOCKET)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
debug("accept() returned error, errno [%d]", errno);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Map the socket
|
|
*/
|
|
|
|
new_sfd = allocate_sfd((int)new_sock);
|
|
|
|
return new_sfd;
|
|
}
|
|
|
|
|
|
int socketpair(int socks[2])
|
|
{
|
|
struct sockaddr_in addr;
|
|
|
|
SOCKET listener;
|
|
|
|
int e;
|
|
|
|
int addrlen = sizeof(addr);
|
|
|
|
/*
|
|
* Clear out last error.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
if (socks == 0)
|
|
{
|
|
WSASetLastError(WSAEINVAL);
|
|
|
|
errno = getWSAErrno();
|
|
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Initialize to invalid sockets.
|
|
*/
|
|
|
|
socks[0] = socks[1] = INVALID_SOCKET;
|
|
|
|
if ((listener = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Zero out the structure and set params.
|
|
*/
|
|
|
|
memset(&addr, 0, sizeof(addr));
|
|
|
|
addr.sin_family = AF_INET;
|
|
addr.sin_addr.s_addr = htonl(0x7f000001);
|
|
addr.sin_port = 0;
|
|
|
|
/*
|
|
* Call base function.
|
|
*/
|
|
|
|
e = bind(listener, (const struct sockaddr*) &addr, sizeof(addr));
|
|
|
|
if (e == SOCKET_ERROR)
|
|
{
|
|
e = WSAGetLastError();
|
|
|
|
closesocket(listener);
|
|
|
|
WSASetLastError(e);
|
|
|
|
errno = getWSAErrno();
|
|
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
/*
|
|
* Find out what ephermeral port got assigned.
|
|
*/
|
|
|
|
e = getsockname(listener, (struct sockaddr*) &addr, &addrlen);
|
|
|
|
if (e == SOCKET_ERROR)
|
|
{
|
|
e = WSAGetLastError();
|
|
|
|
closesocket(listener);
|
|
|
|
WSASetLastError(e);
|
|
|
|
errno = getWSAErrno();
|
|
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
do
|
|
{
|
|
if (listen(listener, 1) == SOCKET_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ((socks[0] = (int) WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0)) == (int) INVALID_SOCKET)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (connect(socks[0], (const struct sockaddr*) &addr, sizeof(addr)) == SOCKET_ERROR)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if ((socks[1] = (int) accept(listener, NULL, NULL)) == (int) INVALID_SOCKET)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/*
|
|
* Don't need to listen anymore.
|
|
*/
|
|
|
|
closesocket(listener);
|
|
|
|
/*
|
|
* Maps the sockets.
|
|
*/
|
|
|
|
socks[0] = allocate_sfd((int)socks[0]);
|
|
socks[1] = allocate_sfd((int)socks[1]);
|
|
|
|
/*
|
|
* All set, return the socket pair.
|
|
*/
|
|
|
|
return 0;
|
|
} while (0);
|
|
|
|
/*
|
|
* Cleanup and return if we bailed out of creation above.
|
|
*/
|
|
|
|
e = WSAGetLastError();
|
|
|
|
closesocket(listener);
|
|
|
|
closesocket(socks[0]);
|
|
|
|
closesocket(socks[1]);
|
|
|
|
WSASetLastError(e);
|
|
|
|
errno = getWSAErrno();
|
|
|
|
socks[0] = INVALID_SOCKET;
|
|
socks[1] = INVALID_SOCKET;
|
|
|
|
return SOCKET_ERROR;
|
|
}
|
|
|
|
int DataAvailable ( HANDLE h )
|
|
{
|
|
INPUT_RECORD irec = {0};
|
|
|
|
DWORD events_read = 0;
|
|
|
|
int ret = PeekConsoleInput (h, &irec, 1, &events_read);
|
|
|
|
if (!ret)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (events_read) // && irec.EventType == KEY_EVENT)
|
|
{
|
|
return events_read ;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
int peekConsoleRead(int sfd)
|
|
{
|
|
DWORD sleep_time = 0;
|
|
|
|
HANDLE h = sfd_to_handle(sfd);
|
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
{
|
|
error("can't get a handle for sfd [%d]", sfd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
FlushConsoleInputBuffer(h);
|
|
|
|
for (;;)
|
|
{
|
|
INPUT_RECORD irec = {0};
|
|
|
|
DWORD events_read = 0;
|
|
|
|
int ret = PeekConsoleInput (h, &irec, 1, &events_read);
|
|
|
|
if (!ret)
|
|
{
|
|
debug("PeekConsoleInput on sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
if (events_read && irec.EventType == KEY_EVENT)
|
|
{
|
|
break;
|
|
}
|
|
else if (events_read)
|
|
{
|
|
ReadConsoleInput (h, &irec, 1, &events_read);
|
|
}
|
|
|
|
Sleep (sleep_time >> 3);
|
|
|
|
if (sleep_time < 80)
|
|
{
|
|
sleep_time++;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int peekConsoleWrite(int sfd)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
int peekPipeRead(int sfd)
|
|
{
|
|
HANDLE h;
|
|
|
|
DWORD n = 0;
|
|
|
|
DWORD pFlags = 0;
|
|
|
|
DWORD sleep_time = 0;
|
|
|
|
int ret = 0;
|
|
|
|
h = sfd_to_handle(sfd);
|
|
|
|
if (h == INVALID_HANDLE_VALUE)
|
|
{
|
|
error("can't get a handle for sfd [%d]", sfd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
ret = GetNamedPipeInfo(h, &pFlags, NULL, NULL, NULL);
|
|
|
|
if (!ret)
|
|
{
|
|
error("GetNamedPipeInfo on sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
ret = PeekNamedPipe (h, NULL, 0, NULL, &n, NULL);
|
|
|
|
if (!ret)
|
|
{
|
|
//error("PeekNamedPipe on sfd [%d] failed with error code [%d]",
|
|
// sfd, GetLastError());
|
|
return 0;
|
|
}
|
|
|
|
if (n > 0)
|
|
{
|
|
break;
|
|
}
|
|
|
|
Sleep (sleep_time >> 3);
|
|
|
|
if (sleep_time < 80)
|
|
{
|
|
sleep_time++;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int peekPipeWrite(int sfd)
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
int selectSocketRead(int sfd)
|
|
{
|
|
DBG_MSG("-> selectSocketRead(sfd = %d)...\n", sfd);
|
|
|
|
int ret = 0;
|
|
|
|
fd_set readsocks;
|
|
|
|
struct timeval timeout = {1, 0};
|
|
|
|
FD_ZERO(&readsocks);
|
|
|
|
FD_SET((SOCKET) sfd_to_handle(sfd), &readsocks);
|
|
|
|
|
|
DBG_MSG("selectSocketRead(sfd = %d) : readsocks.fd_count = %d\n", sfd, readsocks.fd_count);
|
|
|
|
DBG_MSG("selectSocketRead(sfd = %d, socket = %d) : select...\n",
|
|
(int) sfd, (int) sfd_to_handle(sfd));
|
|
|
|
while(ret == 0)
|
|
{
|
|
FD_ZERO(&readsocks);
|
|
|
|
FD_SET((SOCKET) sfd_to_handle(sfd), &readsocks);
|
|
|
|
ret = select(0, &readsocks, NULL, NULL, &timeout);
|
|
}
|
|
|
|
DBG_MSG("selectSocketRead(sfd = %d, socket = %d) : end select...\n",
|
|
(int) sfd, (int) sfd_to_handle(sfd));
|
|
|
|
/*
|
|
* Bail if select failed for some reason.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
error("select on sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
|
|
DBG_MSG("<- selectSocketRead(sfd = %d)...\n", sfd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DBG_MSG("<- selectSocketRead(sfd = %d)...\n", sfd);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int selectSocketWrite(int sfd)
|
|
{
|
|
DBG_MSG("-> selectSocketWrite(sfd = %d)...\n", sfd);
|
|
|
|
int ret = 0;
|
|
|
|
fd_set writesocks;
|
|
|
|
struct timeval timeout = {1, 0};
|
|
|
|
FD_ZERO(&writesocks);
|
|
|
|
FD_SET((SOCKET) sfd_to_handle(sfd), &writesocks);
|
|
|
|
DBG_MSG("selectSocketWrite(sfd = %d) : writesocks.fd_count = %d...\n", sfd, writesocks.fd_count);
|
|
|
|
DBG_MSG("selectSocketWrite(sfd = %d, socket = %d) : select...\n",
|
|
(int) sfd, (int) sfd_to_handle(sfd));
|
|
|
|
while (ret == 0)
|
|
{
|
|
FD_ZERO(&writesocks);
|
|
|
|
FD_SET((SOCKET) sfd_to_handle(sfd), &writesocks);
|
|
|
|
ret = select(0, NULL, &writesocks, NULL, &timeout);
|
|
}
|
|
|
|
DBG_MSG("selectSocketWrite(sfd = %d, socket = %d) : end select...\n",
|
|
(int) sfd, (int) sfd_to_handle(sfd));
|
|
|
|
/*
|
|
* Fail if select failed for some reason.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
error("select on sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
|
|
DBG_MSG("<- selectSocketWrite(sfd = %d)...\n", sfd);
|
|
|
|
return 0;
|
|
}
|
|
|
|
DBG_MSG("<- selectSocketWrite(sfd = %d)...\n", sfd);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
DWORD WINAPI selectThread( LPVOID lpParam )
|
|
{
|
|
DBG_MSG("-> selectThread()...\n");
|
|
|
|
DWORD dwWaitResult;
|
|
|
|
thread_data_p thread_data;
|
|
|
|
thread_data = (thread_data_p)lpParam;
|
|
|
|
int sfd = thread_data -> sfd;
|
|
int thread_no = thread_data -> thread_no;
|
|
int test_type = thread_data -> test_type;
|
|
|
|
debug2("starting thread [%i] for sfd [%i] with test type[%i]",
|
|
thread_no, sfd, test_type);
|
|
|
|
while(1)
|
|
{
|
|
|
|
dwWaitResult = WaitForSingleObject(thread_data -> semaphore1, INFINITE);
|
|
|
|
if (thread_data -> exit)
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
switch (dwWaitResult)
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
{
|
|
switch(get_sfd_type(sfd))
|
|
{
|
|
case SFD_TYPE_FD:
|
|
{
|
|
break;
|
|
}
|
|
|
|
case SFD_TYPE_SOCKET:
|
|
{
|
|
if (test_type == TEST_READ)
|
|
{
|
|
selectSocketRead(sfd);
|
|
}
|
|
else
|
|
{
|
|
selectSocketWrite(sfd);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SFD_TYPE_PIPE:
|
|
{
|
|
if (test_type == TEST_READ)
|
|
{
|
|
peekPipeRead(sfd);
|
|
}
|
|
else
|
|
{
|
|
peekPipeWrite(sfd);
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SFD_TYPE_CONSOLE:
|
|
{
|
|
if (test_type == TEST_READ)
|
|
{
|
|
peekConsoleRead(sfd);
|
|
}
|
|
else
|
|
{
|
|
peekConsoleWrite(sfd);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (thread_data -> exit)
|
|
{
|
|
goto out;
|
|
}
|
|
|
|
if (!ReleaseSemaphore(thread_data -> semaphore2, 1, NULL))
|
|
{
|
|
error("WaitForSingleObject in thread [%d] failed with error code [%d]",
|
|
thread_no, GetLastError());
|
|
|
|
return 0;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
error("ReleaseSemaphore in thread [%d] failed with error code [%d]",
|
|
thread_no, GetLastError());
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
out:
|
|
|
|
debug2("stopping thread [%i] for sfd [%i] with test type[%i]",
|
|
thread_no, sfd, test_type);
|
|
|
|
thread_data -> exited = 1;
|
|
|
|
DBG_MSG("<- selectThread()...\n");
|
|
|
|
ExitThread(1);
|
|
|
|
return 1;
|
|
}
|
|
|
|
|
|
int startSelectThread(int sfd, int test_type)
|
|
{
|
|
DBG_MSG("-> startSelectThread(sfd = %d, test_type = %d)...\n", sfd, test_type);
|
|
|
|
int thread_no = 0;
|
|
|
|
int i;
|
|
|
|
DWORD ID;
|
|
|
|
for (i = 0; i < MAX_THREADS; i++)
|
|
{
|
|
if (thread_data_set[i] == NULL)
|
|
{
|
|
thread_no = i;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (thread_data_set[thread_no] != NULL)
|
|
{
|
|
fatal("MAX_THREADS exceed");
|
|
}
|
|
|
|
thread_data_set[thread_no] = (thread_data_p) HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(thread_data_t));
|
|
|
|
if (thread_data_set[thread_no] == NULL)
|
|
{
|
|
fatal("heap allocation failed with error code [%d]", GetLastError());
|
|
}
|
|
|
|
thread_data_set[thread_no] -> sfd = sfd;
|
|
thread_data_set[thread_no] -> thread_no = thread_no;
|
|
thread_data_set[thread_no] -> test_type = test_type;
|
|
thread_data_set[thread_no] -> signaled = 0;
|
|
thread_data_set[thread_no] -> exit = 0;
|
|
thread_data_set[thread_no] -> exited = 0;
|
|
|
|
thread_data_set[thread_no] -> semaphore1 = CreateSemaphore(NULL, 1, 1, NULL);
|
|
|
|
if (thread_data_set[thread_no] -> semaphore1 == NULL)
|
|
{
|
|
fatal("CreateSemaphore failed with error code [%d]",
|
|
GetLastError());
|
|
}
|
|
|
|
thread_data_set[thread_no] -> semaphore2 = CreateSemaphore(NULL, 0, 1, NULL);
|
|
|
|
if (thread_data_set[thread_no] -> semaphore2 == NULL)
|
|
{
|
|
fatal("CreateSemaphore failed with error code [%d]", GetLastError());
|
|
}
|
|
|
|
thread_data_set[thread_no] -> thread = CreateThread(NULL, 0, selectThread,
|
|
thread_data_set[thread_no],
|
|
0, &ID);
|
|
|
|
thread_data_set[thread_no] -> thread_id = ID;
|
|
|
|
|
|
if (thread_data_set[thread_no] -> thread == NULL)
|
|
{
|
|
fatal("CreateThread failed with error code [%d]", GetLastError());
|
|
}
|
|
|
|
DBG_MSG("<- startSelectThread(thread_no = %d)...\n", thread_no);
|
|
|
|
return thread_no;
|
|
}
|
|
|
|
|
|
int cleanSelectThread(int thread_no)
|
|
{
|
|
DBG_MSG("-> cleanSelectThread(thread_no = %d)...\n", thread_no);
|
|
|
|
CloseHandle(thread_data_set[thread_no] -> semaphore1);
|
|
CloseHandle(thread_data_set[thread_no] -> semaphore2);
|
|
CloseHandle(thread_data_set[thread_no] -> thread);
|
|
|
|
if(thread_data_set[thread_no] != NULL)
|
|
{
|
|
thread_data_p ap = thread_data_set[thread_no];
|
|
thread_data_set[thread_no] = NULL;
|
|
HeapFree(GetProcessHeap(), 0, ap);
|
|
|
|
}
|
|
|
|
DBG_MSG("<- cleanSelectThread()...\n");
|
|
|
|
return 1;
|
|
}
|
|
|
|
// Add a Child process to be added to select mux so thyat we know when it has exited
|
|
HANDLE ChildToWatch = NULL;
|
|
int WSHELPAddChildToWatch ( HANDLE processtowatch)
|
|
{
|
|
ChildToWatch = processtowatch;
|
|
return 0;
|
|
}
|
|
|
|
int WSHELPDelChildToWatch ( HANDLE processtowatch)
|
|
{
|
|
if ( ChildToWatch == processtowatch )
|
|
ChildToWatch = NULL ;
|
|
return 0;
|
|
}
|
|
|
|
int WSHELPselect(int fds, fd_set* readsfds, fd_set* writesfds,
|
|
fd_set* exceptsfds, const struct timeval* timeout)
|
|
{
|
|
DBG_MSG("-> WSHELPselect(fds = %d)...\n", fds);
|
|
|
|
DWORD dwWaitResult;
|
|
|
|
DWORD ms;
|
|
|
|
unsigned int i;
|
|
|
|
int count = 0;
|
|
|
|
static int sfd_read_to_thread_map[MAX_THREADS] = {0};
|
|
|
|
static int sfd_write_to_thread_map[MAX_THREADS] = {0};
|
|
|
|
HANDLE semaphores[MAX_THREADS] = {NULL};
|
|
|
|
int i_sem = 0;
|
|
|
|
int semaphores_to_thread_map[MAX_THREADS] = {0};
|
|
|
|
static unsigned int threads_count = 0;
|
|
|
|
/*
|
|
* 'except' should be implemented.
|
|
*/
|
|
|
|
if (exceptsfds)
|
|
{
|
|
fatal("exceptsfds not implemented");
|
|
}
|
|
|
|
/*
|
|
* convert timeout to ms or to INFINITE if null.
|
|
*/
|
|
|
|
ms = timeout ? (DWORD) (timeout -> tv_sec * 1000) + (timeout -> tv_usec / 1000) : INFINITE;
|
|
|
|
if (ms == 0 && timeout -> tv_usec)
|
|
{
|
|
ms = 1;
|
|
}
|
|
|
|
/*
|
|
* just wait if all set's are empty.
|
|
*/
|
|
|
|
if (!readsfds && !writesfds && !exceptsfds)
|
|
{
|
|
HANDLE empty = NULL;
|
|
|
|
dwWaitResult = WaitForSingleObject(empty, ms);
|
|
|
|
switch (dwWaitResult)
|
|
{
|
|
case WAIT_OBJECT_0:
|
|
{
|
|
errno = EINTR;
|
|
|
|
DBG_MSG("<- WSHELPselect(fds = %d, ret = -1)...\n", fds);
|
|
|
|
return -1;
|
|
}
|
|
|
|
case WAIT_FAILED:
|
|
{
|
|
fatal("WaitForSingleObject failed with error code [%d]", GetLastError());
|
|
}
|
|
|
|
case WAIT_TIMEOUT:
|
|
{
|
|
DBG_MSG("<- WSHELPselect(fds = %d, ret = 0)...\n", fds);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* threads for read fds removed from set should be stopped.
|
|
*/
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : stopping threads for read fds "
|
|
"removed from set...\n", fds);
|
|
|
|
if (read_sfd_set.fd_count != 0)
|
|
{
|
|
for (i = 0; i < read_sfd_set.fd_count; ++i)
|
|
{
|
|
int sfd = (int) read_sfd_set.fd_array[i];
|
|
|
|
if (!FD_ISSET(sfd, readsfds))
|
|
{
|
|
//int thread_no = thread_data_set[sfd_read_to_thread_map[sfd]] -> thread_no;
|
|
|
|
//debug("WSHELPselect(fds = %d) : stoping thread_no = %d for sfd = %d...\n", fds, thread_no, sfd);
|
|
|
|
thread_data_set[sfd_read_to_thread_map[sfd]] -> exit = 1;
|
|
|
|
FD_CLR((SOCKET) sfd, &read_sfd_set);
|
|
|
|
sfd_read_to_thread_map[sfd] = -1;
|
|
}
|
|
//else
|
|
//{
|
|
// debug("WSHELPselect(fds = %d) : i = %d : sfd = %d, FD_ISSET != 0...\n", fds, sfd);
|
|
//}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* threads for write fds removed from set should be stopped.
|
|
*/
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : stopping threads for write fds removed from set...\n", fds);
|
|
|
|
if (write_sfd_set.fd_count != 0)
|
|
{
|
|
for (i = 0; i < write_sfd_set.fd_count; ++i)
|
|
{
|
|
int sfd = (int) write_sfd_set.fd_array[i];
|
|
|
|
if (!FD_ISSET(sfd, writesfds))
|
|
{
|
|
//int thread_no = thread_data_set[sfd_read_to_thread_map[sfd]] -> thread_no;
|
|
|
|
//debug("WSHELPselect(fds = %d) : stopping thread_no = %d for sfd = %d...\n", fds, thread_no, sfd);
|
|
|
|
thread_data_set[sfd_write_to_thread_map[sfd]] -> exit = 1;
|
|
|
|
FD_CLR((SOCKET) sfd, &write_sfd_set);
|
|
|
|
sfd_write_to_thread_map[sfd] = -1;
|
|
}
|
|
//else
|
|
//{
|
|
// debug("WSHELPselect(fds = %d) : i = %d : sfd = %d, FD_ISSET != 0...\n", fds, sfd);
|
|
//}
|
|
}
|
|
}
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : Weaking up threads signaled in previous run...\n", fds);
|
|
|
|
for (i = 0; i < MAX_THREADS; i++)
|
|
{
|
|
/*
|
|
* threads signaled in previous run should be waken up.
|
|
*/
|
|
|
|
if (thread_data_set[i] != NULL && thread_data_set[i] -> signaled == 1)
|
|
{
|
|
if (!ReleaseSemaphore(thread_data_set[i] -> semaphore1, 1, NULL))
|
|
{
|
|
fatal("ReleaseSemaphore failed with error code [%d]", GetLastError());
|
|
}
|
|
|
|
thread_data_set[i] -> signaled = 0;
|
|
}
|
|
|
|
/*
|
|
* Cleaning after exited threads.
|
|
*/
|
|
|
|
if (thread_data_set[i] != NULL && thread_data_set[i] -> exited == 1)
|
|
{
|
|
cleanSelectThread(i);
|
|
|
|
threads_count--;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* new thread should be started for each new read fd.
|
|
*/
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : Starting new thread for each new read fd...\n", fds);
|
|
|
|
if (readsfds != NULL && readsfds -> fd_count != 0)
|
|
{
|
|
for (i = 0; i < readsfds -> fd_count; ++i)
|
|
{
|
|
int sfd = (int) readsfds -> fd_array[i];
|
|
|
|
if (!FD_ISSET(sfd, &read_sfd_set))
|
|
{
|
|
int thread_no = startSelectThread(sfd, TEST_READ);
|
|
|
|
//debug("WSHELPselect(fds = %d) : Starting read thread (thread_no = %d) for sfd = %d...\n",
|
|
// fds, thread_no, sfd);
|
|
|
|
read_sfd_set_add(sfd);
|
|
|
|
sfd_read_to_thread_map[sfd] = thread_no;
|
|
|
|
threads_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* New thread should be started for each new write fd.
|
|
*/
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : Starting new thread for each new write fd...\n", fds);
|
|
|
|
if (writesfds != NULL && writesfds -> fd_count != 0)
|
|
{
|
|
for (i = 0; i < writesfds -> fd_count; ++i)
|
|
{
|
|
int sfd = (int) writesfds -> fd_array[i];
|
|
|
|
if (!FD_ISSET(sfd, &write_sfd_set))
|
|
{
|
|
int thread_no = startSelectThread(sfd, TEST_WRITE);
|
|
|
|
//debug("WSHELPselect(fds = %d) : Starting write thread (thread_no = %d) for sfd = %d...\n",
|
|
// fds, thread_no, sfd);
|
|
|
|
|
|
write_sfd_set_add(sfd);
|
|
|
|
sfd_write_to_thread_map[sfd] = thread_no;
|
|
|
|
threads_count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* constructing array of semaphores for working threads
|
|
* new array is needed because in threads map we can have
|
|
* threads which should exit right now.
|
|
*/
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : constructing array of semaphores for working threads...\n", fds);
|
|
|
|
for (i = 0; i < MAX_THREADS; i++)
|
|
{
|
|
if (thread_data_set[i] != NULL && !thread_data_set[i] -> exit )
|
|
{
|
|
semaphores[i_sem] = thread_data_set[i] -> semaphore2;
|
|
|
|
semaphores_to_thread_map[i_sem] = i;
|
|
|
|
i_sem++;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* wait for signal from threads.
|
|
*/
|
|
|
|
#ifdef DEBUG
|
|
|
|
{
|
|
char str[256] = "{";
|
|
char tmp[32] = "";
|
|
|
|
for (i = 0; i < read_sfd_set.fd_count; ++i)
|
|
{
|
|
int sfd = (int) read_sfd_set.fd_array[i];
|
|
|
|
sprintf(tmp, " %d", sfd);
|
|
|
|
strcat(str, tmp);
|
|
}
|
|
|
|
strcat(str, " }");
|
|
|
|
debug("read_sfd_set = %s", str);
|
|
|
|
/*
|
|
*
|
|
*/
|
|
|
|
str[0] = '{';
|
|
str[1] = '\0';
|
|
|
|
for (i = 0; i < write_sfd_set.fd_count; ++i)
|
|
{
|
|
int sfd = (int) write_sfd_set.fd_array[i];
|
|
|
|
sprintf(tmp, " %d", sfd);
|
|
|
|
strcat(str, tmp);
|
|
}
|
|
|
|
strcat(str, " }");
|
|
|
|
debug("write_sfd_set = %s", str);
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : Waiting for signal from threads...\n", fds);
|
|
|
|
DBG_MSG("i_sem = %d\n", i_sem);
|
|
|
|
// add a child process handle to the mux if it was registered
|
|
if ( ChildToWatch ) {
|
|
semaphores[i_sem] = ChildToWatch ;
|
|
i_sem++;
|
|
}
|
|
|
|
dwWaitResult = WaitForMultipleObjects(i_sem, semaphores, FALSE, ms);
|
|
|
|
//debug("WSHELPselect(fds = %d) : FD_ZERO(readsfds)...\n", fds);
|
|
|
|
if (readsfds) FD_ZERO(readsfds);
|
|
|
|
//debug("WSHELPselect(fds = %d) : FD_ZERO(writesfds)...\n", fds);
|
|
|
|
if (writesfds) FD_ZERO(writesfds);
|
|
|
|
//debug("WSHELPselect(fds = %d) : FD_ZERO(exceptsfds)...\n", fds);
|
|
|
|
if (exceptsfds) FD_ZERO(exceptsfds);
|
|
|
|
switch (dwWaitResult)
|
|
{
|
|
case WAIT_FAILED:
|
|
{
|
|
fatal("WaitForMultipleObjects failed with error code [%d]", GetLastError());
|
|
}
|
|
|
|
case WAIT_TIMEOUT:
|
|
{
|
|
DBG_MSG("<- WSHELPselect(fds = %d, ret = 0)...\n", fds);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Prepare return fd sets with signaled fd's.
|
|
*/
|
|
|
|
//debug("WSHELPselect(fds = %d) : preparing return fd sets with signaled fd's...\n", fds);
|
|
|
|
for (i = 0; i<MAX_THREADS; i++)
|
|
{
|
|
if (dwWaitResult == WAIT_OBJECT_0 + i)
|
|
{
|
|
int thread_no = semaphores_to_thread_map[i];
|
|
|
|
if (thread_data_set[thread_no] -> test_type == TEST_READ)
|
|
{
|
|
FD_SET((SOCKET) thread_data_set[thread_no] -> sfd, readsfds);
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : "
|
|
"thread_no = %d, sfd = %d, readsfds = %d...\n",
|
|
fds, thread_no,
|
|
thread_data_set[thread_no] -> sfd, (int) readsfds);
|
|
}
|
|
else
|
|
{
|
|
FD_SET((SOCKET) thread_data_set[thread_no] -> sfd, writesfds);
|
|
|
|
DBG_MSG("WSHELPselect(fds = %d) : "
|
|
"thread_no = %d, sfd = %d, readsfds = %d...\n",
|
|
fds, thread_no,
|
|
thread_data_set[thread_no] -> sfd, (int) writesfds);
|
|
}
|
|
|
|
count ++;
|
|
|
|
thread_data_set[thread_no] -> signaled = 1;
|
|
}
|
|
}
|
|
|
|
DBG_MSG("<- WSHELPselect(fds = %d, ret = %d)...\n", fds, count);
|
|
|
|
return count;
|
|
}
|
|
|
|
/*
|
|
* IO functions.
|
|
*/
|
|
|
|
int WSHELPread(int sfd, char *dst, unsigned int max)
|
|
{
|
|
DBG_MSG("-> WSHELPread(sfd = %d)...\n", sfd);
|
|
|
|
|
|
SOCKET sock;
|
|
|
|
int ret = -1;
|
|
int sfd_type = get_sfd_type(sfd);
|
|
|
|
switch (sfd_type)
|
|
{
|
|
case SFD_TYPE_SOCKET:
|
|
{
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = recv(sock, dst, max, 0);
|
|
|
|
if (FD_ISSET(sfd, &debug_sfds))
|
|
{
|
|
if (ret > 0)
|
|
{
|
|
dst[ret] = '\0';
|
|
|
|
debug("read[%d]: %s", sfd, dst);
|
|
}
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
debug("read from socket sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
}
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
DBG_MSG("WSHELPread(sfd = %d) : SOCKET_ERROR...\n", sfd);
|
|
|
|
DBG_MSG("<- WSHELPread(sfd = %d, ret = -1)...\n", sfd);
|
|
|
|
return -1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SFD_TYPE_FD:
|
|
case SFD_TYPE_PIPE:
|
|
//case SFD_TYPE_CONSOLE:
|
|
{
|
|
|
|
ret = _read(sfd_to_fd(sfd), dst, max);
|
|
|
|
if (FD_ISSET(sfd_to_fd(sfd), &debug_sfds))
|
|
{
|
|
if (ret > 0)
|
|
{
|
|
dst[ret] = '\0';
|
|
|
|
debug("read[%d] len %d: %s", sfd_to_fd(sfd), ret, dst);
|
|
}
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
error("read from pipe/console sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SFD_TYPE_CONSOLE:
|
|
{
|
|
//if (sfd_type == SFD_TYPE_CONSOLE) {
|
|
// we could be send here due to ctrl-c input, so no data to read
|
|
//if ( DataAvailable (sfd_to_handle(sfd)) <=0 )
|
|
//return 1; // no data to read
|
|
//}
|
|
ret = ReadConsoleForTermEmul( sfd_to_handle(sfd), dst, max);
|
|
|
|
if (ret < 0)
|
|
{
|
|
error("read from pipe/console sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
}
|
|
if (ret == 0)
|
|
return 0; //1;
|
|
|
|
break;
|
|
}
|
|
case 99:
|
|
{
|
|
ret = _getch();
|
|
if ( ( ret == 0) || (ret == 0xE0) ) {
|
|
dst[0] = ret ;
|
|
ret = _getch(); // function key or arrow key needs 2 calls, the first returning a 0 or 0xE0
|
|
dst[1] = ret;
|
|
ret = 2;
|
|
}
|
|
else {
|
|
dst[0] = ret;
|
|
ret = 1;
|
|
}
|
|
|
|
if (FD_ISSET(sfd_to_fd(sfd), &debug_sfds))
|
|
{
|
|
if (ret > 0)
|
|
{
|
|
dst[ret] = '\0';
|
|
|
|
debug("read[%d] len %d: %s", sfd_to_fd(sfd), ret, dst);
|
|
}
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
error("read from pipe/console sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
DBG_MSG("<- WSHELPread(sfd = %d, ret = %d)...\n", sfd, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int WSHELPwrite(int sfd, const char *buf, unsigned int max)
|
|
{
|
|
DBG_MSG("-> WSHELPwrite(sfd = %d)...\n", sfd);
|
|
|
|
SOCKET sock;
|
|
|
|
int ret = -1;
|
|
|
|
int sfd_type = get_sfd_type(sfd);
|
|
if ( (glob_itissshclient) && ( sfd_type == SFD_TYPE_CONSOLE ) )
|
|
sfd_type = SFD_TYPE_PIPE ; // client write type uses _write() in place ofn console insertion
|
|
|
|
switch(sfd_type)
|
|
{
|
|
case SFD_TYPE_SOCKET:
|
|
{
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
if (FD_ISSET(sfd, &crlf_sfds) && max == 1 && buf[0] == 13)
|
|
{
|
|
/*
|
|
* FIXME: We're getting CR's (13) instead of CR + LF or just LF,
|
|
* either of which would work.
|
|
*/
|
|
|
|
char locbuf[1] = {10};
|
|
|
|
ret = send(sock, locbuf, 1, 0);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
ret = send(sock, buf, max, 0);
|
|
}
|
|
|
|
if (FD_ISSET(sfd, &debug_sfds))
|
|
{
|
|
if (ret > 0)
|
|
{
|
|
static int writecount = 0;
|
|
|
|
char *locbuf = malloc(max + 1);
|
|
|
|
memcpy(locbuf, buf, max);
|
|
|
|
locbuf[max] = '\0';
|
|
|
|
writecount += max;
|
|
|
|
debug("write[%d] len %d: %s", sfd, max, locbuf);
|
|
|
|
if (max == 1)
|
|
{
|
|
debug("write[%d] one char: %08x", sfd, locbuf[0]);
|
|
}
|
|
|
|
free(locbuf);
|
|
}
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
/*
|
|
* write error only if failed sfd is not a stderr (2).
|
|
*/
|
|
|
|
if (sfd != 2)
|
|
{
|
|
//error("write to socket sfd [%d] failed with error code [%d]",
|
|
// sfd, GetLastError());
|
|
|
|
DBG_MSG("<- WSHELPwrite(sfd = %d, ret = -1)...\n", sfd);
|
|
}
|
|
|
|
exit(-1);
|
|
}
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
DBG_MSG("WSHELPwrite(sfd = %d) : SOCKET_ERROR...\n", sfd);
|
|
|
|
DBG_MSG("<- WSHELPwrite(sfd = %d, ret = -1)...\n", sfd);
|
|
|
|
return -1;
|
|
}
|
|
break;
|
|
}
|
|
|
|
case SFD_TYPE_FD:
|
|
case SFD_TYPE_PIPE:
|
|
//case SFD_TYPE_CONSOLE:
|
|
{
|
|
ret = _write(sfd_to_fd(sfd), buf, max);
|
|
|
|
if (FD_ISSET(sfd_to_fd(sfd), &debug_sfds))
|
|
{
|
|
if (ret > 0)
|
|
{
|
|
char *locbuf = malloc(max + 1);
|
|
|
|
memcpy(locbuf, buf, max);
|
|
|
|
locbuf[max] = '\0';
|
|
|
|
debug("write[%d]: %s", sfd_to_fd(sfd), locbuf);
|
|
|
|
free(locbuf);
|
|
}
|
|
}
|
|
|
|
if (ret < 0)
|
|
{
|
|
/*
|
|
* write error only if failed sfd is not a stderr (2).
|
|
*/
|
|
|
|
if (sfd != 2)
|
|
{
|
|
error("write to pipe/console sfd [%d] failed with error code [%d]",
|
|
sfd, GetLastError());
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case SFD_TYPE_CONSOLE:
|
|
{
|
|
//ret = _write(sfd_to_fd(sfd), buf, max);
|
|
size_t dwWritten = 0 ;
|
|
ret = WriteToConsole(sfd_to_handle(sfd), buf, max, &dwWritten, 0) ;
|
|
ret = max ;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
DBG_MSG("<- WSHELPwrite(sfd = %d, ret = %d)...\n", sfd, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
int WSHELPclose(int sfd)
|
|
{
|
|
DBG_MSG("-> WSHELPclose(sfd = %d)...\n", sfd);
|
|
|
|
int i;
|
|
|
|
int socketInUse = 0;
|
|
|
|
SOCKET sock;
|
|
|
|
int ret = -1;
|
|
|
|
switch(get_sfd_type(sfd))
|
|
{
|
|
case SFD_TYPE_SOCKET:
|
|
{
|
|
/*
|
|
* Clear errno.
|
|
*/
|
|
|
|
errno = 0;
|
|
|
|
/*
|
|
* Get the SOCKET.
|
|
*/
|
|
|
|
sock = (SOCKET) sfd_to_handle(sfd);
|
|
|
|
if (sock == INVALID_SOCKET)
|
|
{
|
|
errno = EBADF;
|
|
|
|
DBG_MSG("WSHELPclose(sfd = %d) : INVALID_SOCKET...\n", sfd);
|
|
|
|
DBG_MSG("<- WSHELPclose(sfd = %d, ret = -1)...\n", sfd);
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Remove cookie in SocketCookieMap var (for AF_UNIX only).
|
|
*/
|
|
|
|
for (i = 0; i < SFD_MAP_SIZE; i++)
|
|
{
|
|
/*
|
|
* Find socket in table.
|
|
*/
|
|
|
|
if (SocketCookieMap[i].socket == sock)
|
|
{
|
|
/*
|
|
* Remove cookie.
|
|
*/
|
|
|
|
SocketCookieMap[i].socket = 0;
|
|
|
|
if (SocketCookieMap[i].cookie)
|
|
{
|
|
free(SocketCookieMap[i].cookie);
|
|
}
|
|
|
|
if (SocketCookieMap[i].f)
|
|
{
|
|
fclose(SocketCookieMap[i].f);
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Test is socket in use by another sfd?
|
|
*/
|
|
|
|
socketInUse = 0;
|
|
|
|
i = 0;
|
|
|
|
while(!socketInUse && i < SFD_MAP_SIZE)
|
|
{
|
|
//DBG_MSG("%d |-> %d ? %d\n", i, sfd_to_handle(i), sock);
|
|
|
|
if (((int) sfd_to_handle(i) == (int) sock) && (i != (int) sfd))
|
|
{
|
|
socketInUse = 1;
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
/*
|
|
* Call the underlying function.
|
|
*/
|
|
|
|
if (!socketInUse)
|
|
{
|
|
DBG_MSG("Closing socket %d\n", sock);
|
|
|
|
ret = closesocket(sock);
|
|
}
|
|
else
|
|
{
|
|
DBG_MSG("Socket %d in use.\n", sock);
|
|
|
|
ret = 0;
|
|
}
|
|
|
|
/*
|
|
* Remove mapping table entry.
|
|
*/
|
|
|
|
free_sfd(sfd);
|
|
|
|
/*
|
|
* Check for errors.
|
|
*/
|
|
|
|
if (ret == SOCKET_ERROR)
|
|
{
|
|
errno = getWSAErrno();
|
|
|
|
DBG_MSG("WSHELPclose(sfd = %d) : SOCKET_ERROR...\n", sfd);
|
|
|
|
DBG_MSG("<- WSHELPclose(sfd = %d, ret = -1)...\n", sfd);
|
|
|
|
return -1;
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case SFD_TYPE_FD:
|
|
case SFD_TYPE_PIPE:
|
|
case SFD_TYPE_CONSOLE:
|
|
{
|
|
ret = _close(sfd_to_fd(sfd));
|
|
|
|
free_sfd(sfd);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
DBG_MSG("<- WSHELPclose(sfd = %d, ret = %d)...\n", sfd, ret);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/*
|
|
* Internal functions.
|
|
*/
|
|
|
|
void WSHELPinitialize()
|
|
{
|
|
DBG_MSG("-> WSHELPinitialize()...\n");
|
|
|
|
WORD wVersionRequested;
|
|
|
|
WSADATA wsaData;
|
|
|
|
int err;
|
|
|
|
wVersionRequested = MAKEWORD(2, 2);
|
|
|
|
if (WSAStartup(wVersionRequested, &wsaData))
|
|
{
|
|
fatal("ERROR: Cannot initialize WinSock DLL.");
|
|
}
|
|
|
|
/*
|
|
* Confirm that the WinSock DLL supports 2.2.
|
|
* Note that if the DLL supports versions greater
|
|
* than 2.2 in addition to 2.2, it will still return
|
|
* 2.2 in wVersion since that is the version we
|
|
* requested.
|
|
*/
|
|
|
|
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
|
|
{
|
|
fatal("ERROR: WinSock 2.2 needed.");
|
|
}
|
|
|
|
/*
|
|
* The WinSock DLL is acceptable. Proceed.
|
|
*/
|
|
|
|
winsock_initialized = 1;
|
|
|
|
#ifndef __MINGW32__
|
|
// _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
|
|
// _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDOUT);
|
|
// _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
|
|
// _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDOUT);
|
|
// _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
|
|
// _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDOUT);
|
|
|
|
#endif
|
|
|
|
|
|
DBG_MSG("<- WSHELPinitialize()...\n");
|
|
}
|
|
|
|
|
|
void allocate_standard_descriptor(int fd)
|
|
{
|
|
DBG_MSG("-> allocate_standard_descriptor(fd = %d)...\n", fd);
|
|
|
|
int asfd = allocate_sfd(fd);
|
|
|
|
void sfd_set_to_console(int sfd);
|
|
if (asfd >= 0)
|
|
sfd_set_to_console(asfd);
|
|
|
|
DBG_MSG("<- allocate_standard_descriptor()...");
|
|
}
|