Shammer's Philosophy

My private adversaria

HTTP Client ver 0.2

HTTP Client ver 0.1 - Shammerismの内容に、nslookup sample C version - Shammerismの内容を追加してみた。

#include <ctype.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;
    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];
	int regexecresult;
	regexecresult = regexec(&preg, v, nmatch, pmatch, 0);
	if( regexecresult == 0 ){
	    printf("%s is valid.\n", v);
	    return 0;
	} else {
	    printf("%s is not valid.\n", v);
	    return -1;
	}
    }
}

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 {
	    // Check whether args[1] is hostname or not.
	    struct addrinfo hints, *res, *res0;
	    int error;
	    void *ptr;

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

	    // Get addrinfor and error check
	    error = getaddrinfo(args[1], NULL, &hints, &res0);
	    if (error) {
		errx(1, "%s", gai_strerror(error));
	    }
	    
	    // Display addrinfo contents
	    int i = 0;
	    for (res = res0 ; res ; res = res->ai_next) {
		printf("Hostname %s 's IP address is :", args[1]);
		switch(res->ai_family){
		case AF_INET:
		    ptr = &(((struct sockaddr_in *)res->ai_addr)->sin_addr);
		    inet_ntop(res->ai_family, ptr, destination_ip, sizeof(destination_ip));
		    break;
		case AF_INET6:
		    ptr = &(((struct sockaddr_in6 *)res->ai_addr)->sin6_addr);
		    inet_ntop(res->ai_family, ptr, destination_ip, sizeof(destination_ip));
		    break;
		}
		i++;
	    }
	    freeaddrinfo(res0);
	}
	if( valid_argument == 0 ){
	    // HTTP Client
	    int sock, bytes_read;
	    struct sockaddr_in destination_addr;
	    unsigned short destination_port = 80;
	    char response[256];
	    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.\n");
		exit(2);
	    }
	    send( sock, "GET / HTTP/1.1\r\n", strlen("GET / HTTP/1.1\r\n"), 0);
	    send( sock, "Host: ", strlen("Host: "), 0);
	    send( sock, destination_ip, strlen(destination_ip), 0);
	    send( sock, "\r\n\r\n", strlen("\r\n\r\n"), 0);
	    while(1) {
		bzero(response, sizeof(response));
		bytes_read = recv(sock, response, sizeof(response), 0);
		if( bytes_read > 0 ){
		    printf("%s", response);
		}
		else {
		    break;
		}
	    }
	    close(sock);
	}
	else {
	    printf("Usage: %s %s\n", args[0], "Destination_IP");
	    printf("       %s %s\n", args[0], "Destination_Hostname");
	}
    }
    return 0;
}

かなり長くなったぞ。コンパイル通ることは確認したが、ちゃんと動作するだろうか。名前解決の処理、やっぱり関数にすべきだろうか。ただ、文字列をやり取りすることになるから正直少し苦手。こういうのを書くより先にポインタと文字列をしっかり抑えるべきだろうか。