1 | #include "server.h" |
2 | #include "message.h" |
3 | |
4 | #define CTEST_MAIN |
5 | #include "ctest.h" |
6 | #include "common.h" |
7 | |
8 | cstr server_host = "127.0.0.1" ; |
9 | int server_port = 8181; |
10 | cstr uri = "ws://localhost:8181/websocket" ; |
11 | cstr content = "Lorem ipsum dolor sit amet" ; |
12 | |
13 | // Server function to process messages. Runs in context of worker thread. |
14 | void process(vws_svr* s, vws_cid_t cid, vrtql_msg* m, void* ctx) |
15 | { |
16 | vrtql_msg_svr* server = (vrtql_msg_svr*)s; |
17 | |
18 | vws.trace(VL_INFO, "process (%lu) %p" , cid, m); |
19 | |
20 | // Echo back. Note: You should always set reply messages format to the |
21 | // format of the connection. |
22 | |
23 | // Create reply message |
24 | vrtql_msg* reply = vrtql_msg_new(); |
25 | reply->format = m->format; |
26 | |
27 | // Copy content |
28 | ucstr data = m->content->data; |
29 | size_t size = m->content->size; |
30 | vws_buffer_append(reply->content, data, size); |
31 | |
32 | // Send. We don't free message as send() does it for us. |
33 | server->send(s, cid, reply, NULL); |
34 | |
35 | // Clean up request |
36 | vrtql_msg_free(m); |
37 | } |
38 | |
39 | void server_thread(void* arg) |
40 | { |
41 | vws_tcp_svr* server = (vws_tcp_svr*)arg; |
42 | vws.tracelevel = VT_THREAD; |
43 | server->trace = vws.tracelevel; |
44 | |
45 | vws_tcp_svr_run(server, server_host, server_port); |
46 | |
47 | vws_cleanup(); |
48 | } |
49 | |
50 | void client_thread(void* arg) |
51 | { |
52 | vws_cnx* cnx = vws_cnx_new(); |
53 | |
54 | while (vws_connect(cnx, uri) == false) |
55 | { |
56 | vws.trace(VL_ERROR, "[client]: connecting %s" , uri); |
57 | } |
58 | |
59 | cstr payload = "payload" ; |
60 | |
61 | int i = 0; |
62 | while (true) |
63 | { |
64 | if (i++ > 10) |
65 | { |
66 | break; |
67 | } |
68 | |
69 | // Create |
70 | vrtql_msg* request = vrtql_msg_new(); |
71 | vrtql_msg_set_content(request, payload); |
72 | |
73 | // Send |
74 | while (vrtql_msg_send(cnx, request) < 0) |
75 | { |
76 | if (vws_socket_is_connected((vws_socket*)cnx) == false) |
77 | { |
78 | goto restart; |
79 | } |
80 | } |
81 | |
82 | // Receive |
83 | vrtql_msg* reply = NULL; |
84 | |
85 | while (reply == NULL) |
86 | { |
87 | printf("vrtql_msg_recv(cnx)\n" ); |
88 | reply = vrtql_msg_recv(cnx); |
89 | if (vws_socket_is_connected((vws_socket*)cnx) == false) |
90 | { |
91 | goto restart; |
92 | } |
93 | } |
94 | |
95 | // Check |
96 | ucstr content = reply->content->data; |
97 | size_t size = reply->content->size; |
98 | ASSERT_TRUE(strncmp(payload, (cstr)content, size) == 0); |
99 | vrtql_msg_free(reply); |
100 | |
101 | restart: |
102 | |
103 | // Cleanup |
104 | vrtql_msg_free(request); |
105 | } |
106 | |
107 | // Disconnect |
108 | vws_disconnect(cnx); |
109 | vws_cnx_free(cnx); |
110 | |
111 | vws_cleanup(); |
112 | } |
113 | |
114 | void client_test(int iterations, int nt) |
115 | { |
116 | for (int i = 0; i < iterations; i++) |
117 | { |
118 | uv_thread_t* threads = vws.malloc(sizeof(uv_thread_t) * nt); |
119 | |
120 | for (int i = 0; i < nt; i++) |
121 | { |
122 | uv_thread_create(&threads[i], client_thread, NULL); |
123 | vws.trace(VL_INFO, "started client thread %p" , threads[i]); |
124 | } |
125 | |
126 | for (int i = 0; i < nt; i++) |
127 | { |
128 | uv_thread_join(&threads[i]); |
129 | vws.trace(VL_INFO, "stopped client thread %p" , threads[i]); |
130 | } |
131 | |
132 | free(threads); |
133 | } |
134 | } |
135 | |
136 | CTEST(test_msg_server, echo) |
137 | { |
138 | vrtql_msg_svr* server = vrtql_msg_svr_new(10, 0, 0); |
139 | server->process = process; |
140 | |
141 | uv_thread_t server_tid; |
142 | uv_thread_create(&server_tid, server_thread, server); |
143 | |
144 | // Wait for server to start up |
145 | while (vws_tcp_svr_state((vws_tcp_svr*)server) != VS_RUNNING) |
146 | { |
147 | vws_msleep(100); |
148 | } |
149 | |
150 | client_test(5, 50); |
151 | |
152 | // Shutdown |
153 | |
154 | // Need to give the server time to properly send out CLOSE frames, etc. If |
155 | // we don't give it time, then it will it may fail to complete sending |
156 | // CLOSE_FRAME ws_svr_process_frame() and look like a memory leak in |
157 | // valgrind. |
158 | sleep(1); |
159 | |
160 | // Shutdown server |
161 | vws_tcp_svr_stop((vws_tcp_svr*)server); |
162 | uv_thread_join(&server_tid); |
163 | vrtql_msg_svr_free(server); |
164 | } |
165 | |
166 | int main(int argc, const char* argv[]) |
167 | { |
168 | return ctest_main(argc, argv); |
169 | } |
170 | |