]> asedeno.scripts.mit.edu Git - PuTTY.git/commitdiff
Open Transport support, maybe. Also renamed macnet.c to mactcp.c, but it's
authorBen Harris <bjh21@bjh21.me.uk>
Mon, 2 Aug 1999 08:06:32 +0000 (08:06 +0000)
committerBen Harris <bjh21@bjh21.me.uk>
Mon, 2 Aug 1999 08:06:32 +0000 (08:06 +0000)
still as broken as before.

[originally from svn r189]

mactcp.c [moved from macnet.c with 99% similarity]
opentpt.c [new file with mode: 0644]

similarity index 99%
rename from macnet.c
rename to mactcp.c
index 480b2b7b9b07f2c8fcdb3186dc6f9f30d1816aeb..995f5ae67a9ed00b399e671859300904de6e4385 100644 (file)
--- 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 (file)
index 0000000..116d1f0
--- /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 <MacTypes.h>
+#include <OpenTransport.h>
+#include <OpenTptInternet.h>
+#incldue <Processes.h>
+
+#include <stdlib.h>
+
+#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:
+ */ 
+
+