/*----------------------------------------------------------------------------*/ udps_err_t udps_accept(void) { pid_t pid; udps_err_t rc; /* Initialize processes controller. */ LOG_SRV(UDPS_LOG_DEBUG, ("Initializing processes controller...")); rc = udps_lock_init(); if(rc != UDPS_OK) { LOG_SRV(UDPS_LOG_EMERG, ("Could not initialize processes " "controller")); udps_close(); return rc; } /* Initialize message queue. */ LOG_SRV(UDPS_LOG_DEBUG, ("Initializing message queue...")); rc = udps_mq_init(); if(rc != UDPS_OK) { LOG_SRV(UDPS_LOG_EMERG, ("Could not initialize message queue")); udps_close(); return rc; } /* Initialize processes pool. */ LOG_SRV(UDPS_LOG_DEBUG, ("Initializing processes pool...")); rc = udps_pool_init(srv.nclients, udps_client_handler); if(rc != UDPS_OK) { LOG_SRV(UDPS_LOG_EMERG, ("Could not initialize processes pool")); udps_close(); return rc; } /* Launch Receiver and PoolUpdater processes. */ pid = fork(); if(pid > 0) { /* Parent. */ srv.pUpdater = 0; rc = udps_receive(); } else if(pid == 0) { /* Child. */ srv.pUpdater = 1; for(;;) { sleep(1); rc = udps_pool_update(); if(rc != UDPS_OK) { LOG_SRV(UDPS_LOG_ALERT, ("Unable to update processes pool")); } } } else { LOG_POOL(UDPS_LOG_CRIT, ("Unable to fork Receiver/PoolUpdater" "processes")); return UDPS_ERR_FORK; } return UDPS_OK; }
void udps_request(TCPIPS* tcpips, IPC* ipc) { if (!tcpips->connected) { error(ERROR_NOT_ACTIVE); return; } switch (HAL_ITEM(ipc->cmd)) { case IPC_OPEN: if (ipc->param2 == LOCALHOST) udps_listen(tcpips, ipc); else udps_connect(tcpips, ipc); break; case IPC_CLOSE: udps_close(tcpips, ipc->param1); break; case IPC_READ: udps_read(tcpips, ipc->param1, (IO*)ipc->param2); break; case IPC_WRITE: udps_write(tcpips, ipc->param1, (IO*)ipc->param2); break; case IPC_FLUSH: udps_flush(tcpips, ipc->param1); break; default: error(ERROR_NOT_SUPPORTED); } }
/** * Handle SIGINT signal. * @param[in] signo */ static void udps_signal_handler(int signo) { (void)signo; LOG_MAIN(UDPS_LOG_NOTICE, ("Signal received: %s (%d). Closing UDP server", strsignal(signo), signo)); udps_close(); exit(EXIT_SUCCESS); }
/*----------------------------------------------------------------------------*/ int main(int argc, char *argv[]) { ushort port; uchar nclients; udps_err_t rc; /* Check server initialization arguments. */ if(argc != 3) { udps_print_usage(argv[0]); } /* Load configuration. */ port = atoi(argv[1]); nclients = atoi(argv[2]); /* Handle signals. * SIGINT = When the user types the INTR character (normally C-c). * SIGTERM = Generic signal used to cause program termination. */ signal(SIGINT, udps_signal_handler); signal(SIGTERM, NULL); /* Initialize. */ rc = udps_init(port, nclients); if(rc != UDPS_OK) { LOG_MAIN(UDPS_LOG_EMERG, ("Unable to initialize UDP server")); exit(EXIT_FAILURE); } /* Accept. */ rc = udps_accept(); if(rc != UDPS_OK) { LOG_MAIN(UDPS_LOG_EMERG, ("Unable to start accepting")); exit(EXIT_FAILURE); } /* Close. */ udps_close(); return EXIT_SUCCESS; }
/*----------------------------------------------------------------------------*/ udps_err_t udps_init(ushort port, uchar nclients) { struct sockaddr_in srvaddr; socklen_t srvlen; int reuse; struct rlimit rlp; /* Setup internal configurations. */ memset(&srv, 0, sizeof(srv)); srv.port = port; srv.nclients = nclients; /* Setup file limits. */ if(getrlimit(RLIMIT_NOFILE, &rlp) != 0) { LOG_SRV(UDPS_LOG_EMERG, ("Could not get RLIMIT_NOFILE: %s (%d)", strerror(errno), errno)); return UDPS_ERR_GET_RLIMIT; } rlp.rlim_cur = UDPS_RLIMIT_NOFILE; if(setrlimit(RLIMIT_NOFILE, &rlp) != 0) { LOG_SRV(UDPS_LOG_EMERG, ("Could not set RLIMIT_NOFILE: %s (%d)", strerror(errno), errno)); return UDPS_ERR_SET_RLIMIT; } /* Create UDP communication endpoint. * AF_INET = Internet domain sockets. * SOCK_STREAM = Byte-stream socket. */ LOG_SRV(UDPS_LOG_DEBUG, ("Creating UDP socket...")); srv.udpfd = socket(AF_INET, SOCK_DGRAM, 0); if(srv.udpfd < 0) { LOG_SRV(UDPS_LOG_EMERG, ("Unable to create UDP communication endpoint: " "%s (%d)", strerror(errno), errno)); return UDPS_ERR_CREATE_UDP_SOCKET; } LOG_SRV(UDPS_LOG_DEBUG, ("UDP socket created: %d", srv.udpfd)); /* Create server address. * INADDR_ANY = the socket will be bound to all local interfaces. */ memset(&srvaddr, 0, sizeof(srvaddr)); srvaddr.sin_family = AF_INET; srvaddr.sin_addr.s_addr = htonl(INADDR_ANY); srvaddr.sin_port = htons(srv.port); /* Allow reuse of local addresses. * SOL_SOCKET = Manipulate the socket-level options. * SO_REUSEADDR = Indicates that the rules used in validating addresses * supplied in a bind() call should allow reuse of local * addresses. */ reuse = 1; if(setsockopt(srv.udpfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) != 0) { LOG_SRV(UDPS_LOG_EMERG, ("Unable to set address as reusable: %s (%d)", strerror(errno), errno)); return UDPS_ERR_SET_ADDR_REUSABLE; } /* Bind UDP endpoint to server address. */ LOG_SRV(UDPS_LOG_DEBUG, ("Binding UDP socket...")); if(bind(srv.udpfd, (struct sockaddr*)&srvaddr, sizeof(srvaddr)) < 0) { LOG_SRV(UDPS_LOG_EMERG, ("Unable to bind server socket with its " "address: %s (%d)", strerror(errno), errno)); udps_close(); return UDPS_ERR_BIND_UDP_SOCKET; } /* Check sockname. */ LOG_SRV(UDPS_LOG_DEBUG, ("Checking sockname...")); srvlen = sizeof(srvaddr); if((getsockname(srv.udpfd, (struct sockaddr*)&srvaddr, &srvlen) < 0) || (srvlen != sizeof(srvaddr))) { LOG_SRV(UDPS_LOG_EMERG, ("Invalid server socket address length: " "%u != %lu", srvlen, sizeof(srvaddr))); udps_close(); return UDPS_ERR_INVALID_UDP_SOCKET; } /* Check address family. */ LOG_SRV(UDPS_LOG_DEBUG, ("Checking address family...")); if(srvaddr.sin_family != AF_INET) { LOG_SRV(UDPS_LOG_EMERG, ("Invalid server socket family: != AF_INET")); udps_close(); return UDPS_ERR_INVALID_UDP_SOCKET; } /* Initialize. */ LOG_SRV(UDPS_LOG_NOTICE, ("Init UDP => udpServer.udpfd: %d " "- port: %u", srv.udpfd, srv.port)); return UDPS_OK; }