Remove RETURN-POSIX-ERROR/RESTART, make syscalls signal errors again.
[iolib.git] / tests / echo-server.c
blob3d312db4b2e2e0c3de0c27a23d5b3353e80bb6e4
1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*-
3 * echo-server.c --- Simple echo server for testing purposes.
5 */
7 /* TODO: IPv6 support, port to Winsock */
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <time.h>
12 #include <ctype.h>
13 #include <string.h>
15 #ifdef _WIN32
16 #include <windows.h>
17 #include <Winsock2.h>
18 #include <Ws2tcpip.h>
19 #else
20 #include <unistd.h>
21 #include <errno.h>
22 #include <sys/types.h>
23 #include <sys/socket.h>
24 #include <netinet/in.h>
25 #include <arpa/inet.h>
26 #include <sys/select.h>
27 #endif
29 #define DEFAULT_PORT 7
30 #define BACKLOG 10
31 #define MAXCONS FD_SETSIZE
33 static int
34 sendallto(int s, char *buf, int len, struct sockaddr *to, socklen_t tolen)
36 int sent = 0;
37 int left = len;
39 while (sent < len) {
40 int n = sendto(s, buf+sent, left, 0, to, tolen);
41 if (n == -1) { return -1; }
42 sent += n;
43 left -= n;
46 return 0;
49 static char time_str[9];
51 static const char* timestamp()
53 time_t now = time(NULL);
54 struct tm *tms = localtime(&now);
55 strftime(time_str, (sizeof time_str)-1, "%T", tms);
56 return time_str;
59 int main(int argc, char *argv[])
61 int fds[MAXCONS];
62 struct sockaddr_in addrs[MAXCONS];
63 int conns = 0;
64 int local_port, listenfd, dgramfd;
65 struct sockaddr_in local;
66 socklen_t sin_size = sizeof(struct sockaddr_in);
68 switch (argc) {
69 case 1: local_port = DEFAULT_PORT; break;
70 case 2: local_port = strtol(argv[1], NULL, 10); break;
71 default:
72 fprintf(stderr, "Usage: %s [port number]\n", argv[0]);
73 fprintf(stderr, "The default port is: %d.\n", DEFAULT_PORT);
74 exit(1);
77 if (local_port <= 0 || local_port > 65535) {
78 fprintf(stderr, "Error: invalid port number.\n");
79 exit(1);
82 printf("[%s] listening on port %d\n", timestamp(), local_port);
84 if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
85 perror("socket");
86 exit(1);
89 fds[conns++] = listenfd;
91 if ((dgramfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
92 perror("dgram socket");
93 exit(1);
96 fds[conns++] = dgramfd;
98 local.sin_family = AF_INET;
99 local.sin_port = htons(local_port);
100 local.sin_addr.s_addr = INADDR_ANY;
101 memset(local.sin_zero, 0, sizeof local.sin_zero);
103 if (bind(listenfd, (struct sockaddr *) &local, sin_size) == -1) {
104 perror("bind");
105 exit(1);
108 if (bind(dgramfd, (struct sockaddr *) &local, sin_size) == -1) {
109 perror("dgram bind");
110 exit(1);
113 if (listen(listenfd, BACKLOG) == -1) {
114 perror("listen");
115 exit(1);
118 for (;;) {
119 int fd, max_fd, i, j, n;
120 fd_set readfds;
121 char buf[4096];
123 FD_ZERO(&readfds);
124 for (i = 0, max_fd = -1; i < conns; i++) {
125 if (fds[i] > max_fd)
126 max_fd = fds[i];
127 FD_SET(fds[i], &readfds);
130 if (select(max_fd+1, &readfds, NULL, NULL, NULL) == -1) {
131 perror("select");
132 exit(1);
135 if (FD_ISSET(listenfd, &readfds)) {
136 fd = accept(listenfd, (struct sockaddr *) &addrs[conns], &sin_size);
138 if (fd == -1) {
139 perror("accept");
140 continue;
141 } else {
142 printf("[%s] accepted connection from %s (fd: %d)\n",
143 timestamp(), inet_ntoa(addrs[conns].sin_addr), fd);
144 fds[conns++] = fd;
148 for (i = 1; i < conns; i++) {
149 if (FD_ISSET(fds[i], &readfds)) {
150 sin_size = sizeof(struct sockaddr_in);
151 n = recvfrom(fds[i], buf, (sizeof buf)-1, 0,
152 (struct sockaddr *) &addrs[i], &sin_size);
153 if (n == -1) {
154 perror("recvfrom");
155 goto error;
158 // n == 0? huh hmm..
159 if (n == 0) goto error;
161 printf("[%s] got %d bytes from %s (%s) ", timestamp(),
162 n, inet_ntoa(addrs[i].sin_addr),
163 i == 1 ? "udp" : "tcp");
165 for (j = 0; j < n; j++) {
166 if (j % 75 == 0)
167 printf("\n ");
169 if (isprint(buf[j]))
170 putchar(buf[j]);
171 else
172 printf("[0x%x]", buf[j]);
174 //putchar(isprint(buf[j]) ? buf[j] : '?');
177 if (sendallto(fds[i], buf, n, (struct sockaddr *) &addrs[i],
178 sizeof(struct sockaddr_in)) == -1) {
179 perror("\nsendto");
180 goto error;
183 printf("\n (echoed)\n");
184 continue;
186 error:
187 if (i == 1) continue;
188 printf("[%s] removing fd %d from set\n", timestamp(), fds[i]);
189 close(fds[i]);
190 for (j = i+1; j < conns; j++) {
191 fds[j-1] = fds[j];
192 addrs[j-1] = addrs[j];
194 conns--;
199 return 0;