Browse code

- Better API for sending replies - Core commands implemented

Jan Janak authored on 03/03/2004 15:36:55
Showing 2 changed files
... ...
@@ -37,7 +37,10 @@
37 37
 #include <sys/types.h>
38 38
 #include <sys/socket.h>
39 39
 #include <sys/stat.h>
40
+#include <signal.h>
40 41
 #include <stdarg.h>
42
+#include <time.h>
43
+#include "config.h"
41 44
 #include "ut.h"
42 45
 #include "globals.h"
43 46
 #include "trim.h"
... ...
@@ -57,12 +60,232 @@ static struct unixsock_cmd* cmd_list;
57 60
 static char reply_buf[UNIXSOCK_BUF_SIZE];
58 61
 static str reply_pos;
59 62
 static struct sockaddr_un reply_addr;
63
+static int reply_addr_len;
60 64
 
61
-#define CMD_NOT_FOUND "500 Command not found"
62
-#define CMD_NOT_FOUND_LEN (sizeof(CMD_NOT_FOUND) - 1)
65
+static time_t up_since;
66
+static char up_since_ctime[MAX_CTIME_LEN];
63 67
 
64
-#define FLINE_ERR "400 First line malformed"
65
-#define FLINE_ERR_LEN (sizeof(FLINE_ERR) - 1)
68
+
69
+#define PRINT_CMD "print"     /* Diagnostic command */
70
+#define VERSION_CMD "version" /* Print the version of the server */
71
+#define UPTIME_CMD "uptime"   /* Print server's uptime */
72
+#define WHICH_CMD "which"     /* Print available FIFO commands */
73
+#define PS_CMD "ps"           /* Print server's process table */
74
+#define ARG_CMD "arg"         /* Print server's command line arguments */
75
+#define PWD_CMD "pwd"         /* Get the current working directory */
76
+#define KILL_CMD "kill"       /* Kill the server */
77
+
78
+
79
+/* 
80
+ * Diagnostic and hello-world command 
81
+ */
82
+static int print_cmd(str* msg)
83
+{
84
+	str line;
85
+	int ret;
86
+
87
+	ret = 0;
88
+
89
+	if (unixsock_read_line(&line, msg) < 0) {
90
+		unixsock_reply_asciiz("500 Error while reading text\n");
91
+		ret = -1;
92
+		goto end;
93
+	}
94
+
95
+	if (unixsock_reply_printf("200 OK\n%.*s\n", line.len, ZSW(line.s)) < 0) {
96
+		unixsock_reply_reset();
97
+		unixsock_reply_asciiz("500 Error while sending reply\n");
98
+		ret = -1;
99
+	}
100
+
101
+ end:
102
+	if (unixsock_reply_send() < 0) ret = -1;
103
+	return ret;
104
+}
105
+
106
+
107
+/*
108
+ * Print the version of the server
109
+ */
110
+static int version_cmd(str* msg)
111
+{
112
+	int ret;
113
+
114
+	ret = 0;
115
+	if (unixsock_reply_asciiz("200 OK\n" SERVER_HDR CRLF) < 0) ret = -1;
116
+	if (unixsock_reply_send() < 0) ret = -1;
117
+	return ret;
118
+}
119
+
120
+
121
+static int uptime_cmd(str* msg)
122
+{
123
+	time_t now;
124
+	int ret;
125
+
126
+	time(&now);
127
+	ret = 0;
128
+	
129
+	if (unixsock_reply_printf("200 OK\nNow: %sUp Since: %sUp time: %.0f [sec]\n",
130
+				  ctime(&now), up_since_ctime, difftime(now, up_since)) < 0) {
131
+		unixsock_reply_reset();
132
+		unixsock_reply_asciiz("500 Error while printing reply\n");
133
+		ret = -1;
134
+	}
135
+	
136
+	if (unixsock_reply_send() < 0) {
137
+		ret = -1;
138
+	}
139
+	
140
+	return ret;
141
+}
142
+
143
+
144
+static int which_cmd(str* msg)
145
+{
146
+	struct unixsock_cmd* c;
147
+	int ret;
148
+
149
+	ret = 0;
150
+	unixsock_reply_asciiz("200 OK\n");
151
+
152
+	for(c = cmd_list; c; c = c->next) {
153
+		if (unixsock_reply_printf("%s\n", c->name) < 0) {
154
+			unixsock_reply_reset();
155
+			unixsock_reply_asciiz("500 Error while creating reply\n");
156
+			ret = -1;
157
+			break;
158
+		}
159
+	}
160
+	
161
+	if (unixsock_reply_send() < 0) {
162
+		ret = -1;
163
+	}
164
+	return ret;
165
+}
166
+
167
+
168
+static int ps_cmd(str* msg)
169
+{
170
+	int p, ret;
171
+
172
+	ret = 0;
173
+	unixsock_reply_asciiz("200 OK\n");
174
+	for (p = 0; p < process_count(); p++) {
175
+		if (unixsock_reply_printf("%d\t%d\t%s\n", p, pt[p].pid, pt[p].desc) < 0) {
176
+			unixsock_reply_reset();
177
+			unixsock_reply_asciiz("500 Error while printing reply\n");
178
+			ret = -1;
179
+			break;
180
+		}
181
+	}
182
+	
183
+	if (unixsock_reply_send() < 0) {
184
+		ret = -1;
185
+	}
186
+	return ret;
187
+}
188
+
189
+
190
+static int pwd_cmd(str* msg)
191
+{
192
+	char *cwd_buf;
193
+	int max_len, ret;
194
+
195
+	max_len = pathmax();
196
+	cwd_buf = pkg_malloc(max_len);
197
+	ret = 0;
198
+	if (!cwd_buf) {
199
+		LOG(L_ERR, "pwd_cmd: No memory left\n");
200
+		unixsock_reply_asciiz("500 No Memory Left\n");
201
+		ret = -1;
202
+	}
203
+
204
+	if (getcwd(cwd_buf, max_len)) {
205
+		if (unixsock_reply_printf("200 OK\n%s\n", cwd_buf) < 0) {
206
+			unixsock_reply_reset();
207
+			unixsock_reply_asciiz("500 Error while sending reply\n");
208
+			ret = -1;
209
+		}
210
+	} else {
211
+		unixsock_reply_asciiz("500 getcwd Failed\n");
212
+		ret = -1;
213
+	}
214
+
215
+	pkg_free(cwd_buf);
216
+	if (unixsock_reply_send() < 0) {
217
+		ret = -1;
218
+	}
219
+	return ret;
220
+}
221
+
222
+
223
+static int arg_cmd(str* msg)
224
+{
225
+	int p, ret;
226
+
227
+	ret = 0;
228
+	unixsock_reply_asciiz("200 OK\n");
229
+	for (p = 0; p < my_argc; p++) {
230
+		if (unixsock_reply_printf("%s\n", my_argv[p]) < 0) {
231
+			unixsock_reply_reset();
232
+			unixsock_reply_asciiz("500 Could not create reply\n");
233
+			ret = -1;
234
+			break;
235
+		}
236
+	}
237
+			
238
+	if (unixsock_reply_send() < 0) {
239
+		ret = -1;
240
+	}
241
+	return ret;
242
+}
243
+
244
+
245
+static int kill_cmd(str* msg)
246
+{
247
+	unixsock_reply_asciiz("200 Killing now\n");
248
+	unixsock_reply_send();
249
+	kill(0, SIGTERM);
250
+	return 0;
251
+}
252
+
253
+
254
+static int register_core_commands(void)
255
+{
256
+	if (unixsock_register_cmd(PRINT_CMD, print_cmd) < 0) {
257
+		return -1;
258
+	}
259
+
260
+	if (unixsock_register_cmd(VERSION_CMD, version_cmd) < 0) {
261
+		return -1;
262
+	}
263
+
264
+	if (unixsock_register_cmd(UPTIME_CMD, uptime_cmd) < 0) {
265
+		return -1;
266
+	}
267
+
268
+	if (unixsock_register_cmd(WHICH_CMD, which_cmd) < 0) {
269
+		return -1;
270
+	}
271
+
272
+	if (unixsock_register_cmd(PS_CMD, ps_cmd) < 0) {
273
+		return -1;
274
+	}
275
+
276
+	if (unixsock_register_cmd(PWD_CMD, pwd_cmd) < 0) {
277
+		return -1;
278
+	}
279
+
280
+	if (unixsock_register_cmd(ARG_CMD, arg_cmd) < 0) {
281
+		return -1;
282
+	}
283
+
284
+	if (unixsock_register_cmd(KILL_CMD, kill_cmd) < 0) {
285
+		return -1;
286
+	}
287
+	return 0;
288
+}
66 289
 
67 290
 
68 291
 /*
... ...
@@ -190,7 +413,7 @@ static void skip_line(str* buffer)
190 413
 
191 414
 static void unix_server_loop(void)
192 415
 {
193
-	int addr_len, ret;
416
+	int ret;
194 417
 	str cmd, buffer;
195 418
 	static char buf[UNIXSOCK_BUF_SIZE];
196 419
 	struct unixsock_cmd* c;
... ...
@@ -198,13 +421,10 @@ static void unix_server_loop(void)
198 421
 	buffer.s = buf;
199 422
 	buffer.len = 0;
200 423
 	
201
-	reply_pos.s = reply_buf;
202
-	reply_pos.len = UNIXSOCK_BUF_SIZE;
203
-
204 424
 	while(1) {
205
-		addr_len = sizeof(reply_addr);
425
+		reply_addr_len = sizeof(reply_addr);
206 426
 		ret = recvfrom(sock, buffer.s, UNIXSOCK_BUF_SIZE, 0, 
207
-			       (struct sockaddr*)&reply_addr, &addr_len);
427
+			       (struct sockaddr*)&reply_addr, &reply_addr_len);
208 428
 		if (ret == -1) {
209 429
 			LOG(L_ERR, "unix_server_loop: recvfrom: (%d) %s\n", 
210 430
 			    errno, strerror(errno));
... ...
@@ -219,10 +439,11 @@ static void unix_server_loop(void)
219 439
 		}
220 440
 
221 441
 		buffer.len = ret;
442
+		unixsock_reply_reset();
222 443
 
223 444
 		if (parse_cmd(&cmd, &buffer) < 0) {
224
-			unixsock_add_to_reply(FLINE_ERR, FLINE_ERR_LEN);
225
-			unixsock_send_reply();
445
+			unixsock_reply_asciiz("400 First line malformed\n");
446
+			unixsock_reply_send();
226 447
 			continue;
227 448
 		}
228 449
 
... ...
@@ -234,8 +455,8 @@ static void unix_server_loop(void)
234 455
 		if (c == 0) {
235 456
 			LOG(L_ERR, "unix_server_loop: Could not find "
236 457
 			    "command '%.*s'\n", cmd.len, ZSW(cmd.s));
237
-			unixsock_add_to_reply(CMD_NOT_FOUND, CMD_NOT_FOUND_LEN);
238
-			unixsock_send_reply();
458
+			unixsock_reply_printf("500 Command %.*s not found\n", cmd.len, ZSW(cmd.s));
459
+			unixsock_reply_send();
239 460
 			continue;
240 461
 		}
241 462
 
... ...
@@ -252,6 +473,21 @@ static void unix_server_loop(void)
252 473
 }
253 474
 
254 475
 
476
+static int get_uptime(void)
477
+{
478
+	char* t;
479
+
480
+	time(&up_since);
481
+	t = ctime(&up_since);
482
+	if (strlen(t) + 1 >= MAX_CTIME_LEN) {
483
+		LOG(L_ERR, "get_uptime: Too long date %d\n", (int)strlen(t));
484
+		return -1;
485
+	}
486
+	memcpy(up_since_ctime, t, strlen(t) + 1);
487
+	return 0;
488
+}
489
+
490
+
255 491
 /*
256 492
  * Initialize Unix domain socket server
257 493
  */
... ...
@@ -273,6 +509,15 @@ int init_unixsock_server(void)
273 509
 		return 1;
274 510
 	}
275 511
 
512
+	if (get_uptime() < 0) {
513
+		return -1;
514
+	}
515
+
516
+        if (register_core_commands() < 0) {
517
+		close(sock);
518
+		return -1;
519
+	}
520
+
276 521
 	for(i = 0; i < unixsock_children; i++) {
277 522
 		process_no++;
278 523
 #ifdef USE_TCP
... ...
@@ -321,6 +566,7 @@ int init_unixsock_server(void)
321 566
 #endif
322 567
 
323 568
 	}
569
+
324 570
 	return 1;
325 571
 }
326 572
 
... ...
@@ -344,11 +590,15 @@ void close_unixsock_server(void)
344 590
 /*
345 591
  * Register a new command
346 592
  */
347
-int unixsock_register_cmd(str* cmd, unixsock_f* f)
593
+int unixsock_register_cmd(char* command, unixsock_f* f)
348 594
 {
595
+	str cmd;
349 596
 	struct unixsock_cmd* new_cmd;
350 597
 
351
-	if (lookup_cmd(cmd)) {
598
+	cmd.s = command;
599
+	cmd.len = strlen(command);
600
+
601
+	if (lookup_cmd(&cmd)) {
352 602
 		LOG(L_ERR, "unixsock_register_cmd: Function already exists\n");
353 603
 		return -1;
354 604
 	}
... ...
@@ -359,14 +609,14 @@ int unixsock_register_cmd(str* cmd, unixsock_f* f)
359 609
 		return -1;
360 610
 	}
361 611
 
362
-	new_cmd->name = *cmd;
612
+	new_cmd->name = cmd;
363 613
 	new_cmd->f = f;
364 614
 
365 615
 	new_cmd->next = cmd_list;
366 616
 	cmd_list = new_cmd;
367 617
 	
368 618
 	DBG("unixsock_register_cmd: New command (%.*s) registered\n", 
369
-	    cmd->len, ZSW(cmd->s));
619
+	    cmd.len, ZSW(cmd.s));
370 620
 	return 1;
371 621
 }
372 622
 
... ...
@@ -388,15 +638,15 @@ int unixsock_add_to_reply(const char* buf, size_t len)
388 638
 /*
389 639
  * Send a reply
390 640
  */
391
-ssize_t unixsock_send_reply(void)
641
+ssize_t unixsock_reply_send(void)
392 642
 {
393 643
 	int ret;
394 644
 
395 645
 	ret = sendto(sock, reply_buf, reply_pos.s - reply_buf, MSG_DONTWAIT, 
396
-		     (struct sockaddr*)&reply_addr, SUN_LEN(&reply_addr));
646
+		     (struct sockaddr*)&reply_addr, reply_addr_len);
397 647
 
398 648
 	if (ret == -1) {
399
-		LOG(L_ERR, "unixsock_send_reply: sendto: %s\n", 
649
+		LOG(L_ERR, "unixsock_reply_send: sendto: %s\n", 
400 650
 		    strerror(errno));
401 651
 	}
402 652
 
... ...
@@ -584,3 +834,90 @@ int unixsock_read_lineset(str* lineset, str* source)
584 834
 	LOG(L_ERR, "unixsock_read_body: Could not find the end of the body\n");
585 835
 	return -1;
586 836
 }
837
+
838
+
839
+/*
840
+ * Reset the reply buffer -- start to write
841
+ * at the beginning
842
+ */
843
+void unixsock_reply_reset(void)
844
+{
845
+	reply_pos.s = reply_buf;
846
+	reply_pos.len = UNIXSOCK_BUF_SIZE;
847
+}
848
+
849
+
850
+/*
851
+ * Add ASCIIZ to the reply buffer
852
+ */
853
+int unixsock_reply_asciiz(char* str)
854
+{
855
+	int len;
856
+	
857
+	if (!str) {
858
+		LOG(L_ERR, "unixsock_reply_asciiz: Invalid parameter value\n");
859
+		return -1;
860
+	}
861
+
862
+	len = strlen(str);
863
+
864
+	if (reply_pos.len < len) {
865
+		LOG(L_ERR, "unixsock_reply_asciiz: Buffer too small\n");
866
+		return -1;
867
+	}
868
+
869
+	memcpy(reply_pos.s, str, len);
870
+	reply_pos.s += len;
871
+	reply_pos.len -= len;
872
+	return 0;
873
+}
874
+
875
+
876
+/*
877
+ * Add a string represented by str structure
878
+ * to the reply buffer
879
+ */
880
+int unixsock_reply_str(str* s)
881
+{
882
+	if (!s) {
883
+		LOG(L_ERR, "unixsock_reply_str: Invalid parameter value\n");
884
+		return -1;
885
+	}
886
+
887
+	if (reply_pos.len < s->len) {
888
+		LOG(L_ERR, "unixsock_reply_str: Buffer too small\n");
889
+		return -1;
890
+	}
891
+	
892
+	memcpy(reply_pos.s, s->s, s->len);
893
+	reply_pos.s += s->len;
894
+	reply_pos.len -= s->len;
895
+	return 0;
896
+}
897
+
898
+
899
+/*
900
+ * Printf-like reply function
901
+ */
902
+int unixsock_reply_printf(char* fmt, ...)
903
+{
904
+	va_list ap;
905
+	int ret;
906
+
907
+	if (!fmt) {
908
+		LOG(L_ERR, "unixsock_reply_printf: Invalid parameter value\n");
909
+		return -1;
910
+	}
911
+
912
+	va_start(ap, fmt);
913
+	ret = vsnprintf(reply_pos.s, reply_pos.len, fmt, ap);
914
+	if ((ret == -1) || (ret >= reply_pos.len)) {
915
+		LOG(L_ERR, "unixsock_reply_printf: Buffer too small\n");
916
+		return -1;
917
+	}
918
+
919
+	va_end(ap);
920
+	reply_pos.s += ret;
921
+	reply_pos.len -= ret;
922
+	return 0;
923
+}
... ...
@@ -60,19 +60,39 @@ void close_unixsock_server(void);
60 60
 /*
61 61
  * Register a new command
62 62
  */
63
-int unixsock_register_cmd(str* name, unixsock_f* f);
63
+int unixsock_register_cmd(char* name, unixsock_f* f);
64 64
 
65 65
 
66 66
 /*
67
- * add a text to the reply
67
+ * Reset the reply buffer -- start to write
68
+ * at the beginning
68 69
  */
69
-int unixsock_add_to_reply(const char* buf, size_t len);
70
+void unixsock_reply_reset(void);
71
+
72
+
73
+/*
74
+ * Add ASCIIZ to the reply buffer
75
+ */
76
+int unixsock_reply_asciiz(char* str);
77
+
78
+
79
+/*
80
+ * Add a string represented by str structure
81
+ * to the reply buffer
82
+ */
83
+int unixsock_reply_str(str* s);
84
+
85
+
86
+/*
87
+ * Printf-like reply function
88
+ */
89
+int unixsock_reply_printf(char* fmt, ...);
70 90
 
71 91
 
72 92
 /*
73 93
  * Send the reply
74 94
  */
75
-ssize_t unixsock_send_reply(void);
95
+ssize_t unixsock_reply_send(void);
76 96
 
77 97
 
78 98
 /*