Shammer's Philosophy

My private adversaria

HTTP Client ver 0.23

C 言語で HTTP クライアントを作ってみよう (2)に有用な情報を発見。Socket も FILE と同じように扱うのがよさそうだ。HTTP Client ver 0.22 - Shammerismで考えた関数化と合わせて以下のように変更。使わない関数もいくつかあるが、今後のメモとして。だいぶ長くなったな。。。

#include <ctype.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.\n", v);
	} else {
	    printf("%s is not valid.\n", v);
	}
    }
    return regexecresult;
}

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 ){
	int is_valid_ipaddr_result = is_valid_ipaddr(args[1]);
	if( is_valid_ipaddr_result == 0 ){
	    // 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(args[1]);
	    destination_addr.sin_port = htons(destination_port);
	    if( connect(sock, (struct sockaddr *)&destination_addr, sizeof(destination_addr)) < 0 ){
		printf("Connect error.\n");
		exit(2);
	    }
	    FILE * fp;
	    fp = fdopen(sock, "r+");
	    if( fp == NULL ){
		fprintf(stderr, "fdopen error\n");
	    }
	    else {
		fprintf_request(fp, args[1]);
		fgets_response(fp);
		fclose(fp);
	    }
	    close(sock);
	}
	else {
	    printf("Usage: %s %s\n", args[0], "Destination_IP");
	}
    }
    else {
	printf("Usage: %s $Destination_IP\n", args[0]);
    }
    return 0;
}