1f41285cfSShuo Chen#include "Acceptor.h"
2f41285cfSShuo Chen#include "InetAddress.h"
3f41285cfSShuo Chen#include "TcpStream.h"
4f41285cfSShuo Chen
5f41285cfSShuo Chen#include <thread>
6f41285cfSShuo Chen
7f41285cfSShuo Chen#include <string.h>
8f41285cfSShuo Chen#include <unistd.h>
9f41285cfSShuo Chen
10f41285cfSShuo Chenint write_n(int fd, const void* buf, int length)
11f41285cfSShuo Chen{
12f41285cfSShuo Chen  int written = 0;
13f41285cfSShuo Chen  while (written < length)
14f41285cfSShuo Chen  {
15f41285cfSShuo Chen    int nw = ::write(fd, static_cast<const char*>(buf) + written, length - written);
16f41285cfSShuo Chen    if (nw > 0)
17f41285cfSShuo Chen    {
18f41285cfSShuo Chen      written += nw;
19f41285cfSShuo Chen    }
20f41285cfSShuo Chen    else if (nw == 0)
21f41285cfSShuo Chen    {
2228d3a254SShuo Chen      break;  // EOF
23f41285cfSShuo Chen    }
24f41285cfSShuo Chen    else if (errno != EINTR)
25f41285cfSShuo Chen    {
26f41285cfSShuo Chen      perror("write");
27f41285cfSShuo Chen      break;
28f41285cfSShuo Chen    }
29f41285cfSShuo Chen  }
30f41285cfSShuo Chen  return written;
31f41285cfSShuo Chen}
32f41285cfSShuo Chen
33f41285cfSShuo Chenvoid run(TcpStreamPtr stream)
34f41285cfSShuo Chen{
3528d3a254SShuo Chen  // Caution: a bad example for closing connection
36f41285cfSShuo Chen  std::thread thr([&stream] () {
37f41285cfSShuo Chen    char buf[8192];
38f41285cfSShuo Chen    int nr = 0;
39f41285cfSShuo Chen    while ( (nr = stream->receiveSome(buf, sizeof(buf))) > 0)
40f41285cfSShuo Chen    {
41f41285cfSShuo Chen      int nw = write_n(STDOUT_FILENO, buf, nr);
42f41285cfSShuo Chen      if (nw < nr)
43f41285cfSShuo Chen      {
44f41285cfSShuo Chen        break;
45f41285cfSShuo Chen      }
46f41285cfSShuo Chen    }
4728d3a254SShuo Chen    ::exit(0);  // should somehow notify main thread instead
48f41285cfSShuo Chen  });
49f41285cfSShuo Chen
50f41285cfSShuo Chen  char buf[8192];
51f41285cfSShuo Chen  int nr = 0;
52f41285cfSShuo Chen  while ( (nr = ::read(STDIN_FILENO, buf, sizeof(buf))) > 0)
53f41285cfSShuo Chen  {
54f41285cfSShuo Chen    int nw = stream->sendAll(buf, nr);
55f41285cfSShuo Chen    if (nw < nr)
56f41285cfSShuo Chen    {
57f41285cfSShuo Chen      break;
58f41285cfSShuo Chen    }
59f41285cfSShuo Chen  }
6028d3a254SShuo Chen  stream->shutdownWrite();
6128d3a254SShuo Chen  thr.join();
62f41285cfSShuo Chen}
63f41285cfSShuo Chen
64f41285cfSShuo Chenint main(int argc, const char* argv[])
65f41285cfSShuo Chen{
66f41285cfSShuo Chen  if (argc < 3)
67f41285cfSShuo Chen  {
68f41285cfSShuo Chen    printf("Usage:\n  %s hostname port\n  %s -l port\n", argv[0], argv[0]);
69f41285cfSShuo Chen    return 0;
70f41285cfSShuo Chen  }
71f41285cfSShuo Chen
72f41285cfSShuo Chen  int port = atoi(argv[2]);
73f41285cfSShuo Chen  if (strcmp(argv[1], "-l") == 0)
74f41285cfSShuo Chen  {
752de24e35SShuo Chen    std::unique_ptr<Acceptor> acceptor(new Acceptor(InetAddress(port)));
762de24e35SShuo Chen    TcpStreamPtr stream(acceptor->accept());
77f41285cfSShuo Chen    if (stream)
78f41285cfSShuo Chen    {
792de24e35SShuo Chen      acceptor.reset();  // stop listening
80f41285cfSShuo Chen      run(std::move(stream));
81f41285cfSShuo Chen    }
82f41285cfSShuo Chen    else
83f41285cfSShuo Chen    {
84f41285cfSShuo Chen      perror("accept");
85f41285cfSShuo Chen    }
86f41285cfSShuo Chen  }
87f41285cfSShuo Chen  else
88f41285cfSShuo Chen  {
8924ca08a8SShuo Chen    InetAddress addr;
90f41285cfSShuo Chen    const char* hostname = argv[1];
9124ca08a8SShuo Chen    if (InetAddress::resolve(hostname, port, &addr))
92f41285cfSShuo Chen    {
93f41285cfSShuo Chen      TcpStreamPtr stream(TcpStream::connect(addr));
94f41285cfSShuo Chen      if (stream)
95f41285cfSShuo Chen      {
96f41285cfSShuo Chen        run(std::move(stream));
97f41285cfSShuo Chen      }
98f41285cfSShuo Chen      else
99f41285cfSShuo Chen      {
100f41285cfSShuo Chen        printf("Unable to connect %s\n", addr.toIpPort().c_str());
101f41285cfSShuo Chen        perror("");
102f41285cfSShuo Chen      }
103f41285cfSShuo Chen    }
104f41285cfSShuo Chen    else
105f41285cfSShuo Chen    {
106f41285cfSShuo Chen      printf("Unable to resolve %s\n", hostname);
107f41285cfSShuo Chen    }
108f41285cfSShuo Chen  }
109f41285cfSShuo Chen}
110