Files: ae008179f033c8409c69b13787a539351bace626 / echosrv.c
3972 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 | fd_set fds; |
98 | int res; |
99 | char buffer[1 << 20]; |
100 | char* ret; |
101 | FILE *socket; |
102 | |
103 | FD_ZERO(&fds); |
104 | |
105 | socket = fdopen(fd, "r+"); |
106 | if (!socket) { |
107 | CHECK_RES_DIE(-1, "fdopen"); |
108 | } |
109 | |
110 | while (1) { |
111 | ret = fgets(buffer, sizeof(buffer), socket); |
112 | if (!ret) { |
113 | fprintf(stderr, "%s", strerror(ferror(socket))); |
114 | return; |
115 | } |
116 | res = fprintf(socket, "%s%s", prefix, buffer); |
117 | if (res < 0) { |
118 | fprintf(stderr, "%s", strerror(ferror(socket))); |
119 | return; |
120 | } |
121 | |
122 | fflush(socket); |
123 | } |
124 | } |
125 | |
126 | void main_loop(int listen_sockets[], int num_addr_listen) |
127 | { |
128 | int in_socket, i; |
129 | |
130 | for (i = 0; i < num_addr_listen; i++) { |
131 | if (!fork()) { |
132 | while (1) |
133 | { |
134 | in_socket = accept(listen_sockets[i], 0, 0); |
135 | if (verbose) fprintf(stderr, "accepted fd %d\n", in_socket); |
136 | |
137 | if (!fork()) |
138 | { |
139 | close(listen_sockets[i]); |
140 | start_echo(in_socket); |
141 | exit(0); |
142 | } |
143 | close(in_socket); |
144 | } |
145 | } |
146 | } |
147 | wait(NULL); |
148 | } |
149 | |
150 | int main(int argc, char *argv[]) |
151 | { |
152 | |
153 | extern char *optarg; |
154 | extern int optind; |
155 | int num_addr_listen; |
156 | |
157 | int *listen_sockets; |
158 | |
159 | parse_cmdline(argc, argv); |
160 | |
161 | num_addr_listen = start_listen_sockets(&listen_sockets, addr_listen); |
162 | |
163 | main_loop(listen_sockets, num_addr_listen); |
164 | |
165 | return 0; |
166 | } |
167 |
Built with git-ssb-web