Source to src/od-win32/bsdsock.c
/*
* UAE - The Un*x Amiga Emulator
*
* bsdsocket.library emulation - Win32 OS-dependent part
*
* Copyright 1997,98 Mathias Ortmann
* Copyright 1999,2000 Brian King
*
* GNU Public License
*
*/
#include "sysconfig.h"
#include "sysdeps.h"
#include <winsock.h>
#include <stddef.h>
#include <process.h>
#include "options.h"
#include "memory.h"
#include "custom.h"
#include "newcpu.h"
#include "autoconf.h"
#include "bsdsocket.h"
#include "osdep/exectasks.h"
#include "threaddep/thread.h"
#include "native2amiga.h"
#include "osdep/resource.h"
#include "osdep/win32gui.h"
static HWND hSockWnd;
extern HWND hAmigaWnd;
int hWndSelector = 0; /* Set this to zero to get hSockWnd */
CRITICAL_SECTION csSigQueueLock;
DWORD threadid;
#ifdef __GNUC__
#define THREAD(func,arg) CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func,(LPVOID)arg,0,&threadid)
#else
#define THREAD(func,arg) _beginthreadex( NULL, 0, func, (void *)arg, 0, (unsigned *)&threadid )
#endif
#define SETERRNO seterrno(sb,WSAGetLastError()-WSABASEERR)
#define SETHERRNO setherrno(sb,WSAGetLastError()-WSABASEERR)
#define WAITSIGNAL waitsig(sb)
#define SETSIGNAL addtosigqueue(sb,0)
#define CANCELSIGNAL cancelsig(sb)
#define BEGINBLOCKING if (sb->ftable[sd-1] & SF_BLOCKING) sb->ftable[sd-1] |= SF_BLOCKINGINPROGRESS
#define ENDBLOCKING sb->ftable[sd-1] &= ~SF_BLOCKINGINPROGRESS
static WSADATA wsbData;
int PASCAL WSAEventSelect(SOCKET,HANDLE,long);
#define MAX_SELECT_THREADS 64
static HANDLE hThreads[MAX_SELECT_THREADS];
uae_u32 *threadargs[MAX_SELECT_THREADS];
static HANDLE hEvents[MAX_SELECT_THREADS];
static HANDLE hSockThread;
static HANDLE hSockReq, hSockReqHandled;
static unsigned int __stdcall sock_thread(void *);
CRITICAL_SECTION SockThreadCS;
#define PREPARE_THREAD EnterCriticalSection( &SockThreadCS )
#define TRIGGER_THREAD { SetEvent( hSockReq ); WaitForSingleObject( hSockReqHandled, INFINITE ); LeaveCriticalSection( &SockThreadCS ); }
#define SOCKVER_MAJOR 2
#define SOCKVER_MINOR 2
int mySockStartup( void )
{
int result = 0;
SOCKET dummy;
DWORD lasterror;
if (WSAStartup(MAKEWORD( SOCKVER_MAJOR, SOCKVER_MINOR ), &wsbData))
{
lasterror = WSAGetLastError();
if( lasterror == WSAVERNOTSUPPORTED )
{
char szMessage[ MAX_PATH ];
WIN32GUI_LoadUIString( IDS_WSOCK2NEEDED, szMessage, MAX_PATH );
gui_message( szMessage );
}
else
write_log ( "BSDSOCK: ERROR - Unable to initialize Windows socket layer! Error code: %d\n", lasterror );
return 0;
}
if (LOBYTE (wsbData.wVersion) != SOCKVER_MAJOR || HIBYTE (wsbData.wVersion) != SOCKVER_MINOR )
{
char szMessage[ MAX_PATH ];
WIN32GUI_LoadUIString( IDS_WSOCK2NEEDED, szMessage, MAX_PATH );
gui_message( szMessage );
return 0;
}
else
{
write_log ( "BSDSOCK: using %s\n", wsbData.szDescription );
// make sure WSP/NSPStartup gets called from within the regular stack
// (Windows 95/98 need this)
if( ( dummy = socket( AF_INET,SOCK_STREAM,IPPROTO_TCP ) ) != INVALID_SOCKET )
{
closesocket( dummy );
result = 1;
}
else
{
write_log ( "BSDSOCK: ERROR - WSPStartup/NSPStartup failed! Error code: %d\n",WSAGetLastError() );
result = 0;
}
}
return result;
}
static int socket_layer_initialized = 0;
int init_socket_layer(void)
{
int result = 0;
#ifndef CAN_DO_STACK_MAGIC
currprefs.socket_emu = 0;
#endif
if( currprefs.socket_emu )
{
if( ( result = mySockStartup() ) )
{
InitializeCriticalSection(&csSigQueueLock);
if( hSockThread == NULL )
{
InitializeCriticalSection( &SockThreadCS );
hSockReq = CreateEvent( NULL, FALSE, FALSE, NULL );
hSockReqHandled = CreateEvent( NULL, FALSE, FALSE, NULL );
hSockThread = (void *)THREAD(sock_thread,NULL);
}
}
}
socket_layer_initialized = result;
return result;
}
void deinit_socket_layer(void)
{
int i;
if( currprefs.socket_emu )
{
WSACleanup();
if( socket_layer_initialized )
{
DeleteCriticalSection( &csSigQueueLock );
if( hSockThread )
{
DeleteCriticalSection( &SockThreadCS );
CloseHandle( hSockReq );
hSockReq = NULL;
CloseHandle( hSockReqHandled );
WaitForSingleObject( hSockThread, INFINITE );
CloseHandle( hSockThread );
}
for (i = 0; i < MAX_SELECT_THREADS; i++)
{
if (hThreads[i])
{
CloseHandle( hThreads[i] );
}
}
}
}
}
#ifdef BSDSOCKET_SUPPORTED
void locksigqueue(void)
{
EnterCriticalSection(&csSigQueueLock);
}
void unlocksigqueue(void)
{
LeaveCriticalSection(&csSigQueueLock);
}
// Asynchronous completion notification
// We use window messages posted to hAmigaWnd in the range from 0xb000 to 0xb000+MAXPENDINGASYNC*2
// Socket events cause even-numbered messages, task events odd-numbered messages
// Message IDs are allocated on a round-robin basis and deallocated by the main thread.
// WinSock tends to choke on WSAAsyncCancelMessage(s,w,m,0,0) called too often with an event pending
// @@@ Enabling all socket event messages for every socket by default and basing things on that would
// be cleaner (and allow us to write a select() emulation that doesn't need to be kludge-aborted).
// However, the latency of the message queue is too high for that at the moment (setting up a dummy
// window from a separate thread would fix that).
// Blocking sockets with asynchronous event notification are currently not safe to use.
struct socketbase *asyncsb[MAXPENDINGASYNC];
SOCKET asyncsock[MAXPENDINGASYNC];
uae_u32 asyncsd[MAXPENDINGASYNC];
int asyncindex;
int host_sbinit(SB)
{
sb->sockAbort = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
if (sb->sockAbort == INVALID_SOCKET) return 0;
if ((sb->hEvent = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL) return 0;
sb->mtable = calloc(sb->dtablesize,sizeof(*sb->mtable));
return 1;
}
void host_closesocketquick(int s)
{
BOOL true = 1;
if( s )
{
setsockopt((SOCKET)s,SOL_SOCKET,SO_DONTLINGER,(char *)&true,sizeof(true));
//shutdown(s,1);
closesocket((SOCKET)s);
}
}
void host_sbcleanup(SB)
{
int i;
for (i = 0; i < MAXPENDINGASYNC; i++) if (asyncsb[i] == sb) asyncsb[i] = NULL;
if (sb->hEvent != NULL) CloseHandle(sb->hEvent);
if (sb->hAsyncTask) WSACancelAsyncRequest(sb->hAsyncTask);
for (i = sb->dtablesize; i--; )
{
if (sb->dtable[i] != (int)INVALID_SOCKET) host_closesocketquick(sb->dtable[i]);
if (sb->mtable[i]) asyncsb[(sb->mtable[i]-0xb000)/2] = NULL;
}
//shutdown(sb->sockAbort,1);
closesocket(sb->sockAbort);
free(sb->mtable);
}
void host_sbreset(void)
{
memset(asyncsb,0,sizeof asyncsb);
memset(asyncsock,0,sizeof asyncsock);
memset(asyncsd,0,sizeof asyncsd);
memset(threadargs,0,sizeof threadargs);
}
void sockmsg(unsigned int msg, unsigned long wParam, unsigned long lParam)
{
SB;
unsigned int index;
int sdi;
index = (msg-0xb000)/2;
sb = asyncsb[index];
if (!(msg & 1))
{
// is this one really for us?
if ((SOCKET)wParam != asyncsock[index])
{
// cancel socket event
WSAAsyncSelect((SOCKET)wParam,hWndSelector ? hAmigaWnd : hSockWnd,0,0);
return;
}
sdi = asyncsd[index]-1;
// asynchronous socket event?
if (sb && !(sb->ftable[sdi] & SF_BLOCKINGINPROGRESS) && sb->mtable[sdi])
{
long wsbevents = WSAGETSELECTEVENT(lParam);
int fmask = 0;
// regular socket event?
if (wsbevents & FD_READ) fmask = REP_READ;
else if (wsbevents & FD_WRITE) fmask = REP_WRITE;
else if (wsbevents & FD_OOB) fmask = REP_OOB;
else if (wsbevents & FD_ACCEPT) fmask = REP_ACCEPT;
else if (wsbevents & FD_CONNECT) fmask = REP_CONNECT;
else if (wsbevents & FD_CLOSE) fmask = REP_CLOSE;
// error?
if (WSAGETSELECTERROR(lParam)) fmask |= REP_ERROR;
// notify
if (sb->ftable[sdi] & fmask) sb->ftable[sdi] |= fmask<<8;
addtosigqueue(sb,1);
return;
}
}
locksigqueue();
if (sb != NULL)
{
if (msg & 1)
{
// is this one really for us?
if (sb->hAsyncTask != (void *)~0L && (void *)wParam != sb->hAsyncTask)
{
unlocksigqueue();
return;
}
}
asyncsb[index] = NULL;
if (WSAGETASYNCERROR(lParam))
{
seterrno(sb,WSAGETASYNCERROR(lParam)-WSABASEERR);
if (sb->sb_errno >= 1001 && sb->sb_errno <= 1005) setherrno(sb,sb->sb_errno-1000);
else if (sb->sb_errno == 55) // ENOBUFS
write_log ("BSDSOCK: ERROR - Buffer overflow - %d bytes requested\n",WSAGETASYNCBUFLEN(lParam));
}
else seterrno(sb,0);
if (msg & 1) sb->hAsyncTask = 0;
SETSIGNAL;
}
unlocksigqueue();
}
static unsigned int allocasyncmsg(SB,uae_u32 sd,SOCKET s)
{
int i;
locksigqueue();
for (i = asyncindex+1; i != asyncindex; i++)
{
if (i == MAXPENDINGASYNC) i = 0;
if (!asyncsb[i])
{
asyncsb[i] = sb;
if (++asyncindex == MAXPENDINGASYNC) asyncindex = 0;
unlocksigqueue();
if (s == INVALID_SOCKET)
{
sb->hAsyncTask = (void *)~0L; // set wildcard value to prevent race condition
return i*2+0xb001;
}
else
{
asyncsd[i] = sd;
asyncsock[i] = s;
return i*2+0xb000;
}
}
}
unlocksigqueue();
seterrno(sb,12); // ENOMEM
write_log ("BSDSOCK: ERROR - Async operation completion table overflow\n");
return 0;
}
static void cancelasyncmsg(unsigned int wMsg)
{
SB;
wMsg = (wMsg-0xb000)/2;
sb = asyncsb[wMsg];
if (sb != NULL)
{
asyncsb[wMsg] = NULL;
CANCELSIGNAL;
}
}
void sockabort(SB)
{
locksigqueue();
if (sb->hAsyncTask)
{
if (WSACancelAsyncRequest(sb->hAsyncTask))
write_log ("BSDSOCK: ERROR - WSACancelAsyncRequest() failed with error code %d\n",WSAGetLastError());
sb->hAsyncTask = 0;
}
unlocksigqueue();
}
// address cleaning
static void prephostaddr(SOCKADDR_IN *addr)
{
addr->sin_family = AF_INET;
}
static void prepamigaaddr(struct sockaddr *realpt, int len)
{
// little endian address family value to the byte sin_family member
((char *)realpt)[1] = *((char *)realpt);
// set size of address
*((char *)realpt) = len;
}
int host_socket(SB, int af, int type, int protocol)
{
int sd;
SOCKET s;
unsigned long nonblocking = 1;
TRACE(("socket(%s,%s,%d) -> ",af == AF_INET ? "AF_INET" : "AF_other",type == SOCK_STREAM ? "SOCK_STREAM" : type == SOCK_DGRAM ? "SOCK_DGRAM " : "SOCK_RAW",protocol));
if ((s = socket(af,type,protocol)) == INVALID_SOCKET)
{
SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
return -1;
}
else
sd = getsd(sb,(int)s);
sb->ftable[sd-1] = SF_BLOCKING;
ioctlsocket(s,FIONBIO,&nonblocking);
TRACE(("%d\n",sd));
return sd;
}
uae_u32 host_bind(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
{
char buf[MAXADDRLEN];
uae_u32 success = 0;
SOCKET s;
TRACE(("bind(%d,0x%lx,%d) -> ",sd,name,namelen));
s = getsock(sb, sd);
if (s != INVALID_SOCKET)
{
if (namelen <= sizeof buf)
{
memcpy(buf,get_real_address (name),namelen);
// some Amiga programs set this field to bogus values
prephostaddr((SOCKADDR_IN *)buf);
if ((success = bind(s,(struct sockaddr *)buf,namelen)) != 0)
{
SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
}
else
TRACE(("OK\n"));
}
else
write_log ("BSDSOCK: ERROR - Excessive namelen (%d) in bind()!\n",namelen);
}
return success;
}
uae_u32 host_listen(SB, uae_u32 sd, uae_u32 backlog)
{
SOCKET s;
uae_u32 success = -1;
TRACE(("listen(%d,%d) -> ",sd,backlog));
s = getsock(sb, sd);
if (s != INVALID_SOCKET)
{
if ((success = listen(s,backlog)) != 0)
{
SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
}
else
TRACE(("OK\n"));
}
return success;
}
void host_accept(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
{
struct sockaddr *rp_name;
int hlen;
SOCKET s, s2;
int success = 0;
unsigned int wMsg;
rp_name = (struct sockaddr *)get_real_address (name);
hlen = get_long (namelen);
TRACE(("accept(%d,%d,%d) -> ",sd,name,hlen));
s = (SOCKET)getsock(sb,(int)sd);
if (s != INVALID_SOCKET)
{
BEGINBLOCKING;
s2 = accept(s,rp_name,&hlen);
if (s2 == INVALID_SOCKET)
{
SETERRNO;
if (sb->ftable[sd-1] & SF_BLOCKING && sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR)
{
if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
{
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_ACCEPT);
WAITSIGNAL;
cancelasyncmsg(wMsg);
if (sb->eintr)
{
TRACE(("[interrupted]\n"));
ENDBLOCKING;
return;
}
s2 = accept(s,rp_name,&hlen);
if (s2 == INVALID_SOCKET)
{
SETERRNO;
if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR) write_log ("BSDSOCK: ERRRO - accept() would block despite FD_ACCEPT message\n");
}
}
}
}
if (s2 == INVALID_SOCKET)
{
sb->resultval = -1;
TRACE(("failed (%d)\n",sb->sb_errno));
}
else
{
sb->resultval = getsd(sb, s2);
sb->ftable[sb->resultval-1] = sb->ftable[sd-1]; // new socket inherits the old socket's properties
prepamigaaddr(rp_name,hlen);
put_long (namelen,hlen);
TRACE(("%d/%d\n",sb->resultval,hlen));
}
ENDBLOCKING;
}
}
typedef enum
{
connect_req,
recvfrom_req,
sendto_req,
abort_req,
last_req
} threadsock_e;
struct threadsock_packet
{
threadsock_e packet_type;
union
{
struct sendto_params
{
char *buf;
char *realpt;
uae_u32 sd;
uae_u32 msg;
uae_u32 len;
uae_u32 flags;
uae_u32 to;
uae_u32 tolen;
} sendto_s;
struct recvfrom_params
{
char *realpt;
uae_u32 addr;
uae_u32 len;
uae_u32 flags;
struct sockaddr *rp_addr;
int *hlen;
} recvfrom_s;
struct connect_params
{
char *buf;
uae_u32 namelen;
} connect_s;
struct abort_params
{
SOCKET *newsock;
} abort_s;
} params;
SOCKET s;
SB;
} sockreq;
BOOL HandleStuff( void )
{
BOOL quit = FALSE;
SB = NULL;
BOOL handled = TRUE;
if( hSockReq )
{
// 100ms sleepiness might need some tuning...
if( WaitForSingleObject( hSockReq, 100 ) == WAIT_OBJECT_0 )
{
switch( sockreq.packet_type )
{
case connect_req:
sockreq.sb->resultval = connect(sockreq.s,(struct sockaddr *)(sockreq.params.connect_s.buf),sockreq.params.connect_s.namelen);
break;
case sendto_req:
if( sockreq.params.sendto_s.to )
{
sockreq.sb->resultval = sendto(sockreq.s,sockreq.params.sendto_s.realpt,sockreq.params.sendto_s.len,sockreq.params.sendto_s.flags,(struct sockaddr *)(sockreq.params.sendto_s.buf),sockreq.params.sendto_s.tolen);
}
else
{
sockreq.sb->resultval = send(sockreq.s,sockreq.params.sendto_s.realpt,sockreq.params.sendto_s.len,sockreq.params.sendto_s.flags);
}
break;
case recvfrom_req:
if( sockreq.params.recvfrom_s.addr )
{
sockreq.sb->resultval = recvfrom( sockreq.s, sockreq.params.recvfrom_s.realpt, sockreq.params.recvfrom_s.len,
sockreq.params.recvfrom_s.flags, sockreq.params.recvfrom_s.rp_addr,
sockreq.params.recvfrom_s.hlen );
}
else
{
sockreq.sb->resultval = recv( sockreq.s, sockreq.params.recvfrom_s.realpt, sockreq.params.recvfrom_s.len,
sockreq.params.recvfrom_s.flags );
}
break;
case abort_req:
*(sockreq.params.abort_s.newsock) = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
//shutdown( sb->sockAbort, 1 );
closesocket(sb->sockAbort);
handled = FALSE; /* Don't bother the SETERRNO section after the switch() */
break;
case last_req:
default:
write_log ( "BSDSOCK: Invalid sock-thread request!\n" );
handled = FALSE;
break;
}
if( handled )
{
if( sockreq.sb->resultval == SOCKET_ERROR )
{
sb = sockreq.sb;
SETERRNO;
}
}
SetEvent( hSockReqHandled );
}
}
else
{
quit = TRUE;
}
return quit;
}
long FAR PASCAL SocketWindowProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
#ifdef BSDSOCKET_SUPPORTED
if( message >= 0xB000 && message < 0xB000+MAXPENDINGASYNC*2 )
{
#if DEBUG_SOCKETS
write_log ( "sockmsg(0x%x, 0x%x, 0x%x)\n", message, wParam, lParam );
#endif
sockmsg( message, wParam, lParam );
return 0;
}
#endif
return DefWindowProc( hwnd, message, wParam, lParam );
}
static unsigned int __stdcall sock_thread(void *blah)
{
unsigned int result = 0;
MSG msg;
WNDCLASS wc; // Set up an invisible window and dummy wndproc
wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW;
wc.lpfnWndProc = SocketWindowProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = 0;
wc.hIcon = LoadIcon (GetModuleHandle (NULL), MAKEINTRESOURCE( IDI_APPICON ) );
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
wc.hbrBackground = GetStockObject (BLACK_BRUSH);
wc.lpszMenuName = 0;
wc.lpszClassName = "SocketFun";
if( RegisterClass (&wc) )
{
hSockWnd = CreateWindowEx ( 0,
"SocketFun", "WinUAE Socket Window",
WS_POPUP,
0, 0,
1, 1,
NULL, NULL, 0, NULL);
if( hSockWnd )
{
// Make sure we're outrunning the wolves
SetThreadPriority( GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL );
while( TRUE )
{
if( PeekMessage( &msg, NULL, WM_USER, 0xB000+MAXPENDINGASYNC*2, PM_REMOVE ) > 0 )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
if( HandleStuff() ) // See if its time to quit...
break;
}
}
}
write_log ( "BSDSOCK: We have exited our sock_thread()\n" );
#ifndef __GNUC__
_endthreadex( result );
#endif
return result;
}
void host_connect(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
{
SOCKET s;
int success = 0;
unsigned int wMsg;
char buf[MAXADDRLEN];
TRACE(("connect(%d,0x%lx,%d) -> ",sd,name,namelen));
s = (SOCKET)getsock(sb,(int)sd);
if (s != INVALID_SOCKET)
{
if (namelen <= MAXADDRLEN)
{
if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
{
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_CONNECT);
BEGINBLOCKING;
PREPARE_THREAD;
memcpy(buf,get_real_address (name),namelen);
prephostaddr((SOCKADDR_IN *)buf);
sockreq.packet_type = connect_req;
sockreq.s = s;
sockreq.sb = sb;
sockreq.params.connect_s.buf = buf;
sockreq.params.connect_s.namelen = namelen;
TRIGGER_THREAD;
if (sb->resultval)
{
if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR)
{
if (sb->ftable[sd-1] & SF_BLOCKING)
{
seterrno(sb,0);
WAITSIGNAL;
if (sb->eintr)
{
// Destroy socket to cancel abort, replace it with fake socket to enable proper closing.
// This is in accordance with BSD behaviour.
//shutdown(s,1);
closesocket(s);
sb->dtable[sd-1] = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
}
}
else
seterrno(sb,36); // EINPROGRESS
}
}
ENDBLOCKING;
cancelasyncmsg(wMsg);
}
}
else
write_log ("BSDSOCK: WARNING - Excessive namelen (%d) in connect()!\n",namelen);
}
TRACE(("%d\n",sb->sb_errno));
}
void host_sendto(SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 to, uae_u32 tolen)
{
SOCKET s;
char *realpt;
unsigned int wMsg;
char buf[MAXADDRLEN];
#ifdef TRACING_ENABLED
if (to) TRACE(("sendto(%d,0x%lx,%d,0x%lx,0x%lx,%d) -> ",sd,msg,len,flags,to,tolen))
else TRACE(("send(%d,0x%lx,%d,%d) -> ",sd,msg,len,flags));
#endif
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
realpt = get_real_address (msg);
if (to)
{
if (tolen > sizeof buf) write_log ("BSDSOCK: WARNING - Target address in sendto() too large (%d)!\n",tolen);
else
{
memcpy(buf,get_real_address (to),tolen);
// some Amiga software sets this field to bogus values
prephostaddr((SOCKADDR_IN *)buf);
}
}
BEGINBLOCKING;
for (;;)
{
PREPARE_THREAD;
sockreq.packet_type = sendto_req;
sockreq.s = s;
sockreq.sb = sb;
sockreq.params.sendto_s.realpt = realpt;
sockreq.params.sendto_s.buf = buf;
sockreq.params.sendto_s.sd = sd;
sockreq.params.sendto_s.msg = msg;
sockreq.params.sendto_s.len = len;
sockreq.params.sendto_s.flags = flags;
sockreq.params.sendto_s.to = to;
sockreq.params.sendto_s.tolen = tolen;
TRIGGER_THREAD;
if (sb->resultval == -1)
{
if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING)) break;
}
else
{
realpt += sb->resultval;
len -= sb->resultval;
if (len <= 0) break;
else continue;
}
if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
{
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_WRITE);
WAITSIGNAL;
cancelasyncmsg(wMsg);
if (sb->eintr)
{
TRACE(("[interrupted]\n"));
return;
}
}
else break;
}
ENDBLOCKING;
}
else sb->resultval = -1;
#ifdef TRACING_ENABLED
if (sb->resultval == -1) TRACE(("failed (%d)\n",sb->sb_errno))
else TRACE(("%d\n",sb->resultval));
#endif
}
void host_recvfrom(SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 addr, uae_u32 addrlen)
{
SOCKET s;
char *realpt;
struct sockaddr *rp_addr = NULL;
int hlen;
unsigned int wMsg;
#ifdef TRACING_ENABLED
if (addr) TRACE(("recvfrom(%d,0x%lx,%d,0x%lx,0x%lx,%d) -> ",sd,msg,len,flags,addr,get_long (addrlen)))
else TRACE(("recv(%d,0x%lx,%d,0x%lx) -> ",sd,msg,len,flags));
#endif
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
realpt = get_real_address (msg);
if (addr)
{
hlen = get_long (addrlen);
rp_addr = (struct sockaddr *)get_real_address (addr);
}
BEGINBLOCKING;
for (;;)
{
PREPARE_THREAD;
sockreq.packet_type = recvfrom_req;
sockreq.s = s;
sockreq.sb = sb;
sockreq.params.recvfrom_s.addr = addr;
sockreq.params.recvfrom_s.flags = flags;
sockreq.params.recvfrom_s.hlen = &hlen;
sockreq.params.recvfrom_s.len = len;
sockreq.params.recvfrom_s.realpt = realpt;
sockreq.params.recvfrom_s.rp_addr = rp_addr;
TRIGGER_THREAD;
if (sb->resultval == -1)
{
if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR && sb->ftable[sd-1] & SF_BLOCKING)
{
if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
{
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_READ);
WAITSIGNAL;
cancelasyncmsg(wMsg);
if (sb->eintr)
{
TRACE(("[interrupted]\n"));
return;
}
}
else break;
}
else break;
}
else break;
}
ENDBLOCKING;
if (addr)
{
prepamigaaddr(rp_addr,hlen);
put_long (addrlen,hlen);
}
}
else sb->resultval = -1;
#ifdef TRACING_ENABLED
if (sb->resultval == -1) TRACE(("failed (%d)\n",sb->sb_errno))
else TRACE(("%d\n",sb->resultval));
#endif
}
uae_u32 host_shutdown(SB, uae_u32 sd, uae_u32 how)
{
SOCKET s;
TRACE(("shutdown(%d,%d) -> ",sd,how));
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
if (shutdown(s,how))
{
SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
}
else
{
TRACE(("OK\n"));
return 0;
}
}
return -1;
}
void host_setsockopt(SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 len)
{
SOCKET s;
char buf[MAXADDRLEN];
TRACE(("setsockopt(%d,%d,0x%lx,0x%lx,%d) -> ",sd,(short)level,optname,optval,len));
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
if (len > sizeof buf)
{
write_log ("BSDSOCK: WARNING - Excessive optlen in setsockopt() (%d)\n",len);
len = sizeof buf;
}
if (level == SOL_SOCKET && optname == SO_LINGER)
{
((LINGER *)buf)->l_onoff = get_long (optval);
((LINGER *)buf)->l_linger = get_long (optval+4);
}
else
{
if (len == 4) *(long *)buf = get_long (optval);
else if (len == 2) *(short *)buf = get_word (optval);
else write_log ("BSDSOCK: ERROR - Unknown optlen (%d) in setsockopt(%d,%d)\n",level,optname);
}
// handle SO_EVENTMASK
if (level == 0xffff && optname == 0x2001)
{
long wsbevents = 0;
uae_u32 eventflags = get_long (optval);
sb->ftable[sd-1] = (sb->ftable[sd-1] & ~REP_ALL) | (eventflags & REP_ALL);
if (eventflags & REP_ACCEPT) wsbevents |= FD_ACCEPT;
if (eventflags & REP_CONNECT) wsbevents |= FD_CONNECT;
if (eventflags & REP_OOB) wsbevents |= FD_OOB;
if (eventflags & REP_READ) wsbevents |= FD_READ;
if (eventflags & REP_WRITE) wsbevents |= FD_WRITE;
if (eventflags & REP_CLOSE) wsbevents |= FD_CLOSE;
if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(sb,sd,s)))
{
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,sb->mtable[sd-1],wsbevents);
sb->resultval = 0;
}
else sb->resultval = -1;
}
else sb->resultval = setsockopt(s,level,optname,buf,len);
if (!sb->resultval)
{
TRACE(("OK\n"));
return;
}
else SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
}
}
uae_u32 host_getsockopt(SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 optlen)
{
SOCKET s;
char buf[MAXADDRLEN];
int len = sizeof(buf);
TRACE(("getsockopt(%d,%d,0x%lx,0x%lx,0x%lx) -> ",sd,(short)level,optname,optval,optlen));
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
if (!getsockopt(s,level,optname,buf,&len))
{
if (level == SOL_SOCKET && optname == SO_LINGER)
{
put_long (optval,((LINGER *)buf)->l_onoff);
put_long (optval+4,((LINGER *)buf)->l_linger);
}
else
{
if (len == 4) put_long (optval,*(long *)buf);
else if (len == 2) put_word (optval,*(short *)buf);
else write_log ("BSDSOCK: ERROR - Unknown optlen (%d) in setsockopt(%d,%d)\n",level,optname);
}
// put_long (optlen,len); // some programs pass the actual ength instead of a pointer to the length, so...
TRACE(("OK (%d,%d)\n",len,*(long *)buf));
return 0;
}
else
{
SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
}
}
return -1;
}
uae_u32 host_getsockname(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
{
SOCKET s;
int len;
struct sockaddr *rp_name;
len = get_long (namelen);
TRACE(("getsockname(%d,0x%lx,%d) -> ",sd,name,len));
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
rp_name = (struct sockaddr *)get_real_address (name);
if (getsockname(s,rp_name,&len))
{
SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
}
else
{
TRACE(("%d\n",len));
prepamigaaddr(rp_name,len);
put_long (namelen,len);
return 0;
}
}
return -1;
}
uae_u32 host_getpeername(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
{
SOCKET s;
int len;
struct sockaddr *rp_name;
len = get_long (namelen);
TRACE(("getpeername(%d,0x%lx,%d) -> ",sd,name,len));
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
rp_name = (struct sockaddr *)get_real_address (name);
if (getpeername(s,rp_name,&len))
{
SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
}
else
{
TRACE(("%d\n",len));
prepamigaaddr(rp_name,len);
put_long (namelen,len);
return 0;
}
}
return -1;
}
uae_u32 host_IoctlSocket(SB, uae_u32 sd, uae_u32 request, uae_u32 arg)
{
SOCKET s;
uae_u32 data;
int success = SOCKET_ERROR;
TRACE(("IoctlSocket(%d,0x%lx,0x%lx) ",sd,request,arg));
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
switch (request)
{
case FIONBIO:
TRACE(("[FIONBIO] -> "));
if (get_long (arg))
{
TRACE(("nonblocking\n"));
sb->ftable[sd-1] &= ~SF_BLOCKING;
}
else
{
TRACE(("blocking\n"));
sb->ftable[sd-1] |= SF_BLOCKING;
}
success = 0;
break;
case FIONREAD:
ioctlsocket(s,request,(u_long *)&data);
TRACE(("[FIONREAD] -> %d\n",data));
put_long (arg,data);
success = 0;
break;
case FIOASYNC:
if (get_long (arg))
{
sb->ftable[sd-1] |= REP_ALL;
TRACE(("[FIOASYNC] -> enabled\n"));
if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(sb,sd,s)))
{
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,sb->mtable[sd-1],FD_ACCEPT | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE | FD_CLOSE);
success = 0;
break;
}
}
else write_log (("BSDSOCK: WARNING - FIOASYNC disabling unsupported.\n"));
success = -1;
break;
default:
write_log ("BSDSOCK: WARNING - Unknown IoctlSocket request: 0x%08lx\n",request);
seterrno(sb,22); // EINVAL
}
}
return success;
}
int host_CloseSocket(SB, int sd)
{
unsigned int wMsg;
SOCKET s;
TRACE(("CloseSocket(%d) -> ",sd));
s = getsock(sb,sd);
if (s != INVALID_SOCKET)
{
if (sb->mtable[sd-1])
{
asyncsb[(sb->mtable[sd-1]-0xb000)/2] = NULL;
sb->mtable[sd-1] = 0;
}
BEGINBLOCKING;
for (;;)
{
//shutdown(s,1);
if (!closesocket(s))
{
releasesock(sb,sd);
TRACE(("OK\n"));
return 0;
}
SETERRNO;
if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING)) break;
if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
{
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : hSockWnd,wMsg,FD_CLOSE);
WAITSIGNAL;
cancelasyncmsg(wMsg);
if (sb->eintr)
{
TRACE(("[interrupted]\n"));
break;
}
}
else break;
}
ENDBLOCKING;
}
TRACE(("failed (%d)\n",sb->sb_errno));
return -1;
}
// For the sake of efficiency, we do not malloc() the fd_sets here.
// 64 sockets should be enough for everyone.
static void makesocktable(SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds, SOCKET addthis)
{
int i, j;
uae_u32 currlong, mask;
SOCKET s;
if (addthis != INVALID_SOCKET)
{
*fd_set_win->fd_array = addthis;
fd_set_win->fd_count = 1;
}
else fd_set_win->fd_count = 0;
if (!fd_set_amiga)
{
fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
return;
}
if (nfds > sb->dtablesize)
{
write_log ("BSDSOCK: ERROR - select()ing more sockets (%d) than socket descriptors available (%d)!\n",nfds,sb->dtablesize);
nfds = sb->dtablesize;
}
for (j = 0; ; j += 32, fd_set_amiga += 4)
{
currlong = get_long (fd_set_amiga);
mask = 1;
for (i = 0; i < 32; i++, mask <<= 1)
{
if (i+j > nfds)
{
fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
return;
}
if (currlong & mask)
{
s = getsock(sb,j+i);
if (s != INVALID_SOCKET)
{
fd_set_win->fd_array[fd_set_win->fd_count++] = s;
if (fd_set_win->fd_count >= FD_SETSIZE)
{
write_log ("BSDSOCK: ERROR - select()ing more sockets (%d) than the hard-coded fd_set limit (%d) - please report\n",nfds,FD_SETSIZE);
return;
}
}
}
}
}
fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
}
static void makesockbitfield(SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds)
{
int n, i, j, val, mask;
SOCKET currsock;
for (n = 0; n < nfds; n += 32)
{
val = 0;
mask = 1;
for (i = 0; i < 32; i++, mask <<= 1)
{
if ((n || i) && (currsock = sb->dtable[n+i-1]) != INVALID_SOCKET)
{
for (j = fd_set_win->fd_count; j--; )
{
if (fd_set_win->fd_array[j] == currsock)
{
val |= mask;
break;
}
}
}
}
put_long (fd_set_amiga,val);
}
}
static void fd_zero(uae_u32 fdset, uae_u32 nfds)
{
unsigned int i;
for (i = 0; i < nfds; i += 32, fdset += 4) put_long (fdset,0);
}
// This seems to be the only way of implementing a cancelable WinSock2 select() call... sigh.
static unsigned int __stdcall thread_WaitSelect(void *index2)
{
uae_u32 index = (uae_u32)index2;
unsigned int result = 0;
long nfds;
uae_u32 readfds, writefds, exceptfds;
uae_u32 timeout;
struct fd_set readsocks, writesocks, exceptsocks;
struct timeval tv;
uae_u32 *args;
SB;
for (;;)
{
WaitForSingleObject(hEvents[index],INFINITE);
if ((args = threadargs[index]) != NULL)
{
sb = (struct socketbase *)*args;
nfds = args[1];
readfds = args[2];
writefds = args[3];
exceptfds = args[4];
timeout = args[5];
// construct descriptor tables
makesocktable(sb,readfds,&readsocks,nfds,sb->sockAbort);
if (writefds) makesocktable(sb,writefds,&writesocks,nfds,INVALID_SOCKET);
if (exceptfds) makesocktable(sb,exceptfds,&exceptsocks,nfds,INVALID_SOCKET);
if (timeout)
{
tv.tv_sec = get_long (timeout);
tv.tv_usec = get_long (timeout+4);
TRACE(("(timeout: %d.%06d) ",tv.tv_sec,tv.tv_usec))
}
TRACE(("-> "));
sb->resultval = select(nfds+1,&readsocks,writefds ? &writesocks : NULL,exceptfds ? &exceptsocks : NULL,timeout ? &tv : 0);
sb->needAbort = 0;
if (sb->resultval == SOCKET_ERROR)
{
SETERRNO;
TRACE(("failed (%d) - ",sb->sb_errno));
if (readfds) fd_zero(readfds,nfds);
if (writefds) fd_zero(writefds,nfds);
if (exceptfds) fd_zero(exceptfds,nfds);
}
else
{
if (readfds) makesockbitfield(sb,readfds,&readsocks,nfds);
if (writefds) makesockbitfield(sb,writefds,&writesocks,nfds);
if (exceptfds) makesockbitfield(sb,exceptfds,&exceptsocks,nfds);
}
SETSIGNAL;
threadargs[index] = NULL;
SetEvent(sb->hEvent);
}
}
#ifndef __GNUC__
_endthreadex( result );
#endif
return result;
}
void host_WaitSelect(SB, uae_u32 nfds, uae_u32 readfds, uae_u32 writefds, uae_u32 exceptfds, uae_u32 timeout, uae_u32 sigmp)
{
uae_u32 sigs, wssigs;
int i;
wssigs = sigmp ? get_long (sigmp) : 0;
TRACE(("WaitSelect(%d,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx) ",nfds,readfds,writefds,exceptfds,timeout,wssigs));
if (!readfds && !writefds && !exceptfds && !timeout && !wssigs)
{
sb->resultval = 0;
TRACE(("-> [ignored]\n"))
return;
}
if (wssigs)
{
m68k_dreg (regs,0) = 0;
m68k_dreg (regs,1) = wssigs;
sigs = CallLib (get_long (4),-0x132) & wssigs; // SetSignal()
if (sigs)
{
TRACE(("-> [preempted by signals 0x%08lx]\n",sigs & wssigs));
put_long (sigmp,sigs & wssigs);
fd_zero(readfds,nfds);
fd_zero(writefds,nfds);
fd_zero(exceptfds,nfds);
sb->resultval = 0;
seterrno(sb,0);
return;
}
}
ResetEvent(sb->hEvent);
sb->needAbort = 1;
for (i = 0; i < MAX_SELECT_THREADS; i++) if (hThreads[i] && !threadargs[i]) break;
if (i >= MAX_SELECT_THREADS)
{
for (i = 0; i < MAX_SELECT_THREADS; i++)
{
if (!hThreads[i])
{
if ((hEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hThreads[i] = (void *)THREAD(thread_WaitSelect,i)) == NULL)
{
hThreads[i] = 0;
write_log ("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n",GetLastError());
seterrno(sb,12); // ENOMEM
sb->resultval = -1;
return;
}
// this should improve responsiveness
SetThreadPriority(hThreads[i],THREAD_PRIORITY_TIME_CRITICAL);
break;
}
}
}
if (i >= MAX_SELECT_THREADS) write_log ("BSDSOCK: ERROR - Too many select()s\n");
else
{
SOCKET newsock = INVALID_SOCKET;
threadargs[i] = (uae_u32 *)&sb;
SetEvent(hEvents[i]);
m68k_dreg (regs,0) = (((uae_u32)1)<<sb->signal)|sb->eintrsigs|wssigs;
sigs = CallLib (get_long (4),-0x13e); // Wait()
if (sb->needAbort)
{
if ((newsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
write_log ("BSDSOCK: ERROR - Cannot create socket: %d\n",WSAGetLastError());
//shutdown(sb->sockAbort,1);
closesocket(sb->sockAbort);
}
WaitForSingleObject(sb->hEvent,INFINITE);
CANCELSIGNAL;
if (newsock != INVALID_SOCKET) sb->sockAbort = newsock;
if( sigmp )
{
put_long (sigmp,sigs & wssigs);
if (sigs & sb->eintrsigs)
{
TRACE(("[interrupted]\n"));
sb->resultval = -1;
seterrno(sb,4); // EINTR
}
else if (sigs & wssigs)
{
TRACE(("[interrupted by signals 0x%08lx]\n",sigs & wssigs));
sb->resultval = 0;
seterrno(sb,0);
}
}
else TRACE(("%d\n",sb->resultval));
}
}
uae_u32 host_Inet_NtoA(SB, uae_u32 in)
{
char *addr;
struct in_addr ina;
uae_u32 scratchbuf;
*(uae_u32 *)&ina = htonl(in);
TRACE(("Inet_NtoA(%lx) -> ",in));
if ((addr = inet_ntoa(ina)) != NULL)
{
scratchbuf = m68k_areg (regs,6)+offsetof(struct UAEBSDBase,scratchbuf);
strncpyha(scratchbuf,addr,SCRATCHBUFSIZE);
TRACE(("%s\n",addr));
return scratchbuf;
}
else SETERRNO;
TRACE(("failed (%d)\n",sb->sb_errno));
return 0;
}
uae_u32 host_inet_addr(uae_u32 cp)
{
uae_u32 addr;
char *cp_rp;
cp_rp = get_real_address (cp);
addr = htonl(inet_addr(cp_rp));
TRACE(("inet_addr(%s) -> 0x%08lx\n",cp_rp,addr));
return addr;
}
void host_gethostbynameaddr(SB, uae_u32 name, uae_u32 namelen, long addrtype)
{
HOSTENT *h;
int size, numaliases = 0, numaddr = 0;
uae_u32 aptr;
char *name_rp;
int i;
uae_u32 addr;
uae_u32 *addr_list[2];
char buf[MAXGETHOSTSTRUCT];
unsigned int wMsg = 0;
name_rp = get_real_address (name);
if (addrtype == -1)
{
TRACE(("gethostbyname(%s) -> ",name_rp));
// workaround for numeric host "names"
if ((addr = inet_addr(name_rp)) != INADDR_NONE)
{
seterrno(sb,0);
((HOSTENT *)buf)->h_name = name_rp;
((HOSTENT *)buf)->h_aliases = NULL;
((HOSTENT *)buf)->h_addrtype = AF_INET;
((HOSTENT *)buf)->h_length = 4;
((HOSTENT *)buf)->h_addr_list = (char **)&addr_list;
addr_list[0] = &addr;
addr_list[1] = NULL;
goto kludge;
}
}
else
{
TRACE(("gethostbyaddr(0x%lx,0x%lx,%ld) -> ",name,namelen,addrtype));
}
if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
{
if ((sb->hAsyncTask = addrtype == -1 ? WSAAsyncGetHostByName(hWndSelector ? hAmigaWnd : hSockWnd,wMsg,name_rp,buf,sizeof buf) : WSAAsyncGetHostByAddr(hWndSelector ? hAmigaWnd : hSockWnd,wMsg,name_rp,namelen,addrtype,buf,sizeof buf)) != NULL)
{
while (sb->hAsyncTask) WAITSIGNAL;
sockabort(sb);
if (!sb->sb_errno)
{
kludge:
h = (HOSTENT *)buf;
// compute total size of hostent
size = 28;
if (h->h_name != NULL) size += strlen(h->h_name)+1;
if (h->h_aliases != NULL)
while (h->h_aliases[numaliases]) size += strlen(h->h_aliases[numaliases++])+5;
if (h->h_addr_list != NULL)
{
while (h->h_addr_list[numaddr]) numaddr++;
size += numaddr*(h->h_length+4);
}
if (sb->hostent)
{
uae_FreeMem( sb->hostent, sb->hostentsize );
}
sb->hostent = uae_AllocMem( size, 0 );
if (!sb->hostent)
{
write_log ("BSDSOCK: WARNING - gethostby%s() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",addrtype == -1 ? "name" : "addr",size,(char *)name);
seterrno(sb,12); // ENOMEM
return;
}
sb->hostentsize = size;
aptr = sb->hostent+28+numaliases*4+numaddr*4;
// transfer hostent to Amiga memory
put_long (sb->hostent+4,sb->hostent+20);
put_long (sb->hostent+8,h->h_addrtype);
put_long (sb->hostent+12,h->h_length);
put_long (sb->hostent+16,sb->hostent+24+numaliases*4);
for (i = 0; i < numaliases; i++) put_long (sb->hostent+20+i*4,addstr(&aptr,h->h_aliases[i]));
put_long (sb->hostent+20+numaliases*4,0);
for (i = 0; i < numaddr; i++) put_long (sb->hostent+24+(numaliases+i)*4,addmem(&aptr,h->h_addr_list[i],h->h_length));
put_long (sb->hostent+24+numaliases*4+numaddr*4,0);
put_long (sb->hostent,aptr);
addstr(&aptr,h->h_name);
TRACE(("OK (%s)\n",h->h_name));
seterrno(sb,0);
}
else
{
TRACE(("failed (%d/%d)\n",sb->sb_errno,sb->sb_herrno))
}
}
else
{
seterrno(sb,12); // ENOMEM - well...
write_log ("BSDSOCK: ERROR - WSAAsyncGetHostBy%s() failed - error code: %d\n",addrtype == -1 ? "Name" : "Addr",WSAGetLastError());
}
if (wMsg) cancelasyncmsg(wMsg);
}
}
void host_getservbynameport(SB, uae_u32 nameport, uae_u32 proto, uae_u32 type)
{
SERVENT *s;
int size, numaliases = 0;
uae_u32 aptr;
char *name_rp = NULL, *proto_rp = NULL;
int i;
char buf[MAXGETHOSTSTRUCT];
unsigned int wMsg;
if (proto) proto_rp = get_real_address (proto);
if (type)
{
TRACE(("getservbyport(%d,%s) -> ",nameport,proto_rp ? proto_rp : "NULL"));
}
else
{
name_rp = get_real_address (nameport);
TRACE(("getservbyname(%s,%s) -> ",name_rp,proto_rp ? proto_rp : "NULL"));
}
if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
{
if ((sb->hAsyncTask = type ? WSAAsyncGetServByPort(hWndSelector ? hAmigaWnd : hSockWnd,wMsg,nameport,proto_rp,buf,sizeof buf) : WSAAsyncGetServByName(hWndSelector ? hAmigaWnd : hSockWnd,wMsg,name_rp,proto_rp,buf,sizeof buf)) != NULL)
{
while (sb->hAsyncTask) WAITSIGNAL;
sockabort(sb);
if (!sb->sb_errno)
{
s = (SERVENT *)buf;
// compute total size of servent
size = 20;
if (s->s_name != NULL) size += strlen(s->s_name)+1;
if (s->s_proto != NULL) size += strlen(s->s_proto)+1;
if (s->s_aliases != NULL)
while (s->s_aliases[numaliases]) size += strlen(s->s_aliases[numaliases++])+5;
if (sb->servent)
{
uae_FreeMem( sb->servent, sb->serventsize );
}
sb->servent = uae_AllocMem( size, 0 );
if (!sb->servent)
{
write_log ("BSDSOCK: WARNING - getservby%s() ran out of Amiga memory (couldn't allocate %ld bytes)\n",type ? "port" : "name",size);
seterrno(sb,12); // ENOMEM
return;
}
sb->serventsize = size;
aptr = sb->servent+20+numaliases*4;
// transfer servent to Amiga memory
put_long (sb->servent+4,sb->servent+16);
put_long (sb->servent+8,(unsigned short)htons(s->s_port));
for (i = 0; i < numaliases; i++) put_long (sb->servent+16+i*4,addstr(&aptr,s->s_aliases[i]));
put_long (sb->servent+16+numaliases*4,0);
put_long (sb->servent,aptr);
addstr(&aptr,s->s_name);
put_long (sb->servent+12,aptr);
addstr(&aptr,s->s_proto);
TRACE(("OK (%s, %d)\n",s->s_name,(unsigned short)htons(s->s_port)));
seterrno(sb,0);
}
else
{
TRACE(("failed (%d)\n",sb->sb_errno))
}
}
else
{
seterrno(sb,12); // ENOMEM - well...
write_log ("BSDSOCK: ERROR - WSAAsyncGetServBy%s() failed - error code: %d\n",type ? "Port" : "Name",WSAGetLastError());
}
cancelasyncmsg(wMsg);
}
}
void host_getprotobyname(SB, uae_u32 name)
{
PROTOENT *p;
int size, numaliases = 0;
uae_u32 aptr;
char *name_rp;
int i;
char buf[MAXGETHOSTSTRUCT];
unsigned int wMsg;
name_rp = get_real_address (name);
TRACE(("getprotobyname(%s) -> ",name_rp));
if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
{
if ((sb->hAsyncTask = WSAAsyncGetProtoByName(hWndSelector ? hAmigaWnd : hSockWnd,wMsg,name_rp,buf,sizeof buf)) != NULL)
{
while (sb->hAsyncTask) WAITSIGNAL;
sockabort(sb);
if (!sb->sb_errno)
{
p = (PROTOENT *)buf;
// compute total size of protoent
size = 16;
if (p->p_name != NULL) size += strlen(p->p_name)+1;
if (p->p_aliases != NULL)
while (p->p_aliases[numaliases]) size += strlen(p->p_aliases[numaliases++])+5;
if (sb->protoent)
{
uae_FreeMem( sb->protoent, sb->protoentsize );
}
sb->protoent = uae_AllocMem( size, 0 );
if (!sb->protoent)
{
write_log ("BSDSOCK: WARNING - getprotobyname() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",size,(char *)name);
seterrno(sb,12); // ENOMEM
return;
}
sb->protoentsize = size;
aptr = sb->protoent+16+numaliases*4;
// transfer protoent to Amiga memory
put_long (sb->protoent+4,sb->protoent+12);
put_long (sb->protoent+8,p->p_proto);
for (i = 0; i < numaliases; i++) put_long (sb->protoent+12+i*4,addstr(&aptr,p->p_aliases[i]));
put_long (sb->protoent+12+numaliases*4,0);
put_long (sb->protoent,aptr);
addstr(&aptr,p->p_name);
TRACE(("OK (%s, %d)\n",p->p_name,p->p_proto));
seterrno(sb,0);
}
else
{
TRACE(("failed (%d)\n",sb->sb_errno))
}
}
else
{
seterrno(sb,12); // ENOMEM - well...
write_log ("BSDSOCK: ERROR - WSAAsyncGetProtoByName() failed - error code: %d\n",WSAGetLastError());
}
cancelasyncmsg(wMsg);
}
}
uae_u32 host_gethostname(uae_u32 name, uae_u32 namelen)
{
return gethostname(get_real_address (name),namelen);
}
#endif