1 /***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 * SPDX-License-Identifier: curl
22 *
23 ***************************************************************************/
24 /* <DESC>
25 * WebSockets pingpong
26 * </DESC>
27 */
28 /* curl stuff */
29 #include "curl_setup.h"
30 #include <curl/curl.h>
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <string.h>
35
36 #ifdef _WIN32
37 #ifndef WIN32_LEAN_AND_MEAN
38 #define WIN32_LEAN_AND_MEAN
39 #endif
40 #include <windows.h>
41 #else
42 #include <sys/time.h>
43 #endif
44
45 #ifndef CURL_DISABLE_WEBSOCKETS
46
ping(CURL * curl,const char * send_payload)47 static CURLcode ping(CURL *curl, const char *send_payload)
48 {
49 size_t sent;
50 CURLcode result =
51 curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0,
52 CURLWS_PING);
53 fprintf(stderr,
54 "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent);
55
56 return result;
57 }
58
recv_pong(CURL * curl,const char * expected_payload)59 static CURLcode recv_pong(CURL *curl, const char *expected_payload)
60 {
61 size_t rlen;
62 const struct curl_ws_frame *meta;
63 char buffer[256];
64 CURLcode result = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta);
65 if(result) {
66 fprintf(stderr, "ws: curl_ws_recv returned %u, received %ld\n",
67 (int)result, (long)rlen);
68 return result;
69 }
70
71 if(!(meta->flags & CURLWS_PONG)) {
72 fprintf(stderr, "recv_pong: wrong frame, got %d bytes rflags %x\n",
73 (int)rlen, meta->flags);
74 return CURLE_RECV_ERROR;
75 }
76
77 fprintf(stderr, "ws: got PONG back\n");
78 if(rlen == strlen(expected_payload) &&
79 !memcmp(expected_payload, buffer, rlen)) {
80 fprintf(stderr, "ws: got the same payload back\n");
81 return CURLE_OK;
82 }
83 fprintf(stderr, "ws: did NOT get the same payload back\n");
84 return CURLE_RECV_ERROR;
85 }
86
87 /* just close the connection */
websocket_close(CURL * curl)88 static void websocket_close(CURL *curl)
89 {
90 size_t sent;
91 CURLcode result =
92 curl_ws_send(curl, "", 0, &sent, 0, CURLWS_CLOSE);
93 fprintf(stderr,
94 "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent);
95 }
96
pingpong(CURL * curl,const char * payload)97 static CURLcode pingpong(CURL *curl, const char *payload)
98 {
99 CURLcode res;
100 int i;
101
102 res = ping(curl, payload);
103 if(res)
104 return res;
105 for(i = 0; i < 10; ++i) {
106 fprintf(stderr, "Receive pong\n");
107 res = recv_pong(curl, payload);
108 if(res == CURLE_AGAIN) {
109 #ifdef _WIN32
110 Sleep(100);
111 #else
112 usleep(100*1000);
113 #endif
114 continue;
115 }
116 websocket_close(curl);
117 return res;
118 }
119 websocket_close(curl);
120 return CURLE_RECV_ERROR;
121 }
122
123 #endif
124
main(int argc,char * argv[])125 int main(int argc, char *argv[])
126 {
127 #ifndef CURL_DISABLE_WEBSOCKETS
128 CURL *curl;
129 CURLcode res = CURLE_OK;
130 const char *url, *payload;
131
132 if(argc != 3) {
133 fprintf(stderr, "usage: ws-pingpong url payload\n");
134 return 2;
135 }
136 url = argv[1];
137 payload = argv[2];
138
139 curl_global_init(CURL_GLOBAL_ALL);
140
141 curl = curl_easy_init();
142 if(curl) {
143 curl_easy_setopt(curl, CURLOPT_URL, url);
144
145 /* use the callback style */
146 curl_easy_setopt(curl, CURLOPT_USERAGENT, "ws-pingpong");
147 curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
148 curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */
149 res = curl_easy_perform(curl);
150 fprintf(stderr, "curl_easy_perform() returned %u\n", (int)res);
151 if(res == CURLE_OK)
152 res = pingpong(curl, payload);
153
154 /* always cleanup */
155 curl_easy_cleanup(curl);
156 }
157 curl_global_cleanup();
158 return (int)res;
159
160 #else /* !CURL_DISABLE_WEBSOCKETS */
161 (void)argc;
162 (void)argv;
163 fprintf(stderr, "WebSockets not enabled in libcurl\n");
164 return 1;
165 #endif /* CURL_DISABLE_WEBSOCKETS */
166 }
167