#ifdef __CYGWIN__
#define SOCKET int
#define _get_osfhandle(a) a
#include <pthread.h>
#else
#include <winsock.h>
void __inline my_fd_zero( fd_set* f) { FD_ZERO( f); }
void __inline my_fd_set( HANDLE fd, fd_set* f) { FD_SET((unsigned int) fd, f); }
#endif
#include "win32\win32guts.h"
#ifndef _APRICOT_H_
#include "apricot.h"
#endif
#include "guts.h"
#include "Component.h"
#include "File.h"
#define var (( PFile) self)->
#define sys (( PDrawableData)(( PComponent) self)-> sysData)->
#define dsys( view) (( PDrawableData)(( PComponent) view)-> sysData)->
#ifdef __cplusplus
extern "C" {
#endif
#ifndef __CYGWIN__
#undef select
#undef fd_set
#undef FD_ZERO
#define FD_ZERO my_fd_zero
#undef FD_SET
#define FD_SET my_fd_set
#endif
static Bool socketThreadStarted = false;
static Bool socketSetChanged = false;
static struct timeval socketTimeout = {0, 200000};
static char socketErrBuf [ 256];
static fd_set socketSet1[3];
static fd_set socketSet2[3];
static int socketCommands[3] = { feRead, feWrite, feException};
void
#ifdef __CYGWIN__
*
#endif
socket_select( void *dummy)
{
int count;
while ( !appDead) {
if ( socketSetChanged) {
// updating handles
int i;
if ( WaitForSingleObject( guts. socketMutex, INFINITE) != WAIT_OBJECT_0) {
strcpy( socketErrBuf, "Failed to obtain socket mutex ownership for thread #2");
PostThreadMessage( guts. mainThreadId, WM_CROAK, 1, ( LPARAM) &socketErrBuf);
break;
}
for ( i = 0; i < 3; i++)
memcpy( socketSet1+i, socketSet2+i, sizeof( fd_set));
socketSetChanged = false;
ReleaseMutex( guts. socketMutex);
}
// calling select()
#ifndef __CYGWIN__
count = socketSet1[0]. fd_count + socketSet1[1]. fd_count + socketSet1[2]. fd_count;
#else
count = 0;
{
int i,j;
for ( i = 0; i < FD_SETSIZE; i++)
for ( j = 0; j < 3; i++)
if ( FD_ISSET( i, socketSet1+j)) {
count++;
goto END;
}
END:;
}
#endif
if ( count > 0) {
int i, j, result = select( FD_SETSIZE-1, &socketSet1[0], &socketSet1[1], &socketSet1[2], &socketTimeout);
socketSetChanged = true;
if ( result == 0) continue;
if ( result < 0) {
int err;
#ifndef __CYGWIN__
if (( err = WSAGetLastError()) == WSAENOTSOCK)
#else
if (( err = errno) == EBADF)
#endif
{
// possibly some socket was closed
guts. socketPostSync = 1;
PostThreadMessage( guts. mainThreadId, WM_SOCKET_REHASH, 0, 0);
while( guts. socketPostSync) Sleep(1);
} else {
// some error
char * msg;
#ifndef __CYGWIN__
msg = err_msg( err, socketErrBuf);
#else
strncpy( msg = socketErrBuf, strerror(err), 255);
socketErrBuf[255] = 0;
#endif
PostThreadMessage( guts. mainThreadId, WM_CROAK, 0, (LPARAM) msg);
}
continue;
}
// posting select() results
for ( j = 0; j < 3; j++)
#ifndef __CYGWIN__
for ( i = 0; i < socketSet1[j]. fd_count; i++) {
#else
for ( i = 0; i < FD_SETSIZE; i++) {
if ( !FD_ISSET( i, socketSet1 + j)) continue;
#endif
guts. socketPostSync = 1;
PostThreadMessage( guts. mainThreadId, WM_SOCKET, socketCommands[j],
#ifndef __CYGWIN__
( LPARAM) socketSet1[j]. fd_array[i]
#else
( LPARAM) i
#endif
);
while( guts. socketPostSync) Sleep(1);
}
} else
// nothing to 'select', sleeping
Sleep( socketTimeout. tv_sec * 1000 + socketTimeout. tv_usec / 1000);
}
// if somehow failed, making restart possible
socketThreadStarted = false;
#ifdef __CYGWIN__
return NULL;
#endif
}
static void
reset_sockets( void)
{
int i;
// enter section
if ( socketThreadStarted) {
if ( WaitForSingleObject( guts. socketMutex, INFINITE) != WAIT_OBJECT_0)
croak("Failed to obtain socket mutex ownership for thread #1");
}
// copying handles
for ( i = 0; i < 3; i++)
FD_ZERO( &socketSet2[i]);
for ( i = 0; i < guts. sockets. count; i++) {
Handle self = guts. sockets. items[i];
if ( var eventMask & feRead)
FD_SET( sys s. file. object, &socketSet2[0]);
if ( var eventMask & feWrite)
FD_SET( sys s. file. object, &socketSet2[1]);
if ( var eventMask & feException)
FD_SET( sys s. file. object, &socketSet2[2]);
}
socketSetChanged = true;
// leave section and start the thread, if needed
if ( !socketThreadStarted) {
if ( !( guts. socketMutex = CreateMutex( NULL, FALSE, NULL))) {
apiErr;
croak("Failed to create socket mutex object");
}
#ifndef __CYGWIN__
guts. socketThread = ( HANDLE) _beginthread( socket_select, 40960, NULL);
#else
pthread_create(( pthread_t*) &guts. socketThread, 0, socket_select, NULL);
#endif
socketThreadStarted = true;
} else
ReleaseMutex( guts. socketMutex);
}
void
socket_rehash( void)
{
int i;
for ( i = 0; i < guts. sockets. count; i++) {
Handle self = guts. sockets. items[i];
CFile( self)-> is_active( self, true);
}
}
Bool
apc_file_attach( Handle self)
{
int fhtype;
objCheck false;
if ( PFile(self)->fd > FD_SETSIZE ) return false;
if ( guts. socket_version == 0) {
int _data, _sz = sizeof( int);
(void)_data;
(void)_sz;
#ifdef __CYGWIN__
_sz = htons(80);
guts. socket_version = 2;
#else
#ifdef PERL_OBJECT // init perl socket library, if any
PL_piSock-> Htons( 80);
#else
win32_htons(80);
#endif
if ( getsockopt(( SOCKET) INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char*)&_data, &_sz) != 0)
guts. socket_version = -1; // no sockets available
else
#if PERL_PATCHLEVEL < 8
guts. socket_version = ( _data == SO_SYNCHRONOUS_NONALERT) ? 1 : 2;
#else
guts. socket_version = 1;
#endif
#endif
}
if ( SOCKETS_NONE)
return false;
sys s. file. object = SOCKETS_AS_HANDLES ?
(( SOCKETHANDLE) _get_osfhandle( var fd)) :
(( SOCKETHANDLE) var fd);
{
int _data, _sz = sizeof( int);
int result =
#ifndef __CYGWIN__
SOCKETS_AS_HANDLES ?
WSAAsyncSelect((SOCKET) sys s. file. object, (HWND) NULL, 0, 0) :
#endif
getsockopt(( SOCKET) sys s. file. object, SOL_SOCKET, SO_TYPE, (char*)&_data, &_sz);
if ( result != 0)
#ifndef __CYGWIN__
fhtype = ( WSAGetLastError() == WSAENOTSOCK) ? FHT_OTHER : FHT_SOCKET;
#else
fhtype = ( errno == EBADF) ? FHT_OTHER : FHT_SOCKET;
#endif
else
fhtype = FHT_SOCKET;
}
sys s. file. type = fhtype;
switch ( fhtype) {
case FHT_SOCKET:
list_add( &guts. sockets, self);
reset_sockets();
break;
default:
if ( guts. files. count == 0)
PostMessage( NULL, WM_FILE, 0, 0);
list_add( &guts. files, self);
break;
}
return true;
}
Bool
apc_file_detach( Handle self)
{
switch ( sys s. file. type) {
case FHT_SOCKET:
list_delete( &guts. sockets, self);
reset_sockets();
break;
default:
list_delete( &guts. files, self);
}
return true;
}
Bool
apc_file_change_mask( Handle self)
{
switch ( sys s. file. type) {
case FHT_SOCKET:
reset_sockets();
break;
default:;
}
return true;
}
#ifdef __cplusplus
}
#endif