1// Copyright 2009 the V8 project authors. All rights reserved.
2
3#include "v8.h"
4#include "platform.h"
5#include "cctest.h"
6
7
8using namespace ::v8::internal;
9
10
11class SocketListenerThread : public Thread {
12 public:
13  explicit SocketListenerThread(int port, int data_size)
14      : port_(port), data_size_(data_size), server_(NULL), client_(NULL),
15        listening_(OS::CreateSemaphore(0)) {
16    data_ = new char[data_size_];
17  }
18  ~SocketListenerThread() {
19    // Close both sockets.
20    delete client_;
21    delete server_;
22    delete listening_;
23    delete[] data_;
24  }
25
26  void Run();
27  void WaitForListening() { listening_->Wait(); }
28  char* data() { return data_; }
29
30 private:
31  int port_;
32  char* data_;
33  int data_size_;
34  Socket* server_;  // Server socket used for bind/accept.
35  Socket* client_;  // Single client connection used by the test.
36  Semaphore* listening_;  // Signalled when the server socket is in listen mode.
37};
38
39
40void SocketListenerThread::Run() {
41  bool ok;
42
43  // Create the server socket and bind it to the requested port.
44  server_ = OS::CreateSocket();
45  server_->SetReuseAddress(true);
46  CHECK(server_ != NULL);
47  ok = server_->Bind(port_);
48  CHECK(ok);
49
50  // Listen for new connections.
51  ok = server_->Listen(1);
52  CHECK(ok);
53  listening_->Signal();
54
55  // Accept a connection.
56  client_ = server_->Accept();
57  CHECK(client_ != NULL);
58
59  // Read the expected niumber of bytes of data.
60  int bytes_read = 0;
61  while (bytes_read < data_size_) {
62    bytes_read += client_->Receive(data_ + bytes_read, data_size_ - bytes_read);
63  }
64}
65
66
67static bool SendAll(Socket* socket, const char* data, int len) {
68  int sent_len = 0;
69  while (sent_len < len) {
70    int status = socket->Send(data, len);
71    if (status <= 0) {
72      return false;
73    }
74    sent_len += status;
75  }
76  return true;
77}
78
79
80static void SendAndReceive(int port, char *data, int len) {
81  static const char* kLocalhost = "localhost";
82
83  bool ok;
84
85  // Make a string with the port number.
86  const int kPortBuferLen = 6;
87  char port_str[kPortBuferLen];
88  OS::SNPrintF(Vector<char>(port_str, kPortBuferLen), "%d", port);
89
90  // Create a socket listener.
91  SocketListenerThread* listener = new SocketListenerThread(port, len);
92  listener->Start();
93  listener->WaitForListening();
94
95  // Connect and write some data.
96  Socket* client = OS::CreateSocket();
97  CHECK(client != NULL);
98  ok = client->Connect(kLocalhost, port_str);
99  CHECK(ok);
100
101  // Send all the data.
102  ok = SendAll(client, data, len);
103  CHECK(ok);
104
105  // Wait until data is received.
106  listener->Join();
107
108  // Check that data received is the same as data send.
109  for (int i = 0; i < len; i++) {
110    CHECK(data[i] == listener->data()[i]);
111  }
112
113  // Close the client before the listener to avoid TIME_WAIT issues.
114  client->Shutdown();
115  delete client;
116  delete listener;
117}
118
119
120TEST(Socket) {
121  // Make sure this port is not used by other tests to allow tests to run in
122  // parallel.
123  static const int kPort = 5859;
124
125  bool ok;
126
127  // Initialize socket support.
128  ok = Socket::Setup();
129  CHECK(ok);
130
131  // Send and receive some data.
132  static const int kBufferSizeSmall = 20;
133  char small_data[kBufferSizeSmall + 1] = "1234567890abcdefghij";
134  SendAndReceive(kPort, small_data, kBufferSizeSmall);
135
136  // Send and receive some more data.
137  static const int kBufferSizeMedium = 10000;
138  char* medium_data = new char[kBufferSizeMedium];
139  for (int i = 0; i < kBufferSizeMedium; i++) {
140    medium_data[i] = i % 256;
141  }
142  SendAndReceive(kPort, medium_data, kBufferSizeMedium);
143  delete[] medium_data;
144
145  // Send and receive even more data.
146  static const int kBufferSizeLarge = 1000000;
147  char* large_data = new char[kBufferSizeLarge];
148  for (int i = 0; i < kBufferSizeLarge; i++) {
149    large_data[i] = i % 256;
150  }
151  SendAndReceive(kPort, large_data, kBufferSizeLarge);
152  delete[] large_data;
153}
154
155
156TEST(HToNNToH) {
157  uint16_t x = 1234;
158  CHECK_EQ(x, Socket::NToH(Socket::HToN(x)));
159
160  uint32_t y = 12345678;
161  CHECK(y == Socket::NToH(Socket::HToN(y)));
162}
163