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