trace_tcp.c 4.85 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/*
	trace tcp connection handling

	Copyright Jeroen Vreeken (jeroen@vreeken.net), 2013

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.

*/

#include <trace_def.h>
#include <trace/trace.h>
#include <log/log.h>
#include <tcp_connect.h>

#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/ioctl.h>
31
#include <stdio.h>
32
33
34

#define TRACE_BUF_BLOCK	4096

Jeroen Vreeken's avatar
Jeroen Vreeken committed
35
36
37
38
39
struct trace *trace_alloc(void)
{
	return calloc(sizeof(struct trace), 1);
}

40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
struct trace *trace_open(char *host, int port)
{
	struct trace *trace;
	
	trace = calloc(sizeof(struct trace), 1);
	if (!trace)
		return NULL;

	trace->host = strdup(host);
	trace->port = port;
	
	trace->fd = tcp_connect(host, port);
	if (trace->fd >= 0) {
		ioctl(trace->fd, FIONBIO, &(int){1});
	}
	
	return trace;
}

59
void trace_initialize_fd(struct trace *trace, int fd)
60
61
{
	trace->fd = fd;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
62
	trace->rx_len = 0;
63
	
64
65
66
67
68
69
70
	if (trace->fd >= 0) {
		ioctl(trace->fd, FIONBIO, &(int){1});
	}
}

void trace_close(struct trace *trace)
{
Jeroen Vreeken's avatar
Jeroen Vreeken committed
71
	log_send(LOG_T_DEBUG, "Close trace on request");
72
73
	if (trace->fd >= 0)
		close(trace->fd);
74
	trace->fd = -1;	
Jeroen Vreeken's avatar
Jeroen Vreeken committed
75
	trace->recover = false;
76
77
78
79
80
81
}

void trace_free(struct trace *trace)
{
	trace_close(trace);

Jeroen Vreeken's avatar
Jeroen Vreeken committed
82
	free(trace->name);
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
	free(trace->rx_buffer);
	free(trace->host);
	free(trace);
}

int trace_fd_get(struct trace *trace)
{
	return trace->fd;
}

bool trace_fd_read(struct trace *trace)
{
	ssize_t ret;
	int i;
	bool rx_ready = false;

Jeroen Vreeken's avatar
Jeroen Vreeken committed
99
	if (trace->rx_buf_size - trace->rx_len < TRACE_BUF_BLOCK) {
100
		unsigned char *newbuf;
101
102
103
104
		
		newbuf = realloc(trace->rx_buffer, trace->rx_buf_size +	TRACE_BUF_BLOCK);
		if (newbuf) {
			trace->rx_buffer = newbuf;
105
			trace->rx_buf_size += TRACE_BUF_BLOCK;
106
107
108
109
110
111
112
113
114
115
116
117
		} else {
			log_send(LOG_T_WARNING, 
			    "Could not enlarge buffer for receiving traces");
			return false;
		}
	}
	
	ret = read(trace->fd, trace->rx_buffer + trace->rx_len, TRACE_BUF_BLOCK);

	if (ret > 0) {
		trace->rx_len += ret;
	}
118

119
120
121
122
123
	for (i = 0; i < trace->rx_len; i++) {
		if (trace->rx_buffer[i] == TRACE_END)
			rx_ready = true;
	}
	
Jeroen Vreeken's avatar
Jeroen Vreeken committed
124
125
	if (((ret < 0 && errno != EAGAIN) || ret == 0) && !rx_ready) {
		log_send(LOG_T_DEBUG, "error during read, closing");
126
127
		close(trace->fd);
		trace->fd = -1;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
128
129
130
		
		if (trace->handler_close)
			trace->handler_close(trace);
131
132
	}
	
133
134
135
136
137
138
	return rx_ready;
}

struct trace_pkt *trace_packet_get(struct trace *trace)
{
	int i;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
139
	size_t len = 0, buflen;
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
	struct trace_pkt *pkt;
	
	while(trace->rx_len && trace->rx_buffer[0] == TRACE_END) {
		memmove(trace->rx_buffer, trace->rx_buffer+1, trace->rx_len-1);
		trace->rx_len--;
	}

	for (i = 0; i < trace->rx_len; i++) {
		if (trace->rx_buffer[i] == TRACE_END) {
			len = i;
			break;
		}
	}
	
	if (!len) {
		return NULL;
	}
	
Jeroen Vreeken's avatar
Jeroen Vreeken committed
158
159
160
	buflen = len;
	
	pkt = trace_packet_new();
161
162
	if (!pkt)
		goto err_pkt;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
163
	if (trace_packet_resize(pkt, len))
164
165
166
167
168
169
170
171
172
		goto err_pkt_data;

	memcpy(pkt->data, trace->rx_buffer, len);
	pkt->type = pkt->data[0];

	for (i = 0; i < len - 1; i++) {
		if (pkt->data[i] == TRACE_ESC) {
			if (pkt->data[i+1] == TRACE_ESC_END)
				pkt->data[i] = TRACE_END;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
173
			memmove(&pkt->data[i+1], &pkt->data[i+2], len - i - 2);
174
175
176
177
178
			len--;
		}
	}
	pkt->len = len;
	
Jeroen Vreeken's avatar
Jeroen Vreeken committed
179
180
	trace->rx_len -= buflen + 1;
	memmove(trace->rx_buffer, trace->rx_buffer + buflen + 1, trace->rx_len);
181
182
183
184
185
186
187
188
189
190
191
192
193
	
	return pkt;

err_pkt_data:
	free(pkt);
err_pkt:
	return NULL;
}

int trace_packet_write(struct trace *trace, struct trace_pkt *pkt)
{
	int i;
	int start = 0;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
194
	ssize_t r;
195
	
196
197
198
	if (!pkt->len)
		return 0;
	
199
200
	while (start < pkt->len) for (i = start; i < pkt->len; i++) {
		if (pkt->data[i] == TRACE_ESC || pkt->data[i] == TRACE_END) {
201
			unsigned char *seq;
202
			
Jeroen Vreeken's avatar
Jeroen Vreeken committed
203
			r = write(trace->fd, pkt->data + start, i - start);
204
			if (r != i - start)
Jeroen Vreeken's avatar
Jeroen Vreeken committed
205
206
				goto err_write;
			
207
208
			start = i + 1;
			if (pkt->data[i] == TRACE_ESC)
209
				seq = (unsigned char[2]){ TRACE_ESC, TRACE_ESC_ESC };
210
			else
211
				seq = (unsigned char[2]){ TRACE_ESC, TRACE_ESC_END };
Jeroen Vreeken's avatar
Jeroen Vreeken committed
212
			r = write(trace->fd, seq, 2);
213
			if (r != 2)
Jeroen Vreeken's avatar
Jeroen Vreeken committed
214
				goto err_write;
215
		}
216
		if (i == pkt->len -1) {
Jeroen Vreeken's avatar
Jeroen Vreeken committed
217
			r = write(trace->fd, pkt->data + start, i - start + 1);
218
			if (r != i - start + 1)
Jeroen Vreeken's avatar
Jeroen Vreeken committed
219
				goto err_write;
220
221
			start = i + 1;
		}
222
	}
Jeroen Vreeken's avatar
Jeroen Vreeken committed
223
224
225
	r = write(trace->fd, &(char[1]){ TRACE_END }, 1);
	if (r < 0)
		goto err_write;
226
227
	
	return 0;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
228
229
230
231
232
233
234
235
236
237

err_write:
	log_send(LOG_T_DEBUG, "Error during write, closing %d", trace->fd);
	if (trace->fd >= 0)
		close(trace->fd);
	trace->fd = -1;
		
	if (trace->handler_close)
		trace->handler_close(trace);
	return -1;
238
}