⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 htmuxch.c

📁 www工具包
💻 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 + -