|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (c) 1990, 1995-1998 Apple Computer, Inc.
27: * All Rights Reserved.
28: *
29: * THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF APPLE COMPUTER, INC.
30: * The copyright notice above does not evidence any actual or
31: * intended publication of such source code.
32: */
33:
34:
35: #include <adsp_local.h>
36: extern atlock_t adspall_lock;
37:
38: static void qRemove(CCBPtr, CCBPtr);
39:
40:
41: /*
42: * CheckOkToClose
43: *
44: * Check to see if it is OK to close this connection cleanly.
45: *
46: * INPUTS:
47: * Stream pointer
48: * OUTPUTS:
49: * True if no outstanding transactions and we can close cleanly
50: */
51: int CheckOkToClose(sp) /* (CCBPtr sp) */
52: CCBPtr sp;
53: {
54:
55: if (sp->sData) /* Outstanding data ? */
56: return 0;
57:
58: if (sp->sapb) /* Outstanding send attention ? */
59: return 0;
60:
61: if (sp->frpb) /* Outstanding forward reset ? */
62: return 0;
63:
64: if (sp->sendAttnAck)
65: return 0;
66:
67: if (sp->sendDataAck)
68: return 0;
69:
70: /*
71: * Must be OK to close
72: */
73: sp->sendCtl |= B_CTL_CLOSE; /* So, need to send close advice */
74: sp->callSend = 1;
75:
76: return 1; /* It's OK to close */
77: }
78:
79:
80: /*
81: * CompleteQueue
82: *
83: * Given the address of the head of a queue of DSP parameter blocks, zero
84: * the queue, and complete each item on the queue with the given result
85: * code.
86: *
87: * INPUTS:
88: * qhead Address of ptr to first queue element
89: * code The result code
90: * OUTPUTS:
91: * none
92: */
93: int CompleteQueue(qhead, code) /* (DSPPBPtr FPTR qhead, OSErr code) */
94: struct adspcmd **qhead;
95: int code;
96: {
97: register struct adspcmd *p;
98: register struct adspcmd *n;
99: register gref_t *gref;
100: register int total = 0;
101: CCBPtr sp = 0;
102: int s;
103:
104: n = *qhead; /* Get first item */
105: *qhead = 0; /* Zero out the queue */
106: if (n) {
107: gref = n->gref;
108: if (gref->info) {
109: sp = (CCBPtr)gbuf_rptr(((gbuf_t *)gref->info));
110: atalk_flush(sp->gref);
111: ATDISABLE(s, sp->lock);
112: }
113: }
114:
115: while (p = n) { /* while items left */
116: n = (struct adspcmd *)(p->qLink); /* Save next guy */
117: p->ioResult = code;
118: if (sp) {
119: completepb(sp, p); /* complete the copy of the request */
120: total++;
121: } else
122: gbuf_freem(p->mp);
123: } /* while */
124: if (sp)
125: ATENABLE(s, sp->lock);
126: return(total);
127: }
128:
129: /*
130: * RemoveCCB
131: *
132: * Called from do close to free up the user's CCB. So, we remove the
133: * CCB from the list of CCB's.
134: *
135: * INPUTS:
136: * sp pointer to ccb
137: * pb a remove param block to complete when done
138: * OUTPUTS:
139: * none
140: */
141:
142: void RemoveCCB(sp, pb) /* (CCBPtr sp, DSPPBPtr pb) */
143: CCBPtr sp;
144: struct adspcmd *pb;
145: {
146: gref_t *gref;
147:
148: if (sp->gref == 0)
149: return;
150: /*
151: * Unlink CCB from list
152: */
153: qRemove(AT_ADSP_STREAMS, sp); /* remove sp from active streams queue */
154:
155: if (pb) {
156: pb->ioResult = 0;
157: if (pb->ioc) /* is this a current or queued request */
158: adspioc_ack(0, pb->ioc, pb->gref); /* current */
159: else {
160: completepb(sp, pb); /* queued */
161: }
162:
163: if (sp->opb && (pb != sp->opb)) { /* if the pb requested is not the */
164: pb = sp->opb; /* waiting open pb, complete it too */
165: sp->opb = 0;
166: pb->ioResult = 0;
167: completepb(sp, pb);
168: } else {
169: sp->opb = 0;
170: }
171: }
172: gref = sp->gref;
173: sp->gref = 0;
174: if (gref->info == (char *)sp->sp_mp) { /* queue head is still valid */
175: unsigned char skt;
176:
177: if ((skt = sp->localSocket) != 0) {
178: if (adspDeassignSocket(sp) == 0)
179: ddp_notify_nbp(skt, sp->pid, DDP_ADSP);
180: }
181:
182: if (gref->info) {
183: gbuf_freem((gbuf_t *)gref->info); /* free the CCB */
184: gref->info = 0;
185: }
186: } else
187: gbuf_freem(sp->sp_mp); /* our head is already gone, be sure
188: * to release our resources too */
189: }
190:
191: int AbortIO(sp, err)
192: CCBPtr sp;
193: OSErr err;
194: {
195: register int total;
196:
197: if (sp->gref == 0)
198: return 0;
199: /*
200: * Complete all outstanding transactions.
201: */
202: total += CompleteQueue(&sp->sapb, err); /* Abort outstanding send attentions */
203: CompleteQueue(&sp->frpb, err); /* Abort outstanding forward resets */
204:
205: if (sp->sbuf_mb) { /* clear the send queue */
206: gbuf_freel(sp->sbuf_mb);
207: sp->sbuf_mb = 0;
208: }
209:
210: if (sp->csbuf_mb) {
211: gbuf_freem(sp->csbuf_mb);
212: sp->csbuf_mb = 0;
213: }
214: sp->sData = 0;
215:
216: return(total);
217: }
218:
219: /*
220: * DoClose
221: *
222: * Called from several places (probe timeout, recv close advice,
223: * dspRemove, etc.) to change state of connection to closed and
224: * complete all outstanding I/O.
225: *
226: * Will also remove the CCB if there is a dsp remove pending.
227: *
228: * INPUTS:
229: * sp An ADSP stream
230: * OUTPUTS:
231: * none
232: */
233: void DoClose(sp, err, force_abort) /* (CCBPtr sp, OSErr err) */
234: register CCBPtr sp;
235: int err;
236: {
237: register struct adspcmd *pb, *np;
238: register gbuf_t *mp;
239: int aborted_count;
240:
241: dPrintf(D_M_ADSP, D_L_TRACE, ("DoClose: pid=%d,e=%d,a=%d,s=%d,r=%d\n",
242: sp->pid, err, force_abort, sp->localSocket, sp->removing));
243: sp->userFlags |= eClosed; /* Set flag */
244: sp->state = sClosed;
245: sp->openState = O_STATE_NOTHING;
246:
247: /*
248: * Clean up any timer elements
249: */
250: RemoveTimerElem(&adspGlobal.slowTimers, &sp->ProbeTimer);
251: RemoveTimerElem(&adspGlobal.fastTimers, &sp->FlushTimer);
252: RemoveTimerElem(&adspGlobal.fastTimers, &sp->RetryTimer);
253: RemoveTimerElem(&adspGlobal.fastTimers, &sp->AttnTimer);
254: RemoveTimerElem(&adspGlobal.fastTimers, &sp->ResetTimer);
255:
256: aborted_count = AbortIO(sp, err);
257: np = sp->opb; /* Get list of close/removes to complete */
258: sp->opb = 0; /* set this list null */
259:
260: while (pb = np) { /* Handle all of the close/remove param blks */
261: np = (struct adspcmd *)pb->qLink; /* Get next guy (if any) */
262: pb->qLink = 0;
263: pb->ioResult = err;
264: completepb(sp, pb);
265: }
266: if (sp->removing && (force_abort >= 0)) { /* Abort outstanding receives */
267: aborted_count += CompleteQueue(&sp->rpb, err);
268:
269: if (sp->deferred_mb) {
270: gbuf_freel(sp->deferred_mb);
271: sp->deferred_mb = 0;
272: }
273: if (sp->attn_mb) {
274: gbuf_freem(sp->attn_mb);
275: sp->attn_mb = 0;
276: }
277: if (sp->rbuf_mb) { /* clear the rcv queue */
278: gbuf_freem(sp->rbuf_mb);
279: sp->rbuf_mb = 0;
280: }
281: if (sp->crbuf_mb) {
282: gbuf_freem(sp->crbuf_mb);
283: sp->crbuf_mb = 0;
284: }
285: sp->rData = 0;
286:
287: /* if our connection has been timed out */
288: /* and the user wasn't notified of the TearDown */
289: /* because of pending requests on this socket */
290: /* then fake a read completion to force the notification */
291:
292: if (force_abort && aborted_count == 0) {
293: if (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) {
294: pb = (struct adspcmd *)gbuf_rptr(mp);
295: gbuf_wset(mp,sizeof(struct adspcmd));
296:
297: bzero((caddr_t) pb, sizeof(struct adspcmd));
298: pb->mp = mp;
299: pb->csCode = dspRead;
300: pb->ioResult = errAborted;
301: completepb(sp, pb); /* send fake read completion */
302: }
303: }
304: sp->removing = 0;
305: RemoveCCB(sp, 0); /* Will call completion routine */
306: }
307: sp->userFlags &= ~eClosed;
308: }
309:
310:
311: /*
312: * dspClose
313: *
314: * Also called for dspRemove and dspCLRemove.
315: * Must handle case of multiple close calls being issued (without
316: * abort bit set) Can only allow one pending remove though.
317: *
318: * INPUTS:
319: * --> ccbRefNum refnum of connection end
320: * --> abort abort the connection
321: *
322: * OUTPUTS:
323: * none
324: *
325: * ERRORS:
326: * errRefNum Bad connection Refnum
327: */
328: int adspClose(sp, pb) /* (DSPPBPtr pb) */
329: register CCBPtr sp;
330: register struct adspcmd *pb;
331: {
332: int s;
333: register gbuf_t *mp;
334:
335: /* Must execute nearly all of this with ints off because user could
336: * be issuing a second dspRemove while the first is pending. Until
337: * we can detect this, we must not allow interrupts.
338: * Also, we can't handle the case where a close was issued earlier,
339: * and now this is the remove. If the write completion for the
340: * close advice packet occurs in the middle of this, we might screw up.
341: */
342:
343: if (sp == 0) {
344: pb->ioResult = errRefNum;
345: return EINVAL;
346: }
347:
348: /*
349: * Handle dspCLRemove
350: */
351: if (pb->csCode == (short)dspCLRemove) { /* Remove connection listener */
352: if (sp->state != (short)sListening) { /* But it's not a listener! */
353: pb->ioResult = errState;
354: return EINVAL;
355: }
356: CompleteQueue(&sp->opb, errAborted); /* Complete all dspListens */
357: RemoveCCB(sp, pb); /* Will call completion routine */
358: return 0;
359: }
360:
361:
362: /*
363: * Either dspClose or dspRemove
364: */
365:
366: if (sp->removing) { /* Don't allow dspRemove or dspClose */
367: /* after one dspRemove has been issued. */
368: pb->ioResult = errState;
369: return EINVAL;
370: }
371:
372:
373: /*
374: * The previous Macintosh ADSP allowed you to call close on a
375: * connection that was in the process of opening or passively
376: * waiting for an open request. It is also legal to close a
377: * connection that is already closed. No error will be generated.
378: *
379: * It is also legal to issue a second close call while the first
380: * is still pending.
381: */
382: if (pb->csCode == (short)dspClose) {
383: ATDISABLE(s, sp->lock);
384: if ((sp->state == (short)sPassive) || (sp->state == (short)sOpening)) {
385: sp->state = sClosed;
386: ATENABLE(s, sp->lock);
387: DoClose(sp, errAborted, 0);
388: pb->ioResult = 0;
389: adspioc_ack(0, pb->ioc, pb->gref);
390: return 0;
391: }
392:
393: if (sp->state == (word)sClosed) { /* Ok to close a closed connection */
394: ATENABLE(s, sp->lock);
395: pb->ioResult = 0;
396: adspioc_ack(0, pb->ioc, pb->gref);
397: return 0;
398: }
399: if ((sp->state != (word)sOpen) && (sp->state != (word)sClosing)) {
400: ATENABLE(s, sp->lock);
401: pb->ioResult = errState;
402: return EINVAL;
403: }
404:
405: sp->state = sClosing; /* No matter what, we're closing */
406: ATENABLE(s, sp->lock);
407: } /* dspClose */
408:
409: else { /* dspRemove */
410: ATDISABLE(s, sp->lock);
411: sp->removing = 1; /* Prevent allowing another dspClose. */
412: /* Tells completion routine of close */
413: /* packet to remove us. */
414:
415: if (sp->state == sPassive || sp->state == sClosed ||
416: sp->state == sOpening) {
417: sp->state = sClosed;
418: ATENABLE(s, sp->lock);
419: DoClose(sp, errAborted, 0); /* Will remove CCB! */
420: return 0;
421: } else { /* sClosing & sOpen */
422: sp->state = sClosing;
423: ATENABLE(s, sp->lock);
424: }
425:
426: } /* dspRemove */
427:
428: if (pb->u.closeParams.abort || CheckOkToClose(sp)) /* going to close */
429: {
430: AbortIO(sp, errAborted);
431: sp->sendCtl = B_CTL_CLOSE; /* Send close advice */
432: }
433:
434: pb->ioResult = 1;
435: if ( (mp = gbuf_copym(pb->mp)) ) { /* duplicate user request */
436: adspioc_ack(0, pb->ioc, pb->gref); /* release user */
437: pb = (struct adspcmd *)gbuf_rptr(mp); /* get new parameter block */
438: pb->ioc = 0;
439: pb->mp = mp;
440: ATDISABLE(s, sp->lock);
441: qAddToEnd(&sp->opb, pb); /* and save it */
442: ATENABLE(s, sp->lock);
443: } else {
444: pb->ioResult = 0;
445: adspioc_ack(0, pb->ioc, pb->gref); /* release user, and keep no copy
446: * for kernel bookkeeping, yetch!
447: */
448: }
449: CheckSend(sp);
450:
451: return 0;
452: }
453:
454: static void qRemove(qptr, elem)
455: register CCBPtr qptr;
456: register CCBPtr elem;
457: {
458: int s;
459:
460: ATDISABLE(s, adspall_lock);
461: while(qptr->ccbLink) {
462: if ((DSPPBPtr)(qptr->ccbLink) == (DSPPBPtr)elem) {
463: qptr->ccbLink = elem->ccbLink;
464: elem->ccbLink = 0;
465: ATENABLE(s, adspall_lock);
466: return;
467: }
468: qptr = qptr->ccbLink;
469: }
470: ATENABLE(s, adspall_lock);
471: }
472:
473: int RxClose(sp)
474: register CCBPtr sp;
475: {
476: register gbuf_t *mp;
477: register struct adspcmd *pb;
478: int s, l;
479:
480: ATDISABLE(l, sp->lockClose);
481: ATDISABLE(s, sp->lock);
482: if ((sp->state == sClosing) || (sp->state == sClosed)) {
483: ATENABLE(s, sp->lock);
484: ATENABLE(l, sp->lockClose);
485: return 0;
486: }
487: sp->state = sClosed;
488: ATENABLE(s, sp->lock);
489: CheckReadQueue(sp); /* try to deliver all remaining data */
490:
491: if ( (mp = gbuf_alloc(sizeof(struct adspcmd), PRI_HI)) ) {
492: pb = (struct adspcmd *)gbuf_rptr(mp);
493: gbuf_wset(mp,sizeof(struct adspcmd));
494: pb->ioc = 0;
495: pb->mp = mp;
496:
497: pb->csCode = dspClose;
498: pb->ioResult = 0;
499: completepb(sp, pb); /* send close completion */
500: }
501:
502: if ((sp->userFlags & eClosed) == 0)
503: DoClose(sp, errAborted, -1); /* abort send requests and timers */
504:
505: ATENABLE(l, sp->lockClose);
506: return 0;
507: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.