diff --git a/macnet.c b/mactcp.c similarity index 99% rename from macnet.c rename to mactcp.c index 480b2b7b..995f5ae6 100644 --- a/macnet.c +++ b/mactcp.c @@ -1,4 +1,4 @@ -/* $Id: macnet.c,v 1.1.2.5 1999/04/07 22:43:35 ben Exp $ */ +/* $Id: mactcp.c,v 1.1.2.1 1999/08/02 08:06:32 ben Exp $ */ /* * Copyright (c) 1999 Ben Harris * All rights reserved. diff --git a/opentpt.c b/opentpt.c new file mode 100644 index 00000000..116d1f0b --- /dev/null +++ b/opentpt.c @@ -0,0 +1,328 @@ +/* $Id: opentpt.c,v 1.1.2.1 1999/08/02 08:06:32 ben Exp $ */ +/* + * Copyright (c) 1999 Ben Harris + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF + * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include +#include +#include +#incldue + +#include + +#include "putty.h" + +/* See the top of macnet.c for some idea of how this is meant to work. */ + +struct otpt_socket { + EndpointRef ep; + Session *sess; + OTLIFO *sendq; + OTLIFO *eventq; + long eventhandler; +}; + +struct otpt_netevent { + OTLink *next; + Net_Event_Type type; +}; + +static int otpt_probe(void); +static void otpt_init(void); +static void *otpt_open(Session *, char const *, int); +static int otpt_recv(void *, void *, int, int); +static int otpt_send(void *, void *, int, int); +static void otpt_close(void *); +static void otpt_destroy(void *); +static pascal void otpt_notifier(void *, OTEventCode, OTResult , void *); +static void otpt_sendevent(struct otpt_socket *, Net_Event_Type); +static pascal void otpt_rcvevent(void *); + +Network_Stack otpt_stack = { + otpt_init, otpt_open, otpt_recv, otpt_send, otpt_poll, otpt_close, + otpt_destroy, otpt_shutdown +}; + +static OTConfiguration *otpt_config = kOTInvalidCOnfigurationPtr; + +static int otpt_init(void) { + OSErr err; + + err = InitOpenTransport(); + if (err != noErr) + return err; + otpt_config = OTCreateConfiguration("tcp"); + if (otpt_config == kOTInvalidConfigurationPtr || + otpt_config == kOTNoMemoryConfigurationPtr) + return 1; + return 0; +} + +/* + * This should only be called once all the connections have been + * closed (we don't bother keeping a table of them). + */ + +void otpt_shutdown(void) { + + CloseOpenTransport(); +} + +static void *otpt_open(Session *sess, char const *host, int port) { + struct otpt_socket *s = NULL; + OSStatus err; + TCall remote; + DNSAddress *remoteaddr; + + s = smalloc(sizeof(*s)); + memset(s, 0, sizeof(*s)); + + /* Get a TCP endpoint (equiv of socket()) */ + s->ep = OTOpenEndpoint(OTCloneConfiguration(otpt_config), 0, NULL, &err); + if (err != kOTNoError || s->ep == NULL) goto splat; + + /* Attach our notifier function (note that this is _not_ a UPP) */ + err = OTInstallNotifier(s->ep, otpt_notifier, (void *)s); + if (err != kOTNoError) goto splat; + s->eventhandler = OTCreateSystemTask(&otpt_rcvevent, (void *)s); + if (s->eventhandler = 0) goto splat; + + /* Bind to any local address */ + err = OTBind(s->ep, NULL, NULL); + if (err != kOTNoError) goto splat; + memset(&remote, 0, sizeof(remote)); + remoteaddr = smalloc(sizeof(*remoteaddr) - sizeof(remoteaddr->fName) + + strlen(host) + 7); /* allow space for port no. */ + remote.addr.buf = (UInt8 *)remoteaddr; + remote.addr.len = OTInitDNSAddress(remoteaddr, host); + remote.addr.len += sprintf(&remoteaddr->fName[strlen(remoteaddr->fName)], + ":%d", port); + /* Asynchronous blocking mode, so we don't have to wait */ + err = OTSetAsynchronous(s->ep); + if (err != kOTNoError) goto splat; + err = OTSetBlocking(s->ep); + if (err != kOTNoError) goto splat; + err = OTConnect(s->ep, &remote, NULL); + if (err != kOTNoDataErr) + goto splat; + return s; + + splat: + otpt_destroy(s); + return NULL; +} + +static int otpt_recv(void *sock, void *buf, int buflen, int flags) { + struct otpt_socket *s = (struct otpt_socket *)sock; + OTResult result; + OTFlags flags; + + OTSetNonBlocking(s->ep); + OTSetSynchronous(s->ep); + result = OTRcv(s->ep, buf, buflen, flags); + if (result >= 0) + return result; + else if (result == kOTNoDataError) + return 0; + else /* confusion! */ + return 0; +} + +static void otpt_poll(void) { + +} + +static int otpt_send(void *sock, void *buf, int buflen, int flags) { + struct otpt_socket *s = (struct otpt_socket *)sock; + + /* XXX: using blocking mode is bogus, but it's far easier than not. */ + OTSetSynchronous(s->ep); + OTSetBlocking(s->ep); + return OTSnd(s->ep, buf, buflen, flags); +} + +/* + * Politely ask the other end to close the connection. + */ + +static void otpt_close(void *sock) { + struct otpt_socket *s = (struct otpt_socket *)sock; + + /* XXX: using blocking mode is bogus, but it's far easier than not. */ + OTSetSynchronous(s->ep); + OTSetBlocking(s->ep); + OTSndOrderlyDisconnect(s->ep); +} + +/* + * This should take a socket in any state and undo it all, freeing any + * allocated memory and generally making it safe to forget about it. + * It should onlu be called at system task time. + */ + +static void otpt_destroy(void *sock) { + struct otpt_socket *s = (struct otpt_socket *)sock; + OSStatus err; + OTLink *link; + + if (s == NULL) + return; + + /* Tear down the connection */ + /* If we ever start using T_MEMORYRELEASED, we need to be careful here. */ + err = OTSetSynchronous(s->ep); + if (err == kOTNoError) + err = OTSetNonBlocking(s->ep); + if (err == kOTNoError) + err = OTCloseProvider(s->ep); + + /* Stop the event handler running */ + if (s->eventhandler != 0) + OTDestroySystemTask(s->eventhandler); + + /* Flush the event and send queues */ + while ((link = OTLIFODequeue(s->eventq)) != NULL) + OTFreeMem(link); + while ((link = OTLIFODequeue(s->sendq)) != NULL) + OTFreeMem(link); + + /* Finally, free the socket record itself */ + sfree(s); +} + +/* + * Any asynchronous events OpenTransport wants to tell us about end up + * here. This function may be called at deferred task or system task + * time, and must be re-entrant. + */ + +static pascal void otpt_notifier(void *contextPtr, OTEventCode code, + OTResult result, void *cookie) { + struct otpt_socket *s = (struct otpt_socket *)contextPtr; + OSStatus status; + TDiscon discon; + + switch (code) { + case T_CONNECT: /* OTConnect completed */ + status = OTRcvConnect(s->ep, NULL); /* XXX do we want the new TCall? */ + if (status == kOTNoDataErr) + break; + else if (status != kOTNoError) { + otpt_sendevent(s, NE_DIED); + break; + } + /* Synchronous non-blocking mode for normal data transfer */ + OTSetSynchronous(s->ep); + OTSetNonBlocking(s->ep); + otpt_sendevent(s, NE_OPEN); + break; + case T_DATA: + otpt_sendevent(s, NE_DATA); + break; + case T_EXDATA: + otpt_sendevent(s, NE_URGENT); + break; + case T_DISCONNECT: /* Disconnection complete or OTConnect rejected */ + memset(&discon, 0, sizeof(discon)); + /* + * This function returns a positive error code. To obtain the + * negative error code, subtract that positive value from + * -3199. + */ + status = OTRcvDisconnect(s->ep, &discon); + if (cookie == NULL) /* spontaneous disconnect */ + switch (E2OSStatus(discon.reason)) { + case kECONNRESETErr: + otpt_sendevent(s, NE_ABORT); + break; + case kETIMEDOUTErr: + otpt_sendevent(s, NE_TIMEOUT); + break; + default: + otpt_sendevent(s, NE_DIED); + break; + } + else /* failed connect */ + otpt_sendevent(s, NE_NOOPEN); + case T_ORDREL: + OTRcvOrderlyDisconnect(s->ep); + otpt_sendevent(s, NE_CLOSING); + } +} + +/* + * This function is called at interrupt time (or thereabouts) to + * dispatch an event that has to be handled at system task time. + * Network backends will expect their msg entries to be called then. + */ + +static void otpt_sendevent(struct otpt_socket *s, Net_Event_Type type) { + struct otpt_netevent *ne; + + ne = OTAllocMem(sizeof(*ne)); + if (ne == NULL) + fatalbox("OTAllocMem failed. Aargh!"); + ne->type = type; + OTLIFOEnqueue(&s->eventq, &ne->next); + /* Schedule something */ + OTScheduleSystemTask(s->eventhandler); +} + +/* + * Pull one or more network events off a socket's queue and handle + * them. Keep gong until we run out (events may be getting enqueued + * while we're running). This is mildly evil as it'll prevent any + * other task running if we're under heavy load. + */ + +static pascal void otpt_rcvevent(void *arg) { + struct otpt_socket *s = (struct otpt_socket *)arg; + OTLink *link; + struct otpt_netevent *ne; + + /* idiom stolen from "Networking With Open Transport". Blame Apple. */ + + while ((link = OTLIFOStealList(s->eventq)) != NULL) { + link = OTReverseList(link); + while (link != NULL) { + ne = (struct otpt_netevent *)link; + link = ne->next; + switch (ne->type) { + default: + (s->sess->back->msg)(s->sess, s, ne->type); + break; + } + OTFreeMem(ne); + } + } + + +/* + * Local Variables: + * c-file-style: "simon" + * End: + */ + +