/* * MariGNOtti * */ #pragma optimize 79 #include #include #include #include #include #include #include #include //#include #include #include #include #include #include //#include #include "net.h" volatile int QuitFlag; static Word MyID; int semID; // this will be used to hold extra info (sockopts, etc) // as well as to keep a list of ipids waiting to close. typedef struct ipidHash { Word ipid; Word flags; struct ipidHash *next; } ipidHash; ipidHash *htable[64] = { }; ipidHash *dlist = NULL; // not yet sure what this is for... typedef void (*selwakeup)(int col_flag, int pid); void debug_str(const char *cp) { asm { ldx srState, sb->srNetworkError, sb->srSndQueued, sb->srRcvQueued, sb->srDestIP, sb->srDestPort, sb->srConnectType, sb->srAcceptCount ); asm { ldx #^buffer ldy #buffer cop 0x84 } } int do_attach( int socknum, void *m, size_t *m_len, struct sockaddr *addr, int *addrlen, void *rights ) { // returns errno or 0. Word ipid; ipidHash *e; int type = socknum; int *sockptr = (int *)m; selwakeup *fx = (selwakeup *)m_len; int *protocol = (int *)addr; //WriteLine("\pdo_attach"); debug_str("do_attach"); if (type != SOCK_STREAM) return EPROTONOSUPPORT; ipid = TCPIPLogin(MyID, 0, 0, 0, 0x0040); if (_toolErr) return EPFNOSUPPORT; // semaphore ... swait(semID); e = (ipidHash *)malloc(sizeof(ipidHash)); e->ipid = ipid; e->flags = 0; e->next = htable[ipid & (64-1)]; htable[ipid & (64 - 1)] = e; ssignal(semID); // end semaphore *sockptr = ipid; return 0; } // netinet/in.h is giving me compile errors... struct xsockaddr_in { short sin_family; unsigned short sin_port; unsigned long sin_addr; char sin_zero[8]; }; int do_connect( int socknum, void *m, size_t *m_len, struct sockaddr *addr, int *addrlen, void *rights) { // returns errno or 0. Word terr; Longword tick, qtick; Word port; Word ipid = (Word)socknum; struct xsockaddr_in *sin = (struct xsockaddr_in *)addr; //WriteLine("\pdo_connect"); debug_str("do_connect"); // port is byte-swapped. port = sin->sin_port; asm { lda sin_addr, port); if (_toolErr) return EPFNOSUPPORT; terr = TCPIPOpenTCP(ipid); if (_toolErr || terr) { return EPFNOSUPPORT; } // wait to loop until actually connected. // 30-second timeout. qtick = GetTick() + 60 * 30; for(;;) { srBuff sr; terr = TCPIPStatusTCP(ipid, &sr); dump_srbuff(&sr); if (sr.srState == TCPSESTABLISHED) return 0; if (sr.srState == TCPSCLOSED) return ECONNREFUSED; if (sr.srState > TCPSESTABLISHED) return ECONNREFUSED; if (GetTick() >= qtick) return ETIMEDOUT; // is this safe? sleep(1); } return 0; } int do_disconnect( int socknum, void *m, size_t *m_len, struct sockaddr *addr, int *addrlen, void *rights) { Word ipid = socknum; debug_str("do_disconnect"); //WriteLine("\pdo_disconnect"); // return value ignored. return 0; } int do_detach( int socknum, void *m, size_t *m_len, struct sockaddr *addr, int *addrlen, void *rights) { Word ipid = socknum; Word terr; ipidHash *e; ipidHash *prev; // returns a GS/OS error. // remove from hashtable. // begin disconnect sequence. // add to dlist. // need to use semaphore to block other thread... //WriteLine("\pdo_detach"); debug_str("do_detach"); terr = TCPIPCloseTCP(ipid); // semaphore... swait(semID); prev = NULL; e = htable[ipid & (64-1)]; for(;;) { if (e->ipid == ipid) break; prev = e; e = e->next; } if (e) { if (prev) prev->next = e->next; else htable[ipid & (64 - 1)] = e->next; e->next = dlist; dlist = e; } ssignal(semID); // end semaphore. return 0; } int do_send( int socknum, void *m, size_t *m_len, struct sockaddr *addr, int *addrlen, void *rights) { // called from GS/OS, busyflag set // (seems like a bug to me....) Word terr; Word ipid = (Word)socknum; void *data = (void *)m; size_t *len = (size_t *)m_len; //WriteLine("\pdo_send"); { static char buffer[64]; sprintf(buffer, "do_send: ipid = %04x len = %04x", ipid, (Word)*len ); debug_str(buffer); } terr = TCPIPWriteTCP(ipid, data, *len, 0, 0); // closing == eof. if (terr == tcperrConClosing) { *len = 0; return ECONNRESET; } return 0; } int do_rcvd( int socknum, void *m, size_t *m_len, struct sockaddr *addr, int *addrlen, void *rights) { // called from GS/OS, busy flag is set. // todo -- EWOULDBLOCK? Word terr; Word ipid = (Word)socknum; void *data = (void *)m; size_t *len = (size_t *)m_len; rrBuff rr; //WriteLine("\pdo_rcvd"); { static char buffer[64]; sprintf(buffer, "do_rcvd: ipid = %04x len = %04x", ipid, (Word)*len ); debug_str(buffer); } // todo -- should block unless O_NONBLOCK set. for (;;) { srBuff sr; terr = TCPIPStatusTCP(ipid, &sr); dump_srbuff(&sr); terr = TCPIPReadTCP(ipid, 0, (Ref)data, *len, &rr); if (rr.rrBuffCount) { *len = rr.rrBuffCount; return 0; } if (terr == tcperrBadConnection) return ENOTCONN; // no data, no more data, then closing. if (terr == tcperrConClosing && !rr.rrMoreFlag) return ECONNRESET; // if NON_BLOCKING, return EWOULDBLOCK. asm { cop 0x7f } // poll in main loop not called, apparently. TCPIPPoll(); // //sleep(1); // cop 0x7f? } return 0; } #pragma databank 1 static int driver( int socknum, int req, void *m, size_t *m_len, struct sockaddr *addr, int *addrlen, void *rights) { { static char buffer[64]; sprintf(buffer, "driver: req = %d", req); debug_str(buffer); } switch (req) { case PRU_ABORT: break; case PRU_ACCEPT: break; case PRU_ATTACH: // KERNsocket(int domain, int type, int protocol, int *ERRNO); return do_attach(socknum, m, m_len, addr, addrlen, rights); break; case PRU_BIND: //WriteLine("\pbind!"); // todo return 0; break; case PRU_CONNECT: // KERNconnect(int fd, struct sockaddr *serv_addr, // int addrlen, int *ERRNO) return do_connect(socknum, m, m_len, addr, addrlen, rights); break; case PRU_CONNECT2: break; case PRU_CONTROL: break; case PRU_DETACH: // int SOCKclose(int sock) part 2 return do_detach(socknum, m, m_len, addr, addrlen, rights); break; case PRU_DISCONNECT: // int SOCKclose(int sock) part 1 return do_disconnect(socknum, m, m_len, addr, addrlen, rights); break; case PRU_LISTEN: break; case PRU_PEERADDR: break; case PRU_RCVD: // SOCKrdwr(struct rwPBlock *pb, word cmd, int sock) return do_rcvd(socknum, m, m_len, addr, addrlen, rights); break; case PRU_RCVOOB: break; case PRU_SEND: // SOCKrdwr(struct rwPBlock *pb, word cmd, int sock) return do_send(socknum, m, m_len, addr, addrlen, rights); break; case PRU_SENDOOB: break; case PRU_SENSE: break; case PRU_SHUTDOWN: break; case PRU_SOCKADDR: break; case PRU_CO_GETOPT: break; case PRU_CO_SETOPT: break; case PRU_SELECT: break; } return EINVAL; } void signal_handler(int sig, int code) { WriteLine("\pWe got signal!"); QuitFlag = 1; } void DisplayMessage(const char *string) { if (string) WriteLine(string); } #pragma databank 0 // startup/shutdown flags. enum { kLoaded = 1, kStarted = 2, kConnected = 4 }; Word StartUp(displayPtr fx) { word status; word flags = 0; // TCPIP is an init, not a tool, so it should always // be loaded. status = TCPIPStatus(); if (_toolErr) { LoadOneTool(54, 0x0300); if (_toolErr) return -1; status = 0; flags |= kLoaded; } #if 0 // require 3.0b3 if (TCPIPLongVersion() < 0x03006003) { if (flags & kLoaded) UnloadOneTool(54); return -1; } #endif if (!status) { TCPIPStartUp(); if (_toolErr) return -1; flags |= kStarted; } status = TCPIPGetConnectStatus(); if (!status) { TCPIPConnect(fx); flags |= kConnected; } return flags; } void ShutDown(word flags, Boolean force, displayPtr fx) { if (flags & kConnected) { TCPIPDisconnect(force, fx); if (_toolErr) return; } if (flags & kStarted) { TCPIPShutDown(); if (_toolErr) return; } if (flags & kLoaded) { UnloadOneTool(54); } } int main(int argc, char **argv) { int flags; MyID = MMStartUp(); flags = StartUp(DisplayMessage); semID = screate(1); InstallNetDriver(driver, 0); QuitFlag = 0; signal(SIGQUIT, signal_handler); signal(SIGINT, signal_handler); signal(SIGHUP, signal_handler); while(!QuitFlag) { ipidHash *e; ipidHash *prev; debug_str("TCPIPPoll()"); TCPIPPoll(); // monitor disconnects... // semaphore ... swait(semID); if (errno == EINTR) continue; e = dlist; prev = NULL; while (e) { Word terr; srBuff sr; ipidHash *next; next = e->next; terr = TCPIPStatusTCP(e->ipid, &sr); dump_srbuff(&sr); // timed wait or closed ... if (sr.srState == TCPSCLOSED) { TCPIPLogout(e->ipid); free(e); if (prev) { prev->next = next; } else { dlist = next; } } else { prev = e; } e = next; } ssignal(semID); // end semaphore. sleep(1); // need a sleep10 to match alarm10 } InstallNetDriver(NULL, 0); sdelete(semID); ShutDown(flags, 0, DisplayMessage); return 0; }