Example #1
0
/*
 *
 *  Function: main()
 *
 */
int
main(int argc, char *argv[])
{
    char *program_name = argv[0];
    int optc;			/* option */
    int sock_fd;		/* socket descriptor for a connection */
    char *server_name;		/* Name (or IP address) of the server */
    sa_family_t family;		/* protocol family */
    char *portnum;		/* port number in string representation */
    struct addrinfo hints;	/* hints for getaddrinfo() */
    struct addrinfo *res;	/* pointer to addrinfo structure */
    int err;			/* return value of getaddrinfo */
    int on;			/* on/off at an socket option */
    int recvbuf_size;		/* size of the receive buffer */
    int sock_optlen;		/* size of the result parameter */
    char *recvbuf;		/* pointer to the received message */
    ssize_t recvbyte_size;	/* size of the receive byte */
    time_t start_time;		/* time when the timer is start */
    double timeout = 0.0;	/* timeout */
    int background = 0;		/* If non-zero work in the background */
    size_t window_scaling = 0;	/* if non-zero, in the window scaling mode */

    debug = 0;

    /* Initilalize the client information */
    family = PF_UNSPEC;
    server_name = NULL;
    portnum = NULL;
    
    /* Retrieve the options */
    while ((optc = getopt(argc, argv, "S:f:p:t:bwdh")) != EOF) {
	switch (optc) {
	    case 'S':
		server_name = strdup(optarg);
		if (server_name == NULL) {
		    fprintf(stderr, "strdup() failed.");
		    exit(EXIT_FAILURE);
		}
		break;

	    case 'f':
		if (strncmp(optarg, "4", 1) == 0)
		    family = PF_INET;	/* IPv4 */
		else if (strncmp(optarg, "6", 1) == 0)
		    family = PF_INET6;	/* IPv6 */
		else {
		    fprintf(stderr, "protocol family should be 4 or 6.\n");
		    usage(program_name, EXIT_FAILURE);
		}
		break;

	    case 'p':
		{
		    unsigned long int tmp;
		    tmp = strtoul(optarg, NULL, 0);
		    if (tmp < PORTNUMMIN || PORTNUMMAX < tmp) {
			fprintf(stderr, "The range of port is from %u to %u\n",
				PORTNUMMIN, PORTNUMMAX);
			usage(program_name, EXIT_FAILURE);
		    }
		    portnum = strdup(optarg);
		}
		break;

	    case 't':
		timeout = strtod(optarg, NULL);
		if (timeout < 0) {
		    fprintf(stderr, "Timeout value is bigger than 0\n");
		    usage(program_name, EXIT_FAILURE);
		}
		break;

	    case 'b':
		background = 1;
		break;

	    case 'w':
		window_scaling = 1;
		break;

	    case 'd':
		debug = 1;
		break;

	    case 'h':
		usage(program_name, EXIT_SUCCESS);
		break;

	    default:
		usage(program_name, EXIT_FAILURE);
	}
    }

    /* Check the server name is specified. */
    if (server_name == NULL) {
	fprintf(stderr, "server name isn't specified.\n");
	usage(program_name, EXIT_FAILURE);
    }

    /* Check the family is specified. */
    if (family == PF_UNSPEC) {
	fprintf(stderr, "protocol family isn't specified.\n");
	usage(program_name, EXIT_FAILURE);
    }

    /* Check the port number is specified. */
    if (portnum == NULL) {
	fprintf(stderr, "port number isn't specified.\n");
	usage(program_name, EXIT_FAILURE);
    }

    /* At first, SIGHUP are Ignored. */
    handler.sa_handler = set_signal_flag;
    handler.sa_flags = 0;
    if (sigfillset(&handler.sa_mask) < 0)
	fatal_error("sigfillset()");
    if (sigaction(SIGHUP, &handler, NULL) < 0)
	fatal_error("sigaction()");

    /* Set the hints to addrinfo() */
    memset(&hints, '\0', sizeof(struct addrinfo));
    hints.ai_family = family;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;

    /* Translate the network and service information of the client */
    err = getaddrinfo(server_name, portnum, &hints, &res);
    if (err) {
	fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(err));
	exit(EXIT_FAILURE);
    }
    if (res->ai_next) {
	fprintf(stderr, "getaddrinfo(): multiple address is found.");
	exit(EXIT_FAILURE);
    }

    /* Create a socket */
    sock_fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
    if (sock_fd < 0)
	fatal_error("socket()");

    /* Enable to reuse the socket */
    on = 1;
    if (setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int)))
	fatal_error("setsockopt()");

    /* Maximize socket buffer, when window scaling mode */
    if (window_scaling)
	maximize_sockbuf(sock_fd);

    /* Connect to the server */
    if (connect(sock_fd, res->ai_addr, res->ai_addrlen) < 0)
	fatal_error("connect()");

    freeaddrinfo(res);
    free(server_name);
    
    /* If -b option is specified, work as a daemon */
    if (background)
	if (daemon(0, 0) < 0)
	    fatal_error("daemon()");

    /* Get the size of receive buffer */
    sock_optlen = sizeof(recvbuf_size);
    if (getsockopt(sock_fd, SOL_SOCKET, SO_RCVBUF, &recvbuf_size, &sock_optlen) < 0)
	fatal_error("getsockopt()");
    if (debug)
	fprintf(stderr, "recvbuf size of socket(%d) is %d\n", sock_fd, recvbuf_size);

    /* Prepare a buffer to receive bytes */
    recvbuf = (char *)malloc(recvbuf_size);
    if (recvbuf == NULL) {
	fprintf(stderr, "malloc() is failed.\n");
	exit(EXIT_FAILURE);
    }

    /*
     * Loop for receiving data from the server
     */
    start_time = time(NULL);
    handler.sa_handler = set_signal_flag;
    if (sigaction(SIGHUP, &handler, NULL) < 0)
	fatal_error("sigaction()");
    for(;;) {
	recvbyte_size = recv(sock_fd, recvbuf, recvbuf_size, 0);
	if (recvbyte_size < (ssize_t)0) {
	    if (catch_sighup)
		break;
	    else
		fatal_error("sendto()");
	}
	else if (recvbyte_size == (ssize_t)0)
	    break;

	/* client timeout */
	if (timeout) 
	    if (timeout < difftime(time(NULL), start_time)) 
		break;
	
	/* Catch SIGHUP */
	if (catch_sighup)
	    break;
    }
    if (close(sock_fd) < 0)
	fatal_error("close()");

    free(recvbuf);

    if (debug)
	fprintf (stderr, "Client is finished without any error\n");

    exit(EXIT_SUCCESS);
}
Example #2
0
/*
 * Function: create_listen_socket()
 * 
 * Descripton:
 *  Create a socket to listen for connections on a socket.
 *  The socket discripter is stored info_p->listen_sd.
 *
 * Argument:
 *  info_p:	pointer to a server infomation
 *
 * Return value:
 *  None
 */
void
create_listen_socket(struct server_info *info_p)
{
    int on;			/* on/off at an socket option */
    int err;			/* return value of getaddrinfo */
    struct addrinfo hints;	/* hints for getaddrinfo() */
    struct addrinfo *res;	/* pointer to addrinfo */

    /* Set the hints to addrinfo() */
    memset(&hints, '\0', sizeof(struct addrinfo));
    hints.ai_family = info_p->family;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;
    
    /* Translate the network and service information of the server */
    err = getaddrinfo(NULL, info_p->portnum, &hints, &res);
    if (err) {
	fprintf(stderr, "getaddrinfo(): %s\n", gai_strerror(err));
	exit(EXIT_FAILURE);
    }
    if (res->ai_next) {
	fprintf(stderr, "getaddrinfo(): multiple address is found.");
	exit(EXIT_FAILURE);
    }

    /* Create a socket for listening. */
    info_p->listen_sd = socket(res->ai_family,
	    res->ai_socktype, res->ai_protocol);
    if (info_p->listen_sd < 0)
	fatal_error("socket()");

#ifdef IPV6_V6ONLY
    /* Don't accept IPv4 mapped address if the protocol family is IPv6 */
    if (res->ai_family == PF_INET6) {
	on = 1;
	if (setsockopt(info_p->listen_sd,
		    IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(int))) 
	    fatal_error("setsockopt()");
    }
#endif

    /* Enable to reuse the socket */
    on = 1;
    if (setsockopt(info_p->listen_sd,
		SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int))) 
	fatal_error("setsockopt()");

    /* Disable the Nagle algorithm, when small sending mode */
    if (info_p->small_sending) {
	on = 1;
	if (setsockopt(info_p->listen_sd,
		    IPPROTO_TCP, TCP_NODELAY, &on, sizeof(int)))
	    fatal_error("setsockopt()");
	if (debug) {
	    fprintf(stderr, "small sending[on]\n");
	}
    }

    /* Maximize socket buffer, when window scaling mode */
    if (info_p->window_scaling)
	maximize_sockbuf(info_p->listen_sd);

    /* Bind to the local address */
    if (bind(info_p->listen_sd, res->ai_addr, res->ai_addrlen) < 0) 
	fatal_error("bind()");
    freeaddrinfo(res);

    /* Start to listen for connections */
    if (listen(info_p->listen_sd, 5) < 0)
	fatal_error("listen()");
}