/* * Copyright (C) 2017 Ortega Froysa, Nicolás * Author: Ortega Froysa, Nicolás * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU Lesser 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program. If not, see * . */ #include "neocomm/connectivity.h" #include "iconnectivity.h" #include "ierror.h" #include #include #include #include #include #include #include #include #include /* * This is an internal OS specific structure for nodes. */ struct NeoComm_directory_node { int in_use; struct sockaddr_in addr; int sockfd; pthread_t thread; int open_directory; unsigned int connections; unsigned int max_connections; }; static struct NeoComm_directory_node *node_list; static unsigned int max_nodes; static unsigned int num_nodes; static int run; static int sockfd; static pthread_t accept_thread; /* * This is a protected bind function that is not accessible as a public * interface. */ int NeoComm_bind(const unsigned short port) { struct sockaddr_in serv_addr; sockfd = socket(AF_INET, SOCK_STREAM, 0); if(sockfd < 0) { /* * This declaration is here because if you put it at `default:' then * it complains about the line being a declaration and not a * statement. */ char error_msg[128]; switch(errno) { case EACCES: NeoComm_error("Insufficient privileges"); break; case ENOBUFS: NeoComm_error("Insufficient resources available"); break; case ENOMEM: NeoComm_error("Insufficient memory to open socket"); break; default: snprintf(error_msg, 128, "Failed to initiate socket with errno `%d'", errno); NeoComm_error(error_msg); break; } return 0; } bzero((char*) &serv_addr, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(port); serv_addr.sin_addr.s_addr = INADDR_ANY; if(bind(sockfd, (struct sockaddr*) &serv_addr, sizeof(serv_addr)) < 0) { char error_msg[128]; // same as before switch(errno) { case EADDRINUSE: NeoComm_error("Address in use"); break; case EADDRNOTAVAIL: NeoComm_error("Address unavailable on system"); break; case EAFNOSUPPORT: NeoComm_error("Unsupported address family for socket"); break; case EALREADY: NeoComm_error("Assignment request already exists for socket"); break; case EINVAL: NeoComm_error("Socket already bound"); break; case ENOBUFS: NeoComm_error("Insufficient resources"); break; case EACCES: NeoComm_error("Insufficient privileges"); break; default: snprintf(error_msg, 128, "Failed to bind to socket with errno `%d'", errno); NeoComm_error(error_msg); break; } return 0; } listen(sockfd, 5); return 1; } void *NeoComm_connect_manager() { while(run) { int cli_sockfd; struct sockaddr_in cli_addr; socklen_t size_cli_addr = sizeof(cli_addr); cli_sockfd = accept(sockfd, (struct sockaddr*) &cli_addr, &size_cli_addr); if(cli_sockfd < 0) { NeoComm_error("Error on accept"); continue; } // TODO: Add the new connection and have it listen on a new thread. } pthread_exit(NULL); } int NeoComm_init_directory(const unsigned int max_num_nodes, const unsigned short portnum) { if(max_num_nodes == 0) { NeoComm_error("Insufficient number of nodes"); return 0; } if(!NeoComm_bind(portnum)) return 0; node_list = calloc(max_num_nodes, sizeof(struct NeoComm_directory_node)); if(!node_list) { NeoComm_error("Failed to allocate memory to directory node list"); return 0; } max_nodes = max_num_nodes; num_nodes = 0; for(unsigned int i = 0; i < max_nodes; ++i) node_list[i].in_use = 0; run = 1; int err = pthread_create(&accept_thread, NULL, NeoComm_connect_manager, NULL); if(err != 0) { NeoComm_error("Insufficient resources to create thread"); return 0; } return 1; } void NeoComm_shutdown_directory() { run = 0; void *res; for(unsigned int i = 0; i < num_nodes; ++i) { // in case the threads are still running, we wait pthread_join(node_list[i].thread, &res); close(node_list[i].sockfd); } pthread_join(accept_thread, &res); close(sockfd); pthread_exit(NULL); }