xref: /curl/tests/http/clients/ws-pingpong.c (revision d78e129d)
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