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
43static 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
55static 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 */
84static 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
93static 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
117int 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