#include #include /// @brief Defauly constructor. This is to provide a definition for SmartPointer /// @param port SocketServer::SocketServer() : mListenPort(-1), mIsOkay(false), mSocketFileDescriptor(-1) { } /// @brief This will construct the socket listener. You must then call listen() to listen for connections /// @param port SocketServer::SocketServer(int port) : mListenPort(port), mIsOkay(false), mSocketFileDescriptor(-1) { std::cout << "SocketServer()" << std::endl; int opt=-1; int result; // create socket file descriptor mSocketFileDescriptor = ::socket(AF_INET,SOCK_STREAM,0); if(0==mSocketFileDescriptor)return; // attach socket to port result = ::setsockopt(mSocketFileDescriptor, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); if(result) { close(); return; } // bind socket to network address and port mInternalSocketAddress.sin_family = AF_INET; mInternalSocketAddress.sin_addr.s_addr=INADDR_ANY; mInternalSocketAddress.sin_port = htons(mListenPort); result = ::bind(mSocketFileDescriptor,(struct sockaddr*)&mInternalSocketAddress,sizeof(mInternalSocketAddress)); if(result) { close(); return; } mIsOkay=true; } /// @brief Close down the listener SocketServer::~SocketServer() { std::cout << "~SocketServer" << std::endl; std::cout << "shutdownConnectionReceivers" << std::endl; shutdownConnectionReceivers(); std::cout << "join" << std::endl; join(); // Then join all socket threads std::cout << "close" << std::endl; close(); // close the listener socket std::cout << "~SocketServer, done" << std::endl; } /// @brief Join all threads /// @param void SocketServer::join(void) { for (std::thread& executionThread : mExecutionThreads) { if (executionThread.joinable()) { executionThread.join(); } } } /// @brief Remove object references to the connection receivers. This will force socket threads to exit and close connections void SocketServer::shutdownConnectionReceivers() { mSocketConnectionReceivers.remove(); } /// @brief returns true if we have a valid socket connection otherwise false /// @return bool SocketServer::isOkay(void) { return mIsOkay; } /// @brief This is the listener. It will wait for incoming connections. /// When an incoming connection is received it will create a SocketConnectionReceiver object and call it's threadFunction /// to handle further interactions such as transmitting a file. void SocketServer::listen(void) { while(isOkay()) { std::cout << "Listening on port " << mListenPort << std::endl; int result = ::listen(mSocketFileDescriptor, MAX_CONNECTIONS); if(result) { std::cout << "Error listening on port " << mListenPort << std::endl; close(); return; } struct sockaddr_in internalSocketAddress; socklen_t addressLength = sizeof(internalSocketAddress); int socket = ::accept(mSocketFileDescriptor, (struct sockaddr*)&internalSocketAddress, &addressLength); if(result) { std::cout << "Error accepting connection " << mListenPort << std::endl; close(); return; } mSocketConnectionReceivers.insert(SmartPointer()); SmartPointer &pSocketConnectionReceiver = mSocketConnectionReceivers[mSocketConnectionReceivers.size()-1]; pSocketConnectionReceiver = ::new SocketConnectionReceiver(socket, internalSocketAddress); pSocketConnectionReceiver.disposition(PointerDisposition::Delete); mExecutionThreads.push_back(std::thread(&SocketConnectionReceiver::threadFunction, *pSocketConnectionReceiver, 0)); } } /// @brief Shut down the listener socket /// @param void SocketServer::close(void) { if(-1==mSocketFileDescriptor)return; std::cout << "SocketServer::close, closing socket" << std::endl; ::close(mSocketFileDescriptor); mSocketFileDescriptor=-1; }