]> jfr.im git - irc/rqf/shadowircd.git/blame - doc/technical/linebuf.txt
SVN Id removal part two
[irc/rqf/shadowircd.git] / doc / technical / linebuf.txt
CommitLineData
212380e3 1
2linebuf - a dbuf replacement for the New World Order(tm)
3
4By Adrian Chadd <adrian@creative.net.au>
5
212380e3 6
7
8History
9-------
10
11I could probably learn the dbuf history, but basically its evil. The
12general idea is that a dbuf holds incoming and outgoing data streams.
13The trouble is that well.. it was evil. You can check it out by getting
14the old src/dbuf.c and include/dbuf.h files if you really want.
15
16
17Replacement
18-----------
19
20The linebuf system is a replacement for the dbuf code. The general idea here
21is that the data should be buffered in "lines" rather than just linearly
22like in the dbuf code. This lends to easier manipulation at a later date
23(think flushing data lines to a socket, and even "sharing" linebufs to
24reduce the copying required for one to many delivery.)
25
26The linebuf system is broken into two structures, the buf_head and buf_line .
27buf_head contains the buffer information (queue head/tail, length, allocated
28length and the write offset for flushing), and buf_line contains the
29line buffer information (buffer and various flags.)
30
31linebuf->terminated is *only* set when a CR/LF combination is received.
32
33linebuf->overflow is set if we get more data than we should, and we simply
34 truncate the incoming data.
35
36linebuf->flushing is set when we are currently writing the buffer. We should
37 _NEVER_ be appending to a buffer which we're flushing!
38
39When you get a buffer through linebuf_get() or write one through
40linebuf_flush(), it will *always* be terminated with a CR/LF (and a NUL if
41its a linebuf_get()).
42
43
44Linebuf manipulation
45--------------------
46
47To use a linebuf, you simply stick a buf_head_t in your structure somewhere.
48You then use the following routines:
49
50int
51linebuf_parse(buf_head_t *bufhead, char *buf, int len)
52
53Parse the given buf. This routine does some complex manipulation:
54
55- if there is an incomplete buffer at the tail, buf is parsed to try and
56 fill that incomplete buffer
57- a buffer is completed by a CR/LF/CRLF/LFCR. It accepts everything purely
58 because I wanted to be "liberal in what you accept" ..
59- If a buffer is terminated, the linebuf is flagged terminated
60- If more data is trying to be squeezed into the buffer than space LEFT
61 in the buffer, we skip to the next "CRLF", and tag the buffer terminated
62 _and_ overflowed.
63- We treat multiple runs of CR/LF/CRLF/LFCR as a single CRLF. This is just
64 a little extra goody to stop people sending hundreds of "CRLF"s and creating
65 unnecessary buffers.
66- The number of lines parsed is returned (so you can implement per-line flood
67 protection ..)
68
69
70void
71linebuf_put(buf_head_t *bufhead, char *buf, int len)
72
73Parse the given buf, ASSUMING it is a single buffer line. This is useful
74for server-generated messages where you know you have a single line, and
75you don't want to go through the overhead of parsing the data just for
76this.
77
78
79int
80linebuf_get(buf_head_t *bufhead, char *buf, int maxlen)
81
82Get a single line from the buffer. This removes data from the head of the
83buffer. If the first buffer is empty or is not terminated, 0 is returned
84which indicates that there is no data to parse. Terminated buffers are
85returned (CR/LF/NUL), and the length INCLUDING the CR/LF/NUL is returned.
86The buffer is copied and the linebuf is then deallocated.
87
88
89int
90linebuf_flush(int fd, buf_head_t *bufhead)
91
92Attempt to flush some data to the given socket. bufhead->writeofs tracks
93where in the head buffer we currently are. If the buffer is not terminated,
94-1 is returned with errno == EWOULDBLOCK to simulate a "retry me" condition.
95(See TODO..)
96
97linebuf_flush() returns whatever write() returns, and sets (ie doesn't touch
98after write()) errno accordingly.
99
100
101int
102linebuf_len(buf_head_t *bufhead)
103
104Return the length of the buffer, in bytes. This should be used when calculating
105how big a buffer is for statistics.
106
107
108int
109linebuf_alloclen(buf_head_t *bufhead)
110
111Return how big the *allocated* space is. This is much more suitable for
112anti-flood checking, as someone might be sending a whole bunch of 1-byte
113linebufs which might not trigger a recvq / sendq limit but might chew up
114way too much memory.
115
116
117
118Notes
119-----
120
121* Remember that the trailing NUL isn't covered in the string length.
122
123
124Limitations
125-----------
126
127* all the buffers are a fixed size - here they are current 513 bytes
128 (510 bytes + CR/LF/NUL)
129
130
131TODO
132----
133
134* linebuf_flush() should be changed a little so if the buffer isn't
135 terminated, we *dont* retry flushing a buffer until we get more data.
136
137* Implement a reference-friendly linebuf to reduce copies ..
138