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