1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil -*-
3 * echo-server.c --- Simple echo server for testing purposes.
7 /* TODO: IPv6 support, port to Winsock */
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>
29 #define DEFAULT_PORT 7
31 #define MAXCONS FD_SETSIZE
34 sendallto(int s
, char *buf
, int len
, struct sockaddr
*to
, socklen_t tolen
)
40 int n
= sendto(s
, buf
+sent
, left
, 0, to
, tolen
);
41 if (n
== -1) { return -1; }
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
);
59 int main(int argc
, char *argv
[])
62 struct sockaddr_in addrs
[MAXCONS
];
64 int local_port
, listenfd
, dgramfd
;
65 struct sockaddr_in local
;
66 socklen_t sin_size
= sizeof(struct sockaddr_in
);
69 case 1: local_port
= DEFAULT_PORT
; break;
70 case 2: local_port
= strtol(argv
[1], NULL
, 10); break;
72 fprintf(stderr
, "Usage: %s [port number]\n", argv
[0]);
73 fprintf(stderr
, "The default port is: %d.\n", DEFAULT_PORT
);
77 if (local_port
<= 0 || local_port
> 65535) {
78 fprintf(stderr
, "Error: invalid port number.\n");
82 printf("[%s] listening on port %d\n", timestamp(), local_port
);
84 if ((listenfd
= socket(AF_INET
, SOCK_STREAM
, 0)) == -1) {
89 fds
[conns
++] = listenfd
;
91 if ((dgramfd
= socket(AF_INET
, SOCK_DGRAM
, 0)) == -1) {
92 perror("dgram socket");
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) {
108 if (bind(dgramfd
, (struct sockaddr
*) &local
, sin_size
) == -1) {
109 perror("dgram bind");
113 if (listen(listenfd
, BACKLOG
) == -1) {
119 int fd
, max_fd
, i
, j
, n
;
124 for (i
= 0, max_fd
= -1; i
< conns
; i
++) {
127 FD_SET(fds
[i
], &readfds
);
130 if (select(max_fd
+1, &readfds
, NULL
, NULL
, NULL
) == -1) {
135 if (FD_ISSET(listenfd
, &readfds
)) {
136 fd
= accept(listenfd
, (struct sockaddr
*) &addrs
[conns
], &sin_size
);
142 printf("[%s] accepted connection from %s (fd: %d)\n",
143 timestamp(), inet_ntoa(addrs
[conns
].sin_addr
), 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
);
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
++) {
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) {
183 printf("\n (echoed)\n");
187 if (i
== 1) continue;
188 printf("[%s] removing fd %d from set\n", timestamp(), fds
[i
]);
190 for (j
= i
+1; j
< conns
; j
++) {
192 addrs
[j
-1] = addrs
[j
];