Shammer's Philosophy

My private adversaria

HTTP Client ver 0.24

HTTP Client ver 0.23 - Shammerismの内容に、nslookup sample C version - 関数版 - Shammerismの関数を加えた。ようやく、IP アドレスでもホスト名でもアクセスできる状態になった。

#include <ctype.h>
#include <err.h>
#include <netdb.h>
#include <regex.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <netinet/in.h>

int is_valid_ipaddr(char v[]){
    regex_t preg;
    int regcompresult, regexecresult;
    regcompresult = regcomp(&preg, "^([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5]).([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])$", REG_NOSUB | REG_EXTENDED | REG_NEWLINE);
    if( regcompresult == 0 ){
        size_t nmatch = 0;
        regmatch_t pmatch[nmatch];
        regexecresult = regexec(&preg, v, nmatch, pmatch, 0);
        if( regexecresult == 0 ){
            printf("%s is valid IP address.\n", v);
        } else {
            printf("%s is not valid IP address.\n", v);
        }
    }
    return regexecresult;
}

char * get_ip_addr(char * hostname){
    char temp[17] = {'0'};
    struct addrinfo hints, *res, *res0;
    int error;
    void * ptr;

    memset(&hints, 0, sizeof(hints));
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;

    error = getaddrinfo(hostname, NULL, &hints, &res0);
    if( error ) {
        errx(1, "%s", gai_strerror(error));
    }

    int i = 0;
    for( res = res0 ; res ; res = res->ai_next ) {
        switch(res->ai_family) {
        case AF_INET:
            ptr = &(((struct sockaddr_in *)res->ai_addr)->sin_addr);
            inet_ntop(res->ai_family, ptr, temp, sizeof(temp));
            break;
        case AF_INET6:
            // Don't use IPv6 address.
            // ptr = &(((struct sockaddr_in6 *)res->ai_addr)->sin6_addr);
            // inet_ntop(res->ai_family, ptr, temp, sizeof(temp));
            continue;
        }
        i++;
    }
    freeaddrinfo(res0);

    char * ip = (char *)malloc(strlen(temp) + 1);
    strcpy(ip, temp);
    
    return ip;
}

void send_request(int sock, char * ipaddr) {
    send(sock, "GET / HTTP/1.1\r\n", strlen("GET / HTTP/1.1\r\n"), 0);
    send(sock, "Host: ", strlen("Host: "), 0);
    send(sock, ipaddr, strlen(ipaddr), 0);
    send(sock, "\r\n", strlen("\r\n"), 0);
    send(sock, "Connection: close\r\n", strlen("Connection: close\r\n"), 0);
    send(sock, "\r\n", strlen("\r\n"), 0);
}

void write_request(int sock, char * ipaddr){
    char send_buf[256];
    sprintf(send_buf, "GET / HTTP/1.1\r\n");
    write(sock, send_buf, strlen(send_buf));
    sprintf(send_buf, "Host: %s\r\n", ipaddr);
    write(sock, send_buf, strlen(send_buf));
    sprintf(send_buf, "Connection: close\r\n");
    write(sock, send_buf, strlen(send_buf));
    sprintf(send_buf, "\r\n");
    write(sock, send_buf, strlen(send_buf));
}

void fprintf_request(FILE * fp, char * ipaddr){
    // Buffering OFF -> _IONBF 
    setvbuf(fp, NULL, _IONBF, 0);

    fprintf(fp, "GET / HTTP/1.1\r\n");
    fprintf(fp, "Host: %s\r\n", ipaddr);
    fprintf(fp, "Connection: close\r\n");
    fprintf(fp, "\r\n");
}

void recv_response(int sock){
    int bytes_read;
    char response[256];
    while(1) {
        bzero(response, sizeof(response));
        bytes_read = recv(sock, response, sizeof(response), 0);
        if( bytes_read > 0 ){
            printf("%s", response);
        }
        else {
            break;
        }
    }
}

void read_response(int sock){
    while (1) {
        char response[256];
        int read_size;
        read_size = read(sock, response, sizeof(response));
        if( read_size > 0 ){
            // 1 means Standard out
            write(1, response, read_size);
        }
        else {
            break;
        }
    }
}

void fgets_response(FILE *fp){
    while (1) {
        char response[256];
        if ( fgets(response, sizeof(response), fp) == NULL ) {
            break;
        }
        printf("%s", response);
    }
}

int main(int argc, char* args[]){
    if( argc == 2 ){
        char* destination_ip;
        int valid_argument = is_valid_ipaddr(args[1]);
        if( valid_argument == 0 ) {
            destination_ip = args[1];
        }
        else {
            destination_ip = get_ip_addr(args[1]);
        }
        // HTTP Client
        int sock;
        struct sockaddr_in destination_addr;
        unsigned short destination_port = 80;
        sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
        if( sock < 0 ){
            printf("Socket open error.\n");
            exit(1);
        }
        memset(&destination_addr, 0, sizeof(destination_addr));
        destination_addr.sin_family = AF_INET;
        destination_addr.sin_addr.s_addr = inet_addr(destination_ip);
        destination_addr.sin_port = htons(destination_port);
        if( connect(sock, (struct sockaddr *)&destination_addr, sizeof(destination_addr)) < 0 ){
            printf("Connect error, destination IP addr is %s.\n", destination_ip);
            exit(2);
        }
        write_request(sock, destination_ip);
        read_response(sock);
        close(sock);
    }
    else {
        printf("Usage: %s %s\n", args[0], "Destination_IP");
        printf("       %s %s\n", args[0], "Destination_Hostname");
    }
    return 0;
}