Annotation of libwww/Library/src/HTMuxCh.c, revision 1.1.2.6
1.1.2.1 frystyk 1: /*
1.1.2.3 frystyk 2: ** MUX CHANNEL, SESSION AND PROTOCOL MANAGEMENT
1.1.2.1 frystyk 3: **
4: ** (c) COPYRIGHT MIT 1995.
5: ** Please first read the full copyright statement in the file COPYRIGH.
1.1.2.6 ! eric 6: ** @(#) $Id: HTMuxCh.c,v 1.1.2.5 1996/11/07 18:47:30 frystyk Exp $
1.1.2.1 frystyk 7: **
1.1.2.3 frystyk 8: ** Handles a MUX Channel with sessions and protocols
1.1.2.1 frystyk 9: **
10: ** Authors
11: ** HFN Henrik Frystyk Nielsen <frystyk@w3.org>
12: **
13: ** HISTORY:
14: ** Oct 96 HFN Written
15: */
16:
17: /* Library Include files */
18: #include "sysdep.h"
19: #include "WWWUtil.h"
20: #include "WWWCore.h"
21: #include "WWWTrans.h"
1.1.2.3 frystyk 22: #include "WWWStream.h"
1.1.2.1 frystyk 23: #include "HTMuxTx.h"
1.1.2.3 frystyk 24: #include "HTMuxHeader.h"
1.1.2.1 frystyk 25: #include "HTDemux.h"
26: #include "HTMuxCh.h" /* Implemented here */
27:
28: #define MAX_SESSIONS 0xFF /* Max 256 sessions */
29:
30: #define SID_BASE 2
31: #define RECEIVER_OFFSET 0 /* Client control session */
32: #define SENDER_OFFSET 1 /* Server control session */
33:
1.1.2.3 frystyk 34: struct _HTStream {
35: const HTStreamClass * isa;
36: /* ... */
37: };
38:
39: struct _HTOutputStream {
40: const HTOutputStreamClass * isa;
41: /* ... */
42: };
43:
44: #define PUTBLOCK(b,l) (*me->isa->put_block)(me,(b),(l))
45:
46: struct _HTMuxProtocol {
1.1.2.2 frystyk 47: HTAtom * name;
48: HTProtocolId pid;
1.1.2.3 frystyk 49: };
50:
51: struct _HTMuxSession {
52: HTMuxSessionId sid;
53: HTProtocolId pid;
54: HTNet * net;
55:
56: /* State */
1.1.2.5 frystyk 57: HTMuxClose close; /* State of the connection */
58: int credit; /* Available credit */
59: int fragment; /* Fragment size */
60: int read; /* Data read sine last credit */
1.1.2.3 frystyk 61:
62: /* Input */
63: HTStream * buffer; /* If we have to buffer data */
64: BOOL buffering;
65: };
1.1.2.2 frystyk 66:
1.1.2.1 frystyk 67: struct _HTMuxChannel {
68: int hash;
1.1.2.5 frystyk 69: HTHost * host;
1.1.2.1 frystyk 70: int max_sid; /* A la max_sockfd in select */
71: HTNet * net;
1.1.2.2 frystyk 72: HTList * protocols; /* List of defined protocols */
1.1.2.3 frystyk 73: HTMuxSession * sessions[MAX_SESSIONS];
1.1.2.1 frystyk 74: };
75:
1.1.2.2 frystyk 76: PRIVATE HTList ** muxchs = NULL; /* List of mux muxchs */
1.1.2.1 frystyk 77:
78: /* ------------------------------------------------------------------------- */
79:
1.1.2.3 frystyk 80: PRIVATE HTMuxSession * session_new (void)
81: {
82: HTMuxSession * me;
83: if ((me = (HTMuxSession *) HT_CALLOC(1, sizeof(HTMuxSession))) == NULL)
84: HT_OUTOFMEM("HTMuxSession_new");
85: me->credit = DEFAULT_CREDIT;
86: return me;
87: }
88:
89: PRIVATE BOOL session_delete (HTMuxSession * session)
90: {
91: if (session) {
92: HT_FREE(session);
93: return YES;
94: }
95: return NO;
96: }
97:
98: PUBLIC HTMuxSession * HTMuxSession_register (HTMuxChannel * muxch,
99: HTMuxSessionId sid, HTProtocolId pid)
100: {
101: if (muxch) {
102: HTMuxSession * session = muxch->sessions[sid];
103: if (session == NULL) {
104: session = session_new();
105: session->sid = sid;
106: session->pid = pid;
107: muxch->sessions[sid] = session;
108: if (MUX_TRACE)
109: HTTrace("Mux Channel. Registered session %d on channel %p\n",
110: sid, muxch);
111: }
112: return session;
113: }
114: if (MUX_TRACE) HTTrace("Mux Channel. Can't register new session\n");
115: return NULL;
116: }
117:
118: PUBLIC HTMuxSessionId HTMuxSession_accept (HTMuxChannel * muxch, HTNet * net,
119: HTProtocolId pid)
120: {
121: if (muxch && net) {
122: HTMuxSession * session;
123: HTMuxSessionId sid = SID_BASE + RECEIVER_OFFSET;
124: for (; sid<MAX_SESSIONS; sid+=2) {
125: if ((session = muxch->sessions[sid]) &&
126: session->net == NULL && session->pid == pid) {
127: if (MUX_TRACE)
128: HTTrace("Mux Channel. Accepting session %d on channel %p\n",
129: sid, muxch);
130: return sid;
131: }
132: }
133: }
134: if (MUX_TRACE) HTTrace("Mux Channel. Can't accept new session\n");
135: return INVSID;
136: }
137:
138: PUBLIC HTMuxSessionId HTMuxSession_connect (HTMuxChannel * muxch, HTNet * net,
139: HTProtocolId pid)
140: {
141: if (muxch && net) {
142: HTMuxSessionId sid = SID_BASE + SENDER_OFFSET;
143: for (; sid<MAX_SESSIONS; sid+=2) {
144: if (muxch->sessions[sid] == NULL) {
145: HTMuxSession * session = session_new();
146: session->sid = sid;
147: session->pid = pid;
148: session->net = net;
149: muxch->sessions[sid] = session;
150: if (MUX_TRACE)
151: HTTrace("Mux Channel. Creating session %d on channel %p\n",
152: sid, muxch);
153: return sid;
154: }
155: }
156: }
157: if (MUX_TRACE) HTTrace("Mux Channel. Can't create new session\n");
158: return INVSID;
159: }
160:
161: PUBLIC int HTMuxSession_close (HTMuxChannel * muxch, HTMuxSessionId sid)
162: {
163: if (muxch) {
164: HTMuxSession * session = muxch->sessions[sid];
1.1.2.5 frystyk 165: HTMuxSession_setClose(muxch, session, MUX_S_END_WRITE);
1.1.2.3 frystyk 166: return YES;
167: }
168: return NO;
169: }
170:
171: PUBLIC HTMuxSessionId HTMuxSession_id (HTMuxSession * session)
172: {
173: return session ? session->sid : INVSID;
174: }
175:
176: PUBLIC HTProtocolId HTMuxSession_pid (HTMuxSession * session)
177: {
178: return session ? session->pid : INVPID;
179: }
180:
181: PUBLIC HTNet * HTMuxSession_net (HTMuxSession * session)
182: {
183: return session ? session->net : NULL;
184: }
185:
1.1.2.5 frystyk 186: PUBLIC BOOL HTMuxSession_setClose (HTMuxChannel * muxch,
187: HTMuxSession * session, HTMuxClose close)
1.1.2.3 frystyk 188: {
1.1.2.5 frystyk 189: if (muxch && session) {
190: session->close |= close;
191:
192: /*
193: ** If both directions are closed down then we can put the session
194: ** to sleep.
195: */
196: if (session->close == MUX_S_END) {
197: if (MUX_TRACE)
198: HTTrace("Mux Channel. Closing session %d on channel %p\n",
199: session->sid, muxch);
200: muxch->sessions[session->sid] = NULL;
201: session_delete(session);
202: }
1.1.2.3 frystyk 203: return YES;
204: }
205: return NO;
206: }
207:
208: PUBLIC int HTMuxSession_credit (HTMuxSession * session)
209: {
210: return session ? session->credit : -1;
211: }
212:
213: PUBLIC BOOL HTMuxSession_setCredit (HTMuxChannel * muxch,
214: HTMuxSessionId sid, int credit)
215: {
216: HTMuxSession * session;
217: if (muxch && (session = muxch->sessions[sid])) {
218: session->credit = credit;
219: return YES;
220: }
221: return NO;
222: }
223:
224: PUBLIC int HTMuxSession_fragment (HTMuxSession * session)
225: {
226: return session ? session->fragment : -1;
227: }
228:
229: PUBLIC BOOL HTMuxSession_setFragment (HTMuxChannel * muxch,
230: HTMuxSessionId sid, int fragment)
231: {
232: HTMuxSession * session;
233: if (muxch && (session = muxch->sessions[sid])) {
234: session->fragment = fragment;
235: return YES;
236: }
237: return NO;
238: }
239:
240: /*
241: ** Tries really hard to get rid of the data.
242: ** Returns:
243: ** -1 Error
244: ** 0 Buffered the data
245: ** 1 Got rid of the data
246: */
247: PUBLIC int HTMuxSession_disposeData (HTMuxSession * me, const char * buf, int len)
248: {
249: if (MUX_TRACE)
250: HTTrace("Mux Channel. Writing %d bytes to session %p\n", len, me);
251:
252: /*
253: ** There are two situations that can occur: Either we have an accepted session
254: ** with a Net object or we have an unaccepted session with no Net object. In
255: ** the former case we try to get rid of the data by pushing it directly to the
256: ** read stream of the Net object. In the latter case we buffer as much as we
257: ** can.
258: */
259: if (me) {
260: HTNet * net;
261: HTStream * sink;
262: int status;
263: if ((net = me->net) && (sink = HTNet_readStream(net))) {
264:
265: /*
266: ** Look first to see if we have old data that we can dispose down
267: ** the sink. We keep the buffer stream so that we can reuse it later.
268: */
269: if (me->buffer && me->buffering) {
270: if ((*me->buffer->isa->flush)(me->buffer) == HT_OK) {
271: if (MUX_TRACE) HTTrace("Mux Channel. Flushed buffered data\n");
272: me->buffering = NO;
273: } else if ((*me->buffer->isa->put_block)(me->buffer, buf, len) >= 0) {
274: if (MUX_TRACE) HTTrace("Mux Channel. Buffer accepted data\n");
275: return 0;
276: }
277: if (MUX_TRACE) HTTrace("Mux Channel. Can't buffer data\n");
278: return (-1);
279: }
280:
281: /*
282: ** See if we can get rid of the new data. If not then try to buffer it.
283: ** If this also fails then we reset the channel. A positive return code
284: ** from the stream means that we got rid of the data successfully.
285: */
286: if ((status = (*sink->isa->put_block)(sink, buf, len)) >= 0) {
287: if (MUX_TRACE) HTTrace("Mux Channel. Stream returned %d\n", status);
1.1.2.4 frystyk 288:
289: /*
290: ** If we get back a HT_LOADED then we have all the data we need
291: ** and we can terminate the request
292: */
1.1.2.5 frystyk 293: if (status == HT_LOADED) {
294: HTNet_execute (net, HTEvent_END);
295: return 0;
296: }
297:
298: /*
299: ** Decide whether we should send a credit message
300: ** MORE TO COME
301: */
302: me->read += len;
303: if (me->read >= DEFAULT_CREDIT / 2) {
304: me->read = 0;
305: return 1;
306: }
307: return 0;
1.1.2.3 frystyk 308: }
309: }
310:
311: /*
312: ** The stream is not ready and we try to buffer the data in
313: ** the meantime.
314: */
315: if (!me->buffer) {
316: me->buffer = HTPipeBuffer(sink, DEFAULT_CREDIT);
317: me->buffering = YES;
318: }
319: status = (*me->buffer->isa->put_block)(me->buffer, buf, len);
1.1.2.4 frystyk 320: if (status >= 0) {
1.1.2.3 frystyk 321: if (MUX_TRACE) HTTrace("Mux Channel. Buffer accepted data\n");
322: return 0;
323: }
324: if (MUX_TRACE) HTTrace("Mux Channel. Buffer returned %d\n", status);
325: }
326: return (-1);
327: }
328:
329: /* ------------------------------------------------------------------------- */
330:
331: PRIVATE BOOL channel_delete (HTMuxChannel * ch)
1.1.2.1 frystyk 332: {
333: if (ch) {
334: HT_FREE(ch);
335: return YES;
336: }
337: return NO;
338: }
339:
1.1.2.5 frystyk 340: PUBLIC HTMuxChannel * HTMuxChannel_new (HTHost * host)
1.1.2.1 frystyk 341: {
1.1.2.5 frystyk 342: if (host) {
1.1.2.1 frystyk 343: HTMuxChannel * me = NULL;
344:
345: /* Create new object */
346: if ((me = (HTMuxChannel *) HT_CALLOC(1, sizeof(HTMuxChannel))) == NULL)
347: HT_OUTOFMEM("HTMuxChannel_new");
1.1.2.5 frystyk 348: me->hash = HTHost_hash(host);
349: me->host = host;
350:
351: /*
352: ** Make sure that we are in interleave mode
353: */
354: HTHost_setMode(host, HT_TP_INTERLEAVE);
1.1.2.1 frystyk 355:
356: /*
357: ** Get a special MUX Net object that we keep to our selves. We don't
358: ** associate a request object as the Net object lives longer.
359: */
360: me->net = HTNet_new(NULL);
1.1.2.5 frystyk 361: HTNet_setReadStream(me->net, HTDemux_new(host, me));
1.1.2.1 frystyk 362:
363: /* Insert into hash table */
364: if (!muxchs) {
1.1.2.5 frystyk 365: if ((muxchs=(HTList **) HT_CALLOC(HOST_HASH_SIZE, sizeof(HTList *))) == NULL)
1.1.2.1 frystyk 366: HT_OUTOFMEM("HTMuxChannel_new");
367: }
368: if (!muxchs[me->hash]) muxchs[me->hash] = HTList_new();
369: HTList_addObject(muxchs[me->hash], (void *) me);
1.1.2.3 frystyk 370: if (MUX_TRACE)
1.1.2.1 frystyk 371: HTTrace("Mux Channel. %p created with hash %d\n",me, me->hash);
372: return me;
373: }
374: return NULL;
375: }
376:
1.1.2.5 frystyk 377: PUBLIC HTMuxChannel * HTMuxChannel_find (HTHost * host)
1.1.2.1 frystyk 378: {
1.1.2.5 frystyk 379: if (muxchs) {
380: int hash = HTHost_hash(host);
1.1.2.1 frystyk 381: HTList * list = muxchs[hash];
382: if (list) {
383: HTMuxChannel * pres = NULL;
384: while ((pres = (HTMuxChannel *) HTList_nextObject(list)))
1.1.2.5 frystyk 385: if (pres->host == host) return pres;
1.1.2.1 frystyk 386: }
387: }
388: return NULL;
389: }
390:
391: PUBLIC BOOL HTMuxChannel_delete (HTMuxChannel * me)
392: {
393: if (me) {
394: HTList * list = NULL;
1.1.2.3 frystyk 395: if (MUX_TRACE) HTTrace("Mux Channel. Deleting %p\n", me);
1.1.2.1 frystyk 396: if (muxchs && (list = muxchs[me->hash])) {
397: HTList_removeObject(list, (void *) me);
1.1.2.3 frystyk 398: channel_delete(me);
1.1.2.1 frystyk 399: return YES;
400: }
401: }
402: return NO;
403: }
404:
405: PUBLIC BOOL HTMuxChannel_deleteAll (void)
406: {
407: if (muxchs) {
408: HTList * cur;
409: int cnt;
1.1.2.5 frystyk 410: for (cnt=0; cnt<HOST_HASH_SIZE; cnt++) {
1.1.2.1 frystyk 411: if ((cur = muxchs[cnt])) {
412: HTMuxChannel * pres;
413: while ((pres = (HTMuxChannel *) HTList_nextObject(cur)))
1.1.2.3 frystyk 414: channel_delete(pres);
1.1.2.1 frystyk 415: }
416: HTList_delete(muxchs[cnt]);
417: }
418: HT_FREE(muxchs);
419: }
420: return YES;
421: }
422:
423: PUBLIC HTNet * HTMuxChannel_net (HTMuxChannel * me)
424: {
425: return me ? me->net : NULL;
426: }
427:
1.1.2.5 frystyk 428: PUBLIC HTMuxSession * HTMuxChannel_findSession (HTMuxChannel * me, HTMuxSessionId sid)
1.1.2.1 frystyk 429: {
430: return (me) ? me->sessions[sid] : NULL;
431: }
432:
1.1.2.5 frystyk 433: #if 0
434: PUBLIC HTMuxSession * HTMuxChannel_findSessionFromNet (HTMuxChannel * me, HTNet * net)
1.1.2.1 frystyk 435: {
436: if (me && net) {
437: int cnt = 0;
1.1.2.3 frystyk 438: HTMuxSession **session = me->sessions;
1.1.2.1 frystyk 439: while (cnt<MAX_SESSIONS) {
1.1.2.5 frystyk 440: if (**session->net == net) return *session;
1.1.2.1 frystyk 441: session++, cnt++;
442: }
443: }
444: return NULL;
445: }
1.1.2.5 frystyk 446: #endif
1.1.2.1 frystyk 447:
1.1.2.5 frystyk 448: PUBLIC HTHost * HTMuxChannel_host (HTMuxChannel * muxch)
1.1.2.1 frystyk 449: {
1.1.2.5 frystyk 450: return muxch ? muxch->host : NULL;
1.1.2.2 frystyk 451: }
452:
1.1.2.3 frystyk 453: PUBLIC int HTMuxChannel_sendControl (HTMuxChannel * muxch, HTMuxSessionId sid,
454: HTMuxHeader opcode, int value,
455: const void * param, int param_size)
456: {
1.1.2.5 frystyk 457: if (muxch && muxch->host) {
458: HTOutputStream * me = HTChannel_output(HTHost_channel(muxch->host));
1.1.2.3 frystyk 459: HTMuxHeader header[2];
460: switch (opcode) {
461: case MUX_STRING:
462: if (param && param_size) {
463: header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_LEN(value));
464: header[1] = HT_WORDSWAP(param_size);
465: PUTBLOCK((const char *) header, 8);
466: PUTBLOCK((const char *) param, MUX_LONG_ALIGN(param_size));
467: }
468: break;
469: case MUX_STACK:
470: if (param && param_size) {
471: header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_LEN(value));
472: header[1] = HT_WORDSWAP(param_size);
473: PUTBLOCK((const char *) header, 8);
474: PUTBLOCK((const char *) param, MUX_LONG_ALIGN(param_size));
475: }
476: break;
477: case MUX_FRAGMENT:
478: header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_SET_SID(sid) | MUX_SET_LEN(value));
479: PUTBLOCK((const char *) header, 4);
480: break;
481: case MUX_CREDIT:
482: header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_SID(sid));
483: header[1] = HT_WORDSWAP(value);
484: PUTBLOCK((const char *) header, 8);
485: break;
486: default:
487: if (MUX_TRACE) HTTrace("Mux Channel. UNKNOWN OPCODE %d\n", opcode);
488: return HT_ERROR;
489: }
1.1.2.5 frystyk 490:
491: /* Flush for now */
492: #if 1
493: return (*me->isa->flush)(me);
494: #else
1.1.2.6 ! eric 495: return HT_OK;
! 496: #endif
1.1.2.3 frystyk 497: }
498: return HT_ERROR;
499: }
500:
1.1.2.2 frystyk 501: /* ------------------------------------------------------------------------- */
502:
1.1.2.3 frystyk 503: PUBLIC BOOL HTMuxProtocol_add (HTMuxChannel * muxch,
1.1.2.2 frystyk 504: HTProtocolId pid, const char * protocol)
505: {
506: if (muxch && protocol) {
507: HTMuxProtocol * ms;
508: if ((ms = (HTMuxProtocol *) HT_CALLOC(1, sizeof(HTMuxProtocol))) == NULL)
509: HT_OUTOFMEM("HTMuxProtocol_new");
510: ms->name = HTAtom_caseFor(protocol);
511: ms->pid = pid;
512: if (!muxch->protocols) muxch->protocols = HTList_new();
513: return HTList_addObject(muxch->protocols, ms);
514: }
515: return NO;
516: }
517:
518: PUBLIC BOOL HTMuxProtocol_delete (HTMuxChannel * muxch, HTProtocolId pid)
519: {
520: if (muxch && muxch->protocols) {
521: HTList * cur = muxch->protocols;
522: HTMuxProtocol * pres;
523: while ((pres = (HTMuxProtocol *) HTList_nextObject(cur))) {
524: if (pres->pid == pid) {
525: HTList_removeObject(muxch->protocols, pres);
526: HT_FREE(pres);
527: return YES;
528: }
529: }
530: }
531: return NO;
1.1.2.1 frystyk 532: }
Webmaster