websocket-updown.c
/*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | * / __| | | | |_) | | * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at https://curl.se/docs/copyright.html. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of the Software, and permit persons to whom the Software is * furnished to do so, under the terms of the COPYING file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * * SPDX-License-Identifier: curl * ***************************************************************************/ /* <DESC> * WebSocket download-only using write callback * </DESC> */ #include <stdio.h> #include <string.h> #include <curl/curl.h> static size_t write_cb(char *b, size_t size, size_t nitems, void *p) { CURL *curl = p; size_t i; unsigned int blen = (unsigned int)(nitems * size); const struct curl_ws_frame *frame = curl_ws_meta(curl); fprintf(stderr, "Type: %s\n", frame->flags & CURLWS_BINARY ? "binary" : "text"); if(frame->flags & CURLWS_BINARY) { fprintf(stderr, "Bytes: %u", blen); for(i = 0; i < nitems; i++) fprintf(stderr, "%02x ", (unsigned char)b[i]); fprintf(stderr, "\n"); } else fprintf(stderr, "Text: %.*s\n", (int)blen, b); return nitems; } struct read_ctx { CURL *curl; char buf[1024]; size_t blen; size_t nsent; }; static size_t read_cb(char *buf, size_t nitems, size_t buflen, void *p) { struct read_ctx *ctx = p; size_t len = nitems * buflen; size_t left = ctx->blen - ctx->nsent; if(!ctx->nsent) { CURLcode result; /* On first call, set the FRAME information to be used (it defaults to * CURLWS_BINARY otherwise). */ result = curl_ws_start_frame(ctx->curl, CURLWS_TEXT, (curl_off_t)ctx->blen); if(result != CURLE_OK) { fprintf(stderr, "error starting frame: %d\n", (int)result); return CURL_READFUNC_ABORT; } } fprintf(stderr, "read(len=%d, left=%d)\n", (int)len, (int)left); if(left) { if(left < len) len = left; memcpy(buf, ctx->buf + ctx->nsent, len); ctx->nsent += len; return len; } return 0; } int main(int argc, const char *argv[]) { CURL *curl; struct read_ctx rctx; const char *payload = "Hello, friend!"; CURLcode result = curl_global_init(CURL_GLOBAL_ALL); if(result != CURLE_OK) return (int)result; memset(&rctx, 0, sizeof(rctx)); curl = curl_easy_init(); if(curl) { if(argc == 2) curl_easy_setopt(curl, CURLOPT_URL, argv[1]); else curl_easy_setopt(curl, CURLOPT_URL, "wss://example.com"); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb); curl_easy_setopt(curl, CURLOPT_WRITEDATA, curl); curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb); /* tell curl that we want to send the payload */ rctx.curl = curl; rctx.blen = strlen(payload); memcpy(rctx.buf, payload, rctx.blen); curl_easy_setopt(curl, CURLOPT_READDATA, &rctx); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* Perform the request, result gets the return code */ result = curl_easy_perform(curl); /* Check for errors */ if(result != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(result)); /* always cleanup */ curl_easy_cleanup(curl); } curl_global_cleanup(); return (int)result; }
Notice
This source code example is simplified and may ignore return
codes and error checks. We do this to highlight the libcurl function calls and
related options and reduce unrelated code.
A real-world application does of course properly check every return value and exit correctly at the first serious error.