• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #include "inspector_socket_server.h"
2 
3 #include "node.h"
4 #include "node_options.h"
5 #include "util-inl.h"
6 #include "gtest/gtest.h"
7 
8 #include <algorithm>
9 #include <memory>
10 #include <sstream>
11 
12 static uv_loop_t loop;
13 
14 static const char HOST[] = "127.0.0.1";
15 
16 static const char CLIENT_CLOSE_FRAME[] = "\x88\x80\x2D\x0E\x1E\xFA";
17 static const char SERVER_CLOSE_FRAME[] = "\x88\x00";
18 
19 static const char MAIN_TARGET_ID[] = "main-target";
20 
21 static const char WS_HANDSHAKE_RESPONSE[] =
22     "HTTP/1.1 101 Switching Protocols\r\n"
23     "Upgrade: websocket\r\n"
24     "Connection: Upgrade\r\n"
25     "Sec-WebSocket-Accept: Dt87H1OULVZnSJo/KgMUYI7xPCg=\r\n\r\n";
26 
27 #define SPIN_WHILE(condition)                                                  \
28   {                                                                            \
29     Timeout timeout(&loop);                                                    \
30     while ((condition) && !timeout.timed_out) {                                \
31       uv_run(&loop, UV_RUN_ONCE);                                              \
32     }                                                                          \
33     ASSERT_FALSE((condition));                                                 \
34   }
35 
36 namespace {
37 
38 using InspectorSocketServer = node::inspector::InspectorSocketServer;
39 using SocketServerDelegate = node::inspector::SocketServerDelegate;
40 
41 class Timeout {
42  public:
Timeout(uv_loop_t * loop)43   explicit Timeout(uv_loop_t* loop) : timed_out(false), done_(false) {
44     uv_timer_init(loop, &timer_);
45     uv_timer_start(&timer_, Timeout::set_flag, 5000, 0);
46     uv_unref(reinterpret_cast<uv_handle_t*>(&timer_));
47   }
48 
~Timeout()49   ~Timeout() {
50     uv_timer_stop(&timer_);
51     uv_close(reinterpret_cast<uv_handle_t*>(&timer_), mark_done);
52     while (!done_) {
53       uv_run(&loop, UV_RUN_NOWAIT);
54     }
55   }
56   bool timed_out;
57 
58  private:
set_flag(uv_timer_t * timer)59   static void set_flag(uv_timer_t* timer) {
60     Timeout* t = node::ContainerOf(&Timeout::timer_, timer);
61     t->timed_out = true;
62   }
63 
mark_done(uv_handle_t * timer)64   static void mark_done(uv_handle_t* timer) {
65     Timeout* t = node::ContainerOf(&Timeout::timer_,
66         reinterpret_cast<uv_timer_t*>(timer));
67     t->done_ = true;
68   }
69 
70   bool done_;
71   uv_timer_t timer_;
72 };
73 
74 class InspectorSocketServerTest : public ::testing::Test {
75  protected:
SetUp()76   void SetUp() override {
77     EXPECT_EQ(0, uv_loop_init(&loop));
78   }
79 
TearDown()80   void TearDown() override {
81     const int err = uv_loop_close(&loop);
82     if (err != 0) {
83       uv_print_all_handles(&loop, stderr);
84     }
85     EXPECT_EQ(0, err);
86   }
87 };
88 
89 class SocketWrapper {
90  public:
SocketWrapper(uv_loop_t * loop)91   explicit SocketWrapper(uv_loop_t* loop) : closed_(false),
92                                             eof_(false),
93                                             loop_(loop),
94                                             socket_(uv_tcp_t()),
95                                             connected_(false),
96                                             sending_(false) { }
97 
Connect(const std::string & host,int port,bool v6=false)98   void Connect(const std::string& host, int port, bool v6 = false) {
99     closed_ = false;
100     connection_failed_ = false;
101     connected_ = false;
102     eof_ = false;
103     contents_.clear();
104     uv_tcp_init(loop_, &socket_);
105     union {sockaddr generic; sockaddr_in v4; sockaddr_in6 v6;} addr;
106     int err = 0;
107     if (v6) {
108       err = uv_ip6_addr(host.c_str(), port, &addr.v6);
109     } else {
110       err = uv_ip4_addr(host.c_str(), port, &addr.v4);
111     }
112     CHECK_EQ(0, err);
113     err = uv_tcp_connect(&connect_, &socket_, &addr.generic, Connected_);
114     CHECK_EQ(0, err);
115     SPIN_WHILE(!connected_)
116     uv_read_start(reinterpret_cast<uv_stream_t*>(&socket_), AllocCallback,
117                   ReadCallback);
118   }
119 
ExpectFailureToConnect(const std::string & host,int port)120   void ExpectFailureToConnect(const std::string& host, int port) {
121     connected_ = false;
122     connection_failed_ = false;
123     closed_ = false;
124     eof_ = false;
125     contents_.clear();
126     uv_tcp_init(loop_, &socket_);
127     sockaddr_in addr;
128     int err = uv_ip4_addr(host.c_str(), port, &addr);
129     CHECK_EQ(0, err);
130     err = uv_tcp_connect(&connect_, &socket_,
131                          reinterpret_cast<const sockaddr*>(&addr),
132                          ConnectionMustFail_);
133     CHECK_EQ(0, err);
134     SPIN_WHILE(!connection_failed_)
135     uv_read_start(reinterpret_cast<uv_stream_t*>(&socket_), AllocCallback,
136                   ReadCallback);
137   }
138 
Close()139   void Close() {
140     uv_close(reinterpret_cast<uv_handle_t*>(&socket_), ClosedCallback);
141     SPIN_WHILE(!closed_);
142   }
143 
Expect(const std::string & expects)144   void Expect(const std::string& expects) {
145     SPIN_WHILE(contents_.size() < expects.length());
146     ASSERT_STREQ(expects.c_str(),
147                  std::string(contents_.data(), expects.length()).c_str());
148     contents_.erase(contents_.begin(), contents_.begin() + expects.length());
149   }
150 
ExpectEOF()151   void ExpectEOF() {
152     SPIN_WHILE(!eof_);
153     Close();
154   }
155 
TestHttpRequest(const std::string & path,const std::string & expected_reply)156   void TestHttpRequest(const std::string& path,
157                        const std::string& expected_reply) {
158     std::ostringstream expectations;
159     expectations << "HTTP/1.0 200 OK\r\n"
160                     "Content-Type: application/json; charset=UTF-8\r\n"
161                     "Cache-Control: no-cache\r\n"
162                     "Content-Length: ";
163     expectations << expected_reply.length() + 2;
164     expectations << "\r\n\r\n" << expected_reply << "\n\n";
165     Write("GET " + path + " HTTP/1.1\r\n"
166           "Host: localhost:9229\r\n\r\n");
167     Expect(expectations.str());
168   }
169 
Write(const std::string & data)170   void Write(const std::string& data) {
171     ASSERT_FALSE(sending_);
172     uv_buf_t buf[1];
173     buf[0].base = const_cast<char*>(data.data());
174     buf[0].len = data.length();
175     sending_ = true;
176     int err = uv_write(&write_, reinterpret_cast<uv_stream_t*>(&socket_),
177                        buf, 1, WriteDone_);
178     CHECK_EQ(err, 0);
179     SPIN_WHILE(sending_);
180   }
181 
182  private:
AllocCallback(uv_handle_t *,size_t size,uv_buf_t * buf)183   static void AllocCallback(uv_handle_t*, size_t size, uv_buf_t* buf) {
184     *buf = uv_buf_init(new char[size], size);
185   }
186 
ClosedCallback(uv_handle_t * handle)187   static void ClosedCallback(uv_handle_t* handle) {
188     SocketWrapper* wrapper =
189         node::ContainerOf(&SocketWrapper::socket_,
190                           reinterpret_cast<uv_tcp_t*>(handle));
191     ASSERT_FALSE(wrapper->closed_);
192     wrapper->closed_ = true;
193   }
194 
Connected_(uv_connect_t * connect,int status)195   static void Connected_(uv_connect_t* connect, int status) {
196     EXPECT_EQ(0, status) << "Unable to connect: " << uv_strerror(status);
197     SocketWrapper* wrapper =
198         node::ContainerOf(&SocketWrapper::connect_, connect);
199     wrapper->connected_ = true;
200   }
201 
ConnectionMustFail_(uv_connect_t * connect,int status)202   static void ConnectionMustFail_(uv_connect_t* connect, int status) {
203     EXPECT_EQ(UV_ECONNREFUSED, status);
204     SocketWrapper* wrapper =
205         node::ContainerOf(&SocketWrapper::connect_, connect);
206     wrapper->connection_failed_ = true;
207   }
208 
ReadCallback(uv_stream_t * stream,ssize_t read,const uv_buf_t * buf)209   static void ReadCallback(uv_stream_t* stream, ssize_t read,
210                            const uv_buf_t* buf) {
211     SocketWrapper* wrapper =
212         node::ContainerOf(&SocketWrapper::socket_,
213                           reinterpret_cast<uv_tcp_t*>(stream));
214     if (read == UV_EOF) {
215       wrapper->eof_ = true;
216     } else {
217       wrapper->contents_.insert(wrapper->contents_.end(), buf->base,
218                                 buf->base + read);
219     }
220     delete[] buf->base;
221   }
WriteDone_(uv_write_t * req,int err)222   static void WriteDone_(uv_write_t* req, int err) {
223     CHECK_EQ(0, err);
224     SocketWrapper* wrapper =
225         node::ContainerOf(&SocketWrapper::write_, req);
226     ASSERT_TRUE(wrapper->sending_);
227     wrapper->sending_ = false;
228   }
IsConnected()229   bool IsConnected() { return connected_; }
230 
231   bool closed_;
232   bool eof_;
233   uv_loop_t* loop_;
234   uv_tcp_t socket_;
235   uv_connect_t connect_;
236   uv_write_t write_;
237   bool connected_;
238   bool connection_failed_;
239   bool sending_;
240   std::vector<char> contents_;
241 };
242 
243 class ServerHolder {
244  public:
ServerHolder(bool has_targets,uv_loop_t * loop,int port)245   ServerHolder(bool has_targets, uv_loop_t* loop, int port)
246                : ServerHolder(has_targets, loop, HOST, port, nullptr) { }
247 
248   ServerHolder(bool has_targets, uv_loop_t* loop,
249                const std::string& host, int port, FILE* out);
250 
operator ->()251   InspectorSocketServer* operator->() {
252     return server_.get();
253   }
254 
port()255   int port() {
256     return server_->Port();
257   }
258 
done()259   bool done() {
260     return server_->done();
261   }
262 
Disconnected()263   void Disconnected() {
264     disconnected++;
265   }
266 
Done()267   void Done() {
268     delegate_done = true;
269   }
270 
Connected(int id)271   void Connected(int id) {
272     buffer_.clear();
273     session_id_ = id;
274     connected++;
275   }
276 
Received(const std::string & message)277   void Received(const std::string& message) {
278     buffer_.insert(buffer_.end(), message.begin(), message.end());
279   }
280 
Write(const std::string & message)281   void Write(const std::string& message) {
282     server_->Send(session_id_, message);
283   }
284 
Expect(const std::string & expects)285   void Expect(const std::string& expects) {
286     SPIN_WHILE(buffer_.size() < expects.length());
287     ASSERT_STREQ(std::string(buffer_.data(), expects.length()).c_str(),
288                  expects.c_str());
289     buffer_.erase(buffer_.begin(), buffer_.begin() + expects.length());
290   }
291 
292   int connected = 0;
293   int disconnected = 0;
294   bool delegate_done = false;
295 
296  private:
297   std::unique_ptr<InspectorSocketServer> server_;
298   std::vector<char> buffer_;
299   int session_id_;
300 };
301 
302 class TestSocketServerDelegate : public SocketServerDelegate {
303  public:
TestSocketServerDelegate(ServerHolder * server,const std::vector<std::string> & target_ids)304   explicit TestSocketServerDelegate(ServerHolder* server,
305                                     const std::vector<std::string>& target_ids)
306       : harness_(server),
307         targets_(target_ids),
308         server_(nullptr),
309         session_id_(0) {}
310 
~TestSocketServerDelegate()311   ~TestSocketServerDelegate() override {
312     harness_->Done();
313   }
314 
AssignServer(InspectorSocketServer * server)315   void AssignServer(InspectorSocketServer* server) override {
316     server_ = server;
317   }
318 
StartSession(int session_id,const std::string & target_id)319   void StartSession(int session_id, const std::string& target_id) override {
320     session_id_ = session_id;
321     CHECK_NE(targets_.end(),
322              std::find(targets_.begin(), targets_.end(), target_id));
323     harness_->Connected(session_id_);
324   }
325 
MessageReceived(int session_id,const std::string & message)326   void MessageReceived(int session_id, const std::string& message) override {
327     CHECK_EQ(session_id_, session_id);
328     harness_->Received(message);
329   }
330 
EndSession(int session_id)331   void EndSession(int session_id) override {
332     CHECK_EQ(session_id_, session_id);
333     harness_->Disconnected();
334   }
335 
GetTargetIds()336   std::vector<std::string> GetTargetIds() override {
337     return targets_;
338   }
339 
GetTargetTitle(const std::string & id)340   std::string GetTargetTitle(const std::string& id) override {
341     return id + " Target Title";
342   }
343 
GetTargetUrl(const std::string & id)344   std::string GetTargetUrl(const std::string& id) override {
345     return "file://" + id + "/script.js";
346   }
347 
348  private:
349   ServerHolder* harness_;
350   const std::vector<std::string> targets_;
351   InspectorSocketServer* server_;
352   int session_id_;
353 };
354 
ServerHolder(bool has_targets,uv_loop_t * loop,const std::string & host,int port,FILE * out)355 ServerHolder::ServerHolder(bool has_targets, uv_loop_t* loop,
356                            const std::string& host, int port, FILE* out) {
357   session_id_ = 0;
358   std::vector<std::string> targets;
359   if (has_targets)
360     targets = { MAIN_TARGET_ID };
361   std::unique_ptr<TestSocketServerDelegate> delegate(
362       new TestSocketServerDelegate(this, targets));
363   node::InspectPublishUid inspect_publish_uid;
364   inspect_publish_uid.console = true;
365   inspect_publish_uid.http = true;
366   server_ = std::make_unique<InspectorSocketServer>(
367       std::move(delegate), loop, host, port, inspect_publish_uid, out);
368 }
369 
TestHttpRequest(int port,const std::string & path,const std::string & expected_body)370 static void TestHttpRequest(int port, const std::string& path,
371                             const std::string& expected_body) {
372   SocketWrapper socket(&loop);
373   socket.Connect(HOST, port);
374   socket.TestHttpRequest(path, expected_body);
375   socket.Close();
376 }
377 
WsHandshakeRequest(const std::string & target_id)378 static const std::string WsHandshakeRequest(const std::string& target_id) {
379   return "GET /" + target_id + " HTTP/1.1\r\n"
380          "Host: localhost:9229\r\n"
381          "Upgrade: websocket\r\n"
382          "Connection: Upgrade\r\n"
383          "Sec-WebSocket-Key: aaa==\r\n"
384          "Sec-WebSocket-Version: 13\r\n\r\n";
385 }
386 }  // anonymous namespace
387 
388 
TEST_F(InspectorSocketServerTest,InspectorSessions)389 TEST_F(InspectorSocketServerTest, InspectorSessions) {
390   ServerHolder server(true, &loop, 0);
391   ASSERT_TRUE(server->Start());
392 
393   SocketWrapper well_behaved_socket(&loop);
394   // Regular connection
395   well_behaved_socket.Connect(HOST, server.port());
396   well_behaved_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
397   well_behaved_socket.Expect(WS_HANDSHAKE_RESPONSE);
398 
399   EXPECT_EQ(1, server.connected);
400 
401   well_behaved_socket.Write("\x81\x84\x7F\xC2\x66\x31\x4E\xF0\x55\x05");
402 
403   server.Expect("1234");
404   server.Write("5678");
405 
406   well_behaved_socket.Expect("\x81\x4" "5678");
407   well_behaved_socket.Write(CLIENT_CLOSE_FRAME);
408   well_behaved_socket.Expect(SERVER_CLOSE_FRAME);
409 
410   EXPECT_EQ(1, server.disconnected);
411 
412   well_behaved_socket.Close();
413 
414   // Bogus target - start session callback should not even be invoked
415   SocketWrapper bogus_target_socket(&loop);
416   bogus_target_socket.Connect(HOST, server.port());
417   bogus_target_socket.Write(WsHandshakeRequest("bogus_target"));
418   bogus_target_socket.Expect("HTTP/1.0 400 Bad Request");
419   bogus_target_socket.ExpectEOF();
420   EXPECT_EQ(1, server.connected);
421   EXPECT_EQ(1, server.disconnected);
422 
423   // Drop connection (no proper close frames)
424   SocketWrapper dropped_connection_socket(&loop);
425   dropped_connection_socket.Connect(HOST, server.port());
426   dropped_connection_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
427   dropped_connection_socket.Expect(WS_HANDSHAKE_RESPONSE);
428 
429   EXPECT_EQ(2, server.connected);
430 
431   server.Write("5678");
432   dropped_connection_socket.Expect("\x81\x4" "5678");
433 
434   dropped_connection_socket.Close();
435   SPIN_WHILE(server.disconnected < 2);
436 
437   // Reconnect regular connection
438   SocketWrapper stays_till_termination_socket(&loop);
439   stays_till_termination_socket.Connect(HOST, server.port());
440   stays_till_termination_socket.Write(WsHandshakeRequest(MAIN_TARGET_ID));
441   stays_till_termination_socket.Expect(WS_HANDSHAKE_RESPONSE);
442 
443   SPIN_WHILE(3 != server.connected);
444 
445   server.Write("5678");
446   stays_till_termination_socket.Expect("\x81\x4" "5678");
447 
448   stays_till_termination_socket
449       .Write("\x81\x84\x7F\xC2\x66\x31\x4E\xF0\x55\x05");
450   server.Expect("1234");
451 
452   server->Stop();
453   server->TerminateConnections();
454 
455   stays_till_termination_socket.Write(CLIENT_CLOSE_FRAME);
456   stays_till_termination_socket.Expect(SERVER_CLOSE_FRAME);
457 
458   SPIN_WHILE(3 != server.disconnected);
459   SPIN_WHILE(!server.done());
460   stays_till_termination_socket.ExpectEOF();
461 }
462 
TEST_F(InspectorSocketServerTest,ServerDoesNothing)463 TEST_F(InspectorSocketServerTest, ServerDoesNothing) {
464   ServerHolder server(true, &loop, 0);
465   ASSERT_TRUE(server->Start());
466   server->Stop();
467   server->TerminateConnections();
468   SPIN_WHILE(!server.done());
469   ASSERT_TRUE(server.delegate_done);
470   SPIN_WHILE(uv_loop_alive(&loop));
471 }
472 
TEST_F(InspectorSocketServerTest,ServerWithoutTargets)473 TEST_F(InspectorSocketServerTest, ServerWithoutTargets) {
474   ServerHolder server(false, &loop, 0);
475   ASSERT_TRUE(server->Start());
476   TestHttpRequest(server.port(), "/json/list", "[ ]");
477   TestHttpRequest(server.port(), "/json", "[ ]");
478 
479   // Declined connection
480   SocketWrapper socket(&loop);
481   socket.Connect(HOST, server.port());
482   socket.Write(WsHandshakeRequest("any target id"));
483   socket.Expect("HTTP/1.0 400 Bad Request");
484   socket.ExpectEOF();
485   server->Stop();
486   server->TerminateConnections();
487   SPIN_WHILE(!server.done());
488   SPIN_WHILE(uv_loop_alive(&loop));
489 }
490 
TEST_F(InspectorSocketServerTest,ServerCannotStart)491 TEST_F(InspectorSocketServerTest, ServerCannotStart) {
492   ServerHolder server1(false, &loop, 0);
493   ASSERT_TRUE(server1->Start());
494   ServerHolder server2(false, &loop, server1.port());
495   ASSERT_FALSE(server2->Start());
496   server1->Stop();
497   server1->TerminateConnections();
498   SPIN_WHILE(!server1.done());
499   ASSERT_TRUE(server1.delegate_done);
500   SPIN_WHILE(uv_loop_alive(&loop));
501 }
502 
TEST_F(InspectorSocketServerTest,StoppingServerDoesNotKillConnections)503 TEST_F(InspectorSocketServerTest, StoppingServerDoesNotKillConnections) {
504   ServerHolder server(false, &loop, 0);
505   ASSERT_TRUE(server->Start());
506   SocketWrapper socket1(&loop);
507   socket1.Connect(HOST, server.port());
508   socket1.TestHttpRequest("/json/list", "[ ]");
509   server->Stop();
510   socket1.TestHttpRequest("/json/list", "[ ]");
511   socket1.Close();
512   uv_run(&loop, UV_RUN_DEFAULT);
513   ASSERT_TRUE(server.delegate_done);
514 }
515 
TEST_F(InspectorSocketServerTest,ClosingConnectionReportsDone)516 TEST_F(InspectorSocketServerTest, ClosingConnectionReportsDone) {
517   ServerHolder server(false, &loop, 0);
518   ASSERT_TRUE(server->Start());
519   SocketWrapper socket1(&loop);
520   socket1.Connect(HOST, server.port());
521   socket1.TestHttpRequest("/json/list", "[ ]");
522   server->Stop();
523   socket1.TestHttpRequest("/json/list", "[ ]");
524   socket1.Close();
525   uv_run(&loop, UV_RUN_DEFAULT);
526   ASSERT_TRUE(server.delegate_done);
527 }
528 
TEST_F(InspectorSocketServerTest,ClosingSocketReportsDone)529 TEST_F(InspectorSocketServerTest, ClosingSocketReportsDone) {
530   ServerHolder server(true, &loop, 0);
531   ASSERT_TRUE(server->Start());
532   SocketWrapper socket1(&loop);
533   socket1.Connect(HOST, server.port());
534   socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
535   socket1.Expect(WS_HANDSHAKE_RESPONSE);
536   server->Stop();
537   ASSERT_FALSE(server.delegate_done);
538   socket1.Close();
539   SPIN_WHILE(!server.delegate_done);
540 }
541 
TEST_F(InspectorSocketServerTest,TerminatingSessionReportsDone)542 TEST_F(InspectorSocketServerTest, TerminatingSessionReportsDone) {
543   ServerHolder server(true, &loop, 0);
544   ASSERT_TRUE(server->Start());
545   SocketWrapper socket1(&loop);
546   socket1.Connect(HOST, server.port());
547   socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
548   socket1.Expect(WS_HANDSHAKE_RESPONSE);
549   server->Stop();
550   ASSERT_FALSE(server.delegate_done);
551   server->TerminateConnections();
552   socket1.Expect(SERVER_CLOSE_FRAME);
553   socket1.Write(CLIENT_CLOSE_FRAME);
554   socket1.ExpectEOF();
555   SPIN_WHILE(!server.delegate_done);
556 }
557 
TEST_F(InspectorSocketServerTest,FailsToBindToNodejsHost)558 TEST_F(InspectorSocketServerTest, FailsToBindToNodejsHost) {
559   ServerHolder server(true, &loop, "nodejs.org", 80, nullptr);
560   ASSERT_FALSE(server->Start());
561   SPIN_WHILE(uv_loop_alive(&loop));
562 }
563 
has_ipv6_address()564 bool has_ipv6_address() {
565   uv_interface_address_s* addresses = nullptr;
566   int address_count = 0;
567   int err = uv_interface_addresses(&addresses, &address_count);
568   if (err != 0) {
569     return false;
570   }
571   bool has_address = false;
572   for (int i = 0; i < address_count; i++) {
573     if (addresses[i].address.address6.sin6_family == AF_INET6) {
574       has_address = true;
575     }
576   }
577   uv_free_interface_addresses(addresses, address_count);
578   return has_address;
579 }
580 
TEST_F(InspectorSocketServerTest,BindsToIpV6)581 TEST_F(InspectorSocketServerTest, BindsToIpV6) {
582   if (!has_ipv6_address()) {
583     fprintf(stderr, "No IPv6 network detected\n");
584     return;
585   }
586   ServerHolder server(true, &loop, "::", 0, nullptr);
587   ASSERT_TRUE(server->Start());
588   SocketWrapper socket1(&loop);
589   socket1.Connect("::1", server.port(), true);
590   socket1.Write(WsHandshakeRequest(MAIN_TARGET_ID));
591   socket1.Expect(WS_HANDSHAKE_RESPONSE);
592   server->Stop();
593   ASSERT_FALSE(server.delegate_done);
594   socket1.Close();
595   SPIN_WHILE(!server.delegate_done);
596 }
597