1// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6//     * Redistributions of source code must retain the above copyright
7//       notice, this list of conditions and the following disclaimer.
8//     * Redistributions in binary form must reproduce the above
9//       copyright notice, this list of conditions and the following
10//       disclaimer in the documentation and/or other materials provided
11//       with the distribution.
12//     * Neither the name of Google Inc. nor the names of its
13//       contributors may be used to endorse or promote products derived
14//       from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include "v8.h"
29#include "platform.h"
30#include "cctest.h"
31
32
33using namespace ::v8::internal;
34
35
36class SocketListenerThread : public Thread {
37 public:
38  SocketListenerThread(int port, int data_size)
39      : Thread("SocketListenerThread"),
40        port_(port),
41        data_size_(data_size),
42        server_(NULL),
43        client_(NULL),
44        listening_(OS::CreateSemaphore(0)) {
45    data_ = new char[data_size_];
46  }
47  ~SocketListenerThread() {
48    // Close both sockets.
49    delete client_;
50    delete server_;
51    delete listening_;
52    delete[] data_;
53  }
54
55  void Run();
56  void WaitForListening() { listening_->Wait(); }
57  char* data() { return data_; }
58
59 private:
60  int port_;
61  char* data_;
62  int data_size_;
63  Socket* server_;  // Server socket used for bind/accept.
64  Socket* client_;  // Single client connection used by the test.
65  Semaphore* listening_;  // Signalled when the server socket is in listen mode.
66};
67
68
69void SocketListenerThread::Run() {
70  bool ok;
71
72  // Create the server socket and bind it to the requested port.
73  server_ = OS::CreateSocket();
74  server_->SetReuseAddress(true);
75  CHECK(server_ != NULL);
76  ok = server_->Bind(port_);
77  CHECK(ok);
78
79  // Listen for new connections.
80  ok = server_->Listen(1);
81  CHECK(ok);
82  listening_->Signal();
83
84  // Accept a connection.
85  client_ = server_->Accept();
86  CHECK(client_ != NULL);
87
88  // Read the expected niumber of bytes of data.
89  int bytes_read = 0;
90  while (bytes_read < data_size_) {
91    bytes_read += client_->Receive(data_ + bytes_read, data_size_ - bytes_read);
92  }
93}
94
95
96static bool SendAll(Socket* socket, const char* data, int len) {
97  int sent_len = 0;
98  while (sent_len < len) {
99    int status = socket->Send(data, len);
100    if (status <= 0) {
101      return false;
102    }
103    sent_len += status;
104  }
105  return true;
106}
107
108
109static void SendAndReceive(int port, char *data, int len) {
110  static const char* kLocalhost = "localhost";
111
112  bool ok;
113
114  // Make a string with the port number.
115  const int kPortBuferLen = 6;
116  char port_str[kPortBuferLen];
117  OS::SNPrintF(Vector<char>(port_str, kPortBuferLen), "%d", port);
118
119  // Create a socket listener.
120  SocketListenerThread* listener = new SocketListenerThread(port, len);
121  listener->Start();
122  listener->WaitForListening();
123
124  // Connect and write some data.
125  Socket* client = OS::CreateSocket();
126  CHECK(client != NULL);
127  ok = client->Connect(kLocalhost, port_str);
128  CHECK(ok);
129
130  // Send all the data.
131  ok = SendAll(client, data, len);
132  CHECK(ok);
133
134  // Wait until data is received.
135  listener->Join();
136
137  // Check that data received is the same as data send.
138  for (int i = 0; i < len; i++) {
139    CHECK(data[i] == listener->data()[i]);
140  }
141
142  // Close the client before the listener to avoid TIME_WAIT issues.
143  client->Shutdown();
144  delete client;
145  delete listener;
146}
147
148
149TEST(Socket) {
150  // Make sure this port is not used by other tests to allow tests to run in
151  // parallel.
152  static const int kPort = 5859 + FlagDependentPortOffset();
153
154  bool ok;
155
156  // Initialize socket support.
157  ok = Socket::SetUp();
158  CHECK(ok);
159
160  // Send and receive some data.
161  static const int kBufferSizeSmall = 20;
162  char small_data[kBufferSizeSmall + 1] = "1234567890abcdefghij";
163  SendAndReceive(kPort, small_data, kBufferSizeSmall);
164
165  // Send and receive some more data.
166  static const int kBufferSizeMedium = 10000;
167  char* medium_data = new char[kBufferSizeMedium];
168  for (int i = 0; i < kBufferSizeMedium; i++) {
169    medium_data[i] = i % 256;
170  }
171  SendAndReceive(kPort, medium_data, kBufferSizeMedium);
172  delete[] medium_data;
173
174  // Send and receive even more data.
175  static const int kBufferSizeLarge = 1000000;
176  char* large_data = new char[kBufferSizeLarge];
177  for (int i = 0; i < kBufferSizeLarge; i++) {
178    large_data[i] = i % 256;
179  }
180  SendAndReceive(kPort, large_data, kBufferSizeLarge);
181  delete[] large_data;
182}
183
184
185TEST(HToNNToH) {
186  uint16_t x = 1234;
187  CHECK_EQ(x, Socket::NToH(Socket::HToN(x)));
188
189  uint32_t y = 12345678;
190  CHECK(y == Socket::NToH(Socket::HToN(y)));
191}
192