免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1111 | 回复: 0
打印 上一主题 下一主题

封装了一个http_download函数 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-06-25 10:11 |只看该作者 |倒序浏览

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
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP