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