quamrulmina fe136bc352 Code fixed for ssh-agent.exe and ssh-add.exe to work in Windows
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.
2016-01-16 00:05:33 -06:00

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()...");
}