Sweden-Number/misc/winsock_async.c

487 lines
13 KiB
C
Raw Normal View History

Release 961201 Sat Nov 30 19:21:17 1996 Alexandre Julliard <julliard@lrc.epfl.ch> * [configure] Re-generated with autoconf 2.11. Let me know if you have problems. * [controls/listbox.c] [controls/oldlbox.c] Listboxes rewritten from scratch. Moved old code still used by comboboxes to oldlbox.c * [misc/registry.c] Use temporary file when saving registry. * [windows/dialog.c] Implemented Win32 version of DlgDirList() and DlgDirListComboBox(). * [windows/winproc.c] Added translation for listbox Win32 messages. Sat Nov 30 21:00:00 Alex Korobka <alex@trantor.pharm.sunysb.edu> * [controls/widgets.c] [controls/button.c] Fixed some incompatibilities with CTL3D DLL. * [windows/dialog.c] Made dialog windows fit into the desktop. * [misc/winsock.c] [misc/winsock_async.c] New Winsock engine. * [windows/message.c] GetMessage() fixes. * [windows/queue.c] [windows/hook.c] [windows/win.c] SetMessageQueue() fixes. Fri Nov 29 10:25:12 1996 Slaven Rezic <eserte@cs.tu-berlin.de> * [objects/text.c] DrawText16(): Fixed return value. Tue Nov 26 14:47:09 1996 Marcus Meissner <msmeissn@cip.informatik.uni-erlangen.de> * [files/profile.c] [*/*] Added Win32 profile functions, updated to new naming standard. * [objects/font.c] [if1632/thunk.c] [include/windows.h] Added EnumFonts32*, EnumFontFamiliesEx*, changed prototypes and structures. * [misc/ole2nls.c] [if1632/thunk.c] Added EnumSystemLocales() (winhelp.exe). * [misc/registry.c] Added Windows 3.1 registry loader supplied by Tor Sjxwall, tor@sn.no * [win32/file.c] Partially fixed CreateFileMapping(), added UnmapViewOfFile(). Sat Nov 23 23:36:05 1996 Ronan Waide <waider@waider.ie> * [misc/shell.c] Fixed some FIXMEs relating to ShellExec() and FindExecutable(). * [misc/main.c] Implemented a few more of the SystemParametersInfo() cases. Tue Nov 19 01:24:34 1996 Philippe De Muyter <phdm@info.ucl.ac.be> * [include/keyboard.h] New file, new macro WINE_VKEY_MAPPINGS (using code taken from event.c). * [include/windows.h] New [VK_A, VK_Z] and [VK_0, VK9] macros. * [misc/keyboard.c] Fixes in KeyTable and ToAscii. * [objects/font.c] FONT_init : Give default value for MSWIN "system" font. FONT_MatchFont : Do not try every size of a font family if the family does not exist. * [windows/event.c] lastEventChar hack removed. KeyStateTable replaced by InputKeyStateTable (maintained in event.c) and QueueKeyStateTable (maintained in message.c). EVENT_key : Corrections to the extended bit setting. * [windows/message.c] [windows/keyboard.c] Implementation of a new QueueKeyStateTable : table of key states valid when messages are retrieved by GetMessage or PeekMessage, and valid for TranslateMessage. TranslateMessage : Convert WM*KEY messages using QueueKeyStateTable and ToAscii. Mon Nov 18 16:59:01 1996 Robert Pouliot <krynos@clic.net> * [graphics/Makefile.in] [graphics/wing.c] [if1632/wing.spec] Some functions for WinG support, mostly empty stubs. * [misc/crtdll.c] [if1632/crtdll.spec] Many functions added to CRTDLL, mostly calls to Unix C library.
1996-12-01 18:17:47 +01:00
/*
* asynchronous winsock services
*
* (C) 1996 Alex Korobka.
*
* FIXME: telftp16 (ftp part) stalls on AsyncSelect with FD_ACCEPT.
*/
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/wait.h>
#include <errno.h>
#include "windows.h"
#include "winsock.h"
#include "debug.h"
#define __WS_ASYNC_DEBUG 0
static int _async_io_max_fd = 0;
static fd_set __async_io_fdset;
static ws_async_op* __async_op_list = NULL;
extern ws_async_ctl async_ctl;
extern int async_qid;
fd_set fd_read, fd_write, fd_excp;
/* ----------------------------------- async/non-blocking I/O */
int WINSOCK_async_io(int fd, int async)
{
int fd_flags;
fcntl(fd, F_SETOWN, getpid());
fd_flags = fcntl(fd, F_GETFL, 0);
if (fcntl(fd, F_SETFL, (async)? fd_flags | FASYNC
: fd_flags & ~FASYNC ) != -1) return 0;
return -1;
}
int WINSOCK_unblock_io(int fd, int noblock)
{
int fd_flags;
fd_flags = fcntl(fd, F_GETFL, 0);
if (fcntl(fd, F_SETFL, (noblock)? fd_flags | O_NONBLOCK
: fd_flags & ~O_NONBLOCK ) != -1) return 0;
return -1;
}
int WINSOCK_check_async_op(ws_async_op* p_aop)
{
ws_async_op* p = __async_op_list;
while( p ) if( p == p_aop ) return 1;
else p = p->next;
return 0;
}
void WINSOCK_cancel_async_op(HTASK16 hTask)
{
ws_async_op* p = __async_op_list;
while( p )
if(hTask == GetWindowTask16(p->hWnd))
p->flags = 0;
}
void WINSOCK_link_async_op(ws_async_op* p_aop)
{
if( __async_op_list ) __async_op_list->prev = p_aop;
else FD_ZERO(&__async_io_fdset);
p_aop->next = __async_op_list;
p_aop->prev = NULL;
__async_op_list = p_aop;
FD_SET(p_aop->fd[0], &__async_io_fdset);
if( p_aop->fd[0] > _async_io_max_fd )
_async_io_max_fd = p_aop->fd[0];
}
void WINSOCK_unlink_async_op(ws_async_op* p_aop)
{
if( p_aop == __async_op_list ) __async_op_list = p_aop->next;
else
{ p_aop->prev->next = p_aop->next;
if( p_aop->next ) p_aop->next->prev = p_aop->prev; }
FD_CLR(p_aop->fd[0], &__async_io_fdset);
if( p_aop->fd[0] == _async_io_max_fd )
_async_io_max_fd--;
}
/* ----------------------------------- SIGIO handler -
*
* link_async_op/unlink_async_op allow to install generic
* async IO handlers (provided that aop_control function is defined).
*
* Note: AsyncGetXbyY expilicitly raise it.
*/
void WINSOCK_sigio(int signal)
{
struct timeval timeout;
fd_set check_set;
ws_async_op* p_aop;
check_set = __async_io_fdset;
bzero(&timeout,sizeof(timeout));
while( select(_async_io_max_fd + 1,
&check_set, NULL, NULL, &timeout) > 0)
{
for( p_aop = __async_op_list;
p_aop ; p_aop = p_aop->next )
if( FD_ISSET(p_aop->fd[0], &check_set) )
if( p_aop->aop_control(p_aop, AOP_IO) == AOP_CONTROL_REMOVE )
{
if( p_aop->pid )
{
kill(p_aop->pid, SIGKILL);
waitpid(p_aop->pid, NULL, 0);
}
WINSOCK_unlink_async_op( p_aop );
}
check_set = __async_io_fdset;
}
}
/* ----------------------------------- child process IPC */
static void _sigusr1_handler_child(int sig)
{
/* read message queue to decide which
* async_ctl parameters to update
*
* Note: we don't want to have SA_RESTART on this signal
* handler, otherwise select() won't notice changed fd sets.
*/
signal( SIGUSR1, _sigusr1_handler_child );
while( msgrcv(async_qid, (struct msgbuf*)&async_ctl.ip,
MTYPE_PARENT_SIZE, MTYPE_PARENT, IPC_NOWAIT) != -1 )
{
/* only ip.lParam is updated */
#if __WS_ASYNC_DEBUG
printf("handler - event %08x\n", async_ctl.ip.lParam );
#endif
switch( async_ctl.ip.lParam )
{
/* These are events we are notified of.
*/
case WS_FD_CONNECTED: async_ctl.lEvent &= ~WS_FD_CONNECT;
FD_SET(async_ctl.ws_sock->fd, &fd_read);
FD_SET(async_ctl.ws_sock->fd, &fd_write);
break;
case WS_FD_ACCEPT: async_ctl.ws_sock->flags |= WS_FD_ACCEPT;
FD_SET(async_ctl.ws_sock->fd, &fd_read);
FD_SET(async_ctl.ws_sock->fd, &fd_write);
break;
case WS_FD_OOB: async_ctl.lEvent |= WS_FD_OOB;
FD_SET(async_ctl.ws_sock->fd, &fd_excp);
break;
case WS_FD_READ: async_ctl.lEvent |= WS_FD_READ;
FD_SET(async_ctl.ws_sock->fd, &fd_read);
break;
case WS_FD_WRITE: async_ctl.lEvent |= WS_FD_WRITE;
FD_SET(async_ctl.ws_sock->fd, &fd_write);
break;
default:
}
}
}
static int notify_parent( unsigned flag )
{
if( flag & WSMSG_ASYNC_SELECT )
{
async_ctl.ip.mtype = MTYPE_CLIENT;
while( msgsnd(async_qid, (struct msgbuf*)&(async_ctl.ip),
MTYPE_CLIENT_SIZE, 0) == -1 )
{
if( errno == EINTR ) continue;
else if( errno == EIDRM ) _exit(0);
else
{
perror("AsyncSelect(child)");
return 0;
}
}
kill(getppid(), SIGUSR1);
#if __WS_ASYNC_DEBUG
printf("handler - notify [%08x]\n", async_ctl.ip.lParam);
#endif
}
else /* use half-duplex pipe to handle variable length packets */
{
write(async_ctl.ws_aop->fd[1], &async_ctl.lLength, sizeof(unsigned) );
write(async_ctl.ws_aop->fd[1], async_ctl.buffer, async_ctl.lLength );
kill(getppid(), SIGIO); /* simulate async I/O */
#if __WS_ASYNC_DEBUG
printf("handler - notify aop [%d, buf %d]\n", async_ctl.lLength, async_ctl.ws_aop->buflen);
#endif
pause();
}
return 1;
}
/* ----------------------------------- async select */
static void setup_fd_sets()
{
FD_ZERO(&fd_read); FD_ZERO(&fd_write); FD_ZERO(&fd_excp);
if( async_ctl.lEvent & WS_FD_OOB)
FD_SET(async_ctl.ws_sock->fd, &fd_excp);
if( async_ctl.lEvent & (WS_FD_ACCEPT | WS_FD_READ |
WS_FD_CONNECT | WS_FD_CLOSE) )
FD_SET(async_ctl.ws_sock->fd, &fd_read);
if( async_ctl.lEvent & (WS_FD_WRITE | WS_FD_CONNECT) )
FD_SET(async_ctl.ws_sock->fd, &fd_write);
}
static void setup_sig_sets(sigset_t* sig_block)
{
sigemptyset(sig_block);
sigaddset(sig_block, SIGUSR1);
sigprocmask( SIG_BLOCK, sig_block, NULL);
signal( SIGUSR1, _sigusr1_handler_child );
}
void WINSOCK_do_async_select()
{
sigset_t sig_block;
int bytes;
setup_sig_sets(&sig_block);
setup_fd_sets();
while(1)
{
int val;
sigprocmask( SIG_UNBLOCK, &sig_block, NULL);
#if __WS_ASYNC_DEBUG
printf("select(2)[%i,%i,%i]... ",
FD_ISSET(async_ctl.ws_sock->fd, &fd_read),
FD_ISSET(async_ctl.ws_sock->fd, &fd_write),
FD_ISSET(async_ctl.ws_sock->fd, &fd_excp));
#endif
if( (val = select(async_ctl.ws_sock->fd + 1,
&fd_read, &fd_write, &fd_excp, NULL)) == -1 )
if( errno == EINTR ) continue;
#if __WS_ASYNC_DEBUG
printf("got %i events\n", val);
#endif
#if __WS_ASYNC_DEBUG
if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
printf("handler - read is READY! [%08x]\n", async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE));
#endif
sigprocmask( SIG_BLOCK, &sig_block, NULL);
async_ctl.ip.lParam = 0;
if( async_ctl.ws_sock->flags & WS_FD_ACCEPT )
{
/* listening socket */
FD_CLR(async_ctl.ws_sock->fd, &fd_read);
FD_CLR(async_ctl.ws_sock->fd, &fd_write);
async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_ACCEPT, 0 );
notify_parent( WSMSG_ASYNC_SELECT );
continue;
}
else /* I/O socket */
{
if( async_ctl.lEvent & WS_FD_CONNECT )
{
if( FD_ISSET(async_ctl.ws_sock->fd, &fd_write) )
{
/* success - reinit fd sets to start I/O */
if( async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE))
FD_SET(async_ctl.ws_sock->fd, &fd_read);
else FD_CLR(async_ctl.ws_sock->fd, &fd_read);
if( async_ctl.lEvent & WS_FD_WRITE )
FD_SET(async_ctl.ws_sock->fd, &fd_write);
else FD_CLR(async_ctl.ws_sock->fd, &fd_write);
async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CONNECT, 0 );
async_ctl.lEvent &= ~WS_FD_CONNECT; /* one-shot */
}
else if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
{
/* failure - do read() to get correct errno */
if( read(async_ctl.ws_sock->fd, &bytes, 4) == -1 )
async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CONNECT, wsaErrno() );
else continue;
} else continue; /* OOB?? */
notify_parent( WSMSG_ASYNC_SELECT );
}
else /* connected socket */
{
if( async_ctl.lEvent & WS_FD_OOB )
if( FD_ISSET(async_ctl.ws_sock->fd, &fd_excp) )
{
async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_OOB, 0 );
async_ctl.lEvent &= ~WS_FD_OOB;
FD_CLR(async_ctl.ws_sock->fd, &fd_excp);
notify_parent( WSMSG_ASYNC_SELECT );
}
else FD_SET(async_ctl.ws_sock->fd, &fd_excp);
if( async_ctl.lEvent & WS_FD_WRITE )
if( FD_ISSET( async_ctl.ws_sock->fd, &fd_write ) )
{
async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_WRITE, 0 );
async_ctl.lEvent &= ~WS_FD_WRITE;
FD_CLR(async_ctl.ws_sock->fd, &fd_write);
notify_parent( WSMSG_ASYNC_SELECT );
}
else FD_SET(async_ctl.ws_sock->fd, &fd_write);
if( async_ctl.lEvent & (WS_FD_READ | WS_FD_CLOSE) )
if( FD_ISSET(async_ctl.ws_sock->fd, &fd_read) )
{
if( ioctl( async_ctl.ws_sock->fd, FIONREAD, (char*)&bytes) != -1 )
{
if( bytes ) /* got data */
{
#if __WS_ASYNC_DEBUG
printf("\t%i bytes pending\n", bytes );
#endif
if( async_ctl.lEvent & WS_FD_READ )
{
async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_READ, 0 );
async_ctl.lEvent &= ~WS_FD_READ;
if( !(async_ctl.lEvent & WS_FD_CLOSE) )
FD_CLR( async_ctl.ws_sock->fd, &fd_read );
}
else if( !(async_ctl.lEvent & (WS_FD_WRITE | WS_FD_OOB)) )
{
sigprocmask( SIG_UNBLOCK, &sig_block, NULL);
pause();
sigprocmask( SIG_BLOCK, &sig_block, NULL);
}
else continue;
}
else /* 0 bytes to read */
{
val = read( async_ctl.ws_sock->fd, (char*)&bytes, 4);
if( errno == EWOULDBLOCK || errno == EINTR )
{
#if __WS_ASYNC_DEBUG
printf("\twould block..\n");
#endif
continue;
}
switch( val )
{
case 0: errno = ENETDOWN; /* ENETDOWN */
case -1: /* ECONNRESET */
async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_CLOSE, wsaErrno() );
break;
default: continue;
}
async_ctl.lEvent &= ~(WS_FD_CLOSE | WS_FD_READ); /* one-shot */
FD_ZERO(&fd_read); FD_ZERO(&fd_write);
}
}
else async_ctl.ip.lParam = WSAMAKESELECTREPLY( WS_FD_READ, wsaErrno() );
notify_parent( WSMSG_ASYNC_SELECT );
}
else FD_SET(async_ctl.ws_sock->fd, &fd_read);
} /* connected socket */
} /* I/O socket */
} /* while */
}
/* ----------------------------------- getXbyY requests */
static void _async_fail()
{
async_ctl.lLength =
(h_errno < 0) ? (unsigned)WSAMAKEASYNCREPLY( 0, wsaErrno() )
: (unsigned)WSAMAKEASYNCREPLY( 0, wsaHerrno() );
write(async_ctl.ws_aop->fd[1], &async_ctl.lLength, sizeof(unsigned) );
kill(getppid(), SIGIO); /* simulate async I/O */
pause();
}
void dump_ws_hostent_offset(struct ws_hostent* wshe)
{
int i;
char* base = (char*)wshe;
unsigned* ptr;
printf("h_name = %08x\t[%s]\n", (unsigned)wshe->h_name, base + (unsigned)wshe->h_name);
printf("h_aliases = %08x\t[%08x]\n", (unsigned)wshe->h_aliases,
(unsigned)(base + (unsigned)wshe->h_aliases));
ptr = (unsigned*)(base + (unsigned)wshe->h_aliases);
for(i = 0; ptr[i]; i++ )
{
printf("%i - %08x ", i + 1, ptr[i]);
printf(" [%s]\n", ((char*)base) + ptr[i]);
}
printf("h_length = %i\n", wshe->h_length);
}
void WS_do_async_gethost(LPWSINFO pwsi, unsigned flag )
{
int size = 0;
struct hostent* p_he;
close(async_ctl.ws_aop->fd[0]);
p_he = (flag & WSMSG_ASYNC_HOSTBYNAME)
? gethostbyname(async_ctl.ws_aop->init)
: gethostbyaddr(async_ctl.ws_aop->init,
async_ctl.lLength, async_ctl.lEvent);
if( p_he ) size = WS_dup_he(pwsi, p_he, WS_DUP_SEGPTR | WS_DUP_OFFSET );
if( size )
{
async_ctl.buffer = pwsi->buffer;
async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
notify_parent( flag );
}
else _async_fail();
_exit(0);
}
void WS_do_async_getproto(LPWSINFO pwsi, unsigned flag )
{
int size = 0;
struct protoent* p_pe;
close(async_ctl.ws_aop->fd[0]);
p_pe = (flag & WSMSG_ASYNC_PROTOBYNAME)
? getprotobyname(async_ctl.ws_aop->init)
: getprotobynumber(async_ctl.lEvent);
if( p_pe ) size = WS_dup_pe(pwsi, p_pe, WS_DUP_SEGPTR | WS_DUP_OFFSET );
if( size )
{
async_ctl.buffer = pwsi->buffer;
async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
notify_parent( flag );
}
else _async_fail();
_exit(0);
}
void WS_do_async_getserv(LPWSINFO pwsi, unsigned flag )
{
int size = 0;
struct servent* p_se;
close(async_ctl.ws_aop->fd[0]);
p_se = (flag & WSMSG_ASYNC_SERVBYNAME)
? getservbyname(async_ctl.ws_aop->init, async_ctl.buffer)
: getservbyport(async_ctl.lEvent, async_ctl.ws_aop->init);
if( p_se ) size = WS_dup_se(pwsi, p_se, WS_DUP_SEGPTR | WS_DUP_OFFSET );
if( size )
{
async_ctl.buffer = pwsi->buffer;
async_ctl.lLength = (unsigned)WSAMAKEASYNCREPLY( (UINT16)size, 0 );
notify_parent( flag );
}
else _async_fail();
_exit(0);
}