log_proxy.c 7.01 KB
Newer Older
Jeroen Vreeken's avatar
Jeroen Vreeken committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
	Copyright Jeroen Vreeken (pe1rxq@amsat.org), 2008
	Copyright Stichting C.A. Muller Radioastronomiestation, 2008

	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/>.

 */

20
21
#define _GNU_SOURCE

Jeroen Vreeken's avatar
Jeroen Vreeken committed
22
23
24
25
26
27
28
29
30
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
31
#include <sys/param.h>
Jeroen Vreeken's avatar
Jeroen Vreeken committed
32
#include <fcntl.h>
33
#include <stdbool.h>
34
#include <time.h>
Jeroen Vreeken's avatar
Jeroen Vreeken committed
35
36
37
38
39

#include "tcp_listen.h"
#include "tcp_connect.h"

#include "dt_port_numbers.h"
Jeroen Vreeken's avatar
Jeroen Vreeken committed
40
#include "dt_host.h"
41
#include "command_server.h"
42
#include "log.h"
Jeroen Vreeken's avatar
Jeroen Vreeken committed
43

44
char *logfile = NULL;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
45

46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
#define LOG_RING_SIZE	1000
#define LOG_ENTRY_SIZE	1000
#define LOG_ENTRY_LEN	(LOG_ENTRY_SIZE-1)

static struct log_entry {
	bool used;
	char buffer[LOG_ENTRY_SIZE];
	size_t buflen;
} log_ring[LOG_RING_SIZE];

static int ring_wr;
static int ring_rd;
static int entries;

static struct log_entry *log_entry_alloc(void)
{
	int i;
	
	i = ring_wr;
	ring_wr++;
	if (ring_wr >= LOG_RING_SIZE)
		ring_wr = 0;
	
	if (!log_ring[i].used)
		entries++;
	log_ring[i].used = true;
	
	return log_ring + i;
}

static struct log_entry *log_entry_pull(void)
{
	struct log_entry *entry;
	
	if (log_ring[ring_rd].used) {
		entry = log_ring + ring_rd;
		entry->used = false;
		ring_rd++;
		if (ring_rd >= LOG_RING_SIZE)
			ring_rd = 0;
	} else {
		entry = NULL;
	}
	
	return entry;
}
92
93
94

int handle_cmd(char *command)
{
95
96
97
	struct log_entry *entry;
	
	entry = log_entry_alloc();
98

99
100
101
102
103
104
	strncpy(entry->buffer, command, LOG_ENTRY_LEN);
	entry->buffer[LOG_ENTRY_LEN] = 0;
	entry->buffer[strlen(entry->buffer)] = 0;
	entry->buflen = strlen(entry->buffer);

	printf("Handling command buflen = %zd\n", entry->buflen);
105
106
107
108

	return 0;
}

Jeroen Vreeken's avatar
Jeroen Vreeken committed
109
110
111
112
113
114
115
int main (int argc, char **argv)
{
	int fd_listen;
	int fd_log;
	int *fd_clients = NULL;
	int nr_clients = 0;
	int fd_logfile = -1;
116
	struct command_server *cmd_srv;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
117
	
Jeroen Vreeken's avatar
Jeroen Vreeken committed
118
119
	if (argc != 1 && argc != 2) {
		printf("Usage: %s <logfile>\n", argv[0]);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
120
		printf("\n");
Jeroen Vreeken's avatar
Jeroen Vreeken committed
121
122
		printf("e.g.: %s\n", argv[0]);
		printf("or:   %s /var/log/controller.log\n", argv[0]);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
123
124
		return 1;
	}
Jeroen Vreeken's avatar
Jeroen Vreeken committed
125
126
	if (argc == 2) {
		logfile = argv[1];
127
128
129
130
131
132
	} else {
		char timestamp[100];
		time_t now = time(NULL);
		
		strftime(timestamp, 100, "%FT%TZ", gmtime(&now));
		asprintf(&logfile, "%s/%s.log", dt_host_log_path(), timestamp);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
133
	}
134
	printf("Log file location: %s\n", logfile);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
135
136
137
138
139
140

	fd_listen = tcp_listen(CONSOLE_LOG_PORT, 0, 100);
	if (fd_listen < 0) {
		printf("Could not open listen port\n");
		return 1;
	}
141
142
143
144
145
146
147
148

	cmd_srv = command_server_create(CONSOLE_LOG_PORT_IN, 0, 100);
	if (!cmd_srv) {
		printf("Could not open listen port for logging\n");
		return 1;
	} else {
		command_server_handler_raw_set(cmd_srv, handle_cmd);
	}
Jeroen Vreeken's avatar
Jeroen Vreeken committed
149
150
151
152
153
	
	signal(SIGPIPE, SIG_IGN);
	
	ioctl(fd_listen, FIONBIO, &(int){ 1 });

Jeroen Vreeken's avatar
Jeroen Vreeken committed
154
	fd_log = tcp_connect(dt_host_controller(), CTRL_LOG_PORT);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
155
156
157
	
	while (1) {
		int fdnew;
158
159
		fd_set fd_rd;
		struct timeval timeout;
160
		int high = 0;
161
		struct log_entry *entry;
162
163
164

		timeout.tv_usec = 0;
		timeout.tv_sec = 1;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
165
		
166
		FD_ZERO(&fd_rd);
167
168
169
170
		if (fd_log >= 0) {
			FD_SET(fd_log, &fd_rd);
			high = fd_log;
		}
171
172
173
174
175
176
		FD_SET(fd_listen, &fd_rd);
		high = MAX(high, fd_listen);
		command_server_fdset_add(cmd_srv, &fd_rd, &high);

		select(high + 1, &fd_rd, NULL, NULL, &timeout);
		
Jeroen Vreeken's avatar
Jeroen Vreeken committed
177
		if (fd_log < 0) {
178
179
180
181
			printf("Trying to connect to server.\n");
			fd_log = tcp_connect(dt_host_controller(), CTRL_LOG_PORT);

			if (fd_log >= 0) {
182
183
184
185
186
187
188
189
				entry = log_entry_alloc();
				
				log_string(entry->buffer, LOG_ENTRY_LEN, LOG_T_INFO, 
				    "Established connection to controller");
				entry->buffer[strlen(entry->buffer)+1] = 0;
				entry->buffer[strlen(entry->buffer)] = '\n';
				printf(entry->buffer);
				entry->buflen = strlen(entry->buffer);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
190
			}
191
		} else if (FD_ISSET(fd_log, &fd_rd)) {
192
193
194
			static char s[LOG_ENTRY_SIZE];
			static size_t pos;
			static ssize_t ret;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
195
			
196
197
			if (pos >= LOG_ENTRY_LEN)
				pos = 0;
Jeroen Vreeken's avatar
Jeroen Vreeken committed
198
			
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
			ret = read(fd_log, s+pos, LOG_ENTRY_LEN - pos);
			if (ret > 0) {
				int i = pos;
				
				printf("read %zd bytes\n", ret);
				
				pos += ret;
				
				printf("buffer now at %zd bytes\n", pos);
				
				for (; i < pos; i++) {
					if (s[i] == '\n') {
						printf("enewline at %d\n", i);
						entry = log_entry_alloc();
						strncpy(entry->buffer, s, i+1);
						entry->buffer[i+1] = 0;
						entry->buflen = i+1;
						
						printf("move %zd bytes back\n", pos - i);
						memmove(s, s+i + 1, pos - i - 1);
						pos -= i + 1;
						i = -1;
					}
				}
			}
Jeroen Vreeken's avatar
Jeroen Vreeken committed
224
			
225
226
227
			if (ret == 0 ||
			    (ret < 0 && errno != EAGAIN && errno != EWOULDBLOCK)) {
				printf("Close connection to server\n");
228
				close(fd_log);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
229
230
				
				fd_log = -1;
231

232
				entry = log_entry_alloc();
233
234
235
236
237
238
				log_string(entry->buffer, LOG_ENTRY_LEN, LOG_T_ERROR, 
				    "Lost connection to controller");
				entry->buffer[strlen(entry->buffer)+1] = 0;
				entry->buffer[strlen(entry->buffer)] = '\n';
				printf(entry->buffer);
				entry->buflen = strlen(entry->buffer);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
239
			}
Jeroen Vreeken's avatar
Jeroen Vreeken committed
240
		}
241
		command_server_fdset_handle(cmd_srv, &fd_rd);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
242
			
Jeroen Vreeken's avatar
Jeroen Vreeken committed
243
244
245
246
247
248
		if (fd_logfile < 0) {
			fd_logfile = open(logfile, 
			    O_WRONLY | O_APPEND | O_CREAT,
			    S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
		}

249

Jeroen Vreeken's avatar
Jeroen Vreeken committed
250
251
		fdnew = tcp_accept(fd_listen);
		if (fdnew >= 0) {
252
			char status[LOG_ENTRY_SIZE];
253
254
			int statlen;
			
Jeroen Vreeken's avatar
Jeroen Vreeken committed
255
256
257
258
259
			nr_clients++;
			fd_clients = realloc(fd_clients, sizeof(int)*nr_clients);
			fd_clients[nr_clients-1] = fdnew;
			ioctl(fdnew, FIONBIO, &(int){ 1 });
			printf("New client. (now at %d)\n", nr_clients);
260
261
			
			if (fd_log >= 0) {
262
				log_string(status, LOG_ENTRY_LEN, LOG_T_INFO, 
263
				    "New connection to proxy, controller conection is established.");
264
265
266
				status[strlen(status)+1] = 0;
				status[strlen(status)] = '\n';
				statlen = strlen(status); 
267
			} else {
268
				log_string(status, LOG_ENTRY_LEN, LOG_T_WARNING, 
269
				    "New connection to proxy, no connection to controller.");
270
271
272
				status[strlen(status)+1] = 0;
				status[strlen(status)] = '\n';
				statlen = strlen(status); 
273
274
			}
			write(fdnew, status, statlen);
Jeroen Vreeken's avatar
Jeroen Vreeken committed
275
		}
276

277
		while ((entry = log_entry_pull())) {
Jeroen Vreeken's avatar
Jeroen Vreeken committed
278
			int i;
279
280
281
282
283
284
285
286
287
288
289

			if (fd_logfile >= 0) {
				int ret;
				
				ret = write(fd_logfile, entry->buffer, entry->buflen);
				if (ret != 1) {
					close(fd_logfile);
					fd_logfile = -1;
				}
			}

Jeroen Vreeken's avatar
Jeroen Vreeken committed
290
291
292
			for (i = 0; i < nr_clients; i++) {
				int ret;
				
293
294
				ret = write(fd_clients[i], entry->buffer, entry->buflen);
				if (ret != entry->buflen) {
Jeroen Vreeken's avatar
Jeroen Vreeken committed
295
296
297
298
299
300
301
302
303
304
305
306
307
308
					int j;
					close(fd_clients[i]);
					for (j = i + 1; j < nr_clients; j++) {
						fd_clients[j-1] = fd_clients[j];
					}
					nr_clients--;
					i--;
					printf("Lost a client. (now at %d)\n",
					    nr_clients);
				}
			}
		}
	}
}