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