Thread: Binance websockets

  1. #1
    Registered User
    Join Date
    Nov 2021
    Posts
    5

    Binance websockets

    Hi, i have to get market data from binance crypto exchange via websockets (as depicted here: Binance API Documentation). The code that is supposed to do it is as follows (runs under Ubuntu 20.04):

    Code:
    #include<sys/socket.h>
    #include<resolv.h>
    #include<netdb.h>
    #include<netinet/in.h>
    #include<arpa/inet.h>
    #include<string.h>
    #include<unistd.h>
    
    #include<openssl/bio.h>
    #include<openssl/ssl.h>
    #include<openssl/err.h>
    #include<openssl/pem.h>
    #include<openssl/x509.h>
    #include<openssl/x509_vfy.h>
    //####################################################################################################
    int create_and_connect_socket(char url_str[1], BIO* out) {
        char hostname[256]  ={0};
        char portnum[6]     ="443";
        char proto[6]       ={0};
    
        char* tmp_ptr = url_str + strlen(url_str);
        if (*tmp_ptr == '/') *tmp_ptr=0;
    
        strncpy(proto, url_str, (strchr(url_str, ':') - url_str));
    
        strncpy(hostname, strstr(url_str, "://") + 3, sizeof(hostname));
    
        tmp_ptr = strchr(hostname, ':');
        if (tmp_ptr) {
            strncpy(portnum, tmp_ptr + 1, sizeof(portnum));
            *tmp_ptr=0;
        }
    
        int port = atoi(portnum);
    
        struct hostent* host = gethostbyname(hostname);
        if (!host) {
            BIO_printf(out, "Error: Cannot resolve hostname %s.\n", hostname);
            exit(EXIT_FAILURE);
        }
    
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    
        struct sockaddr_in dest_addr={0};
        dest_addr.sin_family = AF_INET;
        dest_addr.sin_port = htons(port);
        dest_addr.sin_addr.s_addr = *(long*)(host->h_addr);
    
        tmp_ptr = inet_ntoa(dest_addr.sin_addr);
    
        if (connect(sockfd,
                    (struct sockaddr*) &dest_addr,
                    sizeof(struct sockaddr)) < 0) {
            BIO_printf(out, "Error: Cannot connect to host %s [%s] on port %d.\n",
                       hostname, tmp_ptr, port);
            exit(EXIT_FAILURE);
        }
    
        return sockfd;
    }
    
    //##################################################################
    int main()
    {
        char* dest_url = "wss://stream.binance.com:9443";
    
        OpenSSL_add_all_algorithms();
        ERR_load_BIO_strings();
        ERR_load_crypto_strings();
        SSL_load_error_strings();
    
        BIO* certbio = BIO_new(BIO_s_file());
        BIO* outbio = BIO_new_fp(stdout, BIO_NOCLOSE);
    
        if (SSL_library_init() < 0)
            BIO_printf(outbio, "Could not initialize the OpenSSL library.\n");
    
        const SSL_METHOD* method = SSLv23_client_method();
    
        SSL_CTX* ctx = SSL_CTX_new(method);
        if (!ctx)
            BIO_printf(outbio, "Unable to create SSL context.\n");
    
        SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
    
        SSL* ssl = SSL_new(ctx);
    
        int serverfd = create_and_connect_socket(dest_url, outbio);
        if (serverfd)
            BIO_printf(outbio,
                       "Successfully made the TCP connection to: %s.\n",
                       dest_url);
    
        SSL_set_fd(ssl, serverfd);
    
        if (SSL_connect(ssl) < 1) {
            BIO_printf(outbio,
                       "Error: Could not build an SSL session to: %s.\n",
                       dest_url);
        } else {
            BIO_printf(outbio,
                       "Successfully enabled SSL/TLS session to: %s.\n",
                       dest_url);
        }
    
        // Save the server's TLS certificate.
        X509* cert = SSL_get_peer_certificate(ssl);
    
        if (!cert) {
           BIO_printf(outbio,
                      "Error: Could not get a certificate from %s.\n",
                      dest_url);
        } else {
           BIO_printf(outbio,
                      "Retrieved the server's certificate from: %s.\n",
                      dest_url);
        }
    
        X509_NAME* certname = X509_get_subject_name(cert);
    
        BIO_printf(outbio, "Displaying the certificate subject data:\n");
        X509_NAME_print_ex(outbio, certname, 0, 0);
        BIO_printf(outbio, "\n");
    
        // All that is above worked OK. No errors
    
        char* message = "{\"method\": \"SUBSCRIBE\",\"params\": [\"btcusdt@aggTrade\",\"btcusdt@depth\"],\"id\":1}";//the query text from API reference;
        if ((n = SSL_write(ssl, message, strlen(message))) < 0)
            perror("ERROR writing to socket.");
        char buffer[4096]={0};
        for (;;) {
            explicit_bzero(buffer, 4096);
            if ((n = SSL_read(ssl, buffer, 4095)) < 0) {
                perror("ERROR reading from socket.");
                break;
            }
            if (!n) break;
            printf("%s", buffer);
        }
    
        // Cleanup
        SSL_free(ssl);
        close(serverfd);
        X509_free(cert);
        SSL_CTX_free(ctx);
        BIO_printf(outbio,
                   "Finished SSL/TLS connection with server: %s.\n",
                   dest_url);
    
        return EXIT_SUCCESS;
    }
    But i receive "400 Bad request" reply. Looks like something is missed before actual request sending (n = SSL_write)... Maybe someone already dealt with a similar task and could point out what`s wrong. I would greately appreciate it
    Last edited by Salem; 08-18-2022 at 08:54 AM. Reason: Removed bold from code, so it works properly

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,190
    A few things.

    1. Don't assume any given send/recv transmits a whole message.
    Eg, at line 130, print the value of n and the length of the string. Did you in fact send the whole message?

    2. Print the message.
    Does it look like what you expect. Did you get all the JSON syntax right?

    3. Things like btcusdt@aggTrade seem to be API placeholder values.
    Maybe you're supposed to replace them with your own credentials you got when you signed up.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    Registered User
    Join Date
    Nov 2021
    Posts
    5
    Thanks a lot! I checked all points and they seem to be ok: i made sure the string length is equal to bytes sent (n), json syntax is ok and the message looks as expected, btcusdt@aggTrade is a public endpoint so no credentials are assumed..so i`m perfectly short of ideas of where to dig else.

  4. #4
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,190
    Do you have some other reference implementation you can observe working?

    If so, then using wireshark to trace the network activity of the working code and your code will tell you where you're going wrong.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Problem Websockets
    By Radec in forum C++ Programming
    Replies: 1
    Last Post: 11-23-2013, 02:44 AM

Tags for this Thread