Annotation of libwww/Library/src/HTMuxCh.c, revision 1.1.2.4

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.4 ! frystyk     6: **     @(#) $Id: HTMuxCh.c,v 1.1.2.3 1996/11/05 21:43:10 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);
1.1.2.4 ! frystyk   286:                
        !           287:                /*
        !           288:                **  If we get back a HT_LOADED then we have all the data we need
        !           289:                **  and we can terminate the request
        !           290:                */
        !           291:                if (status == HT_LOADED) HTNet_execute (net, HTEvent_END);
1.1.2.3   frystyk   292:                return 1;
                    293:            }
                    294:        }
                    295: 
                    296:        /*
                    297:        **  The stream is not ready and we try to buffer the data in
                    298:        **  the meantime.
                    299:        */
                    300:        if (!me->buffer) {
                    301:            me->buffer = HTPipeBuffer(sink, DEFAULT_CREDIT);
                    302:            me->buffering = YES;
                    303:        }
                    304:        status = (*me->buffer->isa->put_block)(me->buffer, buf, len);
1.1.2.4 ! frystyk   305:        if (status >= 0) {
1.1.2.3   frystyk   306:            if (MUX_TRACE) HTTrace("Mux Channel. Buffer accepted data\n");
                    307:            return 0;
                    308:        }
                    309:        if (MUX_TRACE) HTTrace("Mux Channel. Buffer returned %d\n", status);
                    310:     }
                    311:     return (-1);
                    312: }
                    313: 
                    314: /* ------------------------------------------------------------------------- */
                    315: 
                    316: PRIVATE BOOL channel_delete (HTMuxChannel * ch)
1.1.2.1   frystyk   317: {
                    318:     if (ch) {
                    319:        HT_FREE(ch);
                    320:        return YES;
                    321:     }
                    322:     return NO;
                    323: }
                    324: 
                    325: PUBLIC HTMuxChannel * HTMuxChannel_new (HTHost * host, HTChannel * ch)
                    326: {
                    327:     if (host && ch) {
                    328:        HTMuxChannel * me = NULL;
                    329: 
                    330:        /* Create new object */
                    331:        if ((me = (HTMuxChannel *) HT_CALLOC(1, sizeof(HTMuxChannel))) == NULL)
                    332:            HT_OUTOFMEM("HTMuxChannel_new");
                    333:        me->hash = HASH(HTChannel_socket(ch));
                    334:        me->ch = ch;
                    335: 
                    336:        /*
                    337:        **  Get a special MUX Net object that we keep to our selves. We don't
                    338:        **  associate a request object as the Net object lives longer.
                    339:        */
                    340:        me->net = HTNet_new(NULL);
1.1.2.2   frystyk   341:        HTNet_setReadStream(me->net, HTDemux_new(host, ch, me));
1.1.2.1   frystyk   342: 
                    343:        /* Insert into hash table */
                    344:        if (!muxchs) {
                    345:            if ((muxchs = (HTList **) HT_CALLOC(HASH_SIZE, sizeof(HTList *))) == NULL)
                    346:                HT_OUTOFMEM("HTMuxChannel_new");
                    347:        }
                    348:        if (!muxchs[me->hash]) muxchs[me->hash] = HTList_new();
                    349:        HTList_addObject(muxchs[me->hash], (void *) me);
1.1.2.3   frystyk   350:        if (MUX_TRACE)
1.1.2.1   frystyk   351:            HTTrace("Mux Channel. %p created with hash %d\n",me, me->hash);
                    352:        return me;
                    353:     }
                    354:     return NULL;
                    355: }
                    356: 
                    357: PUBLIC HTMuxChannel * HTMuxChannel_find (HTChannel * ch)
                    358: {
                    359:     if (muxchs && ch) {
                    360:        int hash = HASH(HTChannel_socket(ch));
                    361:        HTList * list = muxchs[hash];
                    362:        if (list) {
                    363:            HTMuxChannel * pres = NULL;
                    364:            while ((pres = (HTMuxChannel *) HTList_nextObject(list)))
                    365:                if (pres->ch == ch) return pres;
                    366:        }
                    367:     }
                    368:     return NULL;
                    369: }
                    370: 
                    371: PUBLIC BOOL HTMuxChannel_delete (HTMuxChannel * me)
                    372: {
                    373:     if (me) {
                    374:        HTList * list = NULL;
1.1.2.3   frystyk   375:        if (MUX_TRACE) HTTrace("Mux Channel. Deleting %p\n", me);
1.1.2.1   frystyk   376:        if (muxchs && (list = muxchs[me->hash])) {
                    377:            HTList_removeObject(list, (void *) me);
1.1.2.3   frystyk   378:            channel_delete(me);
1.1.2.1   frystyk   379:            return YES;
                    380:        }
                    381:     }
                    382:     return NO;
                    383: }
                    384: 
                    385: PUBLIC BOOL HTMuxChannel_deleteAll (void)
                    386: {
                    387:     if (muxchs) {
                    388:        HTList * cur;
                    389:        int cnt;
                    390:        for (cnt=0; cnt<HASH_SIZE; cnt++) {
                    391:            if ((cur = muxchs[cnt])) { 
                    392:                HTMuxChannel * pres;
                    393:                while ((pres = (HTMuxChannel *) HTList_nextObject(cur)))
1.1.2.3   frystyk   394:                    channel_delete(pres);
1.1.2.1   frystyk   395:            }
                    396:            HTList_delete(muxchs[cnt]);
                    397:        }
                    398:        HT_FREE(muxchs);
                    399:     }
                    400:     return YES;
                    401: }
                    402: 
                    403: PUBLIC HTNet * HTMuxChannel_net (HTMuxChannel * me)
                    404: {
                    405:     return me ? me->net : NULL;
                    406: }
                    407: 
1.1.2.3   frystyk   408: PUBLIC HTMuxSession * HTMuxChannel_findSessionFromId (HTMuxChannel * me,
                    409:                                                      HTMuxSessionId sid)
1.1.2.1   frystyk   410: {
                    411:     return (me) ? me->sessions[sid] : NULL;
                    412: }
                    413: 
1.1.2.3   frystyk   414: PUBLIC HTMuxSession * HTMuxChannel_findSessionFromNet (HTMuxChannel * me,
                    415:                                                       HTNet * net)
1.1.2.1   frystyk   416: {
                    417:     if (me && net) {
                    418:        int cnt = 0;
1.1.2.3   frystyk   419:        HTMuxSession **session = me->sessions;
1.1.2.1   frystyk   420:        while (cnt<MAX_SESSIONS) {
1.1.2.3   frystyk   421:            if (HTMuxSession_net(*session) == net) return *session;
1.1.2.1   frystyk   422:            session++, cnt++;
                    423:        }           
                    424:     }
                    425:     return NULL;
                    426: }
                    427: 
                    428: PUBLIC HTChannel * HTMuxChannel_channel (HTMuxChannel * muxch)
                    429: {
                    430:     return muxch ? muxch->ch : NULL;
1.1.2.2   frystyk   431: }
                    432: 
1.1.2.3   frystyk   433: PUBLIC int HTMuxChannel_sendControl (HTMuxChannel * muxch, HTMuxSessionId sid,
                    434:                                     HTMuxHeader opcode, int value,
                    435:                                     const void * param, int param_size)
                    436: {
                    437:     if (muxch && muxch->ch) {
                    438:        HTOutputStream * me = HTChannel_output(muxch->ch);
                    439:        HTMuxHeader header[2];
                    440:        switch (opcode) {
                    441:        case MUX_STRING:
                    442:            if (param && param_size) {
                    443:                header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_LEN(value));
                    444:                header[1] = HT_WORDSWAP(param_size);
                    445:                PUTBLOCK((const char *) header, 8);
                    446:                PUTBLOCK((const char *) param, MUX_LONG_ALIGN(param_size));
                    447:            }
                    448:            break;
                    449:        case MUX_STACK:
                    450:            if (param && param_size) {
                    451:                header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_LEN(value));
                    452:                header[1] = HT_WORDSWAP(param_size);
                    453:                PUTBLOCK((const char *) header, 8);
                    454:                PUTBLOCK((const char *) param, MUX_LONG_ALIGN(param_size));
                    455:            }
                    456:            break;
                    457:        case MUX_FRAGMENT:
                    458:            header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_SET_SID(sid) | MUX_SET_LEN(value));
                    459:            PUTBLOCK((const char *) header, 4);
                    460:            break;
                    461:        case MUX_CREDIT:
                    462:            header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_SID(sid));
                    463:            header[1] = HT_WORDSWAP(value);
                    464:            PUTBLOCK((const char *) header, 8);
                    465:            break;
                    466:        default:
                    467:            if (MUX_TRACE) HTTrace("Mux Channel. UNKNOWN OPCODE %d\n", opcode);
                    468:            return HT_ERROR;
                    469:        }
                    470:        return HT_OK;
                    471:     }
                    472:     return HT_ERROR;
                    473: }
                    474: 
1.1.2.2   frystyk   475: /* ------------------------------------------------------------------------- */
                    476: 
1.1.2.3   frystyk   477: PUBLIC BOOL HTMuxProtocol_add (HTMuxChannel * muxch,
1.1.2.2   frystyk   478:                               HTProtocolId pid, const char * protocol)
                    479: {
                    480:     if (muxch && protocol) {   
                    481:        HTMuxProtocol * ms;
                    482:        if ((ms = (HTMuxProtocol *) HT_CALLOC(1, sizeof(HTMuxProtocol))) == NULL)
                    483:            HT_OUTOFMEM("HTMuxProtocol_new");
                    484:        ms->name = HTAtom_caseFor(protocol);
                    485:        ms->pid = pid;
                    486:        if (!muxch->protocols) muxch->protocols = HTList_new();
                    487:        return HTList_addObject(muxch->protocols, ms);
                    488:     }
                    489:     return NO;
                    490: }
                    491: 
                    492: PUBLIC BOOL HTMuxProtocol_delete (HTMuxChannel * muxch, HTProtocolId pid)
                    493: {
                    494:     if (muxch && muxch->protocols) {
                    495:        HTList * cur = muxch->protocols;
                    496:        HTMuxProtocol * pres;
                    497:        while ((pres = (HTMuxProtocol *) HTList_nextObject(cur))) {
                    498:            if (pres->pid == pid) {
                    499:                HTList_removeObject(muxch->protocols, pres);
                    500:                HT_FREE(pres);
                    501:                return YES;
                    502:            }
                    503:        }
                    504:     }
                    505:     return NO;
1.1.2.1   frystyk   506: }

Webmaster