View Single Post
  #1   (View Single Post)  
Old 24th February 2021
Omphalotus_japonicus Omphalotus_japonicus is offline
New User
 
Join Date: Jan 2021
Posts: 9
Default I am having trouble receiving uncorrupted file data with unix sockets.

I'm a relative newbie when it comes to the world of programming and have only recently taken up unix networking. I first created a program which downloaded files over the HTTP protocol to avail, and am now trying to make a file downloader that instead uses the Gemini protocol.

The issue, however, is that I can not apply my method of receiving uncorrupted data that I used with my HTTP file downloader as I used the content length header which Gemini lacks. I've experimented a little and came up with what I thought could be a solution, but does not work and I have yet to understand why.

Here's my code:

Code:
/*
 * Simple program which downloads a file originating from the Gemini protocol
 * using unix socket programming and the LibreSSL library.
 */

#include <netdb.h>
#include <libressl/openssl/ssl.h>

#include <cassert>
#include <iostream>
#include <fstream>

int
main()
{
        /*
         * Flag the to-be-created pointer to a linked-list pointer to allow
         * both IPV4 and IPV6 IP addresses and use TCP.
         */

        struct addrinfo flags = {0};
                        flags.ai_family = AF_UNSPEC;
                        flags.ai_socktype = SOCK_STREAM;

        /*
         * Return value for error handling.
         */

        int rv = 0;

        /*
         * Stores given address, port, and above-defined flags into a pointer
         * to a linked-list pointer which contains necessary connection
         * information.
         */

        struct addrinfo *conninfo;
        rv = getaddrinfo("skyjake.fi", "1965", &flags, &conninfo);
        assert(rv == 0);

        /*
         * Creates a communication endpoint and returns a file descriptor
         * relating to that endpoint and assigns it to the "sockfd" int.
         */

        int sockfd = socket(conninfo->ai_family, conninfo->ai_socktype,
                            conninfo->ai_protocol);
        assert(sockfd != -1);

        /*
         * Connects to given address on the socket referred
         * to by the "sockfd" int.
         */

        rv = connect(sockfd, conninfo->ai_addr, conninfo->ai_addrlen);
        assert(rv == 0);

        SSL_library_init();

        /*
         * Creates an SSL structure containing TLS/SSL connection information
         * including the SSL_CTX object which initializes the cipher list,
         * session cache setting, callbacks, and the keys of
         * certificates based off the connection method given, being the
         * TLSv1.2 protocol.
         */

        SSL *ssl = SSL_new(SSL_CTX_new(TLSv1_2_client_method()));
        assert(ssl != nullptr);

        /*
         * Sets the above-defined SSL object's socket file descriptor to the
         * one contained in the "sockfd" int.
         */

        rv = SSL_set_fd(ssl, sockfd);
        assert(rv == 1);


        /*
         * Initializes a TLS/SSL handshake with the connected server.
         */

        rv = SSL_connect(ssl);
        assert(rv == 1);

        std::string req = "gemini://skyjake.fi/lagrange/lagrange_about.png"
                          "\r\n";

        /*
         * Sends a GET request to the connected server for the requested file.
         */

        rv = SSL_write(ssl, req.data(), req.size());
        assert(rv > 0);

        std::string buffer = {0};
        int read_size = 8192;

        /*
         * Inputs received data into a buffer while its available and with each
         * iteration resize the buffer and read data by an addition of the read
         * size, storing the new data in a new portion of the buffer to prevent
         * any overwriting.... or so I thought
         */

        while (rv != 0)
        {
                int old_size = buffer.size();
                buffer.resize(old_size + read_size);
                rv = SSL_read(ssl, buffer.data() + old_size, old_size + read_size);
        }

        /*
         * Removes the Gemini header from the buffer.
         */

        buffer.erase(0, buffer.find("\r\n") + 2);

        std::ofstream file("image.png", std::ios::binary | std::ios::out
                                      | std::ios::trunc);


        SSL_shutdown(ssl);
        shutdown(sockfd, 2);

        return 0;
}

Last edited by J65nko; 23rd March 2021 at 04:31 AM. Reason: Added [code] and [/code] tags
Reply With Quote