xref: /curl/tests/http/clients/ws-pingpong.c (revision a86fcb28)
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 
29 /* curl stuff */
30 #include "curl_setup.h"
31 #include <curl/curl.h>
32 
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 /* somewhat unix-specific */
38 #include <sys/time.h>
39 #include <unistd.h>
40 
41 #ifdef USE_WEBSOCKETS
42 
ping(CURL * curl,const char * send_payload)43 static CURLcode ping(CURL *curl, const char *send_payload)
44 {
45   size_t sent;
46   CURLcode result =
47     curl_ws_send(curl, send_payload, strlen(send_payload), &sent, 0,
48                  CURLWS_PING);
49   fprintf(stderr,
50           "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent);
51 
52   return result;
53 }
54 
recv_pong(CURL * curl,const char * expected_payload)55 static CURLcode recv_pong(CURL *curl, const char *expected_payload)
56 {
57   size_t rlen;
58   const struct curl_ws_frame *meta;
59   char buffer[256];
60   CURLcode result = curl_ws_recv(curl, buffer, sizeof(buffer), &rlen, &meta);
61   if(result) {
62     fprintf(stderr, "ws: curl_ws_recv returned %u, received %ld\n",
63             (int)result, (long)rlen);
64     return result;
65   }
66 
67   if(!(meta->flags & CURLWS_PONG)) {
68     fprintf(stderr, "recv_pong: wrong frame, got %d bytes rflags %x\n",
69             (int)rlen, meta->flags);
70     return CURLE_RECV_ERROR;
71   }
72 
73   fprintf(stderr, "ws: got PONG back\n");
74   if(rlen == strlen(expected_payload) &&
75      !memcmp(expected_payload, buffer, rlen)) {
76     fprintf(stderr, "ws: got the same payload back\n");
77     return CURLE_OK;
78   }
79   fprintf(stderr, "ws: did NOT get the same payload back\n");
80   return CURLE_RECV_ERROR;
81 }
82 
83 /* just close the connection */
websocket_close(CURL * curl)84 static void websocket_close(CURL *curl)
85 {
86   size_t sent;
87   CURLcode result =
88     curl_ws_send(curl, "", 0, &sent, 0, CURLWS_CLOSE);
89   fprintf(stderr,
90           "ws: curl_ws_send returned %u, sent %u\n", (int)result, (int)sent);
91 }
92 
pingpong(CURL * curl,const char * payload)93 static CURLcode pingpong(CURL *curl, const char *payload)
94 {
95   CURLcode res;
96   int i;
97 
98   res = ping(curl, payload);
99   if(res)
100     return res;
101   for(i = 0; i < 10; ++i) {
102     fprintf(stderr, "Receive pong\n");
103     res = recv_pong(curl, payload);
104     if(res == CURLE_AGAIN) {
105       usleep(100*1000);
106       continue;
107     }
108     websocket_close(curl);
109     return res;
110   }
111   websocket_close(curl);
112   return CURLE_RECV_ERROR;
113 }
114 
115 #endif
116 
main(int argc,char * argv[])117 int main(int argc, char *argv[])
118 {
119 #ifdef USE_WEBSOCKETS
120   CURL *curl;
121   CURLcode res = CURLE_OK;
122   const char *url, *payload;
123 
124   if(argc != 3) {
125     fprintf(stderr, "usage: ws-pingpong url payload\n");
126     return 2;
127   }
128   url = argv[1];
129   payload = argv[2];
130 
131   curl_global_init(CURL_GLOBAL_ALL);
132 
133   curl = curl_easy_init();
134   if(curl) {
135     curl_easy_setopt(curl, CURLOPT_URL, url);
136 
137     /* use the callback style */
138     curl_easy_setopt(curl, CURLOPT_USERAGENT, "ws-pingpong");
139     curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
140     curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 2L); /* websocket style */
141     res = curl_easy_perform(curl);
142     fprintf(stderr, "curl_easy_perform() returned %u\n", (int)res);
143     if(res == CURLE_OK)
144       res = pingpong(curl, payload);
145 
146     /* always cleanup */
147     curl_easy_cleanup(curl);
148   }
149   curl_global_cleanup();
150   return (int)res;
151 
152 #else /* USE_WEBSOCKETS */
153   (void)argc;
154   (void)argv;
155   fprintf(stderr, "websockets not enabled in libcurl\n");
156   return 1;
157 #endif /* !USE_WEBSOCKETS */
158 }
159