Annotation of uae/src/od-win32/bsdsock.c, revision 1.1

1.1     ! root        1:  /*
        !             2:   * UAE - The Un*x Amiga Emulator
        !             3:   *
        !             4:   * bsdsocket.library emulation - Win32 OS-dependent part
        !             5:   *
        !             6:   * Copyright 1997,98 Mathias Ortmann
        !             7:   *
        !             8:   */
        !             9: 
        !            10: #include <windows.h>
        !            11: #include <winsock.h>
        !            12: 
        !            13: #include "sysconfig.h"
        !            14: #include "sysdeps.h"
        !            15: 
        !            16: #include <stddef.h>
        !            17: 
        !            18: #include "config.h"   
        !            19: #include "options.h"
        !            20: #include "include/memory.h"
        !            21: #include "custom.h"
        !            22: #include "readcpu.h"  
        !            23: #include "newcpu.h"
        !            24: #include "autoconf.h"
        !            25: #include "bsdsocket.h"
        !            26: 
        !            27: CRITICAL_SECTION csSigQueueLock;
        !            28: 
        !            29: DWORD threadid;
        !            30: 
        !            31: #define THREAD(func,arg) CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)func,(LPVOID)arg,0,&threadid)
        !            32: 
        !            33: #define SETERRNO seterrno(sb,WSAGetLastError()-WSABASEERR)
        !            34: #define SETHERRNO setherrno(sb,WSAGetLastError()-WSABASEERR)
        !            35: #define WAITSIGNAL waitsig(sb)
        !            36: 
        !            37: #define SETSIGNAL addtosigqueue(sb,0)
        !            38: #define CANCELSIGNAL cancelsig(sb)
        !            39: 
        !            40: #define BEGINBLOCKING if (sb->ftable[sd-1] & SF_BLOCKING) sb->ftable[sd-1] |= SF_BLOCKINGINPROGRESS
        !            41: #define ENDBLOCKING sb->ftable[sd-1] &= ~SF_BLOCKINGINPROGRESS
        !            42: 
        !            43: static WSADATA wsbData;
        !            44: 
        !            45: int PASCAL WSAEventSelect(SOCKET,HANDLE,long);
        !            46: 
        !            47: #define MAX_SELECT_THREADS 64
        !            48: static HANDLE hThreads[MAX_SELECT_THREADS];
        !            49: uae_u32 *threadargs[MAX_SELECT_THREADS];
        !            50: static HANDLE hEvents[MAX_SELECT_THREADS];
        !            51: 
        !            52: static HANDLE hConnectThread;
        !            53: static HANDLE hConnectEvent, hConnectEventReply;
        !            54: static void thread_connect(void);
        !            55: 
        !            56: int init_socket_layer(void)
        !            57: {
        !            58:        SOCKET dummy;
        !            59:        DWORD lasterror;
        !            60: 
        !            61:        if (WSAStartup(2, &wsbData))
        !            62:        {
        !            63:                lasterror = WSAGetLastError();
        !            64:                
        !            65:                if (lasterror == WSAVERNOTSUPPORTED) write_log("Please upgrade to WinSock2.\n");
        !            66:                else write_log("bsdsocket: ERROR: Unable to initialize Windows socket layer! Error code: %d\n",lasterror);
        !            67:                return 0;
        !            68:        }
        !            69: 
        !            70:        InitializeCriticalSection(&csSigQueueLock);
        !            71: 
        !            72:        // make sure WSP/NSPStartup gets called from within the regular stack
        !            73:        // (Windows 95/98 need this)
        !            74:        if ((dummy = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) != INVALID_SOCKET) closesocket(dummy);
        !            75:        else write_log("bsdsocket: ERROR: WSPStartup/NSPStartup failed! Error code: %d\n",WSAGetLastError());
        !            76: 
        !            77:        if (hConnectThread == NULL)
        !            78:        {
        !            79:                hConnectThread = THREAD(thread_connect,NULL);
        !            80:                hConnectEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
        !            81:                hConnectEventReply = CreateEvent(NULL,FALSE,FALSE,NULL);
        !            82:        }
        !            83:        
        !            84:        return 1;
        !            85: }
        !            86: 
        !            87: void deinit_socket_layer(void)
        !            88: {
        !            89:        WSACleanup();
        !            90: }
        !            91: 
        !            92: void locksigqueue(void)
        !            93: {
        !            94:        EnterCriticalSection(&csSigQueueLock);
        !            95: }
        !            96: 
        !            97: void unlocksigqueue(void)
        !            98: {
        !            99:        LeaveCriticalSection(&csSigQueueLock);
        !           100: }
        !           101: 
        !           102: // Asynchronous completion notification
        !           103: 
        !           104: // We use window messages posted to hAmigaWnd in the range from 0xb000 to 0xb000+MAXPENDINGASYNC*2
        !           105: // Socket events cause even-numbered messages, task events odd-numbered messages
        !           106: // Message IDs are allocated on a round-robin basis and deallocated by the main thread.
        !           107: 
        !           108: // WinSock tends to choke on WSAAsyncCancelMessage(s,w,m,0,0) called too often with an event pending
        !           109: 
        !           110: // @@@ Enabling all socket event messages for every socket by default and basing things on that would
        !           111: // be cleaner (and allow us to write a select() emulation that doesn't need to be kludge-aborted).
        !           112: // However, the latency of the message queue is too high for that at the moment (setting up a dummy
        !           113: // window from a separate thread would fix that).
        !           114: 
        !           115: // Blocking sockets with asynchronous event notification are currently not safe to use.
        !           116: 
        !           117: struct socketbase *asyncsb[MAXPENDINGASYNC];
        !           118: SOCKET asyncsock[MAXPENDINGASYNC];
        !           119: uae_u32 asyncsd[MAXPENDINGASYNC];
        !           120: int asyncindex;
        !           121: 
        !           122: int host_sbinit(SB)
        !           123: {
        !           124:        sb->sockAbort = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        !           125:        
        !           126:        if (sb->sockAbort == INVALID_SOCKET) return 0;
        !           127:        if ((sb->hEvent = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL) return 0;
        !           128: 
        !           129:        sb->mtable = calloc(sb->dtablesize,sizeof(*sb->mtable));
        !           130:        
        !           131:        return 1;
        !           132: }
        !           133: 
        !           134: void host_closesocketquick(int s)
        !           135: {
        !           136:        BOOL true = 1;
        !           137: 
        !           138:        setsockopt((SOCKET)s,SOL_SOCKET,SO_DONTLINGER,(char *)&true,sizeof(true));
        !           139:        closesocket((SOCKET)s);
        !           140: }
        !           141: 
        !           142: void host_sbcleanup(SB)
        !           143: {
        !           144:        int i;
        !           145: 
        !           146:        for (i = 0; i < MAXPENDINGASYNC; i++) if (asyncsb[i] == sb) asyncsb[i] = NULL;
        !           147: 
        !           148:        if (sb->hEvent != NULL) CloseHandle(sb->hEvent);
        !           149:        if (sb->hAsyncTask) WSACancelAsyncRequest(sb->hAsyncTask);
        !           150:        
        !           151:        for (i = sb->dtablesize; i--; )
        !           152:        {
        !           153:                if (sb->dtable[i] != (int)INVALID_SOCKET) host_closesocketquick(sb->dtable[i]);
        !           154:                
        !           155:                if (sb->mtable[i]) asyncsb[(sb->mtable[i]-0xb000)/2] = NULL;
        !           156:        }
        !           157: 
        !           158:        closesocket(sb->sockAbort);
        !           159: 
        !           160:        free(sb->mtable);
        !           161: }
        !           162: 
        !           163: void host_sbreset(void)
        !           164: {
        !           165:        memset(asyncsb,0,sizeof asyncsb);
        !           166:        memset(asyncsock,0,sizeof asyncsock);
        !           167:        memset(asyncsd,0,sizeof asyncsd);
        !           168:        memset(threadargs,0,sizeof threadargs);
        !           169: }
        !           170: 
        !           171: void sockmsg(unsigned int msg, unsigned long wParam, unsigned long lParam)
        !           172: {
        !           173:        SB;
        !           174:        unsigned int index;
        !           175:        int sdi;
        !           176: 
        !           177:        index = (msg-0xb000)/2;
        !           178:        sb = asyncsb[index];
        !           179: 
        !           180:        if (!(msg & 1))
        !           181:        {
        !           182:                // is this one really for us?
        !           183:                if ((SOCKET)wParam != asyncsock[index])
        !           184:                {
        !           185:                        // cancel socket event
        !           186:                        WSAAsyncSelect((SOCKET)wParam,hAmigaWnd,0,0);
        !           187:                        return;
        !           188:                }
        !           189: 
        !           190:                sdi = asyncsd[index]-1;
        !           191: 
        !           192:                // asynchronous socket event?
        !           193:                if (sb && !(sb->ftable[sdi] & SF_BLOCKINGINPROGRESS) && sb->mtable[sdi])
        !           194:                {
        !           195:                        long wsbevents = WSAGETSELECTEVENT(lParam);
        !           196:                        int fmask = 0;
        !           197: 
        !           198:                        // regular socket event?
        !           199:                        if (wsbevents & FD_READ) fmask = REP_READ;
        !           200:                        else if (wsbevents & FD_WRITE) fmask = REP_WRITE;
        !           201:                        else if (wsbevents & FD_OOB) fmask = REP_OOB;
        !           202:                        else if (wsbevents & FD_ACCEPT) fmask = REP_ACCEPT;
        !           203:                        else if (wsbevents & FD_CONNECT) fmask = REP_CONNECT;
        !           204:                        else if (wsbevents & FD_CLOSE) fmask = REP_CLOSE;
        !           205: 
        !           206:                        // error?
        !           207:                        if (WSAGETSELECTERROR(lParam)) fmask |= REP_ERROR;
        !           208: 
        !           209:                        // notify
        !           210:                        if (sb->ftable[sdi] & fmask) sb->ftable[sdi] |= fmask<<8;
        !           211: 
        !           212:                        addtosigqueue(sb,1);
        !           213:                        return;
        !           214:                }
        !           215:        }
        !           216: 
        !           217:        locksigqueue();
        !           218: 
        !           219:        if (sb != NULL)
        !           220:        {
        !           221:                if (msg & 1)
        !           222:                {
        !           223:                        // is this one really for us?
        !           224:                        if (sb->hAsyncTask != (void *)~0L && (void *)wParam != sb->hAsyncTask)
        !           225:                        {
        !           226:                                unlocksigqueue();
        !           227:                                return;
        !           228:                        }
        !           229:                }
        !           230: 
        !           231:                asyncsb[index] = NULL;
        !           232: 
        !           233:                if (WSAGETASYNCERROR(lParam))
        !           234:                {
        !           235:                        seterrno(sb,WSAGETASYNCERROR(lParam)-WSABASEERR);
        !           236:                        if (sb->sb_errno >= 1001 && sb->sb_errno <= 1005) setherrno(sb,sb->sb_errno-1000);
        !           237:                        else if (sb->sb_errno == 55)    // ENOBUFS
        !           238:                                write_log("bsdsocket: ERROR: Buffer overflow - %d bytes requested\n",WSAGETASYNCBUFLEN(lParam));
        !           239:                }
        !           240:                else seterrno(sb,0);
        !           241: 
        !           242:                if (msg & 1) sb->hAsyncTask = 0;
        !           243: 
        !           244:                SETSIGNAL;
        !           245:        }
        !           246:        
        !           247:        unlocksigqueue();
        !           248: }
        !           249: 
        !           250: static unsigned int allocasyncmsg(SB,uae_u32 sd,SOCKET s)
        !           251: {
        !           252:        int i;
        !           253:        
        !           254:        locksigqueue();
        !           255:        
        !           256:        for (i = asyncindex+1; i != asyncindex; i++)
        !           257:        {
        !           258:                if (i == MAXPENDINGASYNC) i = 0;
        !           259:                
        !           260:                if (!asyncsb[i])
        !           261:                {
        !           262:                        asyncsb[i] = sb;
        !           263:                        if (++asyncindex == MAXPENDINGASYNC) asyncindex = 0;
        !           264:                        unlocksigqueue();
        !           265:                        
        !           266:                        if (s == INVALID_SOCKET)
        !           267:                        {
        !           268:                                sb->hAsyncTask = (void *)~0L;   // set wildcard value to prevent race condition
        !           269:                                return i*2+0xb001;
        !           270:                        }
        !           271:                        else
        !           272:                        {
        !           273:                                asyncsd[i] = sd;
        !           274:                                asyncsock[i] = s;
        !           275:                                return i*2+0xb000;
        !           276:                        }
        !           277:                }
        !           278:        }
        !           279:        
        !           280:        unlocksigqueue();
        !           281: 
        !           282:        seterrno(sb,12); // ENOMEM
        !           283:        write_log("bsdsocket: ERROR: Async operation completion table overflow\n");
        !           284:        
        !           285:        return 0;
        !           286: }
        !           287: 
        !           288: static void cancelasyncmsg(unsigned int wMsg)
        !           289: {
        !           290:        SB;
        !           291:        
        !           292:        wMsg = (wMsg-0xb000)/2;
        !           293: 
        !           294:        sb = asyncsb[wMsg];
        !           295: 
        !           296:        if (sb != NULL)
        !           297:        {
        !           298:                asyncsb[wMsg] = NULL;
        !           299:                CANCELSIGNAL;
        !           300:        }
        !           301: }
        !           302: 
        !           303: void sockabort(SB)
        !           304: {      
        !           305:        locksigqueue();
        !           306: 
        !           307:        if (sb->hAsyncTask)
        !           308:        {
        !           309:                if (WSACancelAsyncRequest(sb->hAsyncTask)) write_log("bsdsocket: ERROR: WSACancelAsyncRequest() failed with error code %d\n",WSAGetLastError());
        !           310:                sb->hAsyncTask = 0;
        !           311:        }
        !           312: 
        !           313:        unlocksigqueue();
        !           314: }
        !           315: 
        !           316: // address cleaning
        !           317: static void prephostaddr(SOCKADDR_IN *addr)
        !           318: {
        !           319:        addr->sin_family = AF_INET;
        !           320: }
        !           321: 
        !           322: static void prepamigaaddr(struct sockaddr *realpt, int len)
        !           323: {
        !           324:        // little endian address family value to the byte sin_family member
        !           325:        ((char *)realpt)[1] = *((char *)realpt);
        !           326:        
        !           327:        // set size of address
        !           328:        *((char *)realpt) = len;
        !           329: }
        !           330: 
        !           331: int host_socket(SB, int af, int type, int protocol)
        !           332: {
        !           333:        int sd;
        !           334:        SOCKET s;
        !           335:        unsigned long nonblocking = 1;
        !           336: 
        !           337:        TRACE(("socket(%d,%d,%d) -> ",af,type,protocol));
        !           338: 
        !           339:        if ((s = socket(af,type,protocol)) == INVALID_SOCKET)
        !           340:        {
        !           341:                SETERRNO;
        !           342:                TRACE(("failed (%d)\n",sb->sb_errno));
        !           343:                return -1;
        !           344:        }
        !           345:        else sd = getsd(sb,(int)s);
        !           346: 
        !           347:        sb->ftable[sd-1] = SF_BLOCKING;
        !           348:        ioctlsocket(s,FIONBIO,&nonblocking);
        !           349:        TRACE(("%d\n",sd));
        !           350: 
        !           351:        return sd;
        !           352: }
        !           353: 
        !           354: uae_u32 host_bind(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
        !           355: {
        !           356:        char buf[MAXADDRLEN];
        !           357:        uae_u32 success = 0;
        !           358:        SOCKET s;
        !           359: 
        !           360:        TRACE(("bind(%d,0x%lx,%d) -> ",sd,name,namelen));
        !           361:        s = getsock(sb, sd);
        !           362: 
        !           363:        if (s != INVALID_SOCKET)
        !           364:        {
        !           365:                if (namelen <= sizeof buf)
        !           366:                {
        !           367:                        memcpy(buf,get_real_address(name),namelen);
        !           368:                        
        !           369:                        // some Amiga programs set this field to bogus values
        !           370:                        prephostaddr((SOCKADDR_IN *)buf);
        !           371: 
        !           372:                        if ((success = bind(s,(struct sockaddr *)buf,namelen)) != 0)
        !           373:                        {
        !           374:                                SETERRNO;
        !           375:                                TRACE(("failed (%d)\n",sb->sb_errno));
        !           376:                        }
        !           377:                        else TRACE(("OK\n"));
        !           378:                }
        !           379:                else write_log("bsdsocket: ERROR: Excessive namelen (%d) in bind()!\n",namelen);
        !           380:        }
        !           381: 
        !           382:        return success;
        !           383: }
        !           384: 
        !           385: uae_u32 host_listen(SB, uae_u32 sd, uae_u32 backlog)
        !           386: {
        !           387:        SOCKET s;
        !           388:        uae_u32 success = -1;
        !           389: 
        !           390:        TRACE(("listen(%d,%d) -> ",sd,backlog));
        !           391:        s = getsock(sb, sd);
        !           392: 
        !           393:        if (s != INVALID_SOCKET)
        !           394:        {
        !           395:                if ((success = listen(s,backlog)) != 0)
        !           396:                {
        !           397:                        SETERRNO;
        !           398:                        TRACE(("failed (%d)\n",sb->sb_errno));
        !           399:                }
        !           400:                else TRACE(("OK\n"));
        !           401:        }
        !           402:                        
        !           403:        return success;
        !           404: }
        !           405: 
        !           406: void host_accept(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
        !           407: {
        !           408:        struct sockaddr *rp_name;
        !           409:        int hlen;
        !           410:        SOCKET s, s2;
        !           411:        int success = 0;
        !           412:        unsigned int wMsg;
        !           413:        
        !           414:        rp_name = (struct sockaddr *)get_real_address(name);
        !           415:        hlen = get_long(namelen);
        !           416:        TRACE(("accept(%d,%d,%d) -> ",sd,name,hlen));
        !           417: 
        !           418:        s = (SOCKET)getsock(sb,(int)sd);
        !           419:        
        !           420:        if (s != INVALID_SOCKET)
        !           421:        {
        !           422:                BEGINBLOCKING;
        !           423:                
        !           424:                s2 = accept(s,rp_name,&hlen);
        !           425: 
        !           426:                if (s2 == INVALID_SOCKET)
        !           427:                {
        !           428:                        SETERRNO;
        !           429: 
        !           430:                        if (sb->ftable[sd-1] & SF_BLOCKING && sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR)
        !           431:                        {
        !           432:                                if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
        !           433:                                {
        !           434:                                        WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_ACCEPT);
        !           435: 
        !           436:                                        WAITSIGNAL;
        !           437: 
        !           438:                                        cancelasyncmsg(wMsg);
        !           439:                                        
        !           440:                                        if (sb->eintr)
        !           441:                                        {
        !           442:                                                TRACE(("[interrupted]\n"));
        !           443:                                                ENDBLOCKING;
        !           444:                                                return;
        !           445:                                        }
        !           446: 
        !           447:                                        s2 = accept(s,rp_name,&hlen);
        !           448: 
        !           449:                                        if (s2 == INVALID_SOCKET)
        !           450:                                        {
        !           451:                                                SETERRNO;
        !           452: 
        !           453:                                                if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR) write_log("bsdsocket: ERRRO: accept() would block despite FD_ACCEPT message\n");
        !           454:                                        }
        !           455:                                }
        !           456:                        }
        !           457:                }
        !           458:                        
        !           459:                if (s2 == INVALID_SOCKET)
        !           460:                {
        !           461:                        sb->resultval = -1;
        !           462:                        TRACE(("failed (%d)\n",sb->sb_errno));
        !           463:                }
        !           464:                else
        !           465:                {
        !           466:                        sb->resultval = getsd(sb, s2);
        !           467:                        sb->ftable[sb->resultval-1] = sb->ftable[sd-1]; // new socket inherits the old socket's properties
        !           468: 
        !           469:                        prepamigaaddr(rp_name,hlen);
        !           470:                        put_long(namelen,hlen);
        !           471:                        TRACE(("%d/%d\n",sb->resultval,hlen));
        !           472:                }
        !           473: 
        !           474:                ENDBLOCKING;
        !           475:        }
        !           476: }
        !           477: 
        !           478: // Windows 9x workaround... Microsoft blows chunks.
        !           479: volatile SOCKET connect_s;
        !           480: volatile uae_u32 connect_name, connect_namelen;
        !           481: struct socketbase *connect_sb;
        !           482: 
        !           483: static void thread_connect(void)
        !           484: {
        !           485:        char buf[MAXADDRLEN];
        !           486:        SB;
        !           487:        
        !           488:        for (;;)
        !           489:        {
        !           490:                WaitForSingleObject(hConnectEvent,INFINITE);
        !           491:                
        !           492:                if ((sb = connect_sb) != NULL)
        !           493:                {
        !           494:                        memcpy(buf,get_real_address(connect_name),connect_namelen);
        !           495:                        prephostaddr((SOCKADDR_IN *)buf);
        !           496: 
        !           497:                        if ((sb->resultval = connect(connect_s,(struct sockaddr *)buf,connect_namelen)) != 0) SETERRNO;
        !           498: 
        !           499:                        connect_sb = NULL;
        !           500:                        SetEvent(hConnectEventReply);
        !           501:                }
        !           502:        }
        !           503: }
        !           504: 
        !           505: void host_connect(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
        !           506: {
        !           507:        SOCKET s;
        !           508:        int success = 0;
        !           509:        unsigned int wMsg;
        !           510:        
        !           511:        TRACE(("connect(%d,0x%lx,%d) -> ",sd,name,namelen));
        !           512: 
        !           513:        s = (SOCKET)getsock(sb,(int)sd);
        !           514:        
        !           515:        if (s != INVALID_SOCKET)
        !           516:        {
        !           517:                if (namelen <= MAXADDRLEN)
        !           518:                {
        !           519:                        if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
        !           520:                        {
        !           521:                                WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_CONNECT);
        !           522: 
        !           523:                                BEGINBLOCKING;
        !           524: 
        !           525:                                connect_s = s;
        !           526:                                connect_name = name;
        !           527:                                connect_namelen = namelen;
        !           528:                                connect_sb = sb;
        !           529:                                SetEvent(hConnectEvent);
        !           530:                                WaitForSingleObject(hConnectEventReply,INFINITE);
        !           531: 
        !           532:                                if (sb->resultval)
        !           533:                                {
        !           534:                                        if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR)
        !           535:                                        {
        !           536:                                                if (sb->ftable[sd-1] & SF_BLOCKING)
        !           537:                                                {
        !           538:                                                        seterrno(sb,0);
        !           539:        
        !           540:                                                        WAITSIGNAL;
        !           541: 
        !           542:                                                        if (sb->eintr)
        !           543:                                                        {
        !           544:                                                                // Destroy socket to cancel abort, replace it with fake socket to enable proper closing.
        !           545:                                                                // This is in accordance with BSD behaviour.
        !           546:                                                                closesocket(s);
        !           547:                                                                sb->dtable[sd-1] = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
        !           548:                                                        }
        !           549:                                                }
        !           550:                                                else seterrno(sb,36);   // EINPROGRESS
        !           551:                                        }
        !           552:                                }
        !           553:                                
        !           554:                                ENDBLOCKING;
        !           555: 
        !           556:                                cancelasyncmsg(wMsg);
        !           557:                        }
        !           558:                }
        !           559:                else write_log("bsdsock: WARNING: Excessive namelen (%d) in connect()!\n",namelen);
        !           560:        }
        !           561: 
        !           562:        TRACE(("%d\n",sb->sb_errno));
        !           563: }
        !           564: 
        !           565: // @@@ move sendto() to an extra thread to make UDP-based apps work under Windows 9x
        !           566: void host_sendto(SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 to, uae_u32 tolen)
        !           567: {
        !           568:        SOCKET s;
        !           569:        char *realpt;
        !           570:        unsigned int wMsg;
        !           571:        char buf[MAXADDRLEN];
        !           572: 
        !           573: #ifdef TRACING_ENABLED
        !           574:        if (to) TRACE(("sendto(%d,0x%lx,%d,0x%lx,0x%lx,%d) -> ",sd,msg,len,flags,to,tolen))
        !           575:        else TRACE(("send(%d,0x%lx,%d,%d) -> ",sd,msg,len,flags));
        !           576: #endif
        !           577: 
        !           578:        s = getsock(sb,sd);
        !           579: 
        !           580:        if (s != INVALID_SOCKET)
        !           581:        {
        !           582:                realpt = get_real_address(msg);
        !           583:                
        !           584:                if (to)
        !           585:                {
        !           586:                        if (tolen > sizeof buf) write_log("bsdsocket: WARNING: Target address in sendto() too large (%d)!\n",tolen);
        !           587:                        else
        !           588:                        {
        !           589:                                memcpy(buf,get_real_address(to),tolen);
        !           590:                                // some Amiga software sets this field to bogus values
        !           591:                                prephostaddr((SOCKADDR_IN *)buf);
        !           592:                        }
        !           593:                }
        !           594:                
        !           595:                BEGINBLOCKING;
        !           596: 
        !           597:                for (;;)
        !           598:                {
        !           599:                        sb->resultval = to ? sendto(s,realpt,len,flags,(struct sockaddr *)buf,tolen) : send(s,realpt,len,flags);
        !           600:                
        !           601:                        if (sb->resultval == -1)
        !           602:                        {
        !           603:                                SETERRNO;
        !           604:                                if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING)) break;
        !           605:                        }
        !           606:                        else
        !           607:                        {
        !           608:                                realpt += sb->resultval;
        !           609:                                len -= sb->resultval;
        !           610:                                
        !           611:                                if (len <= 0) break;
        !           612:                                else continue;
        !           613:                        }
        !           614: 
        !           615:                        if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
        !           616:                        {
        !           617:                                WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_WRITE);
        !           618:                        
        !           619:                                WAITSIGNAL;
        !           620:                                
        !           621:                                cancelasyncmsg(wMsg);
        !           622:                                
        !           623:                                if (sb->eintr)
        !           624:                                {
        !           625:                                        TRACE(("[interrupted]\n"));
        !           626:                                        return;
        !           627:                                }
        !           628:                        }
        !           629:                        else break;
        !           630:                }
        !           631: 
        !           632:                ENDBLOCKING;
        !           633:        }
        !           634:        else sb->resultval = -1;
        !           635: 
        !           636: #ifdef TRACING_ENABLED
        !           637:        if (sb->resultval == -1) TRACE(("failed (%d)\n",sb->sb_errno))
        !           638:        else TRACE(("%d\n",sb->resultval));
        !           639: #endif
        !           640: }
        !           641: 
        !           642: void host_recvfrom(SB, uae_u32 sd, uae_u32 msg, uae_u32 len, uae_u32 flags, uae_u32 addr, uae_u32 addrlen)
        !           643: {
        !           644:        SOCKET s;
        !           645:        char *realpt;
        !           646:        struct sockaddr *rp_addr = NULL;
        !           647:        int hlen;
        !           648:        char buf[MAXADDRLEN];
        !           649:        unsigned int wMsg;
        !           650: 
        !           651: #ifdef TRACING_ENABLED
        !           652:        if (addr) TRACE(("recvfrom(%d,0x%lx,%d,0x%lx,0x%lx,0x%lx) -> ",sd,msg,len,flags,addr,addrlen))
        !           653:        else TRACE(("recv(%d,0x%lx,%d,0x%lx) -> ",sd,msg,len,flags));
        !           654: #endif
        !           655: 
        !           656:        s = getsock(sb,sd);
        !           657: 
        !           658:        if (s != INVALID_SOCKET)
        !           659:        {
        !           660:                realpt = get_real_address(msg);
        !           661: 
        !           662:                if (addr)
        !           663:                {
        !           664:                        hlen = get_long(addrlen);
        !           665:                        rp_addr = (struct sockaddr *)get_real_address(addr);
        !           666:                }
        !           667: 
        !           668:                BEGINBLOCKING;
        !           669: 
        !           670:                for (;;)
        !           671:                {
        !           672:                        sb->resultval = addr ? recvfrom(s,realpt,len,flags,rp_addr,&hlen) : recv(s,realpt,len,flags);
        !           673: 
        !           674:                        if (sb->resultval == -1)
        !           675:                        {
        !           676:                                SETERRNO;
        !           677:                        
        !           678:                                if (sb->sb_errno == WSAEWOULDBLOCK-WSABASEERR && sb->ftable[sd-1] & SF_BLOCKING)
        !           679:                                {
        !           680:                                        if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
        !           681:                                        {
        !           682:                                                WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_READ);
        !           683: 
        !           684:                                                WAITSIGNAL;
        !           685:                                        
        !           686:                                                cancelasyncmsg(wMsg);
        !           687:                                        
        !           688:                                                if (sb->eintr)
        !           689:                                                {
        !           690:                                                        TRACE(("[interrupted]\n"));
        !           691:                                                        return;
        !           692:                                                }
        !           693:                                        }
        !           694:                                        else break;
        !           695:                                }
        !           696:                                else break;
        !           697:                        }
        !           698:                        else break;
        !           699:                }
        !           700:                
        !           701:                ENDBLOCKING;
        !           702: 
        !           703:                if (addr)
        !           704:                {
        !           705:                        prepamigaaddr(rp_addr,hlen);
        !           706:                        put_long(addrlen,hlen);
        !           707:                }
        !           708:        }
        !           709:        else sb->resultval = -1;
        !           710: 
        !           711: #ifdef TRACING_ENABLED
        !           712:        if (sb->resultval == -1) TRACE(("failed (%d)\n",sb->sb_errno))
        !           713:        else TRACE(("%d\n",sb->resultval));
        !           714: #endif
        !           715: }
        !           716: 
        !           717: uae_u32 host_shutdown(SB, uae_u32 sd, uae_u32 how)
        !           718: {
        !           719:        SOCKET s;
        !           720:        
        !           721:        TRACE(("shutdown(%d,%d) -> ",sd,how));
        !           722:        
        !           723:        s = getsock(sb,sd);
        !           724: 
        !           725:        if (s != INVALID_SOCKET)
        !           726:        {
        !           727:                if (shutdown(s,how))
        !           728:                {
        !           729:                        SETERRNO;
        !           730:                        TRACE(("failed (%d)\n",sb->sb_errno));
        !           731:                }
        !           732:                else
        !           733:                {
        !           734:                        TRACE(("OK\n"));
        !           735:                        return 0;
        !           736:                }
        !           737:        }
        !           738:        
        !           739:        return -1;
        !           740: }
        !           741: 
        !           742: void host_setsockopt(SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 len)
        !           743: {
        !           744:        SOCKET s;
        !           745:        char buf[MAXADDRLEN];
        !           746: 
        !           747:        TRACE(("setsockopt(%d,%d,0x%lx,0x%lx,%d) -> ",sd,(short)level,optname,optval,len));
        !           748: 
        !           749:        s = getsock(sb,sd);
        !           750: 
        !           751:        if (s != INVALID_SOCKET)
        !           752:        {
        !           753:                if (len > sizeof buf)
        !           754:                {
        !           755:                        write_log("bsdsocket: WARNING: Excessive optlen in setsockopt() (%d)\n",len);
        !           756:                        len = sizeof buf;
        !           757:                }       
        !           758:                
        !           759:                if (level == SOL_SOCKET && optname == SO_LINGER)
        !           760:                {
        !           761:                        ((LINGER *)buf)->l_onoff = get_long(optval);
        !           762:                        ((LINGER *)buf)->l_linger = get_long(optval+4);
        !           763:                }
        !           764:                else
        !           765:                {
        !           766:                        if (len == 4) *(long *)buf = get_long(optval);
        !           767:                        else if (len == 2) *(short *)buf = get_word(optval);
        !           768:                        else write_log("bsdsocket: ERROR: Unknown optlen (%d) in setsockopt(%d,%d)\n",level,optname);
        !           769:                }
        !           770: 
        !           771:                // handle SO_EVENTMASK
        !           772:                if (level == 0xffff && optname == 0x2001)
        !           773:                {
        !           774:                        long wsbevents = 0;
        !           775:                        uae_u32 eventflags = get_long(optval);
        !           776: 
        !           777:                        sb->ftable[sd-1] = (sb->ftable[sd-1] & ~REP_ALL) | (eventflags & REP_ALL);
        !           778: 
        !           779:                        if (eventflags & REP_ACCEPT) wsbevents |= FD_ACCEPT;
        !           780:                        if (eventflags & REP_CONNECT) wsbevents |= FD_CONNECT;
        !           781:                        if (eventflags & REP_OOB) wsbevents |= FD_OOB;
        !           782:                        if (eventflags & REP_READ) wsbevents |= FD_READ;
        !           783:                        if (eventflags & REP_WRITE) wsbevents |= FD_WRITE;
        !           784:                        if (eventflags & REP_CLOSE) wsbevents |= FD_CLOSE;
        !           785:                        
        !           786:                        if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(sb,sd,s)))
        !           787:                        {
        !           788:                                WSAAsyncSelect(s,hAmigaWnd,sb->mtable[sd-1],wsbevents);
        !           789:                                sb->resultval = 0;
        !           790:                        }
        !           791:                        else sb->resultval = -1;
        !           792:                }
        !           793:                else sb->resultval = setsockopt(s,level,optname,buf,len);
        !           794:                
        !           795:                if (!sb->resultval)
        !           796:                {
        !           797:                        TRACE(("OK\n"));
        !           798:                        return;
        !           799:                }
        !           800:                else SETERRNO;
        !           801:                
        !           802:                TRACE(("failed (%d)\n",sb->sb_errno));
        !           803:        }
        !           804: }
        !           805: 
        !           806: uae_u32 host_getsockopt(SB, uae_u32 sd, uae_u32 level, uae_u32 optname, uae_u32 optval, uae_u32 optlen)
        !           807: {
        !           808:        SOCKET s;
        !           809:        char buf[MAXADDRLEN];
        !           810:        int len = sizeof(buf);
        !           811: 
        !           812:        TRACE(("getsockopt(%d,%d,0x%lx,0x%lx,0x%lx) -> ",sd,(short)level,optname,optval,optlen));
        !           813: 
        !           814:        s = getsock(sb,sd);
        !           815:        
        !           816:        if (s != INVALID_SOCKET)
        !           817:        {
        !           818:                if (!getsockopt(s,level,optname,buf,&len))
        !           819:                {
        !           820:                        if (level == SOL_SOCKET && optname == SO_LINGER)
        !           821:                        {
        !           822:                                put_long(optval,((LINGER *)buf)->l_onoff);
        !           823:                                put_long(optval+4,((LINGER *)buf)->l_linger);
        !           824:                        }
        !           825:                        else
        !           826:                        {
        !           827:                                if (len == 4) put_long(optval,*(long *)buf);
        !           828:                                else if (len == 2) put_word(optval,*(short *)buf);
        !           829:                                else write_log("bsdsocket: ERROR: Unknown optlen (%d) in setsockopt(%d,%d)\n",level,optname);
        !           830:                        }
        !           831: 
        !           832: //                     put_long(optlen,len); // some programs pass the actual ength instead of a pointer to the length, so...
        !           833:                        TRACE(("OK (%d,%d)\n",len,*(long *)buf));
        !           834:                        return 0;
        !           835:                }
        !           836:                else
        !           837:                {
        !           838:                        SETERRNO;
        !           839:                        TRACE(("failed (%d)\n",sb->sb_errno));
        !           840:                }
        !           841:        }
        !           842: 
        !           843:        return -1;
        !           844: }
        !           845: 
        !           846: uae_u32 host_getsockname(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
        !           847: {
        !           848:        SOCKET s;
        !           849:        int len;
        !           850:        struct sockaddr *rp_name;
        !           851:        
        !           852:        len = get_long(namelen);
        !           853:        
        !           854:        TRACE(("getsockname(%d,0x%lx,%d) -> ",sd,name,len));
        !           855:        
        !           856:        s = getsock(sb,sd);
        !           857:        
        !           858:        if (s != INVALID_SOCKET)
        !           859:        {
        !           860:                rp_name = (struct sockaddr *)get_real_address(name);
        !           861:                
        !           862:                if (getsockname(s,rp_name,&len))
        !           863:                {
        !           864:                        SETERRNO;
        !           865:                        TRACE(("failed (%d)\n",sb->sb_errno));
        !           866:                }
        !           867:                else
        !           868:                {
        !           869:                        TRACE(("%d\n",len));
        !           870:                        prepamigaaddr(rp_name,len);
        !           871:                        put_long(namelen,len);
        !           872:                        return 0;
        !           873:                }
        !           874:        }       
        !           875: 
        !           876:        return -1;
        !           877: }
        !           878: 
        !           879: uae_u32 host_getpeername(SB, uae_u32 sd, uae_u32 name, uae_u32 namelen)
        !           880: {
        !           881:        SOCKET s;
        !           882:        int len;
        !           883:        struct sockaddr *rp_name;
        !           884:        
        !           885:        len = get_long(namelen);
        !           886:        
        !           887:        TRACE(("getpeername(%d,0x%lx,%d) -> ",sd,name,len));
        !           888:        
        !           889:        s = getsock(sb,sd);
        !           890:        
        !           891:        if (s != INVALID_SOCKET)
        !           892:        {
        !           893:                rp_name = (struct sockaddr *)get_real_address(name);
        !           894:                
        !           895:                if (getpeername(s,rp_name,&len))
        !           896:                {
        !           897:                        SETERRNO;
        !           898:                        TRACE(("failed (%d)\n",sb->sb_errno));
        !           899:                }
        !           900:                else
        !           901:                {
        !           902:                        TRACE(("%d\n",len));
        !           903:                        prepamigaaddr(rp_name,len);
        !           904:                        put_long(namelen,len);
        !           905:                        return 0;
        !           906:                }
        !           907:        }       
        !           908: 
        !           909:        return -1;
        !           910: }
        !           911: 
        !           912: uae_u32 host_IoctlSocket(SB, uae_u32 sd, uae_u32 request, uae_u32 arg)
        !           913: {
        !           914:        SOCKET s;
        !           915:        uae_u32 data;
        !           916:        int success = SOCKET_ERROR;
        !           917: 
        !           918:        TRACE(("IoctlSocket(%d,0x%lx,0x%lx) ",sd,request,arg));
        !           919: 
        !           920:        s = getsock(sb,sd);
        !           921: 
        !           922:        if (s != INVALID_SOCKET)
        !           923:        {
        !           924:                switch (request)
        !           925:                {
        !           926:                        case FIONBIO:
        !           927:                                TRACE(("[FIONBIO] -> "));
        !           928:                                if (get_long(arg))
        !           929:                                {
        !           930:                                        TRACE(("nonblocking\n"));
        !           931:                                        sb->ftable[sd-1] &= ~SF_BLOCKING;
        !           932:                                }
        !           933:                                else
        !           934:                                {
        !           935:                                        TRACE(("blocking\n"));
        !           936:                                        sb->ftable[sd-1] |= SF_BLOCKING;
        !           937:                                }
        !           938:                                success = 0;
        !           939:                                break;
        !           940:                        case FIONREAD:
        !           941:                                ioctlsocket(s,request,(u_long *)&data);
        !           942:                                TRACE(("[FIONREAD] -> %d\n",data));
        !           943:                                put_long(arg,data);
        !           944:                                success = 0;
        !           945:                                break;
        !           946:                        case FIOASYNC:
        !           947:                                if (get_long(arg))
        !           948:                                {
        !           949:                                        sb->ftable[sd-1] |= REP_ALL;
        !           950: 
        !           951:                                        TRACE(("[FIOASYNC] -> enabled\n"));
        !           952:                                        if (sb->mtable[sd-1] || (sb->mtable[sd-1] = allocasyncmsg(sb,sd,s)))
        !           953:                                        {
        !           954:                                                WSAAsyncSelect(s,hAmigaWnd,sb->mtable[sd-1],FD_ACCEPT | FD_CONNECT | FD_OOB | FD_READ | FD_WRITE | FD_CLOSE);
        !           955:                                                success = 0;
        !           956:                                                break;
        !           957:                                        }
        !           958:                                }
        !           959:                                else write_log(("bsdsocket: WARNING: FIOASYNC disabling unsupported.\n"));
        !           960: 
        !           961:                                success = -1;
        !           962:                                break;
        !           963:                        default:
        !           964:                                write_log("bsdsocket: WARNING: Unknown IoctlSocket request: 0x%08lx\n",request);
        !           965:                                seterrno(sb,22);        // EINVAL
        !           966:                }
        !           967:        }
        !           968:        
        !           969:        return success;
        !           970: }
        !           971: 
        !           972: int host_CloseSocket(SB, int sd)
        !           973: {
        !           974:        unsigned int wMsg;
        !           975:        SOCKET s;
        !           976: 
        !           977:        TRACE(("CloseSocket(%d) -> ",sd));
        !           978: 
        !           979:        s = getsock(sb,sd);
        !           980: 
        !           981:        if (s != INVALID_SOCKET)
        !           982:        {
        !           983:                if (sb->mtable[sd-1])
        !           984:                {
        !           985:                        asyncsb[(sb->mtable[sd-1]-0xb000)/2] = NULL;
        !           986:                        sb->mtable[sd-1] = 0;
        !           987:                }
        !           988: 
        !           989:                BEGINBLOCKING;
        !           990: 
        !           991:                for (;;)
        !           992:                {
        !           993:                        if (!closesocket(s))
        !           994:                        {
        !           995:                                releasesock(sb,sd);
        !           996:                                TRACE(("OK\n"));
        !           997:                                return 0;
        !           998:                        }
        !           999: 
        !          1000:                        SETERRNO;
        !          1001:        
        !          1002:                        if (sb->sb_errno != WSAEWOULDBLOCK-WSABASEERR || !(sb->ftable[sd-1] & SF_BLOCKING)) break;
        !          1003:        
        !          1004:                        if ((wMsg = allocasyncmsg(sb,sd,s)) != 0)
        !          1005:                        {
        !          1006:                                WSAAsyncSelect(s,hAmigaWnd,wMsg,FD_CLOSE);
        !          1007:                        
        !          1008:                                WAITSIGNAL;
        !          1009:                                
        !          1010:                                cancelasyncmsg(wMsg);
        !          1011:                                
        !          1012:                                if (sb->eintr)
        !          1013:                                {
        !          1014:                                        TRACE(("[interrupted]\n"));
        !          1015:                                        break;
        !          1016:                                }
        !          1017:                        }
        !          1018:                        else break;
        !          1019:                }
        !          1020: 
        !          1021:                ENDBLOCKING;
        !          1022:        }
        !          1023:        
        !          1024:        TRACE(("failed (%d)\n",sb->sb_errno));
        !          1025:        
        !          1026:        return -1;
        !          1027: }
        !          1028: 
        !          1029: // For the sake of efficiency, we do not malloc() the fd_sets here.
        !          1030: // 64 sockets should be enough for everyone.
        !          1031: static void makesocktable(SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds, SOCKET addthis)
        !          1032: {
        !          1033:        int i, j, maxbit;
        !          1034:        uae_u32 currlong, mask;
        !          1035:        SOCKET s;
        !          1036: 
        !          1037:        if (addthis != INVALID_SOCKET)
        !          1038:        {
        !          1039:                *fd_set_win->fd_array = addthis;
        !          1040:                fd_set_win->fd_count = 1;
        !          1041:        }
        !          1042:        else fd_set_win->fd_count = 0;
        !          1043: 
        !          1044:        if (!fd_set_amiga)
        !          1045:        {
        !          1046:                fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
        !          1047:                return;
        !          1048:        }
        !          1049: 
        !          1050:        if (nfds > sb->dtablesize)
        !          1051:        {
        !          1052:                write_log("bsdsock: ERROR: select()ing more sockets (%d) than socket descriptors available (%d)!\n",nfds,sb->dtablesize);
        !          1053:                nfds = sb->dtablesize;
        !          1054:        }
        !          1055: 
        !          1056:        for (j = 0; ; j += 32, fd_set_amiga += 4)
        !          1057:        {
        !          1058:                currlong = get_long(fd_set_amiga);
        !          1059: 
        !          1060:                mask = 1;
        !          1061: 
        !          1062:                for (i = 0; i < 32; i++, mask <<= 1)
        !          1063:                {
        !          1064:                        if (i+j > nfds)
        !          1065:                        {
        !          1066:                                fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
        !          1067:                                return;
        !          1068:                        }
        !          1069:                        
        !          1070:                        if (currlong & mask)
        !          1071:                        {
        !          1072:                                s = getsock(sb,j+i);
        !          1073:                                
        !          1074:                                if (s != INVALID_SOCKET)
        !          1075:                                {
        !          1076:                                        fd_set_win->fd_array[fd_set_win->fd_count++] = s;
        !          1077: 
        !          1078:                                        if (fd_set_win->fd_count >= FD_SETSIZE)
        !          1079:                                        {
        !          1080:                                                write_log("bsdsock: ERROR: select()ing more sockets (%d) than the hard-coded fd_set limit (%d) - please report\n",nfds,FD_SETSIZE);
        !          1081:                                                return;
        !          1082:                                        }
        !          1083:                                }
        !          1084:                        }
        !          1085:                }
        !          1086:        }
        !          1087: 
        !          1088:        fd_set_win->fd_array[fd_set_win->fd_count] = INVALID_SOCKET;
        !          1089: }
        !          1090: 
        !          1091: static void makesockbitfield(SB, uae_u32 fd_set_amiga, struct fd_set *fd_set_win, int nfds)
        !          1092: {
        !          1093:        int n, i, j, val, mask;
        !          1094:        SOCKET currsock;
        !          1095: 
        !          1096:        for (n = 0; n < nfds; n += 32)
        !          1097:        {
        !          1098:                val = 0;
        !          1099:                mask = 1;
        !          1100:                
        !          1101:                for (i = 0; i < 32; i++, mask <<= 1)
        !          1102:                {
        !          1103:                        if ((n || i) && (currsock = sb->dtable[n+i-1]) != INVALID_SOCKET)
        !          1104:                        {
        !          1105:                                for (j = fd_set_win->fd_count; j--; )
        !          1106:                                {
        !          1107:                                        if (fd_set_win->fd_array[j] == currsock)
        !          1108:                                        {
        !          1109:                                                val |= mask;
        !          1110:                                                break;
        !          1111:                                        }
        !          1112:                                }
        !          1113:                        }
        !          1114:                }
        !          1115: 
        !          1116:                put_long(fd_set_amiga,val);
        !          1117:        }
        !          1118: }
        !          1119: 
        !          1120: static void fd_zero(uae_u32 fdset, uae_u32 nfds)
        !          1121: {
        !          1122:        unsigned int i;
        !          1123:        
        !          1124:        for (i = 0; i < nfds; i += 32, fdset += 4) put_long(fdset,0);
        !          1125: }
        !          1126: 
        !          1127: // This seems to be the only way of implementing a cancelable WinSock2 select() call... sigh.
        !          1128: static void thread_WaitSelect(uae_u32 index)
        !          1129: {
        !          1130:        long nfds;
        !          1131:        uae_u32 readfds, writefds, exceptfds;
        !          1132:        uae_u32 timeout;
        !          1133:        uae_u32 sigmp;
        !          1134:        struct fd_set readsocks, writesocks, exceptsocks;
        !          1135:        struct timeval tv;
        !          1136:        uae_u32 *args;
        !          1137: 
        !          1138:        SB;
        !          1139: 
        !          1140:        for (;;)
        !          1141:        {
        !          1142:                WaitForSingleObject(hEvents[index],INFINITE);
        !          1143: 
        !          1144:                if ((args = threadargs[index]) != NULL)
        !          1145:                {
        !          1146:                        sb = (struct socketbase *)*args;
        !          1147:                        nfds = args[1];
        !          1148:                        readfds = args[2];
        !          1149:                        writefds = args[3];
        !          1150:                        exceptfds = args[4];
        !          1151:                        timeout = args[5];
        !          1152:                
        !          1153:                        // construct descriptor tables
        !          1154:                        makesocktable(sb,readfds,&readsocks,nfds,sb->sockAbort);
        !          1155:                        if (writefds) makesocktable(sb,writefds,&writesocks,nfds,INVALID_SOCKET);
        !          1156:                        if (exceptfds) makesocktable(sb,exceptfds,&exceptsocks,nfds,INVALID_SOCKET);
        !          1157:                
        !          1158:                        if (timeout)
        !          1159:                        {
        !          1160:                                tv.tv_sec = get_long(timeout);
        !          1161:                                tv.tv_usec = get_long(timeout+4);
        !          1162:                                TRACE(("(timeout: %d.%06d) ",tv.tv_sec,tv.tv_usec))
        !          1163:                        }
        !          1164:                
        !          1165:                        TRACE(("-> "));
        !          1166:                
        !          1167:                        sb->resultval = select(nfds+1,&readsocks,writefds ? &writesocks : NULL,exceptfds ? &exceptsocks : NULL,timeout ? &tv : 0);
        !          1168:                        sb->needAbort = 0;
        !          1169: 
        !          1170:                        if (sb->resultval == SOCKET_ERROR)
        !          1171:                        {
        !          1172:                                SETERRNO;
        !          1173:                                TRACE(("failed (%d) - ",sb->sb_errno));
        !          1174:                                if (readfds) fd_zero(readfds,nfds);
        !          1175:                                if (writefds) fd_zero(writefds,nfds);
        !          1176:                                if (exceptfds) fd_zero(exceptfds,nfds);
        !          1177:                        }
        !          1178:                        else
        !          1179:                        {
        !          1180:                                if (readfds) makesockbitfield(sb,readfds,&readsocks,nfds);
        !          1181:                                if (writefds) makesockbitfield(sb,writefds,&writesocks,nfds);
        !          1182:                                if (exceptfds) makesockbitfield(sb,exceptfds,&exceptsocks,nfds);
        !          1183:                        }
        !          1184:                
        !          1185:                        SETSIGNAL;
        !          1186: 
        !          1187:                        threadargs[index] = NULL;
        !          1188:                        SetEvent(sb->hEvent);
        !          1189:                }
        !          1190:        }
        !          1191: }
        !          1192: 
        !          1193: void __stdcall host_WaitSelect(SB, uae_u32 nfds, uae_u32 readfds, uae_u32 writefds, uae_u32 exceptfds, uae_u32 timeout, uae_u32 sigmp)
        !          1194: {
        !          1195:        uae_u32 sigs, wssigs;
        !          1196:        int i;
        !          1197: 
        !          1198:        wssigs = sigmp ? get_long(sigmp) : 0;
        !          1199: 
        !          1200:        TRACE(("WaitSelect(%d,0x%lx,0x%lx,0x%lx,0x%lx,0x%lx) ",nfds,readfds,writefds,exceptfds,timeout,wssigs));
        !          1201: 
        !          1202:        if (!readfds && !writefds && !exceptfds && !timeout && !wssigs)
        !          1203:        {
        !          1204:                sb->resultval = 0;
        !          1205:                TRACE(("-> [ignored]\n"))
        !          1206:                return;
        !          1207:        }
        !          1208: 
        !          1209:        if (wssigs)
        !          1210:        {
        !          1211:                m68k_dreg(regs,0) = 0;
        !          1212:                m68k_dreg(regs,1) = wssigs;
        !          1213:                sigs = CallLib(get_long(4),-0x132) & wssigs;    // SetSignal()
        !          1214:                
        !          1215:                if (sigs)
        !          1216:                {
        !          1217:                        TRACE(("-> [preempted by signals 0x%08lx]\n",sigs & wssigs));
        !          1218:                        put_long(sigmp,sigs & wssigs);
        !          1219:                        fd_zero(readfds,nfds);
        !          1220:                        fd_zero(writefds,nfds);
        !          1221:                        fd_zero(exceptfds,nfds);
        !          1222:                        sb->resultval = 0;
        !          1223:                        seterrno(sb,0);
        !          1224:                        return;
        !          1225:                }
        !          1226:        }
        !          1227: 
        !          1228:        ResetEvent(sb->hEvent);
        !          1229: 
        !          1230:        sb->needAbort = 1;
        !          1231: 
        !          1232:        for (i = 0; i < MAX_SELECT_THREADS; i++) if (hThreads[i] && !threadargs[i]) break;
        !          1233: 
        !          1234:        if (i >= MAX_SELECT_THREADS)
        !          1235:        {
        !          1236:                for (i = 0; i < MAX_SELECT_THREADS; i++) if (!hThreads[i])
        !          1237:                {
        !          1238:                        if ((hEvents[i] = CreateEvent(NULL,FALSE,FALSE,NULL)) == NULL || (hThreads[i] = THREAD(thread_WaitSelect,i)) == NULL)
        !          1239:                        {
        !          1240:                                hThreads[i] = 0;
        !          1241:                                write_log("bsdsocket: ERROR: Thread/Event creation failed - error code: %d\n",GetLastError());
        !          1242:                                seterrno(sb,12);        // ENOMEM
        !          1243:                                sb->resultval = -1;
        !          1244:                                return;
        !          1245:                        }
        !          1246: 
        !          1247:                        // this should improve responsiveness
        !          1248:                        SetThreadPriority(hThreads[i],THREAD_PRIORITY_TIME_CRITICAL);
        !          1249:                        break;
        !          1250:                }
        !          1251:        }
        !          1252:        
        !          1253:        if (i >= MAX_SELECT_THREADS) write_log("bsdsocket: ERROR: Too many select()s\n");
        !          1254:        else
        !          1255:        {
        !          1256:                SOCKET newsock = INVALID_SOCKET;
        !          1257: 
        !          1258:                threadargs[i] = (uae_u32 *)&sb;
        !          1259: 
        !          1260:                SetEvent(hEvents[i]);
        !          1261: 
        !          1262:                m68k_dreg(regs,0) = (((uae_u32)1)<<sb->signal)|sb->eintrsigs|wssigs;
        !          1263:                sigs = CallLib(get_long(4),-0x13e);     // Wait()
        !          1264: 
        !          1265:                if (sb->needAbort)
        !          1266:                {
        !          1267:                        if ((newsock = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == INVALID_SOCKET)
        !          1268:                                write_log("bsdsocket: ERROR: Cannot create socket: %d\n",WSAGetLastError());
        !          1269: 
        !          1270:                        closesocket(sb->sockAbort);
        !          1271:                }
        !          1272: 
        !          1273:                WaitForSingleObject(sb->hEvent,INFINITE);
        !          1274: 
        !          1275:                CANCELSIGNAL;
        !          1276: 
        !          1277:                if (newsock != INVALID_SOCKET) sb->sockAbort = newsock;
        !          1278: 
        !          1279:                put_long(sigmp,sigs & wssigs);
        !          1280: 
        !          1281:                if (sigs & sb->eintrsigs)
        !          1282:                {
        !          1283:                        TRACE(("[interrupted]\n"));
        !          1284:                        sb->resultval = -1;
        !          1285:                        seterrno(sb,4); // EINTR
        !          1286:                }
        !          1287:                else if (sigs & wssigs)
        !          1288:                {
        !          1289:                        TRACE(("[interrupted by signals 0x%08lx]\n",sigs & wssigs));
        !          1290:                        sb->resultval = 0;
        !          1291:                        seterrno(sb,0);
        !          1292:                }
        !          1293:                else TRACE(("%d\n",sb->resultval));
        !          1294:        }
        !          1295: }
        !          1296: 
        !          1297: uae_u32 host_Inet_NtoA(SB, uae_u32 in)
        !          1298: {
        !          1299:        char *addr;
        !          1300:        struct in_addr ina;
        !          1301:        uae_u32 scratchbuf;
        !          1302: 
        !          1303:        *(uae_u32 *)&ina = htonl(in);
        !          1304: 
        !          1305:        TRACE(("Inet_NtoA(%lx) -> ",in));
        !          1306: 
        !          1307:        if ((addr = inet_ntoa(ina)) != NULL)
        !          1308:        {
        !          1309:                scratchbuf = m68k_areg(regs,6)+offsetof(struct UAEBSDBase,scratchbuf);
        !          1310:                strncpyha(scratchbuf,addr,SCRATCHBUFSIZE);
        !          1311:                TRACE(("%s\n",addr));
        !          1312:                return scratchbuf;
        !          1313:        }
        !          1314:        else SETERRNO;
        !          1315: 
        !          1316:        TRACE(("failed (%d)\n",sb->sb_errno));
        !          1317: 
        !          1318:        return 0;
        !          1319: }
        !          1320: 
        !          1321: uae_u32 host_inet_addr(uae_u32 cp)
        !          1322: {
        !          1323:        uae_u32 addr;
        !          1324:        char *cp_rp;
        !          1325: 
        !          1326:        cp_rp = get_real_address(cp);
        !          1327: 
        !          1328:        addr = htonl(inet_addr(cp_rp));
        !          1329: 
        !          1330:        TRACE(("inet_addr(%s) -> 0x%08lx\n",cp_rp,addr));
        !          1331: 
        !          1332:        return addr;
        !          1333: }
        !          1334: 
        !          1335: void host_gethostbynameaddr(SB, uae_u32 name, uae_u32 namelen, long addrtype)
        !          1336: {
        !          1337:        HOSTENT *h;
        !          1338:        int size, numaliases = 0, numaddr = 0;
        !          1339:        uae_u32 aptr, asize;
        !          1340:        char *name_rp;
        !          1341:        int i;
        !          1342:        uae_u32 addr;
        !          1343:        uae_u32 *addr_list[2];
        !          1344: 
        !          1345:        char buf[MAXGETHOSTSTRUCT];
        !          1346:        unsigned int wMsg = 0;
        !          1347: 
        !          1348:        name_rp = get_real_address(name);
        !          1349: 
        !          1350:        if (addrtype == -1)
        !          1351:        {
        !          1352:                TRACE(("gethostbyname(%s) -> ",name_rp));
        !          1353:                
        !          1354:                // workaround for numeric host "names"
        !          1355:                if ((addr = inet_addr(name_rp)) != INADDR_NONE)
        !          1356:                {
        !          1357:                        seterrno(sb,0);
        !          1358:                        ((HOSTENT *)buf)->h_name = name_rp;
        !          1359:                        ((HOSTENT *)buf)->h_aliases = NULL;
        !          1360:                        ((HOSTENT *)buf)->h_addrtype = AF_INET;
        !          1361:                        ((HOSTENT *)buf)->h_length = 4;
        !          1362:                        ((HOSTENT *)buf)->h_addr_list = (char **)&addr_list;
        !          1363:                        addr_list[0] = &addr;
        !          1364:                        addr_list[1] = NULL;
        !          1365:        
        !          1366:                        goto kludge;
        !          1367:                }
        !          1368:        }
        !          1369:        else
        !          1370:        {
        !          1371:                TRACE(("gethostbyaddr(0x%lx,0x%lx,%ld) -> ",name,namelen,addrtype));
        !          1372:        }
        !          1373:        
        !          1374:        if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
        !          1375:        {
        !          1376:                if ((sb->hAsyncTask = addrtype == -1 ? WSAAsyncGetHostByName(hAmigaWnd,wMsg,name_rp,buf,sizeof buf) : WSAAsyncGetHostByAddr(hAmigaWnd,wMsg,name_rp,namelen,addrtype,buf,sizeof buf)) != NULL)
        !          1377:                {
        !          1378:                        while (sb->hAsyncTask) WAITSIGNAL;
        !          1379: 
        !          1380:                        sockabort(sb);
        !          1381: 
        !          1382:                        if (!sb->sb_errno)
        !          1383:                        {
        !          1384: kludge:
        !          1385:                                h = (HOSTENT *)buf;
        !          1386:                                
        !          1387:                                // compute total size of hostent
        !          1388:                                size = 28;
        !          1389:                                if (h->h_name != NULL) size += strlen(h->h_name)+1;
        !          1390:                
        !          1391:                                if (h->h_aliases != NULL)
        !          1392:                                        while (h->h_aliases[numaliases]) size += strlen(h->h_aliases[numaliases++])+5;
        !          1393:                
        !          1394:                                if (h->h_addr_list != NULL)
        !          1395:                                {
        !          1396:                                        while (h->h_addr_list[numaddr]) numaddr++;
        !          1397:                                        size += numaddr*(h->h_length+4);
        !          1398:                                }
        !          1399:                
        !          1400:                                if (sb->hostent)
        !          1401:                                {
        !          1402:                                        m68k_areg(regs,1) = sb->hostent;
        !          1403:                                        m68k_dreg(regs,0) = sb->hostentsize;
        !          1404:                                        CallLib(get_long(4),-0xd2);     // FreeMem()
        !          1405:                                }
        !          1406:                
        !          1407:                                m68k_dreg(regs,0) = size;
        !          1408:                                m68k_dreg(regs,1) = 0;
        !          1409:                                sb->hostent = CallLib(get_long(4),-0xc6); // AllocMem()
        !          1410:                
        !          1411:                                if (!sb->hostent)
        !          1412:                                {
        !          1413:                                        write_log("bsdsocket: 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);
        !          1414:                                        seterrno(sb,12); // ENOMEM
        !          1415:                                        return;
        !          1416:                                }
        !          1417:                                
        !          1418:                                sb->hostentsize = size;
        !          1419:                                
        !          1420:                                aptr = sb->hostent+28+numaliases*4+numaddr*4;
        !          1421:                        
        !          1422:                                // transfer hostent to Amiga memory
        !          1423:                                put_long(sb->hostent+4,sb->hostent+20);
        !          1424:                                put_long(sb->hostent+8,h->h_addrtype);
        !          1425:                                put_long(sb->hostent+12,h->h_length);
        !          1426:                                put_long(sb->hostent+16,sb->hostent+24+numaliases*4);
        !          1427:                                
        !          1428:                                for (i = 0; i < numaliases; i++) put_long(sb->hostent+20+i*4,addstr(&aptr,h->h_aliases[i]));
        !          1429:                                put_long(sb->hostent+20+numaliases*4,0);
        !          1430:                                for (i = 0; i < numaddr; i++) put_long(sb->hostent+24+(numaliases+i)*4,addmem(&aptr,h->h_addr_list[i],h->h_length));
        !          1431:                                put_long(sb->hostent+24+numaliases*4+numaddr*4,0);
        !          1432:                                put_long(sb->hostent,aptr);
        !          1433:                                addstr(&aptr,h->h_name);
        !          1434: 
        !          1435:                                TRACE(("OK (%s)\n",h->h_name));
        !          1436:                                seterrno(sb,0);
        !          1437:                        }
        !          1438:                        else
        !          1439:                        {
        !          1440:                                TRACE(("failed (%d/%d)\n",sb->sb_errno,sb->sb_herrno))
        !          1441:                        }
        !          1442:                }
        !          1443:                else
        !          1444:                {
        !          1445:                        seterrno(sb,12); // ENOMEM - well...
        !          1446:                        write_log("bsdsocket: ERROR: WSAAsyncGetHostBy%s() failed - error code: %d\n",addrtype == -1 ? "Name" : "Addr",WSAGetLastError());
        !          1447:                }
        !          1448: 
        !          1449:                if (wMsg) cancelasyncmsg(wMsg);
        !          1450:        }
        !          1451: }
        !          1452: 
        !          1453: void host_getservbynameport(SB, uae_u32 nameport, uae_u32 proto, uae_u32 type)
        !          1454: {
        !          1455:        SERVENT *s;
        !          1456:        int size, numaliases = 0;
        !          1457:        uae_u32 aptr, asize;
        !          1458:        char *name_rp = NULL, *proto_rp = NULL;
        !          1459:        int i;
        !          1460: 
        !          1461:        char buf[MAXGETHOSTSTRUCT];
        !          1462:        unsigned int wMsg;
        !          1463: 
        !          1464:        if (proto) proto_rp = get_real_address(proto);
        !          1465: 
        !          1466:        if (type)
        !          1467:        {
        !          1468:                TRACE(("getservbyport(%d,%s) -> ",nameport,proto_rp ? proto_rp : "NULL"));
        !          1469:        }
        !          1470:        else
        !          1471:        {
        !          1472:                name_rp = get_real_address(nameport);
        !          1473:                TRACE(("getservbyname(%s,%s) -> ",name_rp,proto_rp ? proto_rp : "NULL"));
        !          1474:        }
        !          1475: 
        !          1476:        if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
        !          1477:        {
        !          1478:                if ((sb->hAsyncTask = type ? WSAAsyncGetServByPort(hAmigaWnd,wMsg,nameport,proto_rp,buf,sizeof buf) : WSAAsyncGetServByName(hAmigaWnd,wMsg,name_rp,proto_rp,buf,sizeof buf)) != NULL)
        !          1479:                {
        !          1480:                        while (sb->hAsyncTask) WAITSIGNAL;
        !          1481: 
        !          1482:                        sockabort(sb);
        !          1483: 
        !          1484:                        if (!sb->sb_errno)
        !          1485:                        {
        !          1486:                                s = (SERVENT *)buf;
        !          1487: 
        !          1488:                                // compute total size of servent
        !          1489:                                size = 20;
        !          1490:                                if (s->s_name != NULL) size += strlen(s->s_name)+1;
        !          1491:                                if (s->s_proto != NULL) size += strlen(s->s_proto)+1;
        !          1492: 
        !          1493:                                if (s->s_aliases != NULL)
        !          1494:                                        while (s->s_aliases[numaliases]) size += strlen(s->s_aliases[numaliases++])+5;
        !          1495: 
        !          1496:                                if (sb->servent)
        !          1497:                                {
        !          1498:                                        m68k_areg(regs,1) = sb->servent;
        !          1499:                                        m68k_dreg(regs,0) = sb->serventsize;
        !          1500:                                        CallLib(get_long(4),-0xd2);     // FreeMem()
        !          1501:                                }
        !          1502: 
        !          1503:                                m68k_dreg(regs,0) = size;
        !          1504:                                m68k_dreg(regs,1) = 0;
        !          1505:                                sb->servent = CallLib(get_long(4),-0xc6); // AllocMem()
        !          1506: 
        !          1507:                                if (!sb->servent)
        !          1508:                                {
        !          1509:                                        write_log("bsdsocket: WARNING: getservby%s() ran out of Amiga memory (couldn't allocate %ld bytes)\n",type ? "port" : "name",size);
        !          1510:                                        seterrno(sb,12); // ENOMEM
        !          1511:                                        return;
        !          1512:                                }
        !          1513: 
        !          1514:                                sb->serventsize = size;
        !          1515:                                
        !          1516:                                aptr = sb->servent+20+numaliases*4;
        !          1517:                        
        !          1518:                                // transfer servent to Amiga memory
        !          1519:                                put_long(sb->servent+4,sb->servent+16);
        !          1520:                                put_long(sb->servent+8,(unsigned short)htons(s->s_port));
        !          1521:                                
        !          1522:                                for (i = 0; i < numaliases; i++) put_long(sb->servent+16+i*4,addstr(&aptr,s->s_aliases[i]));
        !          1523:                                put_long(sb->servent+16+numaliases*4,0);
        !          1524:                                put_long(sb->servent,aptr);
        !          1525:                                addstr(&aptr,s->s_name);
        !          1526:                                put_long(sb->servent+12,aptr);
        !          1527:                                addstr(&aptr,s->s_proto);
        !          1528: 
        !          1529:                                TRACE(("OK (%s, %d)\n",s->s_name,(unsigned short)htons(s->s_port)));
        !          1530:                                seterrno(sb,0);
        !          1531:                        }
        !          1532:                        else
        !          1533:                        {
        !          1534:                                TRACE(("failed (%d)\n",sb->sb_errno))
        !          1535:                        }
        !          1536:                }
        !          1537:                else
        !          1538:                {
        !          1539:                        seterrno(sb,12); // ENOMEM - well...
        !          1540:                        write_log("bsdsocket: ERROR: WSAAsyncGetServBy%s() failed - error code: %d\n",type ? "Port" : "Name",WSAGetLastError());
        !          1541:                }
        !          1542:                
        !          1543:                cancelasyncmsg(wMsg);
        !          1544:        }
        !          1545: }
        !          1546: 
        !          1547: void host_getprotobyname(SB, uae_u32 name)
        !          1548: {
        !          1549:        PROTOENT *p;
        !          1550:        int size, numaliases = 0;
        !          1551:        uae_u32 aptr, asize;
        !          1552:        char *name_rp;
        !          1553:        int i;
        !          1554: 
        !          1555:        char buf[MAXGETHOSTSTRUCT];
        !          1556:        unsigned int wMsg;
        !          1557: 
        !          1558:        name_rp = get_real_address(name);
        !          1559: 
        !          1560:        TRACE(("getprotobyname(%s) -> ",name_rp));
        !          1561:        
        !          1562:        if ((wMsg = allocasyncmsg(sb,0,INVALID_SOCKET)) != 0)
        !          1563:        {
        !          1564:                if ((sb->hAsyncTask = WSAAsyncGetProtoByName(hAmigaWnd,wMsg,name_rp,buf,sizeof buf)) != NULL)
        !          1565:                {
        !          1566:                        while (sb->hAsyncTask) WAITSIGNAL;
        !          1567: 
        !          1568:                        sockabort(sb);
        !          1569: 
        !          1570:                        if (!sb->sb_errno)
        !          1571:                        {
        !          1572:                                p = (PROTOENT *)buf;
        !          1573: 
        !          1574:                                // compute total size of protoent
        !          1575:                                size = 16;
        !          1576:                                if (p->p_name != NULL) size += strlen(p->p_name)+1;
        !          1577: 
        !          1578:                                if (p->p_aliases != NULL)
        !          1579:                                        while (p->p_aliases[numaliases]) size += strlen(p->p_aliases[numaliases++])+5;
        !          1580: 
        !          1581:                                if (sb->protoent)
        !          1582:                                {
        !          1583:                                        m68k_areg(regs,1) = sb->protoent;
        !          1584:                                        m68k_dreg(regs,0) = sb->protoentsize;
        !          1585:                                        CallLib(get_long(4),-0xd2);     // FreeMem()
        !          1586:                                }
        !          1587: 
        !          1588:                                m68k_dreg(regs,0) = size;
        !          1589:                                m68k_dreg(regs,1) = 0;
        !          1590:                                sb->protoent = CallLib(get_long(4),-0xc6); // AllocMem()
        !          1591: 
        !          1592:                                if (!sb->protoent)
        !          1593:                                {
        !          1594:                                        write_log("bsdsocket: WARNING: getprotobyname() ran out of Amiga memory (couldn't allocate %ld bytes) while returning result of lookup for '%s'\n",size,(char *)name);
        !          1595:                                        seterrno(sb,12); // ENOMEM
        !          1596:                                        return;
        !          1597:                                }
        !          1598: 
        !          1599:                                sb->protoentsize = size;
        !          1600:                                
        !          1601:                                aptr = sb->protoent+16+numaliases*4;
        !          1602:                        
        !          1603:                                // transfer protoent to Amiga memory
        !          1604:                                put_long(sb->protoent+4,sb->protoent+12);
        !          1605:                                put_long(sb->protoent+8,p->p_proto);
        !          1606:                                
        !          1607:                                for (i = 0; i < numaliases; i++) put_long(sb->protoent+12+i*4,addstr(&aptr,p->p_aliases[i]));
        !          1608:                                put_long(sb->protoent+12+numaliases*4,0);
        !          1609:                                put_long(sb->protoent,aptr);
        !          1610:                                addstr(&aptr,p->p_name);
        !          1611:                                TRACE(("OK (%s, %d)\n",p->p_name,p->p_proto));
        !          1612:                                seterrno(sb,0);
        !          1613:                        }
        !          1614:                        else
        !          1615:                        {
        !          1616:                                TRACE(("failed (%d)\n",sb->sb_errno))
        !          1617:                        }
        !          1618:                }
        !          1619:                else
        !          1620:                {
        !          1621:                        seterrno(sb,12); // ENOMEM - well...
        !          1622:                        write_log("bsdsocket: ERROR: WSAAsyncGetProtoByName() failed - error code: %d\n",WSAGetLastError());
        !          1623:                }
        !          1624:                
        !          1625:                cancelasyncmsg(wMsg);
        !          1626:        }
        !          1627: }
        !          1628: 
        !          1629: uae_u32 host_gethostname(uae_u32 name, uae_u32 namelen)
        !          1630: {
        !          1631:        return gethostname(get_real_address(name),namelen);
        !          1632: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.