?? htmuxch.c
字號:
/*** MUX CHANNEL, SESSION AND PROTOCOL MANAGEMENT**** (c) COPYRIGHT MIT 1995.** Please first read the full copyright statement in the file COPYRIGH.** @(#) $Id: HTMuxCh.c,v 2.4 1999/02/22 22:10:11 frystyk Exp $**** Handles a MUX Channel with sessions and protocols**** Authors** HFN Henrik Frystyk Nielsen <frystyk@w3.org>**** HISTORY:** Oct 96 HFN Written*//* Library Include files */#include "wwwsys.h"#include "WWWUtil.h"#include "WWWCore.h"#include "WWWTrans.h"#include "WWWStream.h"#include "HTMuxTx.h"#include "HTMuxHeader.h"#include "HTDemux.h"#include "HTMuxCh.h" /* Implemented here */#define MAX_SESSIONS 0xFF /* Max 256 sessions */#define SID_BASE 2#define RECEIVER_OFFSET 0 /* Client control session */#define SENDER_OFFSET 1 /* Server control session */struct _HTStream { const HTStreamClass * isa; /* ... */};struct _HTOutputStream { const HTOutputStreamClass * isa; /* ... */};#define PUTBLOCK(b,l) (*me->isa->put_block)(me,(b),(l))struct _HTMuxProtocol { HTAtom * name; HTProtocolId pid;};struct _HTMuxSession { HTMuxSessionId sid; HTProtocolId pid; HTNet * net; /* State */ HTMuxClose close; /* State of the connection */ int credit; /* Available credit */ int fragment; /* Fragment size */ int read; /* Data read sine last credit */ /* Input */ HTStream * buffer; /* If we have to buffer data */ BOOL buffering;};struct _HTMuxChannel { int hash; HTHost * host; int max_sid; /* A la max_sockfd in select */ HTNet * net; HTList * protocols; /* List of defined protocols */ HTMuxSession * sessions[MAX_SESSIONS];};PRIVATE HTList ** muxchs = NULL; /* List of mux muxchs *//* ------------------------------------------------------------------------- */PRIVATE HTMuxSession * session_new (void){ HTMuxSession * me; if ((me = (HTMuxSession *) HT_CALLOC(1, sizeof(HTMuxSession))) == NULL) HT_OUTOFMEM("HTMuxSession_new"); me->credit = DEFAULT_CREDIT; return me;}PRIVATE BOOL session_delete (HTMuxSession * session){ if (session) { HT_FREE(session); return YES; } return NO;}PUBLIC HTMuxSession * HTMuxSession_register (HTMuxChannel * muxch, HTMuxSessionId sid, HTProtocolId pid){ if (muxch) { HTMuxSession * session = muxch->sessions[sid]; if (session == NULL) { session = session_new(); session->sid = sid; session->pid = pid; muxch->sessions[sid] = session; HTTRACE(MUX_TRACE, "Mux Channel. Registered session %d on channel %p\n" _ sid _ muxch); } return session; } HTTRACE(MUX_TRACE, "Mux Channel. Can't register new session\n"); return NULL;}PUBLIC HTMuxSessionId HTMuxSession_accept (HTMuxChannel * muxch, HTNet * net, HTProtocolId pid){ if (muxch && net) { HTMuxSession * session; HTMuxSessionId sid = SID_BASE + RECEIVER_OFFSET; for (; sid<MAX_SESSIONS; sid+=2) { if ((session = muxch->sessions[sid]) && session->net == NULL && session->pid == pid) { HTTRACE(MUX_TRACE, "Mux Channel. Accepting session %d on channel %p\n" _ sid _ muxch); return sid; } } } HTTRACE(MUX_TRACE, "Mux Channel. Can't accept new session\n"); return INVSID;}PUBLIC HTMuxSessionId HTMuxSession_connect (HTMuxChannel * muxch, HTNet * net, HTProtocolId pid){ if (muxch && net) { HTMuxSessionId sid = SID_BASE + SENDER_OFFSET; for (; sid<MAX_SESSIONS; sid+=2) { if (muxch->sessions[sid] == NULL) { HTMuxSession * session = session_new(); session->sid = sid; session->pid = pid; session->net = net; muxch->sessions[sid] = session; HTTRACE(MUX_TRACE, "Mux Channel. Creating session %d on channel %p\n" _ sid _ muxch); return sid; } } } HTTRACE(MUX_TRACE, "Mux Channel. Can't create new session\n"); return INVSID;}PUBLIC int HTMuxSession_close (HTMuxChannel * muxch, HTMuxSessionId sid){ if (muxch) { HTMuxSession * session = muxch->sessions[sid]; HTMuxSession_setClose(muxch, session, MUX_S_END_WRITE); return YES; } return NO;}PUBLIC HTMuxSessionId HTMuxSession_id (HTMuxSession * session){ return session ? session->sid : INVSID;}PUBLIC HTProtocolId HTMuxSession_pid (HTMuxSession * session){ return session ? session->pid : INVPID;}PUBLIC HTNet * HTMuxSession_net (HTMuxSession * session){ return session ? session->net : NULL;}PUBLIC BOOL HTMuxSession_setClose (HTMuxChannel * muxch, HTMuxSession * session, HTMuxClose close){ if (muxch && session) { session->close |= close; /* ** If both directions are closed down then we can put the session ** to sleep. */ if (session->close == MUX_S_END) { HTTRACE(MUX_TRACE, "Mux Channel. Closing session %d on channel %p\n" _ session->sid _ muxch); muxch->sessions[session->sid] = NULL; session_delete(session); } return YES; } return NO;}PUBLIC int HTMuxSession_credit (HTMuxSession * session){ return session ? session->credit : -1;}PUBLIC BOOL HTMuxSession_setCredit (HTMuxChannel * muxch, HTMuxSessionId sid, int credit){ HTMuxSession * session; if (muxch && (session = muxch->sessions[sid])) { session->credit = credit; return YES; } return NO;}PUBLIC int HTMuxSession_fragment (HTMuxSession * session){ return session ? session->fragment : -1;}PUBLIC BOOL HTMuxSession_setFragment (HTMuxChannel * muxch, HTMuxSessionId sid, int fragment){ HTMuxSession * session; if (muxch && (session = muxch->sessions[sid])) { session->fragment = fragment; return YES; } return NO;}/*** Tries really hard to get rid of the data.** Returns:** -1 Error** 0 Buffered the data** 1 Got rid of the data*/PUBLIC int HTMuxSession_disposeData (HTMuxSession * me, const char * buf, int len){ HTTRACE(MUX_TRACE, "Mux Channel. Writing %d bytes to session %p\n" _ len _ me); /* ** There are two situations that can occur: Either we have an accepted session ** with a Net object or we have an unaccepted session with no Net object. In ** the former case we try to get rid of the data by pushing it directly to the ** read stream of the Net object. In the latter case we buffer as much as we ** can. */ if (me) { HTNet * net; HTStream * sink; int status; if ((net = me->net) && (sink = HTNet_readStream(net))) { /* ** Look first to see if we have old data that we can dispose down ** the sink. We keep the buffer stream so that we can reuse it later. */ if (me->buffer && me->buffering) { if ((*me->buffer->isa->flush)(me->buffer) == HT_OK) { HTTRACE(MUX_TRACE, "Mux Channel. Flushed buffered data\n"); me->buffering = NO; } else if ((*me->buffer->isa->put_block)(me->buffer, buf, len) >= 0) { HTTRACE(MUX_TRACE, "Mux Channel. Buffer accepted data\n"); return 0; } HTTRACE(MUX_TRACE, "Mux Channel. Can't buffer data\n"); return (-1); } /* ** See if we can get rid of the new data. If not then try to buffer it. ** If this also fails then we reset the channel. A positive return code ** from the stream means that we got rid of the data successfully. */ if ((status = (*sink->isa->put_block)(sink, buf, len)) >= 0) { HTTRACE(MUX_TRACE, "Mux Channel. Stream returned %d\n" _ status); /* ** If we get back a HT_LOADED then we have all the data we need ** and we can terminate the request */ if (status == HT_LOADED) { HTNet_execute (net, HTEvent_END); return 0; } /* ** Decide whether we should send a credit message ** MORE TO COME */ me->read += len; if (me->read >= DEFAULT_CREDIT / 2) { me->read = 0; return 1; } return 0; } } /* ** The stream is not ready and we try to buffer the data in ** the meantime. */ if (!me->buffer) { me->buffer = HTPipeBuffer(sink, DEFAULT_CREDIT); me->buffering = YES; } status = (*me->buffer->isa->put_block)(me->buffer, buf, len); if (status >= 0) { HTTRACE(MUX_TRACE, "Mux Channel. Buffer accepted data\n"); return 0; } HTTRACE(MUX_TRACE, "Mux Channel. Buffer returned %d\n" _ status); } return (-1);}/* ------------------------------------------------------------------------- */PRIVATE BOOL channel_delete (HTMuxChannel * ch){ if (ch) { HT_FREE(ch); return YES; } return NO;}PUBLIC HTMuxChannel * HTMuxChannel_new (HTHost * host){ if (host) { HTMuxChannel * me = NULL; /* Create new object */ if ((me = (HTMuxChannel *) HT_CALLOC(1, sizeof(HTMuxChannel))) == NULL) HT_OUTOFMEM("HTMuxChannel_new"); me->hash = HTHost_hash(host); me->host = host; /* ** Make sure that we are in interleave mode */ HTHost_setMode(host, HT_TP_INTERLEAVE); /* ** Get a special MUX Net object that we keep to our selves. We don't ** associate a request object as the Net object lives longer. */ me->net = HTNet_new(NULL); HTNet_setReadStream(me->net, HTDemux_new(host, me)); /* Insert into hash table */ if (!muxchs) { if ((muxchs=(HTList **) HT_CALLOC(HOST_HASH_SIZE, sizeof(HTList *))) == NULL) HT_OUTOFMEM("HTMuxChannel_new"); } if (!muxchs[me->hash]) muxchs[me->hash] = HTList_new(); HTList_addObject(muxchs[me->hash], (void *) me); HTTRACE(MUX_TRACE, "Mux Channel. %p created with hash %d\n" _ me _ me->hash); return me; } return NULL;}PUBLIC HTMuxChannel * HTMuxChannel_find (HTHost * host){ if (muxchs) { int hash = HTHost_hash(host); HTList * list = muxchs[hash]; if (list) { HTMuxChannel * pres = NULL; while ((pres = (HTMuxChannel *) HTList_nextObject(list))) if (pres->host == host) return pres; } } return NULL;}PUBLIC BOOL HTMuxChannel_delete (HTMuxChannel * me){ if (me) { HTList * list = NULL; HTTRACE(MUX_TRACE, "Mux Channel. Deleting %p\n" _ me); if (muxchs && (list = muxchs[me->hash])) { HTList_removeObject(list, (void *) me); channel_delete(me); return YES; } } return NO;}PUBLIC BOOL HTMuxChannel_deleteAll (void){ if (muxchs) { HTList * cur; int cnt; for (cnt=0; cnt<HOST_HASH_SIZE; cnt++) { if ((cur = muxchs[cnt])) { HTMuxChannel * pres; while ((pres = (HTMuxChannel *) HTList_nextObject(cur))) channel_delete(pres); } HTList_delete(muxchs[cnt]); } HT_FREE(muxchs); } return YES;}PUBLIC HTNet * HTMuxChannel_net (HTMuxChannel * me){ return me ? me->net : NULL;}PUBLIC HTMuxSession * HTMuxChannel_findSession (HTMuxChannel * me, HTMuxSessionId sid){ return (me) ? me->sessions[sid] : NULL;}#if 0PRIVATE HTMuxSession * HTMuxChannel_findSessionFromNet (HTMuxChannel * me, HTNet * net){ if (me && net) { int cnt = 0; HTMuxSession **session = me->sessions; while (cnt<MAX_SESSIONS) { if (**session->net == net) return *session; session++, cnt++; } } return NULL;}#endifPUBLIC HTHost * HTMuxChannel_host (HTMuxChannel * muxch){ return muxch ? muxch->host : NULL;}PUBLIC int HTMuxChannel_sendControl (HTMuxChannel * muxch, HTMuxSessionId sid, HTMuxHeader opcode, int value, const void * param, int param_size){ if (muxch && muxch->host) { HTOutputStream * me = HTChannel_output(HTHost_channel(muxch->host)); HTMuxHeader header[2]; switch (opcode) { case MUX_STRING: if (param && param_size) { header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_LEN(value)); header[1] = HT_WORDSWAP(param_size); PUTBLOCK((const char *) header, 8); PUTBLOCK((const char *) param, MUX_LONG_ALIGN(param_size)); } break; case MUX_STACK: if (param && param_size) { header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_LEN(value)); header[1] = HT_WORDSWAP(param_size); PUTBLOCK((const char *) header, 8); PUTBLOCK((const char *) param, MUX_LONG_ALIGN(param_size)); } break; case MUX_FRAGMENT: header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_SET_SID(sid) | MUX_SET_LEN(value)); PUTBLOCK((const char *) header, 4); break; case MUX_CREDIT: header[0] = HT_WORDSWAP(MUX_CONTROL | MUX_LONG_LENGTH | MUX_SET_SID(sid)); header[1] = HT_WORDSWAP(value); PUTBLOCK((const char *) header, 8); break; default: HTTRACE(MUX_TRACE, "Mux Channel. UNKNOWN OPCODE %d\n" _ opcode); return HT_ERROR; } /* Flush for now */#if 1 return (*me->isa->flush)(me);#else return HT_OK;#endif } return HT_ERROR;}/* ------------------------------------------------------------------------- */PUBLIC BOOL HTMuxProtocol_add (HTMuxChannel * muxch, HTProtocolId pid, const char * protocol){ if (muxch && protocol) { HTMuxProtocol * ms; if ((ms = (HTMuxProtocol *) HT_CALLOC(1, sizeof(HTMuxProtocol))) == NULL) HT_OUTOFMEM("HTMuxProtocol_new"); ms->name = HTAtom_caseFor(protocol); ms->pid = pid; if (!muxch->protocols) muxch->protocols = HTList_new(); return HTList_addObject(muxch->protocols, ms); } return NO;}PUBLIC BOOL HTMuxProtocol_delete (HTMuxChannel * muxch, HTProtocolId pid){ if (muxch && muxch->protocols) { HTList * cur = muxch->protocols; HTMuxProtocol * pres; while ((pres = (HTMuxProtocol *) HTList_nextObject(cur))) { if (pres->pid == pid) { HTList_removeObject(muxch->protocols, pres); HT_FREE(pres); return YES; } } } return NO;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -