| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
// Derived from: |
|
2
|
|
|
|
|
|
|
|
|
3
|
|
|
|
|
|
|
/* $OpenBSD: buffer.c,v 1.31 2006/08/03 03:34:41 deraadt Exp $ */ |
|
4
|
|
|
|
|
|
|
/* |
|
5
|
|
|
|
|
|
|
* Author: Tatu Ylonen <ylo@cs.hut.fi> |
|
6
|
|
|
|
|
|
|
* Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland |
|
7
|
|
|
|
|
|
|
* All rights reserved |
|
8
|
|
|
|
|
|
|
* Functions for manipulating fifo buffers (that can grow if needed). |
|
9
|
|
|
|
|
|
|
* |
|
10
|
|
|
|
|
|
|
* As far as I am concerned, the code I have written for this software |
|
11
|
|
|
|
|
|
|
* can be used freely for any purpose. Any derived versions of this |
|
12
|
|
|
|
|
|
|
* software must be clearly marked as such, and if the derived work is |
|
13
|
|
|
|
|
|
|
* incompatible with the protocol description in the RFC file, it must be |
|
14
|
|
|
|
|
|
|
* called by a name other than "ssh" or "Secure Shell". |
|
15
|
|
|
|
|
|
|
*/ |
|
16
|
|
|
|
|
|
|
|
|
17
|
|
|
|
|
|
|
#include "buffer.h" |
|
18
|
|
|
|
|
|
|
|
|
19
|
|
|
|
|
|
|
#define BUFFER_MAX_CHUNK 0x1400000 |
|
20
|
|
|
|
|
|
|
#define BUFFER_MAX_LEN 0x1400000 |
|
21
|
|
|
|
|
|
|
#define BUFFER_ALLOCSZ 0x002000 |
|
22
|
|
|
|
|
|
|
#define BUFFER_COMPACT_PERCENT 0.8 |
|
23
|
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
/* Initializes the buffer structure. */ |
|
25
|
|
|
|
|
|
|
|
|
26
|
|
|
|
|
|
|
void |
|
27
|
3
|
|
|
|
|
|
buffer_init(Buffer *buffer, uint32_t len) |
|
28
|
|
|
|
|
|
|
{ |
|
29
|
3
|
50
|
|
|
|
|
if (!len) len = BUFFER_ALLOCSZ; |
|
30
|
|
|
|
|
|
|
|
|
31
|
3
|
|
|
|
|
|
buffer->alloc = 0; |
|
32
|
3
|
|
|
|
|
|
New(0, buffer->buf, (int)len, u_char); |
|
33
|
3
|
|
|
|
|
|
buffer->alloc = len; |
|
34
|
3
|
|
|
|
|
|
buffer->offset = 0; |
|
35
|
3
|
|
|
|
|
|
buffer->end = 0; |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
#ifdef XS_DEBUG |
|
38
|
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "Buffer allocated with %d bytes\n", len); |
|
39
|
|
|
|
|
|
|
#endif |
|
40
|
3
|
|
|
|
|
|
} |
|
41
|
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
/* Frees any memory used for the buffer. */ |
|
43
|
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
void |
|
45
|
3
|
|
|
|
|
|
buffer_free(Buffer *buffer) |
|
46
|
|
|
|
|
|
|
{ |
|
47
|
3
|
50
|
|
|
|
|
if (buffer->alloc > 0) { |
|
48
|
|
|
|
|
|
|
#ifdef XS_DEBUG |
|
49
|
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "Buffer high water mark: %d\n", buffer->alloc); |
|
50
|
|
|
|
|
|
|
#endif |
|
51
|
3
|
|
|
|
|
|
memset(buffer->buf, 0, buffer->alloc); |
|
52
|
3
|
|
|
|
|
|
buffer->alloc = 0; |
|
53
|
3
|
|
|
|
|
|
Safefree(buffer->buf); |
|
54
|
|
|
|
|
|
|
} |
|
55
|
3
|
|
|
|
|
|
} |
|
56
|
|
|
|
|
|
|
|
|
57
|
|
|
|
|
|
|
/* Appends data to the buffer, expanding it if necessary. */ |
|
58
|
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
void |
|
60
|
104
|
|
|
|
|
|
buffer_append(Buffer *buffer, const void *data, uint32_t len) |
|
61
|
|
|
|
|
|
|
{ |
|
62
|
|
|
|
|
|
|
void *p; |
|
63
|
104
|
|
|
|
|
|
p = buffer_append_space(buffer, len); |
|
64
|
104
|
|
|
|
|
|
Copy(data, p, (int)len, u_char); |
|
65
|
104
|
|
|
|
|
|
} |
|
66
|
|
|
|
|
|
|
|
|
67
|
|
|
|
|
|
|
static int |
|
68
|
0
|
|
|
|
|
|
buffer_compact(Buffer *buffer) |
|
69
|
|
|
|
|
|
|
{ |
|
70
|
|
|
|
|
|
|
/* |
|
71
|
|
|
|
|
|
|
* If the buffer is at least BUFFER_COMPACT_PERCENT empty, move the |
|
72
|
|
|
|
|
|
|
* data to the beginning. |
|
73
|
|
|
|
|
|
|
*/ |
|
74
|
0
|
0
|
|
|
|
|
if (buffer->offset * 1.0 / buffer->alloc >= BUFFER_COMPACT_PERCENT ) { |
|
75
|
|
|
|
|
|
|
#ifdef XS_DEBUG |
|
76
|
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "Buffer compacting (%d -> %d)\n", buffer->offset + buffer_len(buffer), buffer_len(buffer)); |
|
77
|
|
|
|
|
|
|
#endif |
|
78
|
0
|
|
|
|
|
|
Move(buffer->buf + buffer->offset, buffer->buf, (int)(buffer->end - buffer->offset), u_char); |
|
79
|
0
|
|
|
|
|
|
buffer->end -= buffer->offset; |
|
80
|
0
|
|
|
|
|
|
buffer->offset = 0; |
|
81
|
0
|
|
|
|
|
|
return (1); |
|
82
|
|
|
|
|
|
|
} |
|
83
|
|
|
|
|
|
|
|
|
84
|
|
|
|
|
|
|
return (0); |
|
85
|
|
|
|
|
|
|
} |
|
86
|
|
|
|
|
|
|
|
|
87
|
|
|
|
|
|
|
/* |
|
88
|
|
|
|
|
|
|
* Appends space to the buffer, expanding the buffer if necessary. This does |
|
89
|
|
|
|
|
|
|
* not actually copy the data into the buffer, but instead returns a pointer |
|
90
|
|
|
|
|
|
|
* to the allocated region. |
|
91
|
|
|
|
|
|
|
*/ |
|
92
|
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
void * |
|
94
|
104
|
|
|
|
|
|
buffer_append_space(Buffer *buffer, uint32_t len) |
|
95
|
|
|
|
|
|
|
{ |
|
96
|
|
|
|
|
|
|
uint32_t newlen; |
|
97
|
|
|
|
|
|
|
void *p; |
|
98
|
|
|
|
|
|
|
|
|
99
|
104
|
50
|
|
|
|
|
if (len > BUFFER_MAX_CHUNK) |
|
100
|
0
|
|
|
|
|
|
croak("buffer_append_space: len %u too large (max %u)", len, BUFFER_MAX_CHUNK); |
|
101
|
|
|
|
|
|
|
|
|
102
|
|
|
|
|
|
|
/* If the buffer is empty, start using it from the beginning. */ |
|
103
|
104
|
100
|
|
|
|
|
if (buffer->offset == buffer->end) { |
|
104
|
79
|
|
|
|
|
|
buffer->offset = 0; |
|
105
|
79
|
|
|
|
|
|
buffer->end = 0; |
|
106
|
|
|
|
|
|
|
} |
|
107
|
|
|
|
|
|
|
|
|
108
|
25
|
|
|
|
|
|
restart: |
|
109
|
|
|
|
|
|
|
/* If there is enough space to store all data, store it now. */ |
|
110
|
104
|
50
|
|
|
|
|
if (buffer->end + len <= buffer->alloc) { |
|
111
|
104
|
|
|
|
|
|
p = buffer->buf + buffer->end; |
|
112
|
104
|
|
|
|
|
|
buffer->end += len; |
|
113
|
104
|
|
|
|
|
|
return p; |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
/* Compact data back to the start of the buffer if necessary */ |
|
117
|
0
|
0
|
|
|
|
|
if (buffer_compact(buffer)) |
|
118
|
0
|
|
|
|
|
|
goto restart; |
|
119
|
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
/* Increase the size of the buffer and retry. */ |
|
121
|
0
|
0
|
|
|
|
|
if (buffer->alloc + len < 4096) |
|
122
|
0
|
|
|
|
|
|
newlen = (buffer->alloc + len) * 2; |
|
123
|
|
|
|
|
|
|
else |
|
124
|
0
|
|
|
|
|
|
newlen = buffer->alloc + len + 4096; |
|
125
|
|
|
|
|
|
|
|
|
126
|
0
|
0
|
|
|
|
|
if (newlen > BUFFER_MAX_LEN) |
|
127
|
0
|
|
|
|
|
|
croak("buffer_append_space: alloc %u too large (max %u)", |
|
128
|
|
|
|
|
|
|
newlen, BUFFER_MAX_LEN); |
|
129
|
|
|
|
|
|
|
#ifdef XS_DEBUG |
|
130
|
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "Buffer extended to %d\n", newlen); |
|
131
|
|
|
|
|
|
|
#endif |
|
132
|
0
|
|
|
|
|
|
Renew(buffer->buf, (int)newlen, u_char); |
|
133
|
0
|
|
|
|
|
|
buffer->alloc = newlen; |
|
134
|
0
|
|
|
|
|
|
goto restart; |
|
135
|
|
|
|
|
|
|
/* NOTREACHED */ |
|
136
|
|
|
|
|
|
|
} |
|
137
|
|
|
|
|
|
|
|
|
138
|
|
|
|
|
|
|
/* Returns the number of bytes of data in the buffer. */ |
|
139
|
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
uint32_t |
|
141
|
161
|
|
|
|
|
|
buffer_len(Buffer *buffer) |
|
142
|
|
|
|
|
|
|
{ |
|
143
|
161
|
|
|
|
|
|
return buffer->end - buffer->offset; |
|
144
|
|
|
|
|
|
|
} |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
/* Gets data from the beginning of the buffer. */ |
|
147
|
|
|
|
|
|
|
|
|
148
|
|
|
|
|
|
|
int |
|
149
|
0
|
|
|
|
|
|
buffer_get_ret(Buffer *buffer, void *buf, uint32_t len) |
|
150
|
|
|
|
|
|
|
{ |
|
151
|
0
|
0
|
|
|
|
|
if (len > buffer->end - buffer->offset) { |
|
152
|
0
|
|
|
|
|
|
warn("buffer_get_ret: trying to get more bytes %d than in buffer %d", len, buffer->end - buffer->offset); |
|
153
|
0
|
|
|
|
|
|
return (-1); |
|
154
|
|
|
|
|
|
|
} |
|
155
|
|
|
|
|
|
|
|
|
156
|
0
|
|
|
|
|
|
Copy(buffer->buf + buffer->offset, buf, (int)len, char); |
|
157
|
0
|
|
|
|
|
|
buffer->offset += len; |
|
158
|
0
|
|
|
|
|
|
return (0); |
|
159
|
|
|
|
|
|
|
} |
|
160
|
|
|
|
|
|
|
|
|
161
|
|
|
|
|
|
|
void |
|
162
|
0
|
|
|
|
|
|
buffer_get(Buffer *buffer, void *buf, uint32_t len) |
|
163
|
|
|
|
|
|
|
{ |
|
164
|
0
|
0
|
|
|
|
|
if (buffer_get_ret(buffer, buf, len) == -1) |
|
165
|
0
|
|
|
|
|
|
croak("buffer_get: buffer error"); |
|
166
|
0
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
/* Consumes the given number of bytes from the beginning of the buffer. */ |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
int |
|
171
|
151
|
|
|
|
|
|
buffer_consume_ret(Buffer *buffer, uint32_t bytes) |
|
172
|
|
|
|
|
|
|
{ |
|
173
|
151
|
50
|
|
|
|
|
if (bytes > buffer->end - buffer->offset) { |
|
174
|
0
|
|
|
|
|
|
warn("buffer_consume_ret: trying to get more bytes %d than in buffer %d", bytes, buffer->end - buffer->offset); |
|
175
|
0
|
|
|
|
|
|
return (-1); |
|
176
|
|
|
|
|
|
|
} |
|
177
|
|
|
|
|
|
|
|
|
178
|
151
|
|
|
|
|
|
buffer->offset += bytes; |
|
179
|
151
|
|
|
|
|
|
return (0); |
|
180
|
|
|
|
|
|
|
} |
|
181
|
|
|
|
|
|
|
|
|
182
|
|
|
|
|
|
|
void |
|
183
|
151
|
|
|
|
|
|
buffer_consume(Buffer *buffer, uint32_t bytes) |
|
184
|
|
|
|
|
|
|
{ |
|
185
|
151
|
50
|
|
|
|
|
if (buffer_consume_ret(buffer, bytes) == -1) |
|
186
|
0
|
|
|
|
|
|
croak("buffer_consume: buffer error"); |
|
187
|
151
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
/* Returns a pointer to the first used byte in the buffer. */ |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
void * |
|
192
|
151
|
|
|
|
|
|
buffer_ptr(Buffer *buffer) |
|
193
|
|
|
|
|
|
|
{ |
|
194
|
151
|
|
|
|
|
|
return buffer->buf + buffer->offset; |
|
195
|
|
|
|
|
|
|
} |
|
196
|
|
|
|
|
|
|
|
|
197
|
|
|
|
|
|
|
// Dumps the contents of the buffer to stderr. |
|
198
|
|
|
|
|
|
|
// Based on: http://sws.dett.de/mini/hexdump-c/ |
|
199
|
|
|
|
|
|
|
#ifdef XS_DEBUG |
|
200
|
|
|
|
|
|
|
void |
|
201
|
|
|
|
|
|
|
buffer_dump(Buffer *buffer, uint32_t size) |
|
202
|
|
|
|
|
|
|
{ |
|
203
|
|
|
|
|
|
|
unsigned char *data = buffer->buf; |
|
204
|
|
|
|
|
|
|
unsigned char c; |
|
205
|
|
|
|
|
|
|
int i = 1; |
|
206
|
|
|
|
|
|
|
int n; |
|
207
|
|
|
|
|
|
|
char bytestr[4] = {0}; |
|
208
|
|
|
|
|
|
|
char hexstr[ 16*3 + 5] = {0}; |
|
209
|
|
|
|
|
|
|
char charstr[16*1 + 5] = {0}; |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
if (!size) { |
|
212
|
|
|
|
|
|
|
size = buffer->end - buffer->offset; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
|
|
|
|
|
|
|
|
215
|
|
|
|
|
|
|
for (n = buffer->offset; n < buffer->offset + size; n++) { |
|
216
|
|
|
|
|
|
|
c = data[n]; |
|
217
|
|
|
|
|
|
|
|
|
218
|
|
|
|
|
|
|
/* store hex str (for left side) */ |
|
219
|
|
|
|
|
|
|
snprintf(bytestr, sizeof(bytestr), "%02x ", c); |
|
220
|
|
|
|
|
|
|
strncat(hexstr, bytestr, sizeof(hexstr)-strlen(hexstr)-1); |
|
221
|
|
|
|
|
|
|
|
|
222
|
|
|
|
|
|
|
/* store char str (for right side) */ |
|
223
|
|
|
|
|
|
|
if (isalnum(c) == 0) { |
|
224
|
|
|
|
|
|
|
c = '.'; |
|
225
|
|
|
|
|
|
|
} |
|
226
|
|
|
|
|
|
|
snprintf(bytestr, sizeof(bytestr), "%c", c); |
|
227
|
|
|
|
|
|
|
strncat(charstr, bytestr, sizeof(charstr)-strlen(charstr)-1); |
|
228
|
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
if (i % 16 == 0) { |
|
230
|
|
|
|
|
|
|
/* line completed */ |
|
231
|
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "%-50.50s %s\n", hexstr, charstr); |
|
232
|
|
|
|
|
|
|
hexstr[0] = 0; |
|
233
|
|
|
|
|
|
|
charstr[0] = 0; |
|
234
|
|
|
|
|
|
|
} |
|
235
|
|
|
|
|
|
|
i++; |
|
236
|
|
|
|
|
|
|
} |
|
237
|
|
|
|
|
|
|
|
|
238
|
|
|
|
|
|
|
if (strlen(hexstr) > 0) { |
|
239
|
|
|
|
|
|
|
/* print rest of buffer if not empty */ |
|
240
|
|
|
|
|
|
|
PerlIO_printf(PerlIO_stderr(), "%-50.50s %s\n", hexstr, charstr); |
|
241
|
|
|
|
|
|
|
} |
|
242
|
|
|
|
|
|
|
} |
|
243
|
|
|
|
|
|
|
#endif |