]> asedeno.scripts.mit.edu Git - PuTTY.git/blob - opentpt.c
Rebranch some files on 'ben-mac-port' from trunk.
[PuTTY.git] / opentpt.c
1 /* $Id: opentpt.c,v 1.1.2.1 1999/08/02 08:06:32 ben Exp $ */
2 /*
3  * Copyright (c) 1999 Ben Harris
4  * All rights reserved.
5  *
6  * Permission is hereby granted, free of charge, to any person
7  * obtaining a copy of this software and associated documentation
8  * files (the "Software"), to deal in the Software without
9  * restriction, including without limitation the rights to use,
10  * copy, modify, merge, publish, distribute, sublicense, and/or
11  * sell copies of the Software, and to permit persons to whom the
12  * Software is furnished to do so, subject to the following
13  * conditions:
14  * 
15  * The above copyright notice and this permission notice shall be
16  * included in all copies or substantial portions of the Software.
17  * 
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21  * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR
22  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
23  * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25  * SOFTWARE.
26  */
27
28 #include <MacTypes.h>
29 #include <OpenTransport.h>
30 #include <OpenTptInternet.h>
31 #incldue <Processes.h>
32
33 #include <stdlib.h>
34
35 #include "putty.h"
36
37 /* See the top of macnet.c for some idea of how this is meant to work. */
38
39 struct otpt_socket {
40     EndpointRef ep;
41     Session *sess;
42     OTLIFO *sendq;
43     OTLIFO *eventq;
44     long eventhandler;
45 };
46
47 struct otpt_netevent {
48     OTLink *next;
49     Net_Event_Type type;
50 };
51
52 static int otpt_probe(void);
53 static void otpt_init(void);
54 static void *otpt_open(Session *, char const *, int);
55 static int otpt_recv(void *, void *, int, int);
56 static int otpt_send(void *, void *, int, int);
57 static void otpt_close(void *);
58 static void otpt_destroy(void *);
59 static pascal void otpt_notifier(void *, OTEventCode, OTResult , void *);
60 static void otpt_sendevent(struct otpt_socket *, Net_Event_Type);
61 static pascal void otpt_rcvevent(void *);
62
63 Network_Stack otpt_stack = {
64     otpt_init, otpt_open, otpt_recv, otpt_send, otpt_poll, otpt_close,
65     otpt_destroy, otpt_shutdown
66 };
67
68 static OTConfiguration *otpt_config = kOTInvalidCOnfigurationPtr;
69
70 static int otpt_init(void) {
71     OSErr err;
72
73     err = InitOpenTransport();
74     if (err != noErr)
75         return err;
76     otpt_config = OTCreateConfiguration("tcp");
77     if (otpt_config == kOTInvalidConfigurationPtr ||
78         otpt_config == kOTNoMemoryConfigurationPtr)
79         return 1;
80     return 0;
81 }
82
83 /*
84  * This should only be called once all the connections have been
85  * closed (we don't bother keeping a table of them).
86  */
87
88 void otpt_shutdown(void) {
89
90     CloseOpenTransport();
91 }
92
93 static void *otpt_open(Session *sess, char const *host, int port) {
94     struct otpt_socket *s = NULL;
95     OSStatus err;
96     TCall remote;
97     DNSAddress *remoteaddr;
98     
99     s = smalloc(sizeof(*s));
100     memset(s, 0, sizeof(*s));
101
102     /* Get a TCP endpoint (equiv of socket()) */
103     s->ep = OTOpenEndpoint(OTCloneConfiguration(otpt_config), 0, NULL, &err);
104     if (err != kOTNoError || s->ep == NULL) goto splat;
105
106     /* Attach our notifier function (note that this is _not_ a UPP) */
107     err = OTInstallNotifier(s->ep, otpt_notifier, (void *)s);
108     if (err != kOTNoError) goto splat;
109     s->eventhandler = OTCreateSystemTask(&otpt_rcvevent, (void *)s);
110     if (s->eventhandler = 0) goto splat;
111
112     /* Bind to any local address */
113     err = OTBind(s->ep, NULL, NULL);
114     if (err != kOTNoError) goto splat;
115     memset(&remote, 0, sizeof(remote));
116     remoteaddr = smalloc(sizeof(*remoteaddr) - sizeof(remoteaddr->fName) +
117                          strlen(host) + 7); /* allow space for port no. */
118     remote.addr.buf = (UInt8 *)remoteaddr;
119     remote.addr.len = OTInitDNSAddress(remoteaddr, host);
120     remote.addr.len += sprintf(&remoteaddr->fName[strlen(remoteaddr->fName)],
121                                ":%d", port);
122     /* Asynchronous blocking mode, so we don't have to wait */
123     err = OTSetAsynchronous(s->ep);
124     if (err != kOTNoError) goto splat;
125     err = OTSetBlocking(s->ep);
126     if (err != kOTNoError) goto splat;
127     err = OTConnect(s->ep, &remote, NULL);
128     if (err != kOTNoDataErr)
129         goto splat;
130     return s;
131
132   splat:
133     otpt_destroy(s);
134     return NULL;
135 }
136
137 static int otpt_recv(void *sock, void *buf, int buflen, int flags) {
138     struct otpt_socket *s = (struct otpt_socket *)sock;
139     OTResult result;
140     OTFlags flags;
141
142     OTSetNonBlocking(s->ep);
143     OTSetSynchronous(s->ep);
144     result = OTRcv(s->ep, buf, buflen, flags);
145     if (result >= 0)
146         return result;
147     else if (result == kOTNoDataError)
148         return 0;
149     else /* confusion! */
150         return 0;
151 }
152
153 static void otpt_poll(void) {
154
155 }
156
157 static int otpt_send(void *sock, void *buf, int buflen, int flags) {
158     struct otpt_socket *s = (struct otpt_socket *)sock;
159
160     /* XXX: using blocking mode is bogus, but it's far easier than not. */
161     OTSetSynchronous(s->ep);
162     OTSetBlocking(s->ep);
163     return OTSnd(s->ep, buf, buflen, flags);
164 }
165
166 /*
167  * Politely ask the other end to close the connection.
168  */
169
170 static void otpt_close(void *sock) {
171     struct otpt_socket *s = (struct otpt_socket *)sock;
172
173     /* XXX: using blocking mode is bogus, but it's far easier than not. */
174     OTSetSynchronous(s->ep);
175     OTSetBlocking(s->ep);
176     OTSndOrderlyDisconnect(s->ep);
177 }
178
179 /*
180  * This should take a socket in any state and undo it all, freeing any
181  * allocated memory and generally making it safe to forget about it.
182  * It should onlu be called at system task time.
183  */
184
185 static void otpt_destroy(void *sock) {
186     struct otpt_socket *s = (struct otpt_socket *)sock;
187     OSStatus err;
188     OTLink *link;
189
190     if (s == NULL)
191         return;
192
193     /* Tear down the connection */
194     /* If we ever start using T_MEMORYRELEASED, we need to be careful here. */
195     err = OTSetSynchronous(s->ep);
196     if (err == kOTNoError)
197         err = OTSetNonBlocking(s->ep);
198     if (err == kOTNoError)
199         err = OTCloseProvider(s->ep);
200     
201     /* Stop the event handler running */
202     if (s->eventhandler != 0)
203         OTDestroySystemTask(s->eventhandler);
204
205     /* Flush the event and send queues */
206     while ((link = OTLIFODequeue(s->eventq)) != NULL)
207         OTFreeMem(link);
208     while ((link = OTLIFODequeue(s->sendq)) != NULL)
209         OTFreeMem(link);
210
211     /* Finally, free the socket record itself */
212     sfree(s);
213 }
214
215 /*
216  * Any asynchronous events OpenTransport wants to tell us about end up
217  * here.  This function may be called at deferred task or system task
218  * time, and must be re-entrant.
219  */
220
221 static pascal void otpt_notifier(void *contextPtr, OTEventCode code,
222                                     OTResult result, void *cookie) {
223     struct otpt_socket *s = (struct otpt_socket *)contextPtr;
224     OSStatus status;
225     TDiscon discon;
226
227     switch (code) {
228       case T_CONNECT: /* OTConnect completed */
229         status = OTRcvConnect(s->ep, NULL); /* XXX do we want the new TCall? */
230         if (status == kOTNoDataErr)
231             break;
232         else if (status != kOTNoError) {
233             otpt_sendevent(s, NE_DIED);
234             break;
235         }
236         /* Synchronous non-blocking mode for normal data transfer */
237         OTSetSynchronous(s->ep);
238         OTSetNonBlocking(s->ep);
239         otpt_sendevent(s, NE_OPEN);
240         break;
241       case T_DATA:
242         otpt_sendevent(s, NE_DATA);
243         break;
244       case T_EXDATA:
245         otpt_sendevent(s, NE_URGENT);
246         break;
247       case T_DISCONNECT: /* Disconnection complete or OTConnect rejected */
248         memset(&discon, 0, sizeof(discon));
249         /*
250          * This function returns a positive error code. To obtain the
251          * negative error code, subtract that positive value from
252          * -3199.
253          */
254         status = OTRcvDisconnect(s->ep, &discon);
255         if (cookie == NULL) /* spontaneous disconnect */
256             switch (E2OSStatus(discon.reason)) {
257               case kECONNRESETErr:
258                 otpt_sendevent(s, NE_ABORT);
259                 break;
260               case kETIMEDOUTErr:
261                 otpt_sendevent(s, NE_TIMEOUT);
262                 break;
263               default:
264                 otpt_sendevent(s, NE_DIED);
265                 break;
266             }
267         else /* failed connect */
268             otpt_sendevent(s, NE_NOOPEN);
269       case T_ORDREL:
270         OTRcvOrderlyDisconnect(s->ep);
271         otpt_sendevent(s, NE_CLOSING);
272     }
273 }
274
275 /*
276  * This function is called at interrupt time (or thereabouts) to
277  * dispatch an event that has to be handled at system task time.
278  * Network backends will expect their msg entries to be called then.
279  */
280
281 static void otpt_sendevent(struct otpt_socket *s, Net_Event_Type type) {
282     struct otpt_netevent *ne;
283
284     ne = OTAllocMem(sizeof(*ne));
285     if (ne == NULL)
286         fatalbox("OTAllocMem failed.  Aargh!");
287     ne->type = type;
288     OTLIFOEnqueue(&s->eventq, &ne->next);
289     /* Schedule something */
290     OTScheduleSystemTask(s->eventhandler);
291 }
292
293 /*
294  * Pull one or more network events off a socket's queue and handle
295  * them.  Keep gong until we run out (events may be getting enqueued
296  * while we're running).  This is mildly evil as it'll prevent any
297  * other task running if we're under heavy load.
298  */
299
300 static pascal void otpt_rcvevent(void *arg) {
301     struct otpt_socket *s = (struct otpt_socket *)arg;
302     OTLink *link;
303     struct otpt_netevent *ne;
304
305     /* idiom stolen from "Networking With Open Transport".  Blame Apple. */
306
307     while ((link = OTLIFOStealList(s->eventq)) != NULL) {
308         link = OTReverseList(link);
309         while (link != NULL) {
310             ne = (struct otpt_netevent *)link;
311             link = ne->next;
312             switch (ne->type) {
313               default:
314                 (s->sess->back->msg)(s->sess, s, ne->type);
315                 break;
316             }
317             OTFreeMem(ne);
318         }
319     }
320     
321
322 /*
323  * Local Variables:
324  * c-file-style: "simon"
325  * End:
326  */ 
327
328