- 论坛徽章:
- 0
|
http_download.h
/*
*
* Http_download.h (c) wzt 2007 - 2008
*
*/
#ifndef HTTP_DOWNLOAD_H
#define HTTP_DOWNLOAD_H
#define DEBUG 1
#if DEBUG == 1
#define DPRINT(mesg, ...) fprintf(stderr, mesg, __VA_ARGS__)
#else
#define DPRINT(mesg, ...)
#endif
#define VERSION 0.1
#define BANNER "Xsec Linux Tiny Http Download Tool"
#define AUTHOR "(c) wzt http://www.xsec.org"
#define MAX_CONNECT_NUM 5
#define SLEEP_TIME 1
#define TIME_OUT 10
#define BUFF_SIZE 4096
#define MAX_HOST_LEN 100
#define MAX_FILE_LEN 200
#define DEFAULT_PORT 80
char *http_data_m = "Accept: */*\r\n"
"Accept-Language: zh-cn\r\n"
"UA-CPU: x86\r\n"
"Accept-Encoding: gzip, deflate\r\n"
"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; SV1; TencentTraveler ; .NET CLR 1.1.4322)\r\n";
char *http_data_e = "Connection: Keep-Alive\r\n\r\n";
typedef struct DOWNLOAD_FILE {
char remote_host[MAX_HOST_LEN];
int remote_port;
char remote_file[MAX_FILE_LEN];
}HTTP_DOWN;
#define CHECK_PORT(port) (port > 0 && port 65535) ? 1 : 0
#endif /* __HTTP_DOWNLOAD_H__ */
http_download.c
#include stdio.h>
#include stdlib.h>
#include string.h>
#include unistd.h>
#include fcntl.h>
#include ctype.h>
#include sys/time.h>
#include sys/types.h>
#include sys/stat.h>
#include signal.h>
#include errno.h>
#include sys/socket.h>
#include netinet/in.h>
#include net/if.h>
#include netdb.h>
#include arpa/inet.h>
#include "http_download.h"
/*
* make_network_ip - make ip from host byte to network byte.
*
* host - remote host ip.
*
* successfull return the network byte,failed return 0;
*/
unsigned int make_network_ip(char *host)
{
struct hostent *h;
unsigned int ret;
if ((h = gethostbyname(host)) == NULL) {
ret = inet_addr(host);
if (ret == -1)
return 0;
return ret;
}
else {
ret = *((unsigned int *)h->h_addr);
if (ret = 0)
return 0;
return ret;
}
}
ssize_t sock_read_timeout(int sock_id, char *buff, size_t n, int time_out)
{
fd_set readfds;
struct timeval timeout;
size_t n_left;
ssize_t n_read = 0;
int ret;
while (1) {
FD_ZERO(&readfds);
FD_SET(sock_id, &readfds);
timeout.tv_sec = time_out;
timeout.tv_usec = 0;
ret = select(sock_id + 1, &readfds, NULL, NULL, &timeout);
if (ret 0) {
if (errno == EINTR)
continue;
return -1;
}
if (ret == 0) {
//fprintf(stdout, "%s", "select read time out ...\n");
return -1;
}
if (FD_ISSET(sock_id, &readfds)) {
if ((n_read = read(sock_id, buff, n)) 0) {
if (errno == EINTR)
continue;
//fprintf(stdout, "%s", "select unkonw error...\n");
return -2;
}
else if (n_read == 0)
break;
else
break;
}
}
return n_read;
}
ssize_t sock_write_timeout(int sock_id, char *buff, size_t n, int time_out)
{
fd_set writefds;
struct timeval timeout;
ssize_t n_written = 0;
int ret;
while (1) {
FD_ZERO(&writefds);
FD_SET(sock_id, &writefds);
timeout.tv_sec = time_out;
timeout.tv_usec = 0;
ret = select(sock_id + 1, NULL, &writefds, NULL, &timeout);
if (ret 0) {
if (errno == EINTR)
continue;
return -1;
}
if (ret == 0) {
//fprintf(stdout, "%s", "select write time out ...\n");
return -1;
}
if (FD_ISSET(sock_id, &writefds)) {
if ((n_written = write(sock_id, buff, n)) 0) {
if (errno == EINTR)
continue;
//fprintf(stdout, "%s", "select unkonw error...\n");
return -2;
}
else if (n_written == 0)
break;
else
break;
}
}
return n_written;
}
int tcp_connect_timeout(unsigned int remote_ip, unsigned int remote_port, int timeout)
{
struct sockaddr_in serv_addr;
int sock_fd;
if ((sock_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
perror("[-] socket");
return -1;
}
setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(int));
setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(int));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = remote_port;
serv_addr.sin_addr.s_addr = remote_ip;
if (connect(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) == -1)
return 0;
return sock_fd;
}
/*
Abstract real file name from full path name, like
/pub/linux/kernel/v2.6/linux-2.6.24.1.tar.sign ---> linux-2.6.24.1.tar.sign
*/
char *abstract_file_name(char *base_url_name)
{
char base_name[500];
char *p = base_url_name;
strcpy(base_name, base_url_name);
p += strlen(base_name) - 1;
while (*p != '/')
*p--;
*p++;
return p;
}
/*
* Abstract download information from url, it can handle port like www.kernel.org:8080.
*/
HTTP_DOWN abstract_url(char *http_url)
{
HTTP_DOWN http_down;
char temp_port[6], *p;
int i = 0, j = 0;
int flag_port = 0;
p += strlen("http://");
while (*p != '/') {
if (*p == ':') {
flag_port = 1;
p++;
while (isdigit(*p))
temp_port[j++] = *p++;
temp_port[j] = '\0';
http_down.remote_port = atoi(temp_port);
if (!CHECK_PORT(http_down.remote_port) || j >= 6) {
DPRINT("%s", "Bad url.\n");
exit(-1);
}
continue;
}
else {
http_down.remote_host[i++] = *p++;
}
}
http_down.remote_host = '\0';
i = 0;
while (*p)
http_down.remote_file[i++] = *p++;
http_down.remote_file = '\0';
if (!flag_port)
http_down.remote_port = DEFAULT_PORT;
return http_down;
}
/* Download a file from url, succeed return 1, failed 0. */
int http_download(char *http_url, char *save_file)
{
HTTP_DOWN file_get;
char local_file[MAX_FILE_LEN], *p;
char post_url_data[1024];
char buff[BUFF_SIZE], *content_len;
char *real_data_pos;
int sock_fd, file_fd, i;
int file_length = 0, r_len;
int http_check;
file_get = abstract_url(http_url);
if (!save_file) {
p = abstract_file_name(file_get.remote_file);
strncpy(local_file, p, strlen(p) + 1);
}
else
strncpy(local_file, save_file, strlen(save_file) + 1);
/* create local file.*/
file_fd = open(local_file, O_WRONLY | O_CREAT);
if (file_fd 0) {
DPRINT("Create local file %s failed.\n", local_file);
return 0;
}
/* connect to http server. */
for (i = 0; i MAX_CONNECT_NUM; i++) {
sock_fd = tcp_connect_timeout(make_network_ip(file_get.remote_host),
htons(file_get.remote_port), TIME_OUT);
if (sock_fd > 0)
break;
}
if (i == MAX_CONNECT_NUM) {
DPRINT("Connect %s:%d failed.\n",
file_get.remote_host, file_get.remote_port);
return 1;
}
/* make http get request. */
snprintf(post_url_data, sizeof(post_url_data),
"GET %s HTTP/1.1\r\n%sHost: %s\r\n%s",
file_get.remote_file, http_data_m, file_get.remote_host, http_data_e);
/* send http request.*/
sock_write_timeout(sock_fd, post_url_data, strlen(post_url_data), TIME_OUT);
/* read the first data from http server. */
r_len = sock_read_timeout(sock_fd, buff, BUFF_SIZE, TIME_OUT);
if (r_len == -1) {
DPRINT("%s", "Read data timeout.\n");
return 0;
}
if (r_len == -2) {
DPRINT("%s", "Host unknown error.\n");
return 0;
}
http_check = atoi(buff + 9);
if ((http_check != 200) && (http_check != 206))
return 0;
content_len = strstr(buff, "Content-Length: ");
if (!content_len) {
content_len = strstr(buff, "Content-length: ");
if (!content_len)
return 0;
}
file_length = atoi(content_len + 16);
/* write the first data to file. */
real_data_pos = strstr(buff, "\r\n\r\n") + 4;
write(file_fd, real_data_pos, strlen(real_data_pos));
while (1) {
r_len = sock_read_timeout(sock_fd, buff, BUFF_SIZE, TIME_OUT);
if (r_len = 0)
break;
write(file_fd, buff, r_len);
}
close(file_fd);
close(sock_fd);
return 1;
}
int main(int argc, char **argv)
{
if (http_download(argv[1], argv[2]) == 1)
printf("done.\n");
else
printf("failed.\n");
return 0;
}
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/15780/showart_1010868.html |
|