2 Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com>
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 #include <sys/select.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
36 static int usage(const string &cmdname)
38 cout << "Usage: " << cmdname << " <port>" << endl
39 << "Read continuous stream of data from standard input and multiplex it" << endl
40 << "to all the connected TCP clients." << endl << endl
41 << "<port> is the TCP port number to listen on" << endl << endl
42 << "Example: tail -F tracelog.bin | " << cmdname << " 7777" << endl << endl
43 << "Copyright (C) 2015 Paul Fertser <fercerpav@gmail.com>, distributed under GPLv3+ conditions" << endl;
47 static int report_error(const string &description)
49 cout << description << strerror(errno) << endl;
53 static void close_socket(int fd)
55 shutdown(fd, SHUT_RDWR);
59 int main(int argc, char *argv[])
62 return usage(argv[0]);
64 struct sigaction sa = { { SIG_IGN } };
65 if (sigaction(SIGPIPE, &sa, NULL) == -1)
66 return report_error("sigaction() error: ");
68 auto sock = socket(AF_INET6, SOCK_STREAM, 0);
70 return report_error("Can not create socket: ");
73 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &so_reuseaddr, sizeof so_reuseaddr) == -1)
74 return report_error("Can not set SO_REUSEADDR: ");
76 struct sockaddr_in6 saddr = {};
77 saddr.sin6_family = AF_INET6;
78 saddr.sin6_port = htons(stoi(argv[1]));
79 saddr.sin6_addr = in6addr_any;
81 if (bind(sock, reinterpret_cast<sockaddr*>(&saddr), sizeof(saddr)) == -1)
82 return report_error("Can not bind socket: ");
84 if (listen(sock, 128) == -1)
85 return report_error("Can not enable listening: ");
93 FD_SET(STDIN_FILENO, &rfds);
96 if (select(sock + 1, &rfds, NULL, NULL, NULL) == -1)
97 return report_error("select() error: ");
99 if (FD_ISSET(sock, &rfds)) {
100 auto newclient = accept(sock, NULL, NULL);
102 return report_error("accept() error: ");
104 fcntl(newclient, F_SETFL, O_NONBLOCK);
105 clients.push_back(newclient);
108 if (FD_ISSET(STDIN_FILENO, &rfds)) {
111 n = read(STDIN_FILENO, b, sizeof(b));
113 return report_error("read() error: ");
115 break; /* EOF received */
117 clients.erase(remove_if(clients.begin(), clients.end(), [&](int fd) {
118 if (write(fd, b, n) != n) {
127 for_each(clients.begin(), clients.end(), close_socket);