Chinaunix首页 | 论坛 | 博客
  • 博客访问: 450001
  • 博文数量: 15
  • 博客积分: 5010
  • 博客等级: 大校
  • 技术积分: 1196
  • 用 户 组: 普通用户
  • 注册时间: 2006-03-15 21:29
文章分类

全部博文(15)

文章存档

2008年(15)

我的朋友

分类: LINUX

2008-06-25 10:11:29


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 "

#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"
                 "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 *p = base_url_name;

        p += strlen(base_url_name) - 1;
        while (*p != '/')
                p--;
        p++;

        return p;
}

/*
 * Abstract download information from url, it can handle port like
 */

HTTP_DOWN abstract_url(char *http_url)
{
    HTTP_DOWN http_down;
    char temp_port[6], *p;

    char *http = "http://";
    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[i] = '\0';

    i = 0;
    while (*p)
        http_down.remote_file[i++] = *p++;
    http_down.remote_file[i] = '\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;
}

阅读(6509) | 评论(11) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2010-06-23 14:39:37

int flag_port = 0; p += strlen(http); 这行中间应该让指针指向要下载的连接 int flag_port = 0; p=http_url; p += strlen(http);

chinaunix网友2010-06-23 14:29:33

编译出来190行有段错误,感觉你传入的 HTTP_DOWN abstract_url(char *http_url)参数根本没使用

chinaunix网友2008-06-30 22:55:38

还需要cookies,REFER等自定义HTTP头,HTTPS支持。等等。

chinaunix网友2008-06-30 14:14:52

代码已修正。

chinaunix网友2008-06-27 12:35:52

这有什么问题呢?