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