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

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.6 ! eric        6: **     @(#) $Id: HTMuxCh.c,v 1.1.2.5 1996/11/07 18:47:30 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 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: 
1.1.2.3   frystyk    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 {
1.1.2.2   frystyk    47:     HTAtom *           name;
                     48:     HTProtocolId       pid;
1.1.2.3   frystyk    49: };
                     50: 
                     51: struct _HTMuxSession {
                     52:     HTMuxSessionId     sid;
                     53:     HTProtocolId       pid;
                     54:     HTNet *            net;
                     55: 
                     56:     /* State */
1.1.2.5   frystyk    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 */
1.1.2.3   frystyk    61: 
                     62:     /* Input */
                     63:     HTStream *         buffer;                 /* If we have to buffer data */
                     64:     BOOL               buffering;
                     65: };
1.1.2.2   frystyk    66: 
1.1.2.1   frystyk    67: struct _HTMuxChannel {
                     68:     int                        hash;
1.1.2.5   frystyk    69:     HTHost *           host;
1.1.2.1   frystyk    70:     int                        max_sid;                /* A la max_sockfd in select */
                     71:     HTNet *            net;
1.1.2.2   frystyk    72:     HTList *           protocols;              /* List of defined protocols */
1.1.2.3   frystyk    73:     HTMuxSession *     sessions[MAX_SESSIONS];
1.1.2.1   frystyk    74: };
                     75: 
1.1.2.2   frystyk    76: PRIVATE HTList ** muxchs = NULL;                      /* List of mux muxchs */
1.1.2.1   frystyk    77: 
                     78: /* ------------------------------------------------------------------------- */
                     79: 
1.1.2.3   frystyk    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];
1.1.2.5   frystyk   165:        HTMuxSession_setClose(muxch, session, MUX_S_END_WRITE);
1.1.2.3   frystyk   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: 
1.1.2.5   frystyk   186: PUBLIC BOOL HTMuxSession_setClose (HTMuxChannel * muxch,
                    187:                                   HTMuxSession * session, HTMuxClose close)
1.1.2.3   frystyk   188: {
1.1.2.5   frystyk   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:        }
1.1.2.3   frystyk   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);
1.1.2.4   frystyk   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:                */
1.1.2.5   frystyk   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;
1.1.2.3   frystyk   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);
1.1.2.4   frystyk   320:        if (status >= 0) {
1.1.2.3   frystyk   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)
1.1.2.1   frystyk   332: {
                    333:     if (ch) {
                    334:        HT_FREE(ch);
                    335:        return YES;
                    336:     }
                    337:     return NO;
                    338: }
                    339: 
1.1.2.5   frystyk   340: PUBLIC HTMuxChannel * HTMuxChannel_new (HTHost * host)
1.1.2.1   frystyk   341: {
1.1.2.5   frystyk   342:     if (host) {
1.1.2.1   frystyk   343:        HTMuxChannel * me = NULL;
                    344: 
                    345:        /* Create new object */
                    346:        if ((me = (HTMuxChannel *) HT_CALLOC(1, sizeof(HTMuxChannel))) == NULL)
                    347:            HT_OUTOFMEM("HTMuxChannel_new");
1.1.2.5   frystyk   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);
1.1.2.1   frystyk   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);
1.1.2.5   frystyk   361:        HTNet_setReadStream(me->net, HTDemux_new(host, me));
1.1.2.1   frystyk   362: 
                    363:        /* Insert into hash table */
                    364:        if (!muxchs) {
1.1.2.5   frystyk   365:            if ((muxchs=(HTList **) HT_CALLOC(HOST_HASH_SIZE, sizeof(HTList *))) == NULL)
1.1.2.1   frystyk   366:                HT_OUTOFMEM("HTMuxChannel_new");
                    367:        }
                    368:        if (!muxchs[me->hash]) muxchs[me->hash] = HTList_new();
                    369:        HTList_addObject(muxchs[me->hash], (void *) me);
1.1.2.3   frystyk   370:        if (MUX_TRACE)
1.1.2.1   frystyk   371:            HTTrace("Mux Channel. %p created with hash %d\n",me, me->hash);
                    372:        return me;
                    373:     }
                    374:     return NULL;
                    375: }
                    376: 
1.1.2.5   frystyk   377: PUBLIC HTMuxChannel * HTMuxChannel_find (HTHost * host)
1.1.2.1   frystyk   378: {
1.1.2.5   frystyk   379:     if (muxchs) {
                    380:        int hash = HTHost_hash(host);
1.1.2.1   frystyk   381:        HTList * list = muxchs[hash];
                    382:        if (list) {
                    383:            HTMuxChannel * pres = NULL;
                    384:            while ((pres = (HTMuxChannel *) HTList_nextObject(list)))
1.1.2.5   frystyk   385:                if (pres->host == host) return pres;
1.1.2.1   frystyk   386:        }
                    387:     }
                    388:     return NULL;
                    389: }
                    390: 
                    391: PUBLIC BOOL HTMuxChannel_delete (HTMuxChannel * me)
                    392: {
                    393:     if (me) {
                    394:        HTList * list = NULL;
1.1.2.3   frystyk   395:        if (MUX_TRACE) HTTrace("Mux Channel. Deleting %p\n", me);
1.1.2.1   frystyk   396:        if (muxchs && (list = muxchs[me->hash])) {
                    397:            HTList_removeObject(list, (void *) me);
1.1.2.3   frystyk   398:            channel_delete(me);
1.1.2.1   frystyk   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;
1.1.2.5   frystyk   410:        for (cnt=0; cnt<HOST_HASH_SIZE; cnt++) {
1.1.2.1   frystyk   411:            if ((cur = muxchs[cnt])) { 
                    412:                HTMuxChannel * pres;
                    413:                while ((pres = (HTMuxChannel *) HTList_nextObject(cur)))
1.1.2.3   frystyk   414:                    channel_delete(pres);
1.1.2.1   frystyk   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: 
1.1.2.5   frystyk   428: PUBLIC HTMuxSession * HTMuxChannel_findSession (HTMuxChannel * me, HTMuxSessionId sid)
1.1.2.1   frystyk   429: {
                    430:     return (me) ? me->sessions[sid] : NULL;
                    431: }
                    432: 
1.1.2.5   frystyk   433: #if 0
                    434: PUBLIC HTMuxSession * HTMuxChannel_findSessionFromNet (HTMuxChannel * me, HTNet * net)
1.1.2.1   frystyk   435: {
                    436:     if (me && net) {
                    437:        int cnt = 0;
1.1.2.3   frystyk   438:        HTMuxSession **session = me->sessions;
1.1.2.1   frystyk   439:        while (cnt<MAX_SESSIONS) {
1.1.2.5   frystyk   440:            if (**session->net == net) return *session;
1.1.2.1   frystyk   441:            session++, cnt++;
                    442:        }           
                    443:     }
                    444:     return NULL;
                    445: }
1.1.2.5   frystyk   446: #endif
1.1.2.1   frystyk   447: 
1.1.2.5   frystyk   448: PUBLIC HTHost * HTMuxChannel_host (HTMuxChannel * muxch)
1.1.2.1   frystyk   449: {
1.1.2.5   frystyk   450:     return muxch ? muxch->host : NULL;
1.1.2.2   frystyk   451: }
                    452: 
1.1.2.3   frystyk   453: PUBLIC int HTMuxChannel_sendControl (HTMuxChannel * muxch, HTMuxSessionId sid,
                    454:                                     HTMuxHeader opcode, int value,
                    455:                                     const void * param, int param_size)
                    456: {
1.1.2.5   frystyk   457:     if (muxch && muxch->host) {
                    458:        HTOutputStream * me = HTChannel_output(HTHost_channel(muxch->host));
1.1.2.3   frystyk   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:        }
1.1.2.5   frystyk   490: 
                    491:        /* Flush for now */
                    492: #if 1
                    493:        return (*me->isa->flush)(me);
                    494: #else
1.1.2.6 ! eric      495:        return HT_OK;
        !           496: #endif
1.1.2.3   frystyk   497:     }
                    498:     return HT_ERROR;
                    499: }
                    500: 
1.1.2.2   frystyk   501: /* ------------------------------------------------------------------------- */
                    502: 
1.1.2.3   frystyk   503: PUBLIC BOOL HTMuxProtocol_add (HTMuxChannel * muxch,
1.1.2.2   frystyk   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;
1.1.2.1   frystyk   532: }

Webmaster