socket_init.c 2.81 KB
/**
 * \file
 *
 * \author	Georg Hopp
 *
 * \copyright
 * Copyright © 2014 Georg Hopp
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#define _POSIX_C_SOURCE 200112L

#include <stdlib.h>     // for atoi() and exit()
#include <errno.h>      // for errno
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>

#include "tr/socket.h"
#include "tr/logger.h"

int
TR_socketInit(TR_Socket this, TR_socketAction_fptr action)
{
    struct addrinfo   hint;
    struct addrinfo * info, * current_info;
	char              port_str[6];
	int               code;

    hint.ai_socktype  = this->type;
    hint.ai_flags     = this->flags;
    hint.ai_family    = AF_UNSPEC;
    hint.ai_protocol  = 0;
    hint.ai_addrlen   = 0;
    hint.ai_canonname = NULL;
    hint.ai_addr      = NULL;
    hint.ai_next      = NULL;

    sprintf(port_str, "%u", this->port);
    code = getaddrinfo(this->host, port_str, &hint, &info);
    if (0 != code) {
        // TODO error handling...
		puts(gai_strerror(code));

        return FALSE;
    }

    current_info = info;
    for (
			current_info = info;
			current_info;
			current_info = current_info->ai_next)
	{
        this->handle = socket(
                current_info->ai_family,
                current_info->ai_socktype,
                current_info->ai_protocol);

        if (-1 == this->handle) {
            continue;
        }

		this->addrlen = current_info->ai_addrlen;
		memcpy(&(this->addr), current_info->ai_addr, this->addrlen);

		if (! action || 0 == action(this)) {
			break; // success / open and bind or open and connect...
		}

		close(this->handle);
		this->handle = -1;
    }

    if (NULL != current_info) {
		int reUse = 1; //! \todo make this configurable
		//int flags = fcntl(this->handle, F_GETFL, 0);

		//fcntl(this->handle, F_SETFL, flags | O_NONBLOCK);
		if (current_info->ai_canonname) {
			this->cname[TR_MAX_CNAME-1] = 0;
			strncpy(this->cname, current_info->ai_canonname, TR_MAX_CNAME-1);
		}
		this->fin_state = TR_FIN_NO;

		//! Make the socket REUSE a TIME_WAIT socket
		setsockopt(this->handle, SOL_SOCKET, SO_REUSEADDR, &reUse, sizeof(reUse));
	}

	freeaddrinfo(info);

	return TRUE;
}

// vim: set ts=4 sw=4: