/* * NAME: binary.c * DESCRIPTION: connection object specialized for binary connections */ inherit "/std/connection"; # include <moo/errors.h> private string inbuf; /* incoming data buffer */ private string outbuf; /* outgoing data buffer */ private int co_flush; /* flush() call_out handle */ private int flags; /* special binary flags */ # define F_CURRENT 0x01 /* execution started with this object */ # define F_CLOSING 0x02 /* connection is trying to close */ # define BUFTHRESH 2048 /* buffer limit before flushing */ /* * NAME: create() * DESCRIPTION: initialize data */ static void create(void) { inbuf = outbuf = ""; ::create(); } /* * NAME: flush() * DESCRIPTION: try to send the output buffer to the connection */ void flush(void) { int len; if (co_flush) { remove_call_out(co_flush); co_flush = 0; } if (! strlen(outbuf)) return; len = send_message(outbuf); if (len >= 0) { if (strlen(outbuf = outbuf[len ..])) co_flush = call_out("flush", 1); } else outbuf = ""; /* not connected? */ } /* * NAME: finish() * DESCRIPTION: called to finish processing; flush the output buffer */ void finish(void) { ::finish(); flush(); flags &= ~F_CURRENT; } /* * NAME: send() * DESCRIPTION: called to send a partial line to the user (raw data) */ void send(string msg) { outbuf += msg; if (! (flags & F_CURRENT) || strlen(outbuf) > BUFTHRESH) flush(); } /* * NAME: notify() * DESCRIPTION: send a line of text */ void notify(string msg) { send(msg + "\r\n"); } /* * NAME: get_line() * DESCRIPTION: return a line of pending input, if available */ string get_line(void) { string line; return (sscanf(inbuf, "%s\r\n%s", line, inbuf) == 2 || sscanf(inbuf, "%s\n%s", line, inbuf) == 2) ? line : 0; } /* * NAME: get_data() * DESCRIPTION: return any pending input as raw data */ string get_data(void) { string data; if (strlen(inbuf)) { data = inbuf; inbuf = ""; } else data = 0; return data; } /* * NAME: receive_message() * DESCRIPTION: called by DGD when binary data arrives */ static void receive_message(string data) { string line; if (flags & F_CLOSING) /* ignore further input */ return; inbuf += data; if (! strlen(inbuf)) return; flags |= F_CURRENT; if (want_binary()) { data = inbuf; inbuf = ""; process_data(data); } else if (line = get_line()) { if (strlen(inbuf)) call_out("receive_message", 0, ""); process_line(line); } finish(); } /* * NAME: destruct() * DESCRIPTION: attempt to flush the output buffer before destructing */ static void destruct(void) { flags |= F_CLOSING; if (co_flush) { call_out("destruct", 1); return; } ::destruct(); }