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

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.
        !             6: **     @(#) $Id: HTMuxCh.c,v 1.1.2.6 1996/11/08 19:49:45 eric Exp $
        !             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 */
        !            18: #include "sysdep.h"
        !            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;
        !           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];
        !           165:        HTMuxSession_setClose(muxch, session, MUX_S_END_WRITE);
        !           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: 
        !           186: PUBLIC BOOL HTMuxSession_setClose (HTMuxChannel * muxch,
        !           187:                                   HTMuxSession * session, HTMuxClose close)
        !           188: {
        !           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:        }
        !           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);
        !           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:                */
        !           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;
        !           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);
        !           320:        if (status >= 0) {
        !           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)
        !           332: {
        !           333:     if (ch) {
        !           334:        HT_FREE(ch);
        !           335:        return YES;
        !           336:     }
        !           337:     return NO;
        !           338: }
        !           339: 
        !           340: PUBLIC HTMuxChannel * HTMuxChannel_new (HTHost * host)
        !           341: {
        !           342:     if (host) {
        !           343:        HTMuxChannel * me = NULL;
        !           344: 
        !           345:        /* Create new object */
        !           346:        if ((me = (HTMuxChannel *) HT_CALLOC(1, sizeof(HTMuxChannel))) == NULL)
        !           347:            HT_OUTOFMEM("HTMuxChannel_new");
        !           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);
        !           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);
        !           361:        HTNet_setReadStream(me->net, HTDemux_new(host, me));
        !           362: 
        !           363:        /* Insert into hash table */
        !           364:        if (!muxchs) {
        !           365:            if ((muxchs=(HTList **) HT_CALLOC(HOST_HASH_SIZE, sizeof(HTList *))) == NULL)
        !           366:                HT_OUTOFMEM("HTMuxChannel_new");
        !           367:        }
        !           368:        if (!muxchs[me->hash]) muxchs[me->hash] = HTList_new();
        !           369:        HTList_addObject(muxchs[me->hash], (void *) me);
        !           370:        if (MUX_TRACE)
        !           371:            HTTrace("Mux Channel. %p created with hash %d\n",me, me->hash);
        !           372:        return me;
        !           373:     }
        !           374:     return NULL;
        !           375: }
        !           376: 
        !           377: PUBLIC HTMuxChannel * HTMuxChannel_find (HTHost * host)
        !           378: {
        !           379:     if (muxchs) {
        !           380:        int hash = HTHost_hash(host);
        !           381:        HTList * list = muxchs[hash];
        !           382:        if (list) {
        !           383:            HTMuxChannel * pres = NULL;
        !           384:            while ((pres = (HTMuxChannel *) HTList_nextObject(list)))
        !           385:                if (pres->host == host) return pres;
        !           386:        }
        !           387:     }
        !           388:     return NULL;
        !           389: }
        !           390: 
        !           391: PUBLIC BOOL HTMuxChannel_delete (HTMuxChannel * me)
        !           392: {
        !           393:     if (me) {
        !           394:        HTList * list = NULL;
        !           395:        if (MUX_TRACE) HTTrace("Mux Channel. Deleting %p\n", me);
        !           396:        if (muxchs && (list = muxchs[me->hash])) {
        !           397:            HTList_removeObject(list, (void *) me);
        !           398:            channel_delete(me);
        !           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;
        !           410:        for (cnt=0; cnt<HOST_HASH_SIZE; cnt++) {
        !           411:            if ((cur = muxchs[cnt])) { 
        !           412:                HTMuxChannel * pres;
        !           413:                while ((pres = (HTMuxChannel *) HTList_nextObject(cur)))
        !           414:                    channel_delete(pres);
        !           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: 
        !           428: PUBLIC HTMuxSession * HTMuxChannel_findSession (HTMuxChannel * me, HTMuxSessionId sid)
        !           429: {
        !           430:     return (me) ? me->sessions[sid] : NULL;
        !           431: }
        !           432: 
        !           433: #if 0
        !           434: PUBLIC HTMuxSession * HTMuxChannel_findSessionFromNet (HTMuxChannel * me, HTNet * net)
        !           435: {
        !           436:     if (me && net) {
        !           437:        int cnt = 0;
        !           438:        HTMuxSession **session = me->sessions;
        !           439:        while (cnt<MAX_SESSIONS) {
        !           440:            if (**session->net == net) return *session;
        !           441:            session++, cnt++;
        !           442:        }           
        !           443:     }
        !           444:     return NULL;
        !           445: }
        !           446: #endif
        !           447: 
        !           448: PUBLIC HTHost * HTMuxChannel_host (HTMuxChannel * muxch)
        !           449: {
        !           450:     return muxch ? muxch->host : NULL;
        !           451: }
        !           452: 
        !           453: PUBLIC int HTMuxChannel_sendControl (HTMuxChannel * muxch, HTMuxSessionId sid,
        !           454:                                     HTMuxHeader opcode, int value,
        !           455:                                     const void * param, int param_size)
        !           456: {
        !           457:     if (muxch && muxch->host) {
        !           458:        HTOutputStream * me = HTChannel_output(HTHost_channel(muxch->host));
        !           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:        }
        !           490: 
        !           491:        /* Flush for now */
        !           492: #if 1
        !           493:        return (*me->isa->flush)(me);
        !           494: #else
        !           495:        return HT_OK;
        !           496: #endif
        !           497:     }
        !           498:     return HT_ERROR;
        !           499: }
        !           500: 
        !           501: /* ------------------------------------------------------------------------- */
        !           502: 
        !           503: PUBLIC BOOL HTMuxProtocol_add (HTMuxChannel * muxch,
        !           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;
        !           532: }

Webmaster