Files: 9cc47a157d0302350ef9b12e141746ef7ef1da3b / echosrv.c
3902 bytesRaw
1 | /* echosrv: a simple line echo server with optional prefix adding. |
2 | * |
3 | * echsrv --listen localhost6:1234 --prefix "ssl: " |
4 | * |
5 | * This will bind to 1234, and echo every line pre-pending "ssl: ". This is |
6 | * used for testing: we create several such servers with different prefixes, |
7 | * then we connect test clients that can then check they get the proper data |
8 | * back (thus testing that shoveling works both ways) with the correct prefix |
9 | * (thus testing it connected to the expected service). |
10 | * **/ |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | |
30 | |
31 | |
32 | |
33 | /* Added to make the code compilable under CYGWIN |
34 | * */ |
35 | |
36 | |
37 | |
38 | |
39 | const char* USAGE_STRING = |
40 | "echosrv\n" \ |
41 | "usage:\n" \ |
42 | "\techosrv [-v] --listen <address:port> [--prefix <prefix>]\n" |
43 | "-v: verbose\n" \ |
44 | "--listen: address to listen on. Can be specified multiple times.\n" \ |
45 | "--prefix: add specified prefix before every line echoed.\n" |
46 | ""; |
47 | |
48 | const char* server_type = "echsrv"; /* keep setup_syslog happy */ |
49 | |
50 | /* |
51 | * Settings that depend on the command line. |
52 | */ |
53 | char* prefix = ""; |
54 | int port; |
55 | |
56 | void parse_cmdline(int argc, char* argv[]) |
57 | { |
58 | int c; |
59 | struct option options[] = { |
60 | { "verbose", no_argument, &verbose, 1 }, |
61 | { "numeric", no_argument, &numeric, 1 }, |
62 | { "listen", required_argument, 0, 'l' }, |
63 | { "prefix", required_argument, 0, 'p' }, |
64 | }; |
65 | struct addrinfo **a; |
66 | |
67 | while ((c = getopt_long_only(argc, argv, "l:p:", options, NULL)) != -1) { |
68 | if (c == 0) continue; |
69 | |
70 | switch (c) { |
71 | |
72 | case 'l': |
73 | /* find the end of the listen list */ |
74 | for (a = &addr_listen; *a; a = &((*a)->ai_next)); |
75 | /* append the specified addresses */ |
76 | resolve_name(a, optarg); |
77 | break; |
78 | |
79 | case 'p': |
80 | prefix = optarg; |
81 | break; |
82 | |
83 | default: |
84 | fprintf(stderr, "%s", USAGE_STRING); |
85 | exit(2); |
86 | } |
87 | } |
88 | |
89 | if (!addr_listen) { |
90 | fprintf(stderr, "No listening port specified\n"); |
91 | exit(1); |
92 | } |
93 | } |
94 | |
95 | void start_echo(int fd) |
96 | { |
97 | int res; |
98 | char buffer[1 << 20]; |
99 | int ret, prefix_len; |
100 | |
101 | prefix_len = strlen(prefix); |
102 | |
103 | memset(buffer, 0, sizeof(buffer)); |
104 | strcpy(buffer, prefix); |
105 | |
106 | while (1) { |
107 | ret = read(fd, buffer + prefix_len, sizeof(buffer)); |
108 | if (ret == -1) { |
109 | fprintf(stderr, "%s", strerror(errno)); |
110 | return; |
111 | } |
112 | res = write(fd, buffer, ret + prefix_len); |
113 | if (res < 0) { |
114 | fprintf(stderr, "%s", strerror(errno)); |
115 | return; |
116 | } |
117 | } |
118 | } |
119 | |
120 | void main_loop(int listen_sockets[], int num_addr_listen) |
121 | { |
122 | int in_socket, i; |
123 | |
124 | for (i = 0; i < num_addr_listen; i++) { |
125 | if (!fork()) { |
126 | while (1) |
127 | { |
128 | in_socket = accept(listen_sockets[i], 0, 0); |
129 | if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket); |
130 | |
131 | if (!fork()) |
132 | { |
133 | close(listen_sockets[i]); |
134 | start_echo(in_socket); |
135 | exit(0); |
136 | } |
137 | close(in_socket); |
138 | } |
139 | } |
140 | } |
141 | wait(NULL); |
142 | } |
143 | |
144 | int main(int argc, char *argv[]) |
145 | { |
146 | |
147 | extern char *optarg; |
148 | extern int optind; |
149 | int num_addr_listen; |
150 | |
151 | int *listen_sockets; |
152 | |
153 | parse_cmdline(argc, argv); |
154 | |
155 | num_addr_listen = start_listen_sockets(&listen_sockets, addr_listen); |
156 | |
157 | main_loop(listen_sockets, num_addr_listen); |
158 | |
159 | return 0; |
160 | } |
161 |
Built with git-ssb-web