11static constexpr size_t BUFFER_SIZE = 4096;
19 size_t buffer_size_value = BUFFER_SIZE;
21 char *buffer = (
char *)malloc(BUFFER_SIZE + 1);
26 rbytes = sock->
read(data,
sizeof(data), 0);
28 fprintf(stderr,
"Connection closed: Error.\n");
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) {
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");
47 ssize_t pos = loc - buffer;
48 h->
header = (
char *)malloc((
size_t)pos + 1);
49 if (h->
header ==
nullptr) {
54 memcpy(h->
header, buffer, (
size_t)pos);
56 size_t body_start = (size_t)pos + 4;
60 if (h->
body ==
nullptr) {
77static int get_terminal_width() {
79 if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == -1) {
85static void print_progress(
size_t length,
size_t progress) {
88 printf(
"\r\033[2K[ Downloading ] - 0%%\n");
92 if (progress > length) {
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);
102 printf(
"\r\033[2K[");
103 for (
int j = 0; j < bar_width; ++j) {
104 if (j < num_equals) {
110 printf(
"] - %d%%", percent);
114int main(
int argc,
char **argv) {
116 fprintf(stderr,
"Error on invoke of dl-file:\nuse:\ndl <host> <port> <file> <output>\n");
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]);
129 if ((bytes = sock.
write(info, strlen(info), MSG_NOSIGNAL)) > 0) {
130 printf(
"dl: request sent.\n");
133 printf(
"Header: %s\n", h.
header);
134 char *len_pos = strcasestr(h.
header,
"Content-Length:");
135 if (len_pos !=
nullptr) {
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");
147 size_t file_length = 0;
150 print_progress(f_len, file_length);
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);
157 fprintf(stderr,
"dl: Connection reset or error: %s\n", strerror(errno));
160 if (file_length == f_len)
161 printf(
"dl: [OK] -> %s\n", argv[4]);
163 printf(
"Incorrect file length: %zu != %zu\n", file_length, f_len);
171 }
else if (bytes == -1 && errno == EPIPE) {
172 fprintf(stderr,
"dl: Error on send, broken pipe.\n");
176 fprintf(stderr,
"Error on connect:\n");
180 std::cerr <<
"Network error: " << e.
text() <<
"\n";
Lightweight exception wrapper for MXNetwork failures.
std::string text() const
Return the stored error text.
C++ wrapper around the MXNetwork socket API.
ssize_t write(const void *buf, size_t bytes, int flags)
Write bytes to the socket.
void close()
Close the socket if it is open.
ssize_t read(void *buf, size_t bytes, int flags)
Read bytes from the socket.
bool connect(const std::string_view host, const std::string_view port)
Connect to a remote Internet endpoint.
bool extract_header(mxnetwork::Socket *sock, struct http_header *h)
void mx_socket_ignore_pipe_signal()
Ignore SIGPIPE on platforms that require it.
@ TYPE_INET
IPv4 stream socket.