--- /dev/null
+#include <msp/core/application.h>
+#include <msp/core/getopt.h>
+#include <msp/core/refptr.h>
+#include <msp/io/console.h>
+#include <msp/io/eventdispatcher.h>
+#include <msp/net/streamlistensocket.h>
+#include <msp/net/streamsocket.h>
+#include <msp/net/resolve.h>
+
+using namespace std;
+using namespace Msp;
+
+class NetCat: public RegisteredApplication<NetCat>
+{
+private:
+ bool ipv6;
+ bool listen;
+ Net::StreamListenSocket *server_sock;
+ Net::StreamSocket *sock;
+ IO::EventDispatcher event_disp;
+
+public:
+ NetCat(int, char **);
+
+private:
+ virtual void tick();
+ void net_data_available();
+ void console_data_available();
+};
+
+NetCat::NetCat(int argc, char **argv):
+ ipv6(false),
+ listen(false),
+ server_sock(0),
+ sock(0)
+{
+ GetOpt getopt;
+ getopt.add_option('6', "ipv6", ipv6, GetOpt::NO_ARG);
+ getopt.add_option('l', "listen", listen, GetOpt::NO_ARG);
+ getopt(argc, argv);
+
+ const vector<string> &args = getopt.get_args();
+ if(args.empty())
+ throw usage_error("host argument missing");
+
+ RefPtr<Net::SockAddr> addr = Net::resolve(args.front(), (ipv6 ? Net::INET6 : Net::INET));
+ if(!listen)
+ {
+ sock = new Net::StreamSocket(addr->get_family());
+ sock->connect(*addr);
+ event_disp.add(*sock);
+ sock->signal_data_available.connect(sigc::mem_fun(this, &NetCat::net_data_available));
+ }
+ else
+ {
+ server_sock = new Net::StreamListenSocket(addr->get_family());
+ server_sock->listen(*addr);
+ event_disp.add(*server_sock);
+ server_sock->signal_data_available.connect(sigc::mem_fun(this, &NetCat::net_data_available));
+ }
+
+ event_disp.add(IO::cin);
+ IO::cin.signal_data_available.connect(sigc::mem_fun(this, &NetCat::console_data_available));
+}
+
+void NetCat::tick()
+{
+ event_disp.tick();
+ if(server_sock && sock)
+ {
+ delete server_sock;
+ server_sock = 0;
+ }
+}
+
+void NetCat::net_data_available()
+{
+ if(server_sock)
+ {
+ sock = server_sock->accept();
+ event_disp.add(*sock);
+ sock->signal_data_available.connect(sigc::mem_fun(this, &NetCat::net_data_available));
+ }
+ else
+ {
+ char buf[1024];
+ unsigned len = sock->read(buf, sizeof(buf));
+ IO::cout.write(buf, len);
+ }
+}
+
+void NetCat::console_data_available()
+{
+ char buf[1024];
+ unsigned len = IO::cin.read(buf, sizeof(buf));
+ if(sock)
+ sock->write(buf, len);
+}