1 /* $Id: opentpt.c,v 1.1.2.4 1999/09/07 23:41:32 ben Exp $ */
3 * Copyright (c) 1999 Ben Harris
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
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
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
29 #include <CodeFragments.h>
30 #include <OpenTransport.h>
31 #include <OpenTptInternet.h>
39 /* See the top of macnet.c for some idea of how this is meant to work. */
49 struct otpt_netevent {
54 static int otpt_init(void);
55 static void otpt_shutdown(void);
56 static void otpt_poll(void);
57 static void *otpt_open(Session *, char const *, int);
58 static int otpt_recv(void *, void *, int, int);
59 static int otpt_send(void *, void *, int, int);
60 static void otpt_close(void *);
61 static void otpt_destroy(void *);
62 static pascal void otpt_notifier(void *, OTEventCode, OTResult , void *);
63 static void otpt_sendevent(struct otpt_socket *, Net_Event_Type);
64 static pascal void otpt_rcvevent(void *);
66 Network_Stack otpt_stack = {
67 otpt_init, otpt_open, otpt_recv, otpt_send, otpt_poll, otpt_close,
68 otpt_destroy, otpt_shutdown
71 static OTConfiguration *otpt_config = kOTInvalidConfigurationPtr;
73 static int otpt_init(void) {
77 /* Check that the OpenTransport libraries were there (really just ppc) */
78 if (&InitOpenTransport == kUnresolvedCFragSymbolAddress)
81 err = InitOpenTransport();
84 otpt_config = OTCreateConfiguration("tcp");
85 if (otpt_config == kOTInvalidConfigurationPtr ||
86 otpt_config == kOTNoMemoryConfigurationPtr)
91 /* Stuff below here is only needed if you actually have Open Transport. */
92 /* #pragma segment OpenTpt */
93 /* Last I looked, this only produced a 1.5k segment, which isn't worth it. */
96 * This should only be called once all the connections have been
97 * closed (we don't bother keeping a table of them).
100 void otpt_shutdown(void) {
102 CloseOpenTransport();
105 static void *otpt_open(Session *sess, char const *host, int port) {
106 struct otpt_socket *s = NULL;
109 DNSAddress *remoteaddr;
111 assert(otpt_config != kOTInvalidConfigurationPtr);
112 s = smalloc(sizeof(*s));
113 memset(s, 0, sizeof(*s));
116 /* Get a TCP endpoint (equiv of socket()) */
117 s->ep = OTOpenEndpoint(OTCloneConfiguration(otpt_config), 0, NULL, &err);
118 if (err != kOTNoError || s->ep == NULL) goto splat;
120 /* Set up a system-task-time event handler (scheduled by the notifier) */
121 s->eventhandler = OTCreateSystemTask(&otpt_rcvevent, (void *)s);
122 if (s->eventhandler == 0) goto splat;
123 /* Attach our notifier function (note that this is _not_ a UPP) */
124 err = OTInstallNotifier(s->ep, otpt_notifier, (void *)s);
125 if (err != kOTNoError) goto splat;
127 /* Bind to any local address */
128 err = OTBind(s->ep, NULL, NULL);
129 if (err != kOTNoError) goto splat;
130 memset(&remote, 0, sizeof(remote));
131 remoteaddr = smalloc(sizeof(*remoteaddr) - sizeof(remoteaddr->fName) +
132 strlen(host) + 7); /* allow space for port no. */
133 remote.addr.buf = (UInt8 *)remoteaddr;
134 /* XXX: I don't _think_ OTInitDNSAddress can modify the hostname. */
135 remote.addr.len = OTInitDNSAddress(remoteaddr, (char *)host);
136 remote.addr.len += sprintf(&remoteaddr->fName[strlen(remoteaddr->fName)],
138 /* Asynchronous blocking mode, so we don't have to wait */
139 err = OTSetAsynchronous(s->ep);
140 if (err != kOTNoError) goto splat;
141 err = OTSetBlocking(s->ep);
142 if (err != kOTNoError) goto splat;
143 err = OTConnect(s->ep, &remote, NULL);
144 if (err != kOTNoDataErr)
153 static int otpt_recv(void *sock, void *buf, int buflen, int flags) {
154 struct otpt_socket *s = (struct otpt_socket *)sock;
158 OTSetNonBlocking(s->ep);
159 OTSetSynchronous(s->ep);
160 result = OTRcv(s->ep, buf, buflen, &otflags);
163 else if (result == kOTNoDataErr)
165 else /* confusion! */
169 static void otpt_poll(void) {
173 static int otpt_send(void *sock, void *buf, int buflen, int flags) {
174 struct otpt_socket *s = (struct otpt_socket *)sock;
176 /* XXX: using blocking mode is bogus, but it's far easier than not. */
177 OTSetSynchronous(s->ep);
178 OTSetBlocking(s->ep);
179 return OTSnd(s->ep, buf, buflen, flags);
183 * Politely ask the other end to close the connection.
186 static void otpt_close(void *sock) {
187 struct otpt_socket *s = (struct otpt_socket *)sock;
189 /* XXX: using blocking mode is bogus, but it's far easier than not. */
190 OTSetSynchronous(s->ep);
191 OTSetBlocking(s->ep);
192 OTSndOrderlyDisconnect(s->ep);
196 * This should take a socket in any state and undo it all, freeing any
197 * allocated memory and generally making it safe to forget about it.
198 * It should only be called at system task time.
201 static void otpt_destroy(void *sock) {
202 struct otpt_socket *s = (struct otpt_socket *)sock;
209 /* Tear down the connection */
210 /* If we ever start using T_MEMORYRELEASED, we need to be careful here. */
211 err = OTSetSynchronous(s->ep);
212 if (err == kOTNoError)
213 err = OTSetNonBlocking(s->ep);
214 if (err == kOTNoError)
215 err = OTCloseProvider(s->ep);
217 /* Stop the event handler running */
218 if (s->eventhandler != 0)
219 OTDestroySystemTask(s->eventhandler);
221 /* Flush the event and send queues */
222 while ((link = OTLIFODequeue(&s->eventq)) != NULL)
224 while ((link = OTLIFODequeue(&s->sendq)) != NULL)
227 /* Finally, free the socket record itself */
232 * Any asynchronous events OpenTransport wants to tell us about end up
233 * here. This function may be called at deferred task or system task
234 * time, and must be re-entrant.
237 static pascal void otpt_notifier(void *contextPtr, OTEventCode code,
238 OTResult result, void *cookie) {
239 struct otpt_socket *s = (struct otpt_socket *)contextPtr;
244 case T_CONNECT: /* OTConnect completed */
245 status = OTRcvConnect(s->ep, NULL); /* XXX do we want the new TCall? */
246 if (status == kOTNoDataErr)
248 else if (status != kOTNoError) {
249 otpt_sendevent(s, NE_DIED);
252 /* Synchronous non-blocking mode for normal data transfer */
253 OTSetSynchronous(s->ep);
254 OTSetNonBlocking(s->ep);
255 otpt_sendevent(s, NE_OPEN);
258 otpt_sendevent(s, NE_DATA);
261 otpt_sendevent(s, NE_URGENT);
263 case T_DISCONNECT: /* Disconnection complete or OTConnect rejected */
264 memset(&discon, 0, sizeof(discon));
266 * This function returns a positive error code. To obtain the
267 * negative error code, subtract that positive value from
270 status = OTRcvDisconnect(s->ep, &discon);
272 if (cookie == NULL) /* spontaneous disconnect */
273 switch (E2OSStatus(discon.reason)) {
275 otpt_sendevent(s, NE_ABORT);
278 otpt_sendevent(s, NE_TIMEOUT);
281 otpt_sendevent(s, NE_DIED);
284 else /* failed connect */
285 otpt_sendevent(s, NE_NOOPEN);
287 OTRcvOrderlyDisconnect(s->ep);
288 otpt_sendevent(s, NE_CLOSING);
293 * This function is called at interrupt time (or thereabouts) to
294 * dispatch an event that has to be handled at system task time.
295 * Network backends will expect their msg entries to be called then.
298 static void otpt_sendevent(struct otpt_socket *s, Net_Event_Type type) {
299 struct otpt_netevent *ne;
301 ne = OTAllocMem(sizeof(*ne));
303 fatalbox("OTAllocMem failed. Aargh!");
305 OTLIFOEnqueue(&s->eventq, &ne->next);
306 /* Schedule something */
307 OTScheduleSystemTask(s->eventhandler);
311 * Pull one or more network events off a socket's queue and handle
312 * them. Keep going until we run out (events may be getting enqueued
313 * while we're running). This is mildly evil as it'll prevent any
314 * other task running if we're under heavy load.
317 static pascal void otpt_rcvevent(void *arg) {
318 struct otpt_socket *s = (struct otpt_socket *)arg;
320 struct otpt_netevent *ne;
322 while ((link = OTLIFOStealList(&s->eventq)) != NULL) {
323 link = OTReverseList(link);
324 while (link != NULL) {
325 ne = (struct otpt_netevent *)link;
326 link = ne->next.fNext;
329 (s->sess->back->msg)(s->sess, s, ne->type);
339 * c-file-style: "simon"