mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
2791 lines
69 KiB
C++
2791 lines
69 KiB
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 <winsock2.h>
|
|
#include <Ws2tcpip.h>
|
|
|
|
#include "sysconfig.h"
|
|
#include "sysdeps.h"
|
|
|
|
#if defined(BSDSOCKET)
|
|
|
|
#include "resource.h"
|
|
|
|
#include <stddef.h>
|
|
#include <process.h>
|
|
|
|
#include "options.h"
|
|
#include "memory.h"
|
|
#include "uae/seh.h"
|
|
#include "custom.h"
|
|
#include "events.h"
|
|
#include "newcpu.h"
|
|
#include "autoconf.h"
|
|
#include "traps.h"
|
|
#include "bsdsocket.h"
|
|
|
|
#include "threaddep/thread.h"
|
|
#include "registry.h"
|
|
#include "native2amiga.h"
|
|
#include "win32gui.h"
|
|
#include "wininet.h"
|
|
#include "mmsystem.h"
|
|
#include "win32.h"
|
|
|
|
int rawsockets = 0;
|
|
static int hWndSelector = 0; /* Set this to zero to get hSockWnd */
|
|
|
|
struct threadargs {
|
|
struct socketbase *sb;
|
|
uae_u32 args1;
|
|
uae_u32 args2;
|
|
int args3;
|
|
long args4;
|
|
uae_char buf[MAXGETHOSTSTRUCT];
|
|
int wscnt;
|
|
};
|
|
|
|
struct threadargsw {
|
|
struct socketbase *sb;
|
|
uae_u32 nfds;
|
|
uae_u32 readfds;
|
|
uae_u32 writefds;
|
|
uae_u32 exceptfds;
|
|
uae_u32 timeout;
|
|
int wscnt;
|
|
};
|
|
|
|
#define MAX_SELECT_THREADS 64
|
|
#define MAX_GET_THREADS 64
|
|
|
|
struct bsdsockdata {
|
|
HWND hSockWnd;
|
|
HANDLE hSockThread;
|
|
HANDLE hSockReq;
|
|
HANDLE hSockReqHandled;
|
|
CRITICAL_SECTION csSigQueueLock;
|
|
CRITICAL_SECTION SockThreadCS;
|
|
unsigned int threadid;
|
|
WSADATA wsbData;
|
|
|
|
volatile HANDLE hGetThreads[MAX_GET_THREADS];
|
|
volatile struct threadargs *threadGetargs[MAX_GET_THREADS];
|
|
volatile int threadGetargs_inuse[MAX_GET_THREADS];
|
|
volatile HANDLE hGetEvents[MAX_GET_THREADS];
|
|
volatile HANDLE hGetEvents2[MAX_GET_THREADS];
|
|
|
|
volatile HANDLE hThreads[MAX_SELECT_THREADS];
|
|
volatile struct threadargsw *threadargsw[MAX_SELECT_THREADS];
|
|
volatile HANDLE hEvents[MAX_SELECT_THREADS];
|
|
|
|
struct socketbase *asyncsb[MAXPENDINGASYNC];
|
|
SOCKET asyncsock[MAXPENDINGASYNC];
|
|
uae_u32 asyncsd[MAXPENDINGASYNC];
|
|
int asyncindex;
|
|
};
|
|
|
|
static struct bsdsockdata *bsd;
|
|
static int threadindextable[MAX_GET_THREADS];
|
|
|
|
static unsigned int __stdcall sock_thread(void *);
|
|
|
|
|
|
extern HWND hAmigaWnd;
|
|
|
|
#define THREAD(func,arg) (HANDLE)_beginthreadex(NULL, 0, func, arg, 0, &bsd->threadid)
|
|
#define THREADEND(result) _endthreadex(result)
|
|
|
|
#define SETERRNO bsdsocklib_seterrno(ctx, sb, WSAGetLastError() - WSABASEERR)
|
|
#define SETHERRNO bsdsocklib_setherrno(ctx, sb, WSAGetLastError() - WSABASEERR)
|
|
#define WAITSIGNAL waitsig(ctx, sb)
|
|
|
|
#define SETSIGNAL addtosigqueue(sb,0)
|
|
#define CANCELSIGNAL cancelsig(ctx, sb)
|
|
|
|
#define FIOSETOWN _IOW('f', 124, long) /* set owner (struct Task *) */
|
|
#define FIOGETOWN _IOR('f', 123, long) /* get owner (struct Task *) */
|
|
|
|
#define BEGINBLOCKING if (sb->ftable[sd - 1] & SF_BLOCKING) sb->ftable[sd - 1] |= SF_BLOCKINGINPROGRESS
|
|
#define ENDBLOCKING sb->ftable[sd - 1] &= ~SF_BLOCKINGINPROGRESS
|
|
|
|
static LRESULT CALLBACK SocketWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
|
|
|
|
#define PREPARE_THREAD EnterCriticalSection(&bsd->SockThreadCS)
|
|
#define TRIGGER_THREAD { SetEvent(bsd->hSockReq); WaitForSingleObject(bsd->hSockReqHandled, INFINITE); LeaveCriticalSection(&bsd->SockThreadCS); }
|
|
|
|
#define SOCKVER_MAJOR 2
|
|
#define SOCKVER_MINOR 2
|
|
|
|
#define SF_RAW_RAW 0x10000000
|
|
#define SF_RAW_UDP 0x08000000
|
|
#define SF_RAW_RUDP 0x04000000
|
|
#define SF_RAW_RICMP 0x02000000
|
|
#define SF_RAW_HDR 0x01000000
|
|
|
|
typedef struct ip_option_information {
|
|
u_char Ttl; /* Time To Live (used for traceroute) */
|
|
u_char Tos; /* Type Of Service (usually 0) */
|
|
u_char Flags; /* IP header flags (usually 0) */
|
|
u_char OptionsSize; /* Size of options data (usually 0, max 40) */
|
|
u_char FAR *OptionsData; /* Options data buffer */
|
|
} IPINFO, *PIPINFO, FAR *LPIPINFO;
|
|
|
|
static void bsdsetpriority (HANDLE thread)
|
|
{
|
|
int pri = THREAD_PRIORITY_NORMAL;
|
|
SetThreadPriority(thread, pri);
|
|
}
|
|
|
|
static int mySockStartup(void)
|
|
{
|
|
int result = 0, i;
|
|
SOCKET dummy;
|
|
DWORD lasterror;
|
|
TCHAR *ss;
|
|
|
|
if (!bsd) {
|
|
bsd = xcalloc (struct bsdsockdata, 1);
|
|
for (i = 0; i < MAX_GET_THREADS; i++)
|
|
threadindextable[i] = i;
|
|
}
|
|
if (WSAStartup (MAKEWORD (SOCKVER_MAJOR, SOCKVER_MINOR), &bsd->wsbData)) {
|
|
lasterror = WSAGetLastError();
|
|
if(lasterror == WSAVERNOTSUPPORTED) {
|
|
TCHAR szMessage[MAX_DPATH];
|
|
WIN32GUI_LoadUIString(IDS_WSOCK2NEEDED, szMessage, MAX_DPATH);
|
|
gui_message(szMessage);
|
|
} else
|
|
write_log (_T("BSDSOCK: ERROR - Unable to initialize Windows socket layer! Error code: %d\n"), lasterror);
|
|
return 0;
|
|
}
|
|
|
|
ss = au (bsd->wsbData.szDescription);
|
|
write_log (_T("BSDSOCK: using %s\n"), ss);
|
|
xfree (ss);
|
|
// 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 (_T("BSDSOCK: ERROR - WSPStartup/NSPStartup failed! Error code: %d\n"),
|
|
WSAGetLastError());
|
|
result = 0;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
int init_socket_layer (void)
|
|
{
|
|
int result = 0;
|
|
|
|
if (bsd)
|
|
return -1;
|
|
deinit_socket_layer ();
|
|
if (currprefs.socket_emu) {
|
|
if((result = mySockStartup())) {
|
|
if(bsd->hSockThread == NULL) {
|
|
WNDCLASS wc; // Set up an invisible window and dummy wndproc
|
|
|
|
InitializeCriticalSection(&bsd->csSigQueueLock);
|
|
InitializeCriticalSection(&bsd->SockThreadCS);
|
|
bsd->hSockReq = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
bsd->hSockReqHandled = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
wc.style = CS_BYTEALIGNCLIENT | CS_BYTEALIGNWINDOW;
|
|
wc.lpfnWndProc = SocketWindowProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInst;
|
|
wc.hIcon = LoadIcon (GetModuleHandle (NULL), MAKEINTRESOURCE (IDI_APPICON));
|
|
wc.hCursor = LoadCursor (NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)GetStockObject (BLACK_BRUSH);
|
|
wc.lpszMenuName = 0;
|
|
wc.lpszClassName = _T("SocketFun");
|
|
RegisterClass(&wc);
|
|
bsd->hSockWnd = CreateWindowEx (0,
|
|
_T("SocketFun"), _T("WinUAE Socket Window"),
|
|
WS_POPUP,
|
|
0, 0,
|
|
1, 1,
|
|
NULL, NULL, 0, NULL);
|
|
bsd->hSockThread = THREAD(sock_thread, NULL);
|
|
if (!bsd->hSockWnd) {
|
|
write_log (_T("bsdsocket initialization failed\n"));
|
|
deinit_socket_layer();
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static void close_selectget_threads(void)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAX_SELECT_THREADS; i++) {
|
|
if (bsd->hEvents[i]) {
|
|
HANDLE h = bsd->hEvents[i];
|
|
bsd->hEvents[i] = NULL;
|
|
CloseHandle (h);
|
|
}
|
|
if (bsd->hThreads[i]) {
|
|
CloseHandle (bsd->hThreads[i]);
|
|
bsd->hThreads[i] = NULL;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_GET_THREADS; i++) {
|
|
if (bsd->hGetThreads[i]) {
|
|
HANDLE h = bsd->hGetThreads[i];
|
|
bsd->hGetThreads[i] = NULL;
|
|
CloseHandle (h);
|
|
}
|
|
if (bsd->hGetEvents[i]) {
|
|
CloseHandle (bsd->hGetEvents[i]);
|
|
bsd->hGetEvents[i] = NULL;
|
|
}
|
|
if (bsd->hGetEvents2[i]) {
|
|
CloseHandle (bsd->hGetEvents2[i]);
|
|
bsd->hGetEvents2[i] = NULL;
|
|
}
|
|
bsd->threadGetargs_inuse[i] = 0;
|
|
}
|
|
|
|
}
|
|
|
|
void deinit_socket_layer(void)
|
|
{
|
|
if (!bsd)
|
|
return;
|
|
if(bsd->hSockThread) {
|
|
HANDLE t = bsd->hSockThread;
|
|
DeleteCriticalSection(&bsd->csSigQueueLock);
|
|
DeleteCriticalSection(&bsd->SockThreadCS);
|
|
bsd->hSockThread = NULL;
|
|
SetEvent (bsd->hSockReq);
|
|
WaitForSingleObject(bsd->hSockThread, INFINITE);
|
|
CloseHandle(t);
|
|
CloseHandle(bsd->hSockReq);
|
|
CloseHandle(bsd->hSockReqHandled);
|
|
bsd->hSockReq = NULL;
|
|
bsd->hSockThread = NULL;
|
|
bsd->hSockReqHandled = NULL;
|
|
DestroyWindow (bsd->hSockWnd);
|
|
bsd->hSockWnd = NULL;
|
|
UnregisterClass (_T("SocketFun"), hInst);
|
|
}
|
|
close_selectget_threads ();
|
|
WSACleanup();
|
|
xfree (bsd);
|
|
bsd = NULL;
|
|
}
|
|
|
|
#ifdef BSDSOCKET
|
|
|
|
void locksigqueue(void)
|
|
{
|
|
EnterCriticalSection(&bsd->csSigQueueLock);
|
|
}
|
|
|
|
void unlocksigqueue(void)
|
|
{
|
|
LeaveCriticalSection(&bsd->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.
|
|
|
|
int host_sbinit(TrapContext *context, 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 = xcalloc(unsigned int, sb->dtablesize);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void host_closesocketquick(SOCKET s)
|
|
{
|
|
BOOL b = 1;
|
|
|
|
if(s) {
|
|
setsockopt(s, SOL_SOCKET, SO_DONTLINGER, (uae_char*)&b, sizeof(b));
|
|
shutdown(s, 1);
|
|
closesocket(s);
|
|
}
|
|
}
|
|
|
|
void host_sbcleanup(SB)
|
|
{
|
|
int i;
|
|
|
|
if (!sb) {
|
|
close_selectget_threads ();
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < MAXPENDINGASYNC; i++) {
|
|
if (bsd->asyncsb[i] == sb)
|
|
bsd->asyncsb[i] = NULL;
|
|
}
|
|
|
|
if (sb->hEvent != NULL) {
|
|
CloseHandle(sb->hEvent);
|
|
sb->hEvent = NULL;
|
|
}
|
|
|
|
for (i = sb->dtablesize; i--; ) {
|
|
if (sb->dtable[i] != INVALID_SOCKET)
|
|
host_closesocketquick(sb->dtable[i]);
|
|
sb->dtable[i] = INVALID_SOCKET;
|
|
|
|
if (sb->mtable && sb->mtable[i])
|
|
bsd->asyncsb[(sb->mtable[i] - 0xb000) / 2] = NULL;
|
|
}
|
|
|
|
shutdown(sb->sockAbort, 1);
|
|
closesocket(sb->sockAbort);
|
|
|
|
free(sb->mtable);
|
|
sb->mtable = NULL;
|
|
}
|
|
|
|
void host_sbreset(void)
|
|
{
|
|
int i;
|
|
for (i = 0; i < MAXPENDINGASYNC; i++) {
|
|
bsd->asyncsb[i] = 0;
|
|
bsd->asyncsock[i] = 0;
|
|
bsd->asyncsd[i] = 0;
|
|
}
|
|
for (i = 0; i < MAX_GET_THREADS; i++) {
|
|
bsd->threadargsw[i] = 0;
|
|
}
|
|
}
|
|
|
|
static void sockmsg(unsigned int msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
SB;
|
|
unsigned int index;
|
|
int sdi;
|
|
TrapContext *ctx = NULL;
|
|
|
|
index = (msg - 0xb000) / 2;
|
|
sb = bsd->asyncsb[index];
|
|
|
|
if (!(msg & 1))
|
|
{
|
|
// is this one really for us?
|
|
if ((SOCKET)wParam != bsd->asyncsock[index])
|
|
{
|
|
// cancel socket event
|
|
WSAAsyncSelect((SOCKET)wParam, hWndSelector ? hAmigaWnd : bsd->hSockWnd, 0, 0);
|
|
BSDTRACE((_T("unknown sockmsg %d\n"), index));
|
|
return;
|
|
}
|
|
|
|
sdi = bsd->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) {
|
|
|
|
bsd->asyncsb[index] = NULL;
|
|
|
|
if (WSAGETASYNCERROR(lParam)) {
|
|
bsdsocklib_seterrno(NULL, sb, WSAGETASYNCERROR(lParam) - WSABASEERR);
|
|
if (sb->sb_errno >= 1001 && sb->sb_errno <= 1005) {
|
|
TrapContext *ctx = alloc_host_thread_trap_context();
|
|
bsdsocklib_setherrno(ctx, sb, sb->sb_errno - 1000);
|
|
free_host_trap_context(ctx);
|
|
} else if (sb->sb_errno == 55) { // ENOBUFS
|
|
write_log (_T("BSDSOCK: ERROR - Buffer overflow - %d bytes requested\n"),
|
|
WSAGETASYNCBUFLEN(lParam));
|
|
}
|
|
} else {
|
|
|
|
TrapContext *ctx = alloc_host_thread_trap_context();
|
|
bsdsocklib_seterrno(ctx, sb,0);
|
|
free_host_trap_context(ctx);
|
|
}
|
|
|
|
SETSIGNAL;
|
|
}
|
|
|
|
unlocksigqueue();
|
|
}
|
|
|
|
static unsigned int allocasyncmsg(TrapContext *ctx, SB,uae_u32 sd,SOCKET s)
|
|
{
|
|
int i;
|
|
|
|
locksigqueue();
|
|
for (i = bsd->asyncindex + 1; i != bsd->asyncindex; i++) {
|
|
if (i >= MAXPENDINGASYNC)
|
|
i = 0;
|
|
if (!bsd->asyncsb[i]) {
|
|
bsd->asyncsb[i] = sb;
|
|
if (++bsd->asyncindex >= MAXPENDINGASYNC)
|
|
bsd->asyncindex = 0;
|
|
unlocksigqueue();
|
|
if (s == INVALID_SOCKET) {
|
|
return i * 2 + 0xb001;
|
|
} else {
|
|
bsd->asyncsd[i] = sd;
|
|
bsd->asyncsock[i] = s;
|
|
return i * 2 + 0xb000;
|
|
}
|
|
}
|
|
}
|
|
unlocksigqueue();
|
|
|
|
bsdsocklib_seterrno(ctx, sb, 12); // ENOMEM
|
|
write_log (_T("BSDSOCK: ERROR - Async operation completion table overflow\n"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void cancelasyncmsg(TrapContext *ctx, unsigned int wMsg)
|
|
{
|
|
SB;
|
|
|
|
wMsg = (wMsg-0xb000) / 2;
|
|
|
|
sb = bsd->asyncsb[wMsg];
|
|
|
|
if (sb != NULL) {
|
|
bsd->asyncsb[wMsg] = NULL;
|
|
CANCELSIGNAL;
|
|
}
|
|
}
|
|
|
|
void sockabort(SB)
|
|
{
|
|
locksigqueue();
|
|
|
|
unlocksigqueue();
|
|
}
|
|
|
|
static void setWSAAsyncSelect(SB, uae_u32 sd, SOCKET s, long lEvent )
|
|
{
|
|
if (sb->mtable[sd - 1]) {
|
|
long wsbevents = 0;
|
|
long eventflags;
|
|
int i;
|
|
locksigqueue();
|
|
|
|
|
|
eventflags = sb->ftable[sd - 1] & 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;
|
|
wsbevents |= lEvent;
|
|
i = (sb->mtable[sd - 1] - 0xb000) / 2;
|
|
bsd->asyncsb[i] = sb;
|
|
bsd->asyncsd[i] = sd;
|
|
bsd->asyncsock[i] = s;
|
|
WSAAsyncSelect(s, hWndSelector ? hAmigaWnd : bsd->hSockWnd, sb->mtable[sd - 1], wsbevents);
|
|
|
|
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
|
|
((uae_u8*)realpt)[1] = *((uae_u8*)realpt);
|
|
|
|
// set size of address
|
|
*((uae_u8*)realpt) = len;
|
|
}
|
|
|
|
|
|
int host_dup2socket(TrapContext *ctx, SB, int fd1, int fd2)
|
|
{
|
|
SOCKET s1,s2;
|
|
|
|
BSDTRACE((_T("dup2socket(%d,%d) -> "),fd1,fd2));
|
|
fd1++;
|
|
|
|
s1 = getsock(ctx, sb, fd1);
|
|
if (s1 != INVALID_SOCKET) {
|
|
if (fd2 != -1) {
|
|
if ((unsigned int) (fd2) >= (unsigned int) sb->dtablesize) {
|
|
BSDTRACE ((_T("Bad file descriptor (%d)\n"), fd2));
|
|
bsdsocklib_seterrno(ctx, sb, 9); /* EBADF */
|
|
}
|
|
fd2++;
|
|
s2 = getsock(ctx, sb, fd2);
|
|
if (s2 != INVALID_SOCKET) {
|
|
shutdown(s2,1);
|
|
closesocket(s2);
|
|
}
|
|
setsd(ctx, sb, fd2, s1);
|
|
BSDTRACE((_T("0\n")));
|
|
return 0;
|
|
} else {
|
|
fd2 = getsd(ctx, sb, 1);
|
|
setsd(ctx, sb, fd2, s1);
|
|
BSDTRACE((_T("%d\n"),fd2));
|
|
return (fd2 - 1);
|
|
}
|
|
}
|
|
BSDTRACE((_T("-1\n")));
|
|
return -1;
|
|
}
|
|
|
|
int host_socket(TrapContext *ctx, SB, int af, int type, int protocol)
|
|
{
|
|
int sd;
|
|
SOCKET s;
|
|
unsigned long nonblocking = 1;
|
|
int faketype;
|
|
|
|
BSDTRACE((_T("socket(%s,%s,%d) -> "),
|
|
af == AF_INET ? _T("AF_INET") : _T("AF_other"),
|
|
type == SOCK_STREAM ? _T("SOCK_STREAM") : type == SOCK_DGRAM ? _T("SOCK_DGRAM ") : _T("SOCK_RAW"),protocol));
|
|
|
|
faketype = type;
|
|
if (protocol == IPPROTO_UDP && type == SOCK_RAW && !rawsockets)
|
|
faketype = SOCK_DGRAM;
|
|
|
|
if ((s = socket(af,faketype,protocol)) == INVALID_SOCKET) {
|
|
SETERRNO;
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
return -1;
|
|
} else {
|
|
sd = getsd(ctx, sb,s);
|
|
}
|
|
|
|
sb->ftable[sd-1] = SF_BLOCKING;
|
|
if (faketype == SOCK_DGRAM || protocol != IPPROTO_TCP)
|
|
sb->ftable[sd-1] |= SF_DGRAM;
|
|
|
|
ioctlsocket(s,FIONBIO,&nonblocking);
|
|
BSDTRACE((_T(" -> Socket=%d %x\n"),sd,s));
|
|
|
|
if (type == SOCK_RAW) {
|
|
if (protocol==IPPROTO_UDP) {
|
|
sb->ftable[sd-1] |= SF_RAW_UDP;
|
|
} else if (protocol==IPPROTO_ICMP) {
|
|
struct sockaddr_in sin = { 0 };
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_addr.s_addr = INADDR_ANY;
|
|
if (bind(s,(struct sockaddr *)&sin,sizeof(sin)))
|
|
write_log (_T("IPPROTO_ICMP socket bind() failed: %d\n"), WSAGetLastError ());
|
|
} else if (protocol==IPPROTO_RAW) {
|
|
sb->ftable[sd-1] |= SF_RAW_RAW;
|
|
}
|
|
}
|
|
callfdcallback (ctx, sb, sd - 1, FDCB_ALLOC);
|
|
return sd-1;
|
|
}
|
|
|
|
uae_u32 host_bind(TrapContext *ctx, SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
|
|
{
|
|
uae_char buf[MAXADDRLEN];
|
|
uae_u32 success = 0;
|
|
SOCKET s;
|
|
|
|
sd++;
|
|
BSDTRACE((_T("bind(%d,0x%x,%d) -> "),sd, name, namelen));
|
|
s = getsock(ctx, sb, sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (namelen <= sizeof buf) {
|
|
if (!addr_valid (_T("host_bind"), name, namelen))
|
|
return 0;
|
|
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;
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
} else
|
|
BSDTRACE((_T("OK\n")));
|
|
} else
|
|
write_log (_T("BSDSOCK: ERROR - Excessive namelen (%d) in bind()!\n"), namelen);
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
uae_u32 host_listen(TrapContext *ctx, SB, uae_u32 sd, uae_u32 backlog)
|
|
{
|
|
SOCKET s;
|
|
uae_u32 success = -1;
|
|
|
|
sd++;
|
|
BSDTRACE((_T("listen(%d,%d) -> "), sd, backlog));
|
|
s = getsock(ctx, sb, sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if ((success = listen(s,backlog)) != 0) {
|
|
SETERRNO;
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
} else
|
|
BSDTRACE((_T("OK\n")));
|
|
}
|
|
return success;
|
|
}
|
|
|
|
void host_accept(TrapContext *ctx, SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
|
|
{
|
|
struct sockaddr *rp_name, *rp_nameuae;
|
|
struct sockaddr sockaddr;
|
|
int hlen, hlenuae = 0;
|
|
SOCKET s, s2;
|
|
int success = 0;
|
|
unsigned int wMsg;
|
|
|
|
sd++;
|
|
if (name != 0) {
|
|
if (!trap_valid_address(ctx, name, sizeof(struct sockaddr)) || !trap_valid_address(ctx, namelen, 4))
|
|
return;
|
|
rp_nameuae = rp_name = (struct sockaddr *)get_real_address (name);
|
|
hlenuae = hlen = trap_get_long(ctx, namelen);
|
|
if (hlenuae < sizeof(sockaddr))
|
|
{ // Fix for CNET BBS Windows must have 16 Bytes (sizeof(sockaddr)) otherwise Error WSAEFAULT
|
|
rp_name = &sockaddr;
|
|
hlen = sizeof(sockaddr);
|
|
}
|
|
} else {
|
|
rp_name = &sockaddr;
|
|
hlen = sizeof(sockaddr);
|
|
}
|
|
BSDTRACE((_T("accept(%d,%d,%d) -> "),sd,name,hlenuae));
|
|
|
|
s = getsock(ctx, 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 (sb->mtable[sd - 1] || (wMsg = allocasyncmsg(ctx, sb, sd, s)) != 0) {
|
|
if (sb->mtable[sd - 1] == 0) {
|
|
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : bsd->hSockWnd, wMsg, FD_ACCEPT);
|
|
} else {
|
|
setWSAAsyncSelect(sb, sd, s, FD_ACCEPT);
|
|
}
|
|
|
|
WAITSIGNAL;
|
|
|
|
if (sb->mtable[sd - 1] == 0) {
|
|
cancelasyncmsg(ctx, wMsg);
|
|
} else {
|
|
setWSAAsyncSelect(sb, sd, s, 0);
|
|
}
|
|
|
|
if (sb->eintr) {
|
|
BSDTRACE((_T("[interrupted]\n")));
|
|
ENDBLOCKING;
|
|
return;
|
|
}
|
|
|
|
s2 = accept(s, rp_name, &hlen);
|
|
|
|
if (s2 == INVALID_SOCKET) {
|
|
SETERRNO;
|
|
|
|
if (sb->sb_errno == WSAEWOULDBLOCK - WSABASEERR)
|
|
write_log (_T("BSDSOCK: ERRRO - accept() would block despite FD_ACCEPT message\n"));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (s2 == INVALID_SOCKET) {
|
|
sb->resultval = -1;
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
} else {
|
|
sb->resultval = getsd(ctx, sb, s2);
|
|
sb->ftable[sb->resultval - 1] = sb->ftable[sd - 1]; // new socket inherits the old socket's properties
|
|
callfdcallback(ctx, sb, sb->resultval - 1, FDCB_ALLOC);
|
|
sb->resultval--;
|
|
if (rp_name != 0) { // 1.11.2002 XXX
|
|
if (hlen <= hlenuae) { // Fix for CNET BBS Part 2
|
|
prepamigaaddr(rp_name, hlen);
|
|
if (namelen != 0) {
|
|
trap_put_long(ctx, namelen, hlen);
|
|
}
|
|
} else { // Copy only the number of bytes requested
|
|
if (hlenuae != 0) {
|
|
prepamigaaddr(rp_name, hlenuae);
|
|
memcpy(rp_nameuae, rp_name, hlenuae);
|
|
trap_put_long(ctx, namelen, hlenuae);
|
|
}
|
|
}
|
|
}
|
|
BSDTRACE((_T("%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
|
|
{
|
|
uae_char *buf;
|
|
uae_char *realpt;
|
|
uae_u32 sd;
|
|
uae_u32 len;
|
|
uae_u32 flags;
|
|
uae_u32 to;
|
|
uae_u32 tolen;
|
|
} sendto_s;
|
|
struct recvfrom_params
|
|
{
|
|
uae_char *realpt;
|
|
uae_u32 addr;
|
|
uae_u32 len;
|
|
uae_u32 flags;
|
|
struct sockaddr *rp_addr;
|
|
int *hlen;
|
|
} recvfrom_s;
|
|
struct connect_params
|
|
{
|
|
uae_char *buf;
|
|
uae_u32 namelen;
|
|
} connect_s;
|
|
struct abort_params
|
|
{
|
|
SOCKET *newsock;
|
|
} abort_s;
|
|
} params;
|
|
SOCKET s;
|
|
SB;
|
|
int wscnt;
|
|
} sockreq;
|
|
|
|
// sockreg.sb may be gone if thread dies at right time.. fixme.. */
|
|
|
|
static BOOL HandleStuff(void)
|
|
{
|
|
BOOL quit = FALSE;
|
|
SB = NULL;
|
|
BOOL handled = TRUE;
|
|
TrapContext *ctx = NULL;
|
|
|
|
if (bsd->hSockReq) {
|
|
// 100ms sleepiness might need some tuning...
|
|
//if(WaitForSingleObject( hSockReq, 100 ) == WAIT_OBJECT_0 )
|
|
{
|
|
BSDTRACE((_T("sockreq start %d:%d\n"), sockreq.packet_type,sockreq.wscnt));
|
|
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);
|
|
if (*(sockreq.params.abort_s.newsock) != sb->sockAbort) {
|
|
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 (_T("BSDSOCK: Invalid sock-thread request!\n"));
|
|
handled = FALSE;
|
|
break;
|
|
}
|
|
if(handled) {
|
|
if(sockreq.sb->resultval == SOCKET_ERROR) {
|
|
sb = sockreq.sb;
|
|
SETERRNO;
|
|
}
|
|
}
|
|
BSDTRACE((_T("sockreq end %d,%d,%d:%d\n"), sockreq.packet_type,sockreq.sb->resultval,sockreq.sb->sb_errno,sockreq.wscnt));
|
|
SetEvent(bsd->hSockReqHandled);
|
|
}
|
|
} else {
|
|
quit = TRUE;
|
|
}
|
|
return quit;
|
|
}
|
|
|
|
static LRESULT CALLBACK SocketWindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(message >= 0xB000 && message < 0xB000 + MAXPENDINGASYNC * 2) {
|
|
BSDTRACE((_T("sockmsg(0x%x[%d], 0x%x, 0x%x)\n"), message, (message - 0xb000) / 2, wParam, lParam));
|
|
sockmsg(message, wParam, lParam);
|
|
return 0;
|
|
}
|
|
return DefWindowProc(hwnd, message, wParam, lParam);
|
|
}
|
|
|
|
static unsigned int sock_thread2(void *blah)
|
|
{
|
|
unsigned int result = 0;
|
|
HANDLE WaitHandle;
|
|
MSG msg;
|
|
|
|
if(bsd->hSockWnd) {
|
|
// Make sure we're outrunning the wolves
|
|
SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_ABOVE_NORMAL);
|
|
|
|
while(bsd->hSockThread && bsd->hSockWnd) {
|
|
DWORD wait;
|
|
WaitHandle = bsd->hSockReq;
|
|
wait = MsgWaitForMultipleObjects (1, &WaitHandle, FALSE, INFINITE, QS_POSTMESSAGE);
|
|
if (wait == WAIT_ABANDONED_0)
|
|
break;
|
|
if (wait == WAIT_OBJECT_0) {
|
|
if (!bsd->hSockThread || !bsd->hSockWnd)
|
|
break;
|
|
if (HandleStuff()) // See if its time to quit...
|
|
break;
|
|
} else if (wait == WAIT_OBJECT_0 + 1) {
|
|
if (!bsd->hSockThread || !bsd->hSockWnd)
|
|
break;
|
|
while(PeekMessage(&msg, NULL, WM_USER, 0xB000 + MAXPENDINGASYNC * 2, PM_REMOVE)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
write_log (_T("BSDSOCK: We have exited our sock_thread()\n"));
|
|
THREADEND(result);
|
|
return result;
|
|
}
|
|
|
|
static unsigned int __stdcall sock_thread(void *p)
|
|
{
|
|
__try {
|
|
return sock_thread2 (p);
|
|
} __except(WIN32_ExceptionFilter (GetExceptionInformation (), GetExceptionCode ())) {
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
void host_connect(TrapContext *ctx, SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
|
|
{
|
|
SOCKET s;
|
|
int success = 0;
|
|
unsigned int wMsg;
|
|
uae_char buf[MAXADDRLEN];
|
|
static int wscounter;
|
|
int wscnt;
|
|
|
|
sd++;
|
|
wscnt = ++wscounter;
|
|
|
|
BSDTRACE((_T("connect(%d,0x%x,%d):%d -> "), sd, name, namelen, wscnt));
|
|
|
|
if (!addr_valid (_T("host_connect"), name, namelen))
|
|
return;
|
|
|
|
s = getsock(ctx, sb,(int)sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (namelen <= MAXADDRLEN) {
|
|
if (sb->mtable[sd-1] || (wMsg = allocasyncmsg(ctx, sb,sd,s)) != 0) {
|
|
if (sb->mtable[sd-1] == 0) {
|
|
WSAAsyncSelect(s, hWndSelector ? hAmigaWnd : bsd->hSockWnd, wMsg, FD_CONNECT);
|
|
} else {
|
|
setWSAAsyncSelect(sb, sd, s, 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;
|
|
sockreq.wscnt = wscnt;
|
|
|
|
TRIGGER_THREAD;
|
|
|
|
if (sb->resultval) {
|
|
if (sb->sb_errno == WSAEWOULDBLOCK - WSABASEERR) {
|
|
if (sb->ftable[sd-1] & SF_BLOCKING) {
|
|
bsdsocklib_seterrno(ctx, 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 {
|
|
bsdsocklib_seterrno(ctx,sb, 36); // EINPROGRESS
|
|
}
|
|
} else {
|
|
CANCELSIGNAL; // Cancel pending signal
|
|
}
|
|
}
|
|
|
|
ENDBLOCKING;
|
|
if (sb->mtable[sd-1] == 0) {
|
|
cancelasyncmsg(ctx, wMsg);
|
|
} else {
|
|
setWSAAsyncSelect(sb,sd,s,0);
|
|
}
|
|
}
|
|
} else {
|
|
write_log (_T("BSDSOCK: WARNING - Excessive namelen (%d) in connect():%d!\n"), namelen, wscnt);
|
|
}
|
|
}
|
|
BSDTRACE((_T(" -> connect %d:%d\n"),sb->sb_errno, wscnt));
|
|
}
|
|
|
|
|
|
#if 0
|
|
struct ip {
|
|
u_char ip_v:4; /* 0 version */
|
|
u_char ip_hl:4; /* 0 header length */
|
|
u_char ip_tos; /* 1 type of service */
|
|
short ip_len; /* 2 total length */
|
|
u_short ip_id; /* 4 identification */
|
|
short ip_off; /* 6 fragment offset field */
|
|
u_char ip_ttl; /* 8 time to live */
|
|
u_char ip_p; /* 9 protocol */
|
|
u_short ip_sum; /* 10 checksum */
|
|
struct in_addr ip_src,ip_dst; /* 12 source and dest address */
|
|
}; /* 20 */
|
|
struct udphdr {
|
|
u_short uh_sport; /* 20 source port */
|
|
u_short uh_dport; /* 22 destination port */
|
|
short uh_ulen; /* 24 udp length */
|
|
u_short uh_sum; /* 26 udp checksum */
|
|
}; /* 28 */
|
|
|
|
#endif
|
|
|
|
void host_sendto (TrapContext *ctx, SB, uae_u32 sd, uae_u32 msg, uae_u8 *hmsg, uae_u32 len, uae_u32 flags, uae_u32 to, uae_u32 tolen)
|
|
{
|
|
SOCKET s;
|
|
char *realpt;
|
|
unsigned int wMsg;
|
|
uae_char buf[MAXADDRLEN];
|
|
SOCKADDR_IN *sa = NULL;
|
|
int iCut = 0;
|
|
static int wscounter;
|
|
int wscnt;
|
|
|
|
wscnt = ++wscounter;
|
|
|
|
|
|
if (to)
|
|
BSDTRACE((_T("sendto(%d,0x%x,%p,%d,0x%x,0x%x,%d):%d-> "),sd,msg,hmsg,len,flags,to,tolen,wscnt));
|
|
else
|
|
BSDTRACE((_T("send(%d,0x%x,%p,%d,%d):%d -> "),sd,msg,hmsg,len,flags,wscnt));
|
|
|
|
sd++;
|
|
s = getsock(ctx, sb, sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (hmsg == NULL) {
|
|
if (!addr_valid (_T("host_sendto1"), msg, 4))
|
|
return;
|
|
realpt = (char*)get_real_address (msg);
|
|
} else {
|
|
realpt = (char*)hmsg;
|
|
}
|
|
|
|
if (ISBSDTRACE) {
|
|
write_log(_T("FT %08x "), sb->ftable[sd - 1]);
|
|
for (int i = 0; i < 28; i++) {
|
|
if (i > 0)
|
|
write_log(_T("."));
|
|
write_log(_T("%02X"), (uae_u8)realpt[i]);
|
|
}
|
|
write_log(_T(" -> "));
|
|
}
|
|
|
|
if (to) {
|
|
if (tolen > sizeof buf) {
|
|
write_log (_T("BSDSOCK: WARNING - Target address in sendto() too large (%d):%d!\n"), tolen,wscnt);
|
|
sb->resultval = -1;
|
|
bsdsocklib_seterrno(ctx, sb, 22); // EINVAL
|
|
goto error;
|
|
} else {
|
|
if (!addr_valid (_T("host_sendto2"), to, tolen))
|
|
return;
|
|
memcpy(buf, get_real_address (to), tolen);
|
|
// some Amiga software sets this field to bogus values
|
|
sa = (SOCKADDR_IN*)buf;
|
|
prephostaddr(sa);
|
|
}
|
|
}
|
|
if (sb->ftable[sd-1] & SF_RAW_RAW) {
|
|
if (realpt[9] == IPPROTO_ICMP) {
|
|
struct sockaddr_in sin;
|
|
|
|
shutdown(s,1);
|
|
closesocket(s);
|
|
s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_addr.s_addr = INADDR_ANY;
|
|
sin.sin_port = htons(realpt[20] * 256 + realpt[21]);
|
|
bind(s,(struct sockaddr *)&sin,sizeof(sin));
|
|
|
|
sb->dtable[sd-1] = s;
|
|
sb->ftable[sd-1]&= ~SF_RAW_RAW;
|
|
sb->ftable[sd-1]|= SF_RAW_RICMP;
|
|
} else if (realpt[9] == IPPROTO_UDP) {
|
|
struct sockaddr_in sin;
|
|
|
|
shutdown(s,1);
|
|
closesocket(s);
|
|
s = socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
|
|
|
|
sin.sin_family = AF_INET;
|
|
sin.sin_addr.s_addr = INADDR_ANY;
|
|
sin.sin_port = htons(realpt[20] * 256 + realpt[21]);
|
|
bind(s,(struct sockaddr *)&sin,sizeof(sin));
|
|
|
|
sb->dtable[sd-1] = s;
|
|
sb->ftable[sd-1]&= ~SF_RAW_RAW;
|
|
sb->ftable[sd-1]|= SF_RAW_RUDP;
|
|
} else {
|
|
write_log(_T("Unknown RAW protocol %d\n"), realpt[9]);
|
|
sb->resultval = -1;
|
|
bsdsocklib_seterrno(ctx, sb, 22); // EINVAL
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
BEGINBLOCKING;
|
|
|
|
for (;;) {
|
|
|
|
PREPARE_THREAD;
|
|
|
|
if (sb->ftable[sd - 1] & SF_RAW_UDP) {
|
|
// Copy DST-Port
|
|
sa->sin_port = htons(realpt[2] * 256 + realpt[3]);
|
|
iCut = 8;
|
|
} else if (sb->ftable[sd - 1] & SF_RAW_RUDP) {
|
|
int iTTL = realpt[8];
|
|
setsockopt(s,IPPROTO_IP,IP_TTL,(char*) &iTTL,sizeof(iTTL));
|
|
// Copy DST-Port
|
|
sa->sin_port = htons(realpt[22] * 256 + realpt[23]);
|
|
iCut = 28;
|
|
} else if (sb->ftable[sd - 1] & SF_RAW_RICMP) {
|
|
int iTTL = realpt[8];
|
|
setsockopt(s,IPPROTO_IP,IP_TTL,(char*) &iTTL,sizeof(iTTL));
|
|
iCut = 20;
|
|
}
|
|
|
|
sockreq.params.sendto_s.realpt = realpt + iCut;
|
|
sockreq.params.sendto_s.len = len - iCut;
|
|
sockreq.packet_type = sendto_req;
|
|
sockreq.s = s;
|
|
sockreq.sb = sb;
|
|
sockreq.params.sendto_s.buf = buf;
|
|
sockreq.params.sendto_s.sd = sd;
|
|
sockreq.params.sendto_s.flags = flags;
|
|
sockreq.params.sendto_s.to = to;
|
|
sockreq.params.sendto_s.tolen = tolen;
|
|
sockreq.wscnt = wscnt;
|
|
|
|
TRIGGER_THREAD;
|
|
|
|
sb->resultval += iCut;
|
|
|
|
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 (sb->mtable[sd - 1] || (wMsg = allocasyncmsg(ctx, sb, sd, s)) != 0) {
|
|
if (sb->mtable[sd - 1] == 0) {
|
|
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : bsd->hSockWnd,wMsg,FD_WRITE);
|
|
} else {
|
|
setWSAAsyncSelect(sb, sd, s, FD_WRITE);
|
|
}
|
|
|
|
WAITSIGNAL;
|
|
|
|
if (sb->mtable[sd-1] == 0) {
|
|
cancelasyncmsg(ctx, wMsg);
|
|
} else {
|
|
setWSAAsyncSelect(sb, sd, s, 0);
|
|
}
|
|
|
|
if (sb->eintr) {
|
|
BSDTRACE((_T("[interrupted]\n")));
|
|
return;
|
|
}
|
|
} else
|
|
break;
|
|
}
|
|
|
|
ENDBLOCKING;
|
|
|
|
} else
|
|
sb->resultval = -1;
|
|
|
|
error:
|
|
if (sb->resultval == -1)
|
|
BSDTRACE((_T("sendto failed (%d):%d\n"),sb->sb_errno,wscnt));
|
|
else
|
|
BSDTRACE((_T("sendto %d:%d\n"),sb->resultval,wscnt));
|
|
}
|
|
|
|
void host_recvfrom(TrapContext *ctx, SB, uae_u32 sd, uae_u32 msg, uae_u8 *hmsg, uae_u32 len, uae_u32 flags, uae_u32 addr, uae_u32 addrlen)
|
|
{
|
|
SOCKET s;
|
|
uae_char *realpt;
|
|
struct sockaddr *rp_addr = NULL;
|
|
int hlen;
|
|
unsigned int wMsg;
|
|
int waitall, waitallgot;
|
|
static int wscounter;
|
|
int wscnt;
|
|
|
|
wscnt = ++wscounter;
|
|
|
|
if (addr)
|
|
BSDTRACE((_T("recvfrom(%d,0x%x,%p,%d,0x%x,0x%x,%d):%d -> "),sd,msg,hmsg,len,flags,addr,get_long (addrlen),wscnt));
|
|
else
|
|
BSDTRACE((_T("recv(%d,0x%x,%p,%d,0x%x):%d -> "),sd,msg,hmsg,len,flags,wscnt));
|
|
|
|
sd++;
|
|
s = getsock(ctx, sb,sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (hmsg == NULL) {
|
|
if (!addr_valid (_T("host_recvfrom1"), msg, 4))
|
|
return;
|
|
realpt = (char*)get_real_address (msg);
|
|
} else {
|
|
realpt = (char*)hmsg;
|
|
}
|
|
|
|
if (addr) {
|
|
if (!addr_valid (_T("host_recvfrom1"), addrlen, 4))
|
|
return;
|
|
hlen = get_long (addrlen);
|
|
if (!addr_valid (_T("host_recvfrom2"), addr, hlen))
|
|
return;
|
|
rp_addr = (struct sockaddr *)get_real_address (addr);
|
|
}
|
|
|
|
BEGINBLOCKING;
|
|
|
|
waitall = flags & 0x40;
|
|
flags &= ~0x40;
|
|
waitallgot = 0;
|
|
|
|
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;
|
|
sockreq.wscnt = wscnt;
|
|
|
|
TRIGGER_THREAD;
|
|
|
|
if (waitall) {
|
|
if (sb->resultval > 0) {
|
|
int l = sb->resultval;
|
|
realpt += l;
|
|
len -= l;
|
|
waitallgot += l;
|
|
if (len <= 0) {
|
|
sb->resultval = waitallgot;
|
|
break;
|
|
} else {
|
|
sb->sb_errno = WSAEWOULDBLOCK - WSABASEERR;
|
|
sb->resultval = -1;
|
|
}
|
|
} else if (sb->resultval == 0) {
|
|
sb->resultval = waitallgot;
|
|
}
|
|
}
|
|
|
|
|
|
if (sb->resultval == -1) {
|
|
if (sb->sb_errno == WSAEWOULDBLOCK - WSABASEERR && (sb->ftable[sd-1] & SF_BLOCKING)) {
|
|
if (sb->mtable[sd-1] || (wMsg = allocasyncmsg(ctx, sb,sd,s)) != 0) {
|
|
if (sb->mtable[sd-1] == 0) {
|
|
WSAAsyncSelect(s, hWndSelector ? hAmigaWnd : bsd->hSockWnd, wMsg, FD_READ|FD_CLOSE);
|
|
} else {
|
|
setWSAAsyncSelect(sb, sd, s, FD_READ|FD_CLOSE);
|
|
}
|
|
|
|
WAITSIGNAL;
|
|
|
|
if (sb->mtable[sd-1] == 0) {
|
|
cancelasyncmsg(ctx, wMsg);
|
|
} else {
|
|
setWSAAsyncSelect(sb, sd, s, 0);
|
|
}
|
|
|
|
if (sb->eintr) {
|
|
BSDTRACE((_T("[interrupted]\n")));
|
|
return;
|
|
}
|
|
|
|
} else
|
|
break;
|
|
} else
|
|
break;
|
|
} else
|
|
break;
|
|
}
|
|
|
|
ENDBLOCKING;
|
|
|
|
if (addr) {
|
|
prepamigaaddr(rp_addr,hlen);
|
|
put_long (addrlen,hlen);
|
|
}
|
|
} else
|
|
sb->resultval = -1;
|
|
|
|
if (sb->resultval == -1)
|
|
BSDTRACE((_T("recv failed (%d):%d\n"),sb->sb_errno,wscnt));
|
|
else
|
|
BSDTRACE((_T("recv %d:%d\n"),sb->resultval,wscnt));
|
|
}
|
|
|
|
uae_u32 host_shutdown(SB, uae_u32 sd, uae_u32 how)
|
|
{
|
|
TrapContext *ctx = NULL;
|
|
SOCKET s;
|
|
|
|
BSDTRACE((_T("shutdown(%d,%d) -> "),sd,how));
|
|
sd++;
|
|
s = getsock(ctx, sb,sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (shutdown(s,how)) {
|
|
SETERRNO;
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
} else {
|
|
BSDTRACE((_T("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)
|
|
{
|
|
TrapContext *ctx = NULL;
|
|
SOCKET s;
|
|
uae_char buf[MAXADDRLEN];
|
|
int i;
|
|
|
|
BSDTRACE((_T("setsockopt(%d,%d,0x%x,0x%x[0x%x],%d) -> "),sd,(short)level,optname,optval,get_long(optval),len));
|
|
sd++;
|
|
s = getsock(ctx, sb,sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (len > sizeof buf) {
|
|
write_log (_T("BSDSOCK: WARNING - Excessive optlen in setsockopt() (%d)\n"), len);
|
|
len = sizeof buf;
|
|
}
|
|
#if 1
|
|
if (level == IPPROTO_IP && optname == IP_HDRINCL) { // IP_HDRINCL emulated by icmp.dll
|
|
sb->resultval = 0;
|
|
return;
|
|
}
|
|
#endif
|
|
for (i = 0; i < len / 4; i++) {
|
|
((long*)buf)[i] = get_long (optval + i * 4);
|
|
}
|
|
if (len - i == 2)
|
|
((long*)buf)[i] = get_word (optval + i * 4);
|
|
else if (len - i == 1)
|
|
((long*)buf)[i] = get_byte (optval + i * 4);
|
|
|
|
/* timeval -> milliseconds */
|
|
if (level == SOL_SOCKET && (optname == SO_SNDTIMEO || optname == SO_RCVTIMEO)) {
|
|
uae_u32 millis = ((long*)buf)[0] * 1000 + ((long*)buf)[1] / 1000;
|
|
((long*)buf)[0] = millis;
|
|
len = 4;
|
|
}
|
|
|
|
// handle SO_EVENTMASK
|
|
if (level == SOL_SOCKET && 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(ctx, sb,sd,s))) {
|
|
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : bsd->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) {
|
|
BSDTRACE((_T("OK\n")));
|
|
return;
|
|
} else
|
|
SETERRNO;
|
|
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
}
|
|
}
|
|
|
|
uae_u32 host_getsockopt(TrapContext *ctx, SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 optlen)
|
|
{
|
|
SOCKET s;
|
|
uae_char buf[MAXADDRLEN];
|
|
int len = sizeof buf;
|
|
uae_u32 outlen;
|
|
|
|
if (optval)
|
|
outlen = get_long (optlen);
|
|
else
|
|
outlen = 0;
|
|
|
|
BSDTRACE((_T("getsockopt(%d,%d,0x%x,0x%x,0x%x[%d]) -> "),sd,(short)level,optname,optval,optlen,outlen));
|
|
sd++;
|
|
s = getsock(ctx, sb,sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (!getsockopt(s,level,optname,buf,&len)) {
|
|
BSDTRACE((_T("0x%x, %d -> "), *((long*)buf), len));
|
|
uae_u32 outcnt = 0;
|
|
if (outlen) {
|
|
if (level == SOL_SOCKET && (optname == SO_SNDTIMEO || optname == SO_RCVTIMEO)) {
|
|
/* long milliseconds -> timeval */
|
|
uae_u32 millis = *((long*)buf);
|
|
((long*)buf)[0] = millis / 1000; /* secs */
|
|
((long*)buf)[1] = (millis % 1000) * 1000; /* usecs */
|
|
len = 8;
|
|
}
|
|
// len can equal 1 */
|
|
for (int i = 0; i < len; i += 4) {
|
|
uae_u32 v;
|
|
if (len - i >= 4)
|
|
v = *((long*)(buf + i));
|
|
else if (len - i >= 2)
|
|
v = *((short*)(buf + i));
|
|
else
|
|
v = buf[i];
|
|
if (outlen >= 4) {
|
|
put_long (optval + outcnt, v);
|
|
outlen -= 4;
|
|
outcnt += 4;
|
|
} else if (outlen >= 2) {
|
|
put_word (optval + outcnt, v);
|
|
outlen -= 2;
|
|
outcnt += 2;
|
|
} else if (outlen > 0) {
|
|
put_byte (optval + outcnt, v);
|
|
outlen -= 1;
|
|
outcnt += 1;
|
|
}
|
|
}
|
|
put_long (optlen,outcnt);
|
|
}
|
|
BSDTRACE((_T("OK (%d,0x%x)\n"),outcnt,get_long(optval)));
|
|
return 0;
|
|
} else {
|
|
SETERRNO;
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
uae_u32 host_getsockname(TrapContext *ctx, SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
|
|
{
|
|
SOCKET s;
|
|
int len;
|
|
struct sockaddr *rp_name;
|
|
|
|
sd++;
|
|
if (!addr_valid (_T("host_getsockname1"), namelen, 4))
|
|
return -1;
|
|
len = get_long (namelen);
|
|
|
|
BSDTRACE((_T("getsockname(%d,0x%x,%d) -> "),sd,name,len));
|
|
|
|
s = getsock(ctx, sb,sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (!trap_valid_address(ctx, name, len))
|
|
return -1;
|
|
rp_name = (struct sockaddr *)get_real_address (name);
|
|
|
|
if (getsockname(s,rp_name,&len)) {
|
|
SETERRNO;
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
} else {
|
|
BSDTRACE((_T("%d\n"),len));
|
|
prepamigaaddr(rp_name,len);
|
|
put_long (namelen,len);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
uae_u32 host_getpeername(TrapContext *ctx, SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
|
|
{
|
|
SOCKET s;
|
|
int len;
|
|
struct sockaddr *rp_name;
|
|
|
|
sd++;
|
|
if (!addr_valid (_T("host_getpeername1"), namelen, 4))
|
|
return -1;
|
|
len = get_long (namelen);
|
|
|
|
BSDTRACE((_T("getpeername(%d,0x%x,%d) -> "),sd,name,len));
|
|
|
|
s = getsock(ctx, sb,sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
if (!trap_valid_address(ctx, name, len))
|
|
return -1;
|
|
rp_name = (struct sockaddr *)get_real_address (name);
|
|
|
|
if (getpeername(s,rp_name,&len)) {
|
|
SETERRNO;
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
} else {
|
|
BSDTRACE((_T("%d\n"),len));
|
|
prepamigaaddr(rp_name,len);
|
|
put_long (namelen,len);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
uae_u32 host_IoctlSocket(TrapContext *ctx, SB, uae_u32 sd, uae_u32 request, uae_u32 arg)
|
|
{
|
|
SOCKET s;
|
|
uae_u32 data;
|
|
int success = SOCKET_ERROR;
|
|
|
|
BSDTRACE((_T("IoctlSocket(%d,0x%x,0x%x) "),sd,request,arg));
|
|
sd++;
|
|
s = getsock(ctx, sb,sd);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
switch (request)
|
|
{
|
|
case FIOSETOWN:
|
|
sb->ownertask = trap_get_long(ctx, arg);
|
|
success = 0;
|
|
break;
|
|
case FIOGETOWN:
|
|
trap_put_long(ctx, arg,sb->ownertask);
|
|
success = 0;
|
|
break;
|
|
case FIONBIO:
|
|
BSDTRACE((_T("[FIONBIO] -> ")));
|
|
if (trap_get_long(ctx, arg)) {
|
|
BSDTRACE((_T("nonblocking\n")));
|
|
sb->ftable[sd-1] &= ~SF_BLOCKING;
|
|
} else {
|
|
BSDTRACE((_T("blocking\n")));
|
|
sb->ftable[sd-1] |= SF_BLOCKING;
|
|
}
|
|
success = 0;
|
|
break;
|
|
case FIONREAD:
|
|
ioctlsocket(s,request,(u_long *)&data);
|
|
BSDTRACE((_T("[FIONREAD] -> %d\n"),data));
|
|
trap_put_long(ctx, arg,data);
|
|
success = 0;
|
|
break;
|
|
case FIOASYNC:
|
|
if (trap_get_long(ctx, arg)) {
|
|
sb->ftable[sd-1] |= REP_ALL;
|
|
|
|
BSDTRACE((_T("[FIOASYNC] -> enabled\n")));
|
|
if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(ctx, sb, sd, s))) {
|
|
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : bsd-> hSockWnd, sb->mtable[sd-1],
|
|
FD_ACCEPT | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE | FD_CLOSE);
|
|
success = 0;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
write_log (_T("BSDSOCK: WARNING - FIOASYNC disabling unsupported.\n"));
|
|
|
|
success = -1;
|
|
break;
|
|
default:
|
|
write_log (_T("BSDSOCK: WARNING - Unknown IoctlSocket request: 0x%08lx\n"), request);
|
|
bsdsocklib_seterrno(ctx, sb, 22); // EINVAL
|
|
break;
|
|
}
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
int host_CloseSocket(TrapContext *ctx, SB, int sd)
|
|
{
|
|
unsigned int wMsg;
|
|
SOCKET s;
|
|
|
|
BSDTRACE((_T("CloseSocket(%d) -> "),sd));
|
|
sd++;
|
|
|
|
s = getsock(ctx, sb,sd);
|
|
if (s != INVALID_SOCKET) {
|
|
|
|
if (sb->mtable[sd-1]) {
|
|
bsd->asyncsb[(sb->mtable[sd-1]-0xb000)/2] = NULL;
|
|
sb->mtable[sd-1] = 0;
|
|
}
|
|
|
|
if (checksd(ctx, sb ,sd) == true)
|
|
return 0;
|
|
|
|
BEGINBLOCKING;
|
|
|
|
for (;;) {
|
|
|
|
shutdown(s,1);
|
|
if (!closesocket(s)) {
|
|
releasesock(ctx, sb, sd);
|
|
BSDTRACE((_T("OK\n")));
|
|
return 0;
|
|
}
|
|
|
|
SETERRNO;
|
|
|
|
if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING))
|
|
break;
|
|
|
|
if ((wMsg = allocasyncmsg(ctx, sb, sd, s)) != 0) {
|
|
WSAAsyncSelect(s,hWndSelector ? hAmigaWnd : bsd->hSockWnd,wMsg,FD_CLOSE);
|
|
|
|
WAITSIGNAL;
|
|
|
|
cancelasyncmsg(ctx, wMsg);
|
|
|
|
if (sb->eintr) {
|
|
BSDTRACE((_T("[interrupted]\n")));
|
|
break;
|
|
}
|
|
} else
|
|
break;
|
|
}
|
|
|
|
ENDBLOCKING;
|
|
}
|
|
|
|
BSDTRACE((_T("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(TrapContext *ctx, SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds, SOCKET addthis, const TCHAR *name)
|
|
{
|
|
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 (_T("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 = trap_get_long (ctx, 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(ctx, sb,j+i+1);
|
|
|
|
if (s != INVALID_SOCKET) {
|
|
BSDTRACE((_T("%s:%d=%x\n"), name, fd_set_win->fd_count, s));
|
|
fd_set_win->fd_array[fd_set_win->fd_count++] = s;
|
|
|
|
if (fd_set_win->fd_count >= FD_SETSIZE) {
|
|
write_log (_T("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(TrapContext *ctx, 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 ((currsock = getsock(ctx, sb, n+i+1)) != INVALID_SOCKET) {
|
|
// Do not use sb->dtable directly because of Newsrog
|
|
for (j = fd_set_win->fd_count; j--; ) {
|
|
if (fd_set_win->fd_array[j] == currsock) {
|
|
val |= mask;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
trap_put_long(ctx, fd_set_amiga, val);
|
|
fd_set_amiga += 4;
|
|
}
|
|
}
|
|
|
|
static void fd_zero(TrapContext *ctx, uae_u32 fdset, uae_u32 nfds)
|
|
{
|
|
unsigned int i;
|
|
for (i = 0; i < nfds; i += 32, fdset += 4)
|
|
trap_put_long(ctx, fdset,0);
|
|
}
|
|
|
|
// This seems to be the only way of implementing a cancelable WinSock2 select() call... sigh.
|
|
static unsigned int thread_WaitSelect2(void *indexp)
|
|
{
|
|
int index = *((int*)indexp);
|
|
unsigned int result = 0, resultval;
|
|
int wscnt;
|
|
long nfds;
|
|
uae_u32 readfds, writefds, exceptfds;
|
|
uae_u32 timeout;
|
|
struct fd_set readsocks, writesocks, exceptsocks;
|
|
struct timeval tv;
|
|
volatile struct threadargsw *args;
|
|
TrapContext *ctx = NULL;
|
|
|
|
SB;
|
|
|
|
while (bsd->hEvents[index]) {
|
|
if (WaitForSingleObject(bsd->hEvents[index], INFINITE) == WAIT_ABANDONED)
|
|
break;
|
|
if (bsd->hEvents[index] == NULL)
|
|
break;
|
|
|
|
if ((args = bsd->threadargsw[index]) != NULL) {
|
|
sb = args->sb;
|
|
nfds = args->nfds;
|
|
readfds = args->readfds;
|
|
writefds = args->writefds;
|
|
exceptfds = args->exceptfds;
|
|
timeout = args->timeout;
|
|
wscnt = args->wscnt;
|
|
|
|
// construct descriptor tables
|
|
makesocktable(ctx, sb, readfds, &readsocks, nfds, sb->sockAbort, _T("R"));
|
|
if (writefds)
|
|
makesocktable(ctx, sb, writefds, &writesocks, nfds, INVALID_SOCKET, _T("W"));
|
|
if (exceptfds)
|
|
makesocktable(ctx, sb, exceptfds, &exceptsocks, nfds, INVALID_SOCKET, _T("E"));
|
|
|
|
if (timeout) {
|
|
tv.tv_sec = get_long (timeout);
|
|
tv.tv_usec = get_long (timeout+4);
|
|
BSDTRACE((_T("(to: %d.%06d) "),tv.tv_sec,tv.tv_usec));
|
|
}
|
|
|
|
BSDTRACE((_T("tWS2(%d) -> "), wscnt));
|
|
|
|
resultval = select(nfds+1,
|
|
readsocks.fd_count > 0 ? &readsocks : NULL,
|
|
writefds && writesocks.fd_count > 0 ? &writesocks : NULL,
|
|
exceptfds && exceptsocks.fd_count > 0 ? &exceptsocks : NULL,
|
|
timeout ? &tv : NULL);
|
|
if (bsd->hEvents[index] == NULL)
|
|
break;
|
|
|
|
BSDTRACE((_T("tWS2(%d,%d) -> "), resultval, wscnt));
|
|
if (resultval == 0) {
|
|
BSDTRACE((_T("timeout -> ")));
|
|
}
|
|
|
|
sb->resultval = resultval;
|
|
if (sb->resultval == SOCKET_ERROR) {
|
|
// select was stopped by sb->sockAbort
|
|
if (readsocks.fd_count > 1) {
|
|
makesocktable(ctx, sb, readfds, &readsocks, nfds, INVALID_SOCKET, _T("R2"));
|
|
tv.tv_sec = 0;
|
|
tv.tv_usec = 10000;
|
|
// Check for 10ms if data is available
|
|
resultval = select(nfds+1, &readsocks, writefds ? &writesocks : NULL,exceptfds ? &exceptsocks : NULL,&tv);
|
|
if (bsd->hEvents[index] == NULL)
|
|
break;
|
|
sb->resultval = resultval;
|
|
|
|
#if 0 /* what was this doing here? */
|
|
if (sb->resultval == 0) { // Now timeout -> really no data available
|
|
if (GetLastError() != 0) {
|
|
sb->resultval = SOCKET_ERROR;
|
|
// Set old resultval
|
|
}
|
|
}
|
|
#endif
|
|
|
|
}
|
|
}
|
|
if (FD_ISSET(sb->sockAbort,&readsocks)) {
|
|
BSDTRACE((_T("tWS2 abort %d:%d\n"), sb->resultval, wscnt));
|
|
if (sb->resultval != SOCKET_ERROR) {
|
|
sb->resultval--;
|
|
}
|
|
} else {
|
|
sb->needAbort = 0;
|
|
}
|
|
if (sb->resultval == SOCKET_ERROR) {
|
|
SETERRNO;
|
|
BSDTRACE((_T("tWS2 failed %d:%d - "),sb->sb_errno,wscnt));
|
|
if (readfds)
|
|
fd_zero(ctx, readfds,nfds);
|
|
if (writefds)
|
|
fd_zero(ctx, writefds,nfds);
|
|
if (exceptfds)
|
|
fd_zero(ctx, exceptfds,nfds);
|
|
} else {
|
|
BSDTRACE((_T("tWS2 ok %d\n"), wscnt));
|
|
if (readfds)
|
|
makesockbitfield(ctx, sb,readfds,&readsocks,nfds);
|
|
if (writefds)
|
|
makesockbitfield(ctx, sb,writefds,&writesocks,nfds);
|
|
if (exceptfds)
|
|
makesockbitfield(ctx, sb,exceptfds,&exceptsocks,nfds);
|
|
}
|
|
|
|
SETSIGNAL;
|
|
|
|
bsd->threadargsw[index] = NULL;
|
|
SetEvent(sb->hEvent);
|
|
}
|
|
}
|
|
write_log (_T("BSDSOCK: thread_WaitSelect2 terminated\n"));
|
|
THREADEND(result);
|
|
return result;
|
|
}
|
|
|
|
static unsigned int __stdcall thread_WaitSelect(void *p)
|
|
{
|
|
__try {
|
|
return thread_WaitSelect2 (p);
|
|
} __except(WIN32_ExceptionFilter(GetExceptionInformation(), GetExceptionCode())) {
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void fddebug(const TCHAR *name, uae_u32 nfds, uae_u32 fd)
|
|
{
|
|
if (!ISBSDTRACE)
|
|
return;
|
|
if (!nfds)
|
|
return;
|
|
if (!fd)
|
|
return;
|
|
TCHAR out[40];
|
|
uae_u32 v = get_long (fd);
|
|
for (int i = 0; i < nfds && i < 32; i++) {
|
|
out[i] = (v & (1 << i)) ? 'x' : '-';
|
|
out[i + 1] = 0;
|
|
}
|
|
BSDTRACE((_T("%s: %08x %s\n"), name, v, out));
|
|
}
|
|
|
|
void host_WaitSelect(TrapContext *ctx, SB, uae_u32 nfds, uae_u32 readfds, uae_u32 writefds, uae_u32 exceptfds, uae_u32 timeout, uae_u32 sigmp)
|
|
{
|
|
static int wscount;
|
|
uae_u32 sigs, wssigs;
|
|
int i;
|
|
struct threadargsw taw;
|
|
int wscnt;
|
|
|
|
wscnt = ++wscount;
|
|
|
|
wssigs = sigmp ? trap_get_long(ctx, sigmp) : 0;
|
|
|
|
BSDTRACE((_T("WaitSelect(%d,0x%x,0x%x,0x%x,0x%x,0x%x):%d\n"),
|
|
nfds, readfds, writefds, exceptfds, timeout, wssigs, wscnt));
|
|
fddebug(_T("read :"), nfds, readfds);
|
|
fddebug(_T("write :"), nfds, writefds);
|
|
fddebug(_T("except:"), nfds, exceptfds);
|
|
|
|
if (!readfds && !writefds && !exceptfds && !timeout && !wssigs) {
|
|
sb->resultval = 0;
|
|
BSDTRACE((_T("-> [ignored]\n")));
|
|
return;
|
|
}
|
|
if (wssigs) {
|
|
trap_call_add_dreg(ctx ,0, 0);
|
|
trap_call_add_dreg(ctx, 1, wssigs);
|
|
sigs = trap_call_lib(ctx, sb->sysbase, -0x132) & wssigs; // SetSignal()
|
|
|
|
if (sigs) {
|
|
BSDTRACE((_T("-> [preempted by signals 0x%08lx]\n"),sigs & wssigs));
|
|
put_long (sigmp,sigs & wssigs);
|
|
// Check for zero address -> otherwise WinUAE crashes
|
|
if (readfds)
|
|
fd_zero(ctx, readfds,nfds);
|
|
if (writefds)
|
|
fd_zero(ctx, writefds,nfds);
|
|
if (exceptfds)
|
|
fd_zero(ctx, exceptfds,nfds);
|
|
sb->resultval = 0;
|
|
bsdsocklib_seterrno(ctx, sb,0);
|
|
return;
|
|
}
|
|
}
|
|
if (nfds == 0) {
|
|
// No sockets to check, only wait for signals
|
|
if (wssigs != 0) {
|
|
trap_call_add_dreg(ctx, 0, wssigs);
|
|
sigs = trap_call_lib(ctx, sb->sysbase, -0x13e); // Wait()
|
|
trap_put_long(ctx, sigmp, sigs & wssigs);
|
|
}
|
|
|
|
if (readfds)
|
|
fd_zero(ctx, readfds,nfds);
|
|
if (writefds)
|
|
fd_zero(ctx, writefds,nfds);
|
|
if (exceptfds)
|
|
fd_zero(ctx, exceptfds,nfds);
|
|
sb->resultval = 0;
|
|
return;
|
|
}
|
|
|
|
ResetEvent(sb->hEvent);
|
|
|
|
sb->needAbort = 1;
|
|
|
|
locksigqueue ();
|
|
|
|
for (i = 0; i < MAX_SELECT_THREADS; i++) {
|
|
if (bsd->hThreads[i] && !bsd->threadargsw[i])
|
|
break;
|
|
}
|
|
|
|
if (i >= MAX_SELECT_THREADS) {
|
|
for (i = 0; i < MAX_SELECT_THREADS; i++) {
|
|
if (!bsd->hThreads[i]) {
|
|
bsd->hEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
bsd->hThreads[i] = THREAD(thread_WaitSelect, &threadindextable[i]);
|
|
if (bsd->hEvents[i] == NULL || bsd->hThreads[i] == NULL) {
|
|
bsd->hThreads[i] = 0;
|
|
unlocksigqueue ();
|
|
write_log (_T("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d\n"),
|
|
GetLastError());
|
|
bsdsocklib_seterrno(ctx, sb,12); // ENOMEM
|
|
sb->resultval = -1;
|
|
return;
|
|
}
|
|
// this should improve responsiveness
|
|
SetThreadPriority(bsd->hThreads[i], THREAD_PRIORITY_ABOVE_NORMAL);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
unlocksigqueue ();
|
|
|
|
if (i >= MAX_SELECT_THREADS) {
|
|
write_log (_T("BSDSOCK: ERROR - Too many select()s, %d\n"), wscnt);
|
|
} else {
|
|
SOCKET newsock = INVALID_SOCKET;
|
|
|
|
taw.sb = sb;
|
|
taw.nfds = nfds;
|
|
taw.readfds = readfds;
|
|
taw.writefds = writefds;
|
|
taw.exceptfds = exceptfds;
|
|
taw.timeout = timeout;
|
|
taw.wscnt = wscnt;
|
|
|
|
bsd->threadargsw[i] = &taw;
|
|
|
|
SetEvent(bsd->hEvents[i]);
|
|
|
|
trap_call_add_dreg(ctx, 0, (((uae_u32)1) << sb->signal) | sb->eintrsigs | wssigs);
|
|
sigs = trap_call_lib(ctx, sb->sysbase, -0x13e); // Wait()
|
|
/*
|
|
if ((1<<sb->signal) & sigs)
|
|
{ // 2.3.2002/SR Fix for AmiFTP -> Thread is ready, no need to Abort
|
|
sb->needAbort = 0;
|
|
}
|
|
*/
|
|
if (sb->needAbort) {
|
|
if ((newsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
|
|
write_log (_T("BSDSOCK: ERROR - Cannot create socket: %d, %d\n"), WSAGetLastError(),wscnt);
|
|
shutdown(sb->sockAbort,1);
|
|
if (newsock != sb->sockAbort) {
|
|
shutdown(sb->sockAbort, 1);
|
|
closesocket(sb->sockAbort);
|
|
}
|
|
}
|
|
|
|
WaitForSingleObject(sb->hEvent, INFINITE);
|
|
|
|
CANCELSIGNAL;
|
|
|
|
if (newsock != INVALID_SOCKET)
|
|
sb->sockAbort = newsock;
|
|
|
|
if(sigmp)
|
|
trap_put_long(ctx, sigmp, sigs & wssigs);
|
|
|
|
if (sigs & wssigs) {
|
|
uae_u32 gotsigs = sigs & wssigs;
|
|
BSDTRACE((_T("[interrupted by signals 0x%08lx]:%d\n"), gotsigs, wscnt));
|
|
if (readfds) fd_zero(ctx, readfds,nfds);
|
|
if (writefds) fd_zero(ctx, writefds,nfds);
|
|
if (exceptfds) fd_zero(ctx, exceptfds,nfds);
|
|
bsdsocklib_seterrno(ctx, sb, 0);
|
|
sb->resultval = 0;
|
|
} else if (sigs & sb->eintrsigs) {
|
|
uae_u32 gotsigs = sigs & sb->eintrsigs;
|
|
BSDTRACE((_T("[interrupted 0x%08x]:%d\n"), gotsigs, wscnt));
|
|
sb->resultval = -1;
|
|
bsdsocklib_seterrno(ctx, sb, 4); // EINTR
|
|
/* EINTR signals are kept active */
|
|
trap_call_add_dreg(ctx, 0, gotsigs);
|
|
trap_call_add_dreg(ctx, 1, gotsigs);
|
|
trap_call_lib(ctx, sb->sysbase, -0x132); // SetSignal
|
|
}
|
|
|
|
if (sb->resultval >= 0) {
|
|
BSDTRACE((_T("WaitSelect, %d:%d\n"),sb->resultval,wscnt));
|
|
} else {
|
|
BSDTRACE((_T("WaitSelect error, %d errno %d:%d\n"),sb->resultval,sb->sb_errno,wscnt));
|
|
}
|
|
}
|
|
}
|
|
|
|
uae_u32 host_Inet_NtoA(TrapContext *ctx, SB, uae_u32 in)
|
|
{
|
|
uae_char *addr;
|
|
struct in_addr ina;
|
|
uae_u32 scratchbuf;
|
|
|
|
*(uae_u32 *)&ina = htonl(in);
|
|
|
|
BSDTRACE((_T("Inet_NtoA(%x) -> "),in));
|
|
|
|
if ((addr = inet_ntoa(ina)) != NULL) {
|
|
scratchbuf = trap_get_areg(ctx, 6) + offsetof(struct UAEBSDBase,scratchbuf);
|
|
strncpyha(ctx, scratchbuf, addr, SCRATCHBUFSIZE);
|
|
if (ISBSDTRACE) {
|
|
TCHAR *s = au (addr);
|
|
BSDTRACE((_T("%s\n"),s));
|
|
xfree (s);
|
|
}
|
|
return scratchbuf;
|
|
} else
|
|
SETERRNO;
|
|
|
|
BSDTRACE((_T("failed (%d)\n"),sb->sb_errno));
|
|
|
|
return 0;
|
|
}
|
|
|
|
uae_u32 host_inet_addr(TrapContext *ctx, uae_u32 cp)
|
|
{
|
|
uae_u32 addr;
|
|
char *cp_rp;
|
|
|
|
if (!trap_valid_address(ctx, cp, 4))
|
|
return 0;
|
|
cp_rp = trap_get_alloc_string(ctx, cp, 256);
|
|
addr = htonl(inet_addr(cp_rp));
|
|
if (ISBSDTRACE) {
|
|
TCHAR *s = au (cp_rp);
|
|
BSDTRACE((_T("inet_addr(%s) -> 0x%08lx\n"), s, addr));
|
|
xfree (s);
|
|
}
|
|
xfree(cp_rp);
|
|
return addr;
|
|
}
|
|
|
|
int isfullscreen (void);
|
|
static BOOL CheckOnline(SB)
|
|
{
|
|
DWORD dwFlags;
|
|
BOOL bReturn = TRUE;
|
|
|
|
if (InternetGetConnectedState(&dwFlags,0) == FALSE) { // Internet is offline
|
|
if (InternetAttemptConnect(0) != ERROR_SUCCESS) { // Show Dialer window
|
|
sb->sb_errno = 10001;
|
|
sb->sb_herrno = 1;
|
|
bReturn = FALSE;
|
|
// No success or aborted
|
|
}
|
|
if (isfullscreen() > 0) {
|
|
ShowWindow (hAmigaWnd, SW_RESTORE);
|
|
SetActiveWindow(hAmigaWnd);
|
|
}
|
|
}
|
|
return bReturn;
|
|
}
|
|
|
|
#define GET_STATE_FREE 0
|
|
#define GET_STATE_ACTIVE 1
|
|
#define GET_STATE_CANCEL 2
|
|
#define GET_STATE_FINISHED 3
|
|
#define GET_STATE_DONE 4
|
|
#define GET_STATE_REALLY_DONE 5
|
|
|
|
static unsigned int thread_get2 (void *indexp)
|
|
{
|
|
int index = *((int*)indexp);
|
|
int wscnt;
|
|
unsigned int result = 0;
|
|
volatile struct threadargs *args;
|
|
uae_u32 name;
|
|
uae_u32 namelen;
|
|
long addrtype;
|
|
char *name_rp;
|
|
SB;
|
|
TrapContext *ctx = NULL;
|
|
|
|
while (bsd->hGetEvents[index]) {
|
|
|
|
if (WaitForSingleObject(bsd->hGetEvents[index], INFINITE) == WAIT_ABANDONED)
|
|
break;
|
|
if (bsd->hGetEvents[index] == NULL)
|
|
break;
|
|
|
|
args = bsd->threadGetargs[index];
|
|
|
|
BSDTRACE((_T("tg2 %p,%d,%d:%d -> "), args->sb, index, bsd->threadGetargs_inuse[index], args->wscnt));
|
|
|
|
if (bsd->threadGetargs_inuse[index] == GET_STATE_ACTIVE) {
|
|
wscnt = args->wscnt;
|
|
sb = args->sb;
|
|
|
|
if (args->args1 == 0) {
|
|
|
|
// gethostbyname or gethostbyaddr
|
|
struct hostent *host;
|
|
name = args->args2;
|
|
namelen = args->args3;
|
|
addrtype = args->args4;
|
|
if (addr_valid (_T("thread_get1"), name, 1))
|
|
name_rp = (char*)get_real_address (name);
|
|
else
|
|
name_rp = "";
|
|
|
|
if (strchr (name_rp, '.') == 0 || CheckOnline(sb) == TRUE) {
|
|
// Local Address or Internet Online ?
|
|
BSDTRACE((_T("tg2_0a %d:%d -> "),addrtype,wscnt));
|
|
if (addrtype == -1) {
|
|
host = gethostbyname (name_rp);
|
|
} else {
|
|
host = gethostbyaddr (name_rp, namelen, addrtype);
|
|
}
|
|
BSDTRACE((_T("tg2_0b %d -> "), wscnt));
|
|
if (bsd->threadGetargs_inuse[index] != GET_STATE_CANCEL) {
|
|
// No CTRL-C Signal
|
|
if (host == 0) {
|
|
// Error occurred
|
|
SETERRNO;
|
|
BSDTRACE((_T("tg2_0 failed %d:%d -> "), sb->sb_errno,wscnt));
|
|
} else {
|
|
bsdsocklib_seterrno(ctx, sb, 0);
|
|
memcpy((void*)args->buf, host, sizeof(HOSTENT));
|
|
}
|
|
}
|
|
}
|
|
|
|
} else if (args->args1 == 1) {
|
|
|
|
// getprotobyname
|
|
struct protoent *proto;
|
|
|
|
name = args->args2;
|
|
if (addr_valid (_T("thread_get2"), name, 1))
|
|
name_rp = (char*)get_real_address (name);
|
|
else
|
|
name_rp = "";
|
|
proto = getprotobyname (name_rp);
|
|
if (bsd->threadGetargs_inuse[index] != GET_STATE_CANCEL) { // No CTRL-C Signal
|
|
if (proto == 0) {
|
|
// Error occurred
|
|
SETERRNO;
|
|
BSDTRACE((_T("tg2_1 failed %d:%d -> "), sb->sb_errno, wscnt));
|
|
} else {
|
|
bsdsocklib_seterrno(ctx, sb, 0);
|
|
memcpy((void*)args->buf, proto, sizeof(struct protoent));
|
|
}
|
|
}
|
|
|
|
} else if (args->args1 == 2) {
|
|
|
|
// getservbyport and getservbyname
|
|
uae_u32 nameport;
|
|
uae_u32 proto;
|
|
uae_u32 type;
|
|
char *proto_rp = 0;
|
|
struct servent *serv;
|
|
|
|
nameport = args->args2;
|
|
proto = args->args3;
|
|
type = args->args4;
|
|
|
|
if (proto) {
|
|
if (addr_valid (_T("thread_get3"), proto, 1))
|
|
proto_rp = (char*)get_real_address (proto);
|
|
}
|
|
|
|
if (type) {
|
|
serv = getservbyport(nameport, proto_rp);
|
|
} else {
|
|
if (addr_valid (_T("thread_get4"), nameport, 1))
|
|
name_rp = (char*)get_real_address (nameport);
|
|
serv = getservbyname(name_rp, proto_rp);
|
|
}
|
|
if (bsd->threadGetargs_inuse[index] != GET_STATE_CANCEL) {
|
|
// No CTRL-C Signal
|
|
if (serv == 0) {
|
|
// Error occurred
|
|
SETERRNO;
|
|
BSDTRACE((_T("tg2_2 failed %d:%d -> "), sb->sb_errno, wscnt));
|
|
} else {
|
|
bsdsocklib_seterrno(ctx, sb, 0);
|
|
memcpy((void*)args->buf, serv, sizeof (struct servent));
|
|
}
|
|
}
|
|
}
|
|
|
|
locksigqueue ();
|
|
bsd->threadGetargs_inuse[index] = GET_STATE_FINISHED;
|
|
unlocksigqueue ();
|
|
|
|
SETSIGNAL;
|
|
|
|
locksigqueue ();
|
|
bsd->threadGetargs_inuse[index] = GET_STATE_DONE;
|
|
unlocksigqueue ();
|
|
|
|
SetEvent(bsd->hGetEvents2[index]);
|
|
|
|
BSDTRACE((_T("tg2 done %d:%d\n"), index, wscnt));
|
|
}
|
|
}
|
|
write_log (_T("BSDSOCK: thread_get2 terminated\n"));
|
|
THREADEND(result);
|
|
return result;
|
|
}
|
|
|
|
static unsigned int __stdcall thread_get(void *p)
|
|
{
|
|
__try {
|
|
return thread_get2 (p);
|
|
} __except(WIN32_ExceptionFilter(GetExceptionInformation(), GetExceptionCode())) {
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int run_get_thread(TrapContext *ctx, SB, struct threadargs *args)
|
|
{
|
|
int i;
|
|
|
|
sb->eintr = 0;
|
|
|
|
locksigqueue ();
|
|
|
|
for (i = 0; i < MAX_GET_THREADS; i++) {
|
|
if (bsd->threadGetargs_inuse[i] == GET_STATE_REALLY_DONE) {
|
|
bsd->threadGetargs_inuse[i] = GET_STATE_FREE;
|
|
}
|
|
if (bsd->hGetThreads[i] && bsd->threadGetargs_inuse[i] == GET_STATE_FREE) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i >= MAX_GET_THREADS) {
|
|
for (i = 0; i < MAX_GET_THREADS; i++) {
|
|
if (bsd->hGetThreads[i] == NULL) {
|
|
bsd->threadGetargs_inuse[i] = GET_STATE_FREE;
|
|
bsd->hGetEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
bsd->hGetEvents2[i] = CreateEvent(NULL,FALSE,FALSE,NULL);
|
|
if (bsd->hGetEvents[i] && bsd->hGetEvents2[i])
|
|
bsd->hGetThreads[i] = THREAD(thread_get, &threadindextable[i]);
|
|
if (bsd->hGetEvents[i] == NULL || bsd->hGetEvents2[i] == NULL || bsd->hGetThreads[i] == NULL) {
|
|
if (bsd->hGetEvents[i])
|
|
CloseHandle (bsd->hGetEvents[i]);
|
|
bsd->hGetEvents[i] = NULL;
|
|
if (bsd->hGetEvents2[i])
|
|
CloseHandle (bsd->hGetEvents2[i]);
|
|
bsd->hGetEvents2[i] = NULL;
|
|
write_log (_T("BSDSOCK: ERROR - Thread/Event creation failed - error code: %d:%d\n"),
|
|
GetLastError(), args->wscnt);
|
|
bsdsocklib_seterrno(ctx, sb, 12); // ENOMEM
|
|
sb->resultval = -1;
|
|
unlocksigqueue ();
|
|
return -1;
|
|
}
|
|
bsdsetpriority (bsd->hGetThreads[i]);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (i >= MAX_GET_THREADS) {
|
|
write_log (_T("BSDSOCK: ERROR - Too many gethostbyname()s:%d\n"), args->wscnt);
|
|
bsdsocklib_seterrno(ctx, sb, 12); // ENOMEM
|
|
sb->resultval = -1;
|
|
unlocksigqueue ();
|
|
return -1;
|
|
} else {
|
|
bsd->threadGetargs[i] = args;
|
|
bsd->threadGetargs_inuse[i] = GET_STATE_ACTIVE;
|
|
ResetEvent(bsd->hGetEvents2[i]);
|
|
SetEvent(bsd->hGetEvents[i]);
|
|
}
|
|
|
|
unlocksigqueue ();
|
|
|
|
while (bsd->threadGetargs_inuse[i] != GET_STATE_FINISHED && bsd->threadGetargs_inuse[i] != GET_STATE_DONE) {
|
|
WAITSIGNAL;
|
|
locksigqueue ();
|
|
int inuse = bsd->threadGetargs_inuse[i];
|
|
if (sb->eintr == 1 && inuse != GET_STATE_FINISHED && inuse != GET_STATE_DONE)
|
|
bsd->threadGetargs_inuse[i] = GET_STATE_CANCEL;
|
|
unlocksigqueue ();
|
|
}
|
|
|
|
if (bsd->threadGetargs_inuse[i] >= GET_STATE_FINISHED)
|
|
WaitForSingleObject(bsd->hGetEvents2[i], INFINITE);
|
|
|
|
CANCELSIGNAL;
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
static void release_get_thread(int index)
|
|
{
|
|
if (index < 0)
|
|
return;
|
|
bsd->threadGetargs_inuse[index] = GET_STATE_REALLY_DONE;
|
|
}
|
|
|
|
void host_gethostbynameaddr (TrapContext *ctx, SB, uae_u32 name, uae_u32 namelen, long addrtype)
|
|
{
|
|
static int wscounter;
|
|
HOSTENT *h;
|
|
int size, numaliases = 0, numaddr = 0;
|
|
uae_u32 aptr;
|
|
char *name_rp;
|
|
int i, tindex;
|
|
struct threadargs args;
|
|
volatile struct threadargs *argsp;
|
|
uae_u32 addr;
|
|
uae_u32 *addr_list[2];
|
|
volatile uae_char *buf;
|
|
unsigned int wMsg = 0;
|
|
|
|
// TCHAR on = 1;
|
|
// InternetSetOption(0,INTERNET_OPTION_SETTINGS_CHANGED,&on,strlen(&on));
|
|
// Do not use: Causes locks with some machines
|
|
|
|
tindex = -1;
|
|
memset(&args, 0, sizeof (args));
|
|
argsp = &args;
|
|
argsp->wscnt = ++wscounter;
|
|
buf = argsp->buf;
|
|
|
|
name_rp = "";
|
|
|
|
if (addr_valid (_T("host_gethostbynameaddr"), name, 1))
|
|
name_rp = (char*)get_real_address (name);
|
|
|
|
if (addrtype == -1) {
|
|
if (ISBSDTRACE) {
|
|
TCHAR *s = au (name_rp);
|
|
BSDTRACE((_T("gethostbyname(%s) -> "),s));
|
|
xfree (s);
|
|
}
|
|
// workaround for numeric host "names"
|
|
if ((addr = inet_addr(name_rp)) != INADDR_NONE) {
|
|
bsdsocklib_seterrno(ctx, 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 = (uae_char**)&addr_list;
|
|
addr_list[0] = &addr;
|
|
addr_list[1] = NULL;
|
|
|
|
goto kludge;
|
|
}
|
|
} else {
|
|
BSDTRACE((_T("gethostbyaddr(0x%x,0x%x,%ld):%d -> "),name,namelen,addrtype,argsp->wscnt));
|
|
}
|
|
|
|
argsp->sb = sb;
|
|
argsp->args1 = 0;
|
|
argsp->args2 = name;
|
|
argsp->args3 = namelen;
|
|
argsp->args4 = addrtype;
|
|
|
|
tindex = run_get_thread(ctx, sb, &args);
|
|
if (tindex < 0)
|
|
return;
|
|
buf = argsp->buf;
|
|
|
|
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(ctx, sb->hostent, sb->hostentsize, sb->sysbase);
|
|
}
|
|
|
|
sb->hostent = uae_AllocMem(ctx, size, 0, sb->sysbase);
|
|
|
|
if (!sb->hostent) {
|
|
write_log (_T("BSDSOCK: WARNING - gethostby%s() ran out of Amiga memory ")
|
|
_T("(couldn't allocate %ld bytes) while returning result of lookup for '%s':%d\n"),
|
|
addrtype == -1 ? _T("name") : _T("addr"), size, name_rp, argsp->wscnt);
|
|
bsdsocklib_seterrno(ctx, sb, 12); // ENOMEM
|
|
release_get_thread (tindex);
|
|
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_ansi(ctx, &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(ctx, &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_ansi(ctx, &aptr, h->h_name);
|
|
|
|
if (ISBSDTRACE) {
|
|
TCHAR *s = au (h->h_name);
|
|
BSDTRACE((_T("OK (%s):%d\n"), s, argsp->wscnt));
|
|
xfree (s);
|
|
}
|
|
|
|
bsdsocklib_seterrno(ctx, sb, 0);
|
|
bsdsocklib_setherrno(ctx, sb, 0);
|
|
|
|
} else {
|
|
BSDTRACE((_T("failed (%d/%d):%d\n"), sb->sb_errno, sb->sb_herrno,argsp->wscnt));
|
|
}
|
|
|
|
release_get_thread (tindex);
|
|
|
|
}
|
|
|
|
void host_getprotobyname(TrapContext *ctx, SB, uae_u32 name)
|
|
{
|
|
static int wscounter;
|
|
PROTOENT *p;
|
|
int size, numaliases = 0;
|
|
uae_u32 aptr;
|
|
char *name_rp;
|
|
int i, tindex;
|
|
struct threadargs args;
|
|
volatile struct threadargs *argsp;
|
|
|
|
memset(&args, 0, sizeof (args));
|
|
argsp = &args;
|
|
argsp->sb = sb;
|
|
argsp->wscnt = ++wscounter;
|
|
|
|
name_rp = NULL;
|
|
if (ISBSDTRACE) {
|
|
if (trap_valid_address(ctx, name, 1)) {
|
|
name_rp = trap_get_alloc_string(ctx, name, 256);
|
|
}
|
|
}
|
|
|
|
if (ISBSDTRACE) {
|
|
TCHAR *s = au (name_rp ? name_rp : "");
|
|
BSDTRACE((_T("getprotobyname(%s):%d -> "),s, argsp->wscnt));
|
|
xfree (s);
|
|
}
|
|
|
|
argsp->args1 = 1;
|
|
argsp->args2 = name;
|
|
|
|
tindex = run_get_thread(ctx, sb, &args);
|
|
if (tindex < 0)
|
|
return;
|
|
|
|
if (!sb->sb_errno) {
|
|
p = (PROTOENT *)argsp->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(ctx, sb->protoent, sb->protoentsize, sb->sysbase);
|
|
}
|
|
|
|
sb->protoent = uae_AllocMem(ctx, size, 0, sb->sysbase);
|
|
|
|
if (!sb->protoent) {
|
|
if (ISBSDTRACE) {
|
|
TCHAR *s = au(name_rp ? name_rp : "");
|
|
write_log (_T("BSDSOCK: WARNING - getprotobyname() ran out of Amiga memory ")
|
|
_T("(couldn't allocate %ld bytes) while returning result of lookup for '%s':%d\n"),
|
|
size, s, argsp->wscnt);
|
|
xfree (s);
|
|
}
|
|
bsdsocklib_seterrno(ctx, sb, 12); // ENOMEM
|
|
release_get_thread (tindex);
|
|
return;
|
|
}
|
|
|
|
sb->protoentsize = size;
|
|
|
|
aptr = sb->protoent + 16 + numaliases * 4;
|
|
|
|
// transfer protoent to Amiga memory
|
|
trap_put_long(ctx, sb->protoent + 4, sb->protoent + 12);
|
|
trap_put_long(ctx, sb->protoent + 8, p->p_proto);
|
|
|
|
for (i = 0; i < numaliases; i++)
|
|
trap_put_long(ctx, sb->protoent + 12 + i * 4, addstr_ansi(ctx, &aptr, p->p_aliases[i]));
|
|
trap_put_long(ctx, sb->protoent + 12 + numaliases * 4,0);
|
|
trap_put_long(ctx, sb->protoent, aptr);
|
|
addstr_ansi(ctx, &aptr, p->p_name);
|
|
if (ISBSDTRACE) {
|
|
TCHAR *s = au (p->p_name);
|
|
BSDTRACE((_T("OK (%s, %d):%d\n"), s, p->p_proto, argsp->wscnt));
|
|
xfree (s);
|
|
}
|
|
bsdsocklib_seterrno(ctx, sb,0);
|
|
|
|
} else {
|
|
BSDTRACE((_T("failed (%d):%d\n"), sb->sb_errno, argsp->wscnt));
|
|
}
|
|
|
|
xfree(name_rp);
|
|
release_get_thread (tindex);
|
|
}
|
|
|
|
void host_getprotobynumber(TrapContext *ctx, SB, uae_u32 name)
|
|
{
|
|
bsdsocklib_seterrno(ctx, sb, 1);
|
|
}
|
|
|
|
void host_getservbynameport(TrapContext *ctx, SB, uae_u32 nameport, uae_u32 proto, uae_u32 type)
|
|
{
|
|
static int wscounter;
|
|
SERVENT *s;
|
|
int size, numaliases = 0;
|
|
uae_u32 aptr;
|
|
TCHAR *name_rp = NULL, *proto_rp = NULL;
|
|
int i, tindex;
|
|
struct threadargs args;
|
|
volatile struct threadargs *argsp;
|
|
|
|
memset(&args, 0, sizeof (args));
|
|
argsp = &args;
|
|
argsp->sb = sb;
|
|
argsp->wscnt = ++wscounter;
|
|
|
|
if (proto) {
|
|
if (trap_valid_address(ctx, proto, 1)) {
|
|
uae_char buf[256];
|
|
trap_get_string(ctx, buf, proto, sizeof buf);
|
|
proto_rp = au(buf);
|
|
}
|
|
}
|
|
|
|
if (type) {
|
|
BSDTRACE((_T("getservbyport(%d,%s);%d -> "), nameport, proto_rp ? proto_rp : _T("NULL"), argsp->wscnt));
|
|
} else {
|
|
if (trap_valid_address(ctx, nameport, 1)) {
|
|
uae_char buf[256];
|
|
trap_get_string(ctx, buf, nameport, sizeof buf);
|
|
name_rp = au(buf);
|
|
}
|
|
BSDTRACE((_T("getservbyname(%s,%s):%d -> "), name_rp, proto_rp ? proto_rp : _T("NULL"), argsp->wscnt));
|
|
}
|
|
|
|
argsp->args1 = 2;
|
|
argsp->args2 = nameport;
|
|
argsp->args3 = proto;
|
|
argsp->args4 = type;
|
|
|
|
tindex = run_get_thread(ctx, sb, &args);
|
|
if (tindex < 0)
|
|
return;
|
|
|
|
if (!sb->sb_errno) {
|
|
s = (SERVENT *)argsp->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(ctx, sb->servent, sb->serventsize, sb->sysbase);
|
|
}
|
|
|
|
sb->servent = uae_AllocMem(ctx, size, 0, sb->sysbase);
|
|
|
|
if (!sb->servent) {
|
|
write_log (_T("BSDSOCK: WARNING - getservby%s() ran out of Amiga memory (couldn't allocate %ld bytes):%d\n"), type ? _T("port") : _T("name"), size, argsp->wscnt);
|
|
bsdsocklib_seterrno(ctx, sb, 12); // ENOMEM
|
|
release_get_thread (tindex);
|
|
return;
|
|
}
|
|
|
|
sb->serventsize = size;
|
|
|
|
aptr = sb->servent + 20 + numaliases * 4;
|
|
|
|
// transfer servent to Amiga memory
|
|
trap_put_long(ctx, sb->servent + 4, sb->servent + 16);
|
|
trap_put_long(ctx, sb->servent + 8, (unsigned short)htons(s->s_port));
|
|
|
|
for (i = 0; i < numaliases; i++)
|
|
trap_put_long(ctx, sb->servent + 16 + i * 4, addstr_ansi(ctx, &aptr,s->s_aliases[i]));
|
|
trap_put_long(ctx, sb->servent + 16 + numaliases * 4,0);
|
|
trap_put_long(ctx, sb->servent, aptr);
|
|
addstr_ansi(ctx, &aptr, s->s_name);
|
|
trap_put_long(ctx, sb->servent + 12, aptr);
|
|
addstr_ansi(ctx, &aptr, s->s_proto);
|
|
|
|
if (ISBSDTRACE) {
|
|
TCHAR *ss = au(s->s_name);
|
|
BSDTRACE((_T("OK (%s, %d):%d\n"), ss, (unsigned short)htons(s->s_port), argsp->wscnt));
|
|
xfree (ss);
|
|
}
|
|
|
|
bsdsocklib_seterrno(ctx, sb, 0);
|
|
|
|
} else {
|
|
BSDTRACE((_T("failed (%d):%d\n"),sb->sb_errno, argsp->wscnt));
|
|
}
|
|
|
|
release_get_thread (tindex);
|
|
}
|
|
|
|
uae_u32 host_gethostname(TrapContext *ctx, uae_u32 name, uae_u32 namelen)
|
|
{
|
|
if (!trap_valid_address(ctx, name, namelen))
|
|
return -1;
|
|
uae_char buf[256];
|
|
trap_get_string(ctx, buf, name, sizeof buf);
|
|
return gethostname(buf, namelen);
|
|
}
|
|
|
|
#endif
|
|
|
|
#endif
|