~roger-booth/mysql-proxy/laminator

926 by jan at mysql
moved the network_queue_* functions to network-queue.[ch]
1
/* $%BEGINLICENSE%$
2
 Copyright (C) 2007-2008 MySQL AB, 2008 Sun Microsystems, Inc
3
4
 This program is free software; you can redistribute it and/or modify
5
 it under the terms of the GNU General Public License as published by
6
 the Free Software Foundation; version 2 of the License.
7
8
 This program is distributed in the hope that it will be useful,
9
 but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 GNU General Public License for more details.
12
13
 You should have received a copy of the GNU General Public License
14
 along with this program; if not, write to the Free Software
15
 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16
17
 $%ENDLICENSE%$ */
18
 
19
20
#ifdef HAVE_CONFIG_H
21
#include "config.h"
22
#endif
23
24
#include "network-queue.h"
25
26
#ifndef DISABLE_DEPRECATED_DECL
27
network_queue *network_queue_init() {
28
	return network_queue_new();
29
}
30
#endif
31
32
network_queue *network_queue_new() {
33
	network_queue *queue;
34
35
	queue = g_new0(network_queue, 1);
36
37
	queue->chunks = g_queue_new();
38
	
39
	return queue;
40
}
41
42
void network_queue_free(network_queue *queue) {
43
	GString *packet;
44
45
	if (!queue) return;
46
47
	while ((packet = g_queue_pop_head(queue->chunks))) g_string_free(packet, TRUE);
48
49
	g_queue_free(queue->chunks);
50
51
	g_free(queue);
52
}
53
54
int network_queue_append(network_queue *queue, GString *s) {
55
	queue->len += s->len;
56
57
	g_queue_push_tail(queue->chunks, s);
58
59
	return 0;
60
}
61
62
/**
63
 * get a string from the head of the queue and leave the queue unchanged 
64
 *
65
 * @param  queue the queue to read from
66
 * @param  peek_len  bytes to collect
67
 * @param  dest      GString to write it. If NULL, we allow a new one and return it
68
 * @return NULL if not enough data
69
 *         if dest is not NULL, dest, otherwise a new GString containing the data
70
 */
71
GString *network_queue_peek_string(network_queue *queue, gsize peek_len, GString *dest) {
72
	gsize we_want = peek_len;
73
	GList *node;
74
75
/* TODO: convert to DTrace probe
76
	g_debug("[%s] looking for %d bytes, queue has %d", G_STRLOC, peek_len, queue->len); */
77
	if (queue->len < peek_len) {
78
		return NULL;
79
	}
80
81
	if (!dest) {
82
		/* no define */
83
		dest = g_string_sized_new(peek_len);
84
	}
85
86
	g_assert_cmpint(dest->allocated_len, >, peek_len);
87
88
	for (node = queue->chunks->head; node && we_want; node = node->next) {
89
		GString *chunk = node->data;
90
91
		if (node == queue->chunks->head) {
92
			gsize we_have = we_want < (chunk->len - queue->offset) ? we_want : (chunk->len - queue->offset);
93
94
			g_string_append_len(dest, chunk->str + queue->offset, we_have);
95
			
96
			we_want -= we_have;
97
		} else {
98
			gsize we_have = we_want < chunk->len ? we_want : chunk->len;
99
			
100
			g_string_append_len(dest, chunk->str, we_have);
101
102
			we_want -= we_have;
103
		}
104
	}
105
106
	return dest;
107
}
108
109
/**
110
 * get a string from the head of the queue and remove the chunks from the queue 
111
 */
112
GString *network_queue_pop_string(network_queue *queue, gsize steal_len, GString *dest) {
113
	gsize we_want = steal_len;
114
	GString *chunk;
115
116
	if (queue->len < steal_len) {
117
		return NULL;
118
	}
119
120
	while ((chunk = g_queue_peek_head(queue->chunks))) {
121
		gsize we_have = we_want < (chunk->len - queue->offset) ? we_want : (chunk->len - queue->offset);
122
123
		if (!dest && (queue->offset == 0) && (chunk->len == steal_len)) {
124
			/* optimize the common case that we want to have to full chunk
125
			 *
126
			 * if dest is null, we can remove the GString from the queue and return it directly without
127
			 * copying it
128
			 */
129
			dest = g_queue_pop_head(queue->chunks);
130
			queue->len -= we_have;
131
			return dest;
132
		}
133
134
		if (!dest) {
135
			/* if we don't have a dest-buffer yet, create one */
136
			dest = g_string_sized_new(steal_len);
137
		}
138
		g_string_append_len(dest, chunk->str + queue->offset, we_have);
139
140
		queue->offset += we_have;
141
		queue->len    -= we_have;
142
		we_want -= we_have;
143
144
		if (chunk->len == queue->offset) {
145
			/* the chunk is done, remove it */
146
			g_string_free(g_queue_pop_head(queue->chunks), TRUE);
147
			queue->offset = 0;
148
		} else {
149
			break;
150
		}
151
	}
152
153
	return dest;
154
}
155
156