114 {
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");
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");
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 }
180 std::cerr <<
"Network error: " << e.
text() <<
"\n";
181 }
182 return EXIT_SUCCESS;
183}
Lightweight exception wrapper for MXNetwork failures.
std::string text() const
Return the stored error text.
C++ wrapper around the MXNetwork socket API.
bool extract_header(mxnetwork::Socket *sock, struct http_header *h)
void mx_socket_ignore_pipe_signal()
Ignore SIGPIPE on platforms that require it.
constexpr size_t buffer_size
@ TYPE_INET
IPv4 stream socket.