MXVK Vulkan Framework 0.24.0
C++20 Vulkan rendering framework for practical 2D and 3D application development with SDL3.
Loading...
Searching...
No Matches
dl-file.cpp
Go to the documentation of this file.
1// I need to reimplement this with more C++ style using string instead of raw pointers
3#include <cstdlib>
4#include <errno.h>
5#include <iostream>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/ioctl.h>
10
11static constexpr size_t BUFFER_SIZE = 4096;
12
14 char *header, *body;
16};
17
19 size_t buffer_size_value = BUFFER_SIZE;
20 size_t length = 0;
21 char *buffer = (char *)malloc(BUFFER_SIZE + 1);
22 ssize_t rbytes = 0;
23 char data[1024];
24 data[0] = 0;
25 while (1) {
26 rbytes = sock->read(data, sizeof(data), 0);
27 if (rbytes <= 0) {
28 fprintf(stderr, "Connection closed: Error.\n");
29 free(buffer);
30 return false;
31 }
32 if (length + (size_t)rbytes >= buffer_size_value) {
33 buffer_size_value *= 2;
34 char *n_buffer = (char *)realloc(buffer, buffer_size_value + 1);
35 if (n_buffer == nullptr) {
36 perror("realloc");
37 free(buffer);
38 return false;
39 }
40 buffer = n_buffer;
41 }
42 memcpy(buffer + length, data, (size_t)rbytes);
43 length += (size_t)rbytes;
44 buffer[length] = '\0';
45 auto loc = strstr(buffer, "\r\n\r\n");
46 if (loc != nullptr) {
47 ssize_t pos = loc - buffer;
48 h->header = (char *)malloc((size_t)pos + 1);
49 if (h->header == nullptr) {
50 free(buffer);
51 perror("malloc");
52 return false;
53 }
54 memcpy(h->header, buffer, (size_t)pos);
55 h->header[pos] = '\0';
56 size_t body_start = (size_t)pos + 4;
57 h->body_length = length - body_start;
58 if (h->body_length > 0) {
59 h->body = (char *)malloc(h->body_length);
60 if (h->body == nullptr) {
61 perror("malloc");
62 free(h->header);
63 free(buffer);
64 return false;
65 }
66 memcpy(h->body, buffer + body_start, h->body_length);
67 } else {
68 h->body = nullptr;
69 }
70 free(buffer);
71 return true;
72 }
73 }
74 return true;
75}
76
77static int get_terminal_width() {
78 struct winsize w;
79 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == -1) {
80 return 80;
81 }
82 return w.ws_col;
83}
84
85static void print_progress(size_t length, size_t progress) {
86
87 if (length == 0) {
88 printf("\r\033[2K[ Downloading ] - 0%%\n");
89 return;
90 }
91
92 if (progress > length) {
93 progress = length;
94 }
95 int term_width = get_terminal_width();
96 int bar_width = term_width - 12;
97 double ratio = (double)progress / (double)length;
98 int num_equals = (int)(ratio * bar_width);
99 int percent = (int)(ratio * 100.0);
100 if (bar_width < 10)
101 bar_width = 10;
102 printf("\r\033[2K[");
103 for (int j = 0; j < bar_width; ++j) {
104 if (j < num_equals) {
105 putchar('=');
106 } else {
107 putchar(' ');
108 }
109 }
110 printf("] - %d%%", percent);
111 fflush(stdout);
112}
113
114int main(int argc, char **argv) {
115 if (argc != 5) {
116 fprintf(stderr, "Error on invoke of dl-file:\nuse:\ndl <host> <port> <file> <output>\n");
117 return EXIT_FAILURE;
118 }
119
120 try {
123 if (sock.connect(argv[1], argv[2])) {
124 printf("dl: connected.\n");
125 static constexpr int buffer_size = 4096;
126 char info[buffer_size];
127 snprintf(info, buffer_size - 1, "GET %s HTTP/1.0\r\nHOST: %s\r\nUser-Agent: C-DL-Client/1.0\r\nConnection: close\r\n\r\n", argv[3], argv[1]);
128 ssize_t bytes = 0;
129 if ((bytes = sock.write(info, strlen(info), MSG_NOSIGNAL)) > 0) {
130 printf("dl: request sent.\n");
131 struct http_header h;
132 if (extract_header(&sock, &h)) {
133 printf("Header: %s\n", h.header);
134 char *len_pos = strcasestr(h.header, "Content-Length:");
135 if (len_pos != nullptr) {
136 len_pos += 15;
137 char *end_pos;
138 size_t f_len = strtoul(len_pos, &end_pos, 10);
139 if (end_pos != len_pos && (end_pos != nullptr && *end_pos != '\0')) {
140 FILE *fptr = fopen(argv[4], "wb");
141 if (!fptr) {
142 perror("fopen");
143 free(h.header);
144 free(h.body);
145 return EXIT_FAILURE;
146 }
147 size_t file_length = 0;
148 if (h.body_length > 0) {
149 file_length += fwrite(h.body, 1, h.body_length, fptr);
150 print_progress(f_len, file_length);
151 }
152 while ((bytes = sock.read(info, buffer_size, 0)) > 0) {
153 file_length += fwrite(info, 1, (size_t)bytes, fptr);
154 print_progress(f_len, file_length);
155 }
156 if (bytes == -1) {
157 fprintf(stderr, "dl: Connection reset or error: %s\n", strerror(errno));
158 } else {
159 printf("\n");
160 if (file_length == f_len)
161 printf("dl: [OK] -> %s\n", argv[4]);
162 else
163 printf("Incorrect file length: %zu != %zu\n", file_length, f_len);
164 }
165 fclose(fptr);
166 }
167 }
168 free(h.header);
169 free(h.body);
170 }
171 } else if (bytes == -1 && errno == EPIPE) {
172 fprintf(stderr, "dl: Error on send, broken pipe.\n");
173 }
174 sock.close();
175 } else {
176 fprintf(stderr, "Error on connect:\n");
177 return EXIT_FAILURE;
178 }
179 } catch (const mxnetwork::Exception &e) {
180 std::cerr << "Network error: " << e.text() << "\n";
181 }
182 return EXIT_SUCCESS;
183}
Lightweight exception wrapper for MXNetwork failures.
Definition exception.hpp:11
std::string text() const
Return the stored error text.
Definition exception.cpp:5
C++ wrapper around the MXNetwork socket API.
Definition socket.hpp:57
ssize_t write(const void *buf, size_t bytes, int flags)
Write bytes to the socket.
Definition socket.cpp:195
void close()
Close the socket if it is open.
Definition socket.cpp:171
ssize_t read(void *buf, size_t bytes, int flags)
Read bytes from the socket.
Definition socket.cpp:187
bool connect(const std::string_view host, const std::string_view port)
Connect to a remote Internet endpoint.
Definition socket.cpp:80
bool extract_header(mxnetwork::Socket *sock, struct http_header *h)
Definition dl-file.cpp:18
int main(void)
Definition main.cpp:7
void mx_socket_ignore_pipe_signal()
Ignore SIGPIPE on platforms that require it.
Definition mxsocket.c:577
@ TYPE_INET
IPv4 stream socket.
Definition socket.hpp:41
size_t body_length
Definition dl-file.cpp:15
char * body
Definition dl-file.cpp:14
char * header
Definition dl-file.cpp:14