blob: f98da94508297901906091babd071d256f8bc778 [file] [log] [blame]
Willy Tarreauc7e42382012-08-24 19:22:53 +02001/*
2 * Buffer management functions.
3 *
4 * Copyright 2000-2012 Willy Tarreau <w@1wt.eu>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <stdio.h>
14#include <string.h>
15
16#include <common/config.h>
17#include <common/buffer.h>
18
19#include <types/global.h>
20
Willy Tarreauaf819352012-08-27 22:08:00 +020021/* This function writes the string <str> at position <pos> which must be in
22 * buffer <b>, and moves <end> just after the end of <str>. <b>'s parameters
23 * <l> and <r> are updated to be valid after the shift. The shift value
24 * (positive or negative) is returned. If there's no space left, the move is
25 * not done. The function does not adjust ->o because it does not make sense to
26 * use it on data scheduled to be sent. For the same reason, it does not make
27 * sense to call this function on unparsed data, so <orig> is not updated. The
28 * string length is taken from parameter <len>. If <len> is null, the <str>
29 * pointer is allowed to be null.
30 */
31int buffer_replace2(struct buffer *b, char *pos, char *end, const char *str, int len)
32{
33 int delta;
34
35 delta = len - (end - pos);
36
37 if (bi_end(b) + delta >= b->data + b->size)
38 return 0; /* no space left */
39
40 if (buffer_not_empty(b) &&
41 bi_end(b) + delta > bo_ptr(b) &&
42 bo_ptr(b) >= bi_end(b))
43 return 0; /* no space left before wrapping data */
44
45 /* first, protect the end of the buffer */
46 memmove(end + delta, end, bi_end(b) - end);
47
48 /* now, copy str over pos */
49 if (len)
50 memcpy(pos, str, len);
51
52 b->i += delta;
53
54 if (buffer_len(b) == 0)
55 b->p = b->data;
56
57 return delta;
58}
59
60/*
61 * Inserts <str> followed by "\r\n" at position <pos> in buffer <b>. The <len>
62 * argument informs about the length of string <str> so that we don't have to
63 * measure it. It does not include the "\r\n". If <str> is NULL, then the buffer
64 * is only opened for len+2 bytes but nothing is copied in. It may be useful in
65 * some circumstances. The send limit is *not* adjusted. Same comments as above
66 * for the valid use cases.
67 *
68 * The number of bytes added is returned on success. 0 is returned on failure.
69 */
70int buffer_insert_line2(struct buffer *b, char *pos, const char *str, int len)
71{
72 int delta;
73
74 delta = len + 2;
75
76 if (bi_end(b) + delta >= b->data + b->size)
77 return 0; /* no space left */
78
79 /* first, protect the end of the buffer */
80 memmove(pos + delta, pos, bi_end(b) - pos);
81
82 /* now, copy str over pos */
83 if (len && str) {
84 memcpy(pos, str, len);
85 pos[len] = '\r';
86 pos[len + 1] = '\n';
87 }
88
89 b->i += delta;
90 return delta;
91}
92
Willy Tarreauc7e42382012-08-24 19:22:53 +020093/* This function realigns input data in a possibly wrapping buffer so that it
94 * becomes contiguous and starts at the beginning of the buffer area. The
95 * function may only be used when the buffer's output is empty.
96 */
97void buffer_slow_realign(struct buffer *buf)
98{
99 /* two possible cases :
100 * - the buffer is in one contiguous block, we move it in-place
101 * - the buffer is in two blocks, we move it via the swap_buffer
102 */
103 if (buf->i) {
104 int block1 = buf->i;
105 int block2 = 0;
106 if (buf->p + buf->i > buf->data + buf->size) {
107 /* non-contiguous block */
108 block1 = buf->data + buf->size - buf->p;
109 block2 = buf->p + buf->i - (buf->data + buf->size);
110 }
111 if (block2)
112 memcpy(swap_buffer, buf->data, block2);
113 memmove(buf->data, buf->p, block1);
114 if (block2)
115 memcpy(buf->data + block1, swap_buffer, block2);
116 }
117
118 buf->p = buf->data;
119}
120
121
122/* Realigns a possibly non-contiguous buffer by bouncing bytes from source to
123 * destination. It does not use any intermediate buffer and does the move in
124 * place, though it will be slower than a simple memmove() on contiguous data,
125 * so it's desirable to use it only on non-contiguous buffers. No pointers are
126 * changed, the caller is responsible for that.
127 */
128void buffer_bounce_realign(struct buffer *buf)
129{
130 int advance, to_move;
131 char *from, *to;
132
133 from = bo_ptr(buf);
134 advance = buf->data + buf->size - from;
135 if (!advance)
136 return;
137
138 to_move = buffer_len(buf);
139 while (to_move) {
140 char last, save;
141
142 last = *from;
143 to = from + advance;
144 if (to >= buf->data + buf->size)
145 to -= buf->size;
146
147 while (1) {
148 save = *to;
149 *to = last;
150 last = save;
151 to_move--;
152 if (!to_move)
153 break;
154
155 /* check if we went back home after rotating a number of bytes */
156 if (to == from)
157 break;
158
159 /* if we ended up in the empty area, let's walk to next place. The
160 * empty area is either between buf->r and from or before from or
161 * after buf->r.
162 */
163 if (from > bi_end(buf)) {
164 if (to >= bi_end(buf) && to < from)
165 break;
166 } else if (from < bi_end(buf)) {
167 if (to < from || to >= bi_end(buf))
168 break;
169 }
170
171 /* we have overwritten a byte of the original set, let's move it */
172 to += advance;
173 if (to >= buf->data + buf->size)
174 to -= buf->size;
175 }
176
177 from++;
178 if (from >= buf->data + buf->size)
179 from -= buf->size;
180 }
181}
182
183
184/*
185 * Dumps part or all of a buffer.
186 */
187void buffer_dump(FILE *o, struct buffer *b, int from, int to)
188{
189 fprintf(o, "Dumping buffer %p\n", b);
190 fprintf(o, " data=%p o=%d i=%d p=%p\n",
191 b->data, b->o, b->i, b->p);
192
193 if (!to || to > buffer_len(b))
194 to = buffer_len(b);
195
196 fprintf(o, "Dumping contents from byte %d to byte %d\n", from, to);
197 for (; from < to; from++) {
198 if ((from & 15) == 0)
199 fprintf(o, " %04x: ", from);
200 fprintf(o, "%02x ", b->data[from]);
201 if ((from & 15) == 7)
202 fprintf(o, "- ");
203 else if (((from & 15) == 15) && (from != to-1))
204 fprintf(o, "\n");
205 }
206 fprintf(o, "\n--\n");
207}
208
209
210/*
211 * Local variables:
212 * c-indent-level: 8
213 * c-basic-offset: 8
214 * End:
215 */