/*******************************************************************************/
/*                                                                             */
/*  Copyright 2004 Pascal Gloor                                                */
/*                                                                             */
/*  Licensed under the Apache License, Version 2.0 (the "License");            */
/*  you may not use this file except in compliance with the License.           */
/*  You may obtain a copy of the License at                                    */
/*                                                                             */
/*     http://www.apache.org/licenses/LICENSE-2.0                              */
/*                                                                             */
/*  Unless required by applicable law or agreed to in writing, software        */
/*  distributed under the License is distributed on an "AS IS" BASIS,          */
/*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   */
/*  See the License for the specific language governing permissions and        */
/*  limitations under the License.                                             */
/*                                                                             */
/*******************************************************************************/


#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/param.h>
#include <fcntl.h>
#include <sys/time.h>
#include <inttypes.h>

#include <p_defs.h>
#include <p_socket.h>


/*  init the listening socket */
int p_socket_start(struct config_t *config)
{
	struct sockaddr_in sockaddr;
	struct timeval timeout;

	timeout.tv_sec = 0;
	timeout.tv_usec = 100000;

	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port   = htons(config->port);
	sockaddr.sin_addr.s_addr = config->ip;

	if ( ( config->sock = socket(PF_INET, SOCK_STREAM, 0) ) == -1 )
	{
		#ifdef DEBUG
		printf("DEBUG: failed to init socket\n");
		#endif
		return -1;
	}
	#ifdef DEBUG
	else { printf("DEBUG: socket() ok\n"); }
	#endif

	if ( setsockopt(config->sock, SOL_SOCKET, SO_REUSEADDR, "1", sizeof(int)) == -1 )
	{
		#ifdef DEBUG
		printf("DEBUG: failed to setsockopt() SO_REUSEADDR\n");
		#endif
		return -1;
	}
	#ifdef DEBUG
	else { printf("DEBUG: setsockopt() (SO_REUSEADDR) ok\n"); }
	#endif

	if ( ( setsockopt(config->sock, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) ) == -1 )
	{
		#ifdef DEBUG
		printf("DEBUG: failed to setsockopt() SO_SNDTIMEO\n");
		#endif
		return -1;
	}
	#ifdef DEBUG
	else { printf("DEBUG: setsockopt() (SO_SNDTIMEO) ok\n"); }
	#endif


	if ( ( setsockopt(config->sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)) ) == -1 )
	{
		#ifdef DEBUG
		printf("DEBUG: failed to setsockopt() SO_RCVTIMEO\n");
		#endif
		return -1;
	}
	#ifdef DEBUG
	else { printf("DEBUG: setsockopt() (SO_RCVTIMEO) ok\n"); }
	#endif

	if ( fcntl(config->sock, F_SETFL, O_NONBLOCK) == -1 )
	{
		#ifdef DEBUG
		printf("DEBUG: failed to fcntl() O_NONBLOCK\n");
		#endif
		return -1;
	}
	#ifdef DEBUG
	else { printf("DEBUG: fcntl() (O_NONBLOCK) ok\n"); }
	#endif

	if ( bind(config->sock, (struct sockaddr*)&sockaddr, sizeof(sockaddr)) == -1 )
	{
		#ifdef DEBUG
		printf("DEBUG: failed to bind socket\n");
		#endif
		return -1;
	}
	#ifdef DEBUG
	else { printf("DEBUG: bind() ok\n"); }
	#endif

	if ( listen(config->sock, 10) == -1 )
	{
		#ifdef DEBUG
		printf("DEBUG: failed to listen() socket\n");
		#endif
		return -1;
	}
	#ifdef DEBUG
	else { printf("DEBUG: listen() ok\n"); }
	#endif

	return 0;
}

/* check for new peers */
int p_socket_accept(struct config_t *config)
{
	int sock;
	struct sockaddr_in sockaddr;
	unsigned int addrlen = sizeof(sockaddr);

	if ( ( sock = accept(config->sock, (struct sockaddr*)&sockaddr, &addrlen) ) == -1 )
	{
		return -1;
	}
	return sock;
}