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

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

Webmaster