void reset_signals() { // Reset the signals to their old action if(sigaction(SIGUSR1, &old_sigusr_action, NULL) == -1) { CRITIC("Can't redirect SIGUSR1 to default handler.", strerror(errno)); } if(sigaction(SIGINT, &old_sigint_action, NULL) == -1) { CRITIC("Can't redirect SIGINT to default handler.", strerror(errno)); } if(sigaction(SIGUSR2, &old_sigthread_action, NULL) == -1) { CRITIC("Can't redirect SIGINT to default handler.", strerror(errno)); } } // reset_signals()
UInt32 RTMFPWriter::headerSize(UInt64 stage) { // max size header = 50 UInt32 size= Util::Get7BitValueSize(id); size+= Util::Get7BitValueSize(stage); if(_stageAck>stage) CRITIC("stageAck ",_stageAck," superior to stage ",stage," on writer ",id); size+= Util::Get7BitValueSize(stage-_stageAck); size+= _stageAck>0 ? 0 : (signature.size()+(flowId==0?2:(4+Util::Get7BitValueSize(flowId)))); return size; }
UInt32 FlowWriter::headerSize(UInt64 stage) { // max size header = 50 UInt32 size= Util::Get7BitValueSize(id); size+= Util::Get7BitValueSize(stage); if(_stageAck>stage) CRITIC("stageAck %s superior to stage %s on flowWriter %s",NumberFormatter::format(_stageAck).c_str(),NumberFormatter::format(stage).c_str(),NumberFormatter::format(id).c_str()); size+= Util::Get7BitValueSize(stage-_stageAck); size+= _stageAck>0 ? 0 : (signature.size()+(flowId==0?2:(4+Util::Get7BitValueSize(flowId)))); return size; }
/************************** *** SIGNAL MANAGEMENT **************************/ void set_signals() { // Redirect SIGUSR1 structure struct sigaction new_sigusr_action; sigemptyset(&new_sigusr_action.sa_mask); new_sigusr_action.sa_handler = SIG_DFL; new_sigusr_action.sa_sigaction = &sigusr_action; new_sigusr_action.sa_flags = SA_SIGINFO; // Redirect SIGINT structure struct sigaction new_sigint_action; sigemptyset(&new_sigint_action.sa_mask); new_sigint_action.sa_handler = SIG_DFL; new_sigint_action.sa_sigaction = &sigint_action; new_sigint_action.sa_flags = SA_SIGINFO; // Redirect SIGUSR2 structure struct sigaction new_sigthread_action; sigemptyset(&new_sigthread_action.sa_mask); new_sigthread_action.sa_handler = SIG_DFL; new_sigthread_action.sa_sigaction = &sigthread_action; new_sigthread_action.sa_flags = SA_SIGINFO; // Redirect signals structure if(sigaction(SIGUSR1, &new_sigusr_action, &old_sigusr_action) == -1) { CRITIC("Can't redirect SIGUSR1 to custom handler.", strerror(errno)); } if(sigaction(SIGUSR2, &new_sigthread_action, &old_sigthread_action) == -1) { CRITIC("Can't redirect SIGUSR2 to custom handler.", strerror(errno)); } if(sigaction(SIGINT, &new_sigint_action, &old_sigint_action) == -1) { CRITIC("Can't redirect SIGINT to custom handler.", strerror(errno)); } } // set_signals()
bool RTMFPCookieComputing::run(Exception& ex) { // First execution is for the DH computing if pDH == null, else it's to compute Diffie-Hellman keys if (!_diffieHellman.initialized()) return _diffieHellman.initialize(ex); // Compute Diffie-Hellman secret _diffieHellman.computeSecret(ex,initiatorKey.data(),initiatorKey.size(),_sharedSecret); if (ex) return false; if (packet.size() > 0) { ex.set(Exception::CRYPTO, "RTMFPCookieComputing already executed"); return false; } // string hex; // DEBUG("Shared Secret : ", Util::FormatHex(_sharedSecret.data(), _sharedSecret.size(), hex)); // It's our key public part int size = _diffieHellman.publicKeySize(ex); if (size<0) { if (!ex) ex.set(Exception::CRYPTO, "DH public key not initialized"); return false; } packet.write7BitLongValue(size+11); UInt32 noncePos = packet.size(); packet.writeRaw(EXPAND_DATA_SIZE("\x03\x1A\x00\x00\x02\x1E\x00")); UInt8 byte2 = DH_KEY_SIZE-size; if(byte2>2) { CRITIC("Generation DH key with less of 126 bytes!"); byte2=2; } packet.write8(0x81); packet.write8(2-byte2); packet.write8(0x0D); packet.write8(0x02); if (size>2000) ERROR("RTMFP diffie hellman public key with an error size key of ",size) // TODO remove this log one time fixed! _diffieHellman.readPublicKey(ex,packet.buffer(size)); packet.write8(0x58); // Compute Keys RTMFP::ComputeAsymetricKeys(_sharedSecret,initiatorNonce.data(),initiatorNonce.size(),packet.data()+noncePos,size+11,decryptKey,encryptKey); waitHandle(); return true; }
void RTMFPWriter::acknowledgment(PacketReader& packet) { UInt64 bufferSize = packet.read7BitLongValue(); // TODO use this value in reliability mechanism? if(bufferSize==0) { // In fact here, we should send a 0x18 message (with id flow), // but it can create a loop... We prefer the following behavior fail("Negative acknowledgment"); return; } UInt64 stageAckPrec = _stageAck; UInt64 stageReaden = packet.read7BitLongValue(); UInt64 stage = _stageAck+1; if(stageReaden>_stage) { ERROR("Acknowledgment received ",stageReaden," superior than the current sending stage ",_stage," on writer ",id); _stageAck = _stage; } else if(stageReaden<=_stageAck) { // already acked if(packet.available()==0) DEBUG("Acknowledgment ",stageReaden," obsolete on writer ",id); } else _stageAck = stageReaden; UInt64 maxStageRecv = stageReaden; UInt32 pos=packet.position(); while(packet.available()>0) maxStageRecv += packet.read7BitLongValue()+packet.read7BitLongValue()+2; if(pos != packet.position()) { // TRACE(stageReaden,"..x"Util::FormatHex(reader.current(),reader.available())); packet.reset(pos); } UInt64 lostCount = 0; UInt64 lostStage = 0; bool repeated = false; bool header = true; bool stop=false; auto it=_messagesSent.begin(); while(!stop && it!=_messagesSent.end()) { RTMFPMessage& message(**it); if(message.fragments.empty()) { CRITIC("RTMFPMessage ",(stage+1)," is bad formatted on fowWriter ",id); ++it; continue; } map<UInt32,UInt64>::iterator itFrag=message.fragments.begin(); while(message.fragments.end()!=itFrag) { // ACK if(_stageAck>=stage) { message.fragments.erase(message.fragments.begin()); itFrag=message.fragments.begin(); ++_ackCount; ++stage; continue; } // Read lost informations while(!stop) { if(lostCount==0) { if(packet.available()>0) { lostCount = packet.read7BitLongValue()+1; lostStage = stageReaden+1; stageReaden = lostStage+lostCount+packet.read7BitLongValue(); } else { stop=true; break; } } // check the range if(lostStage>_stage) { // Not yet sent ERROR("Lost information received ",lostStage," have not been yet sent on writer ",id); stop=true; } else if(lostStage<=_stageAck) { // already acked --lostCount; ++lostStage; continue; } break; } if(stop) break; // lostStage > 0 and lostCount > 0 if(lostStage!=stage) { if(repeated) { ++stage; ++itFrag; header=true; } else // No repeated, it means that past lost packet was not repeatable, we can ack this intermediate received sequence _stageAck = stage; continue; } /// Repeat message asked! if(!message.repeatable) { if(repeated) { ++itFrag; ++stage; header=true; } else { INFO("RTMFPWriter ",id," : message ",stage," lost"); --_ackCount; ++_lostCount; _stageAck = stage; } --lostCount; ++lostStage; continue; } repeated = true; // Don't repeate before that the receiver receives the itFrag->second sending stage if(itFrag->second >= maxStageRecv) { ++stage; header=true; --lostCount; ++lostStage; ++itFrag; continue; } // Repeat message DEBUG("RTMFPWriter ",id," : stage ",stage," repeated"); UInt32 fragment(itFrag->first); itFrag->second = _stage; // Save actual stage sending to wait that the receiver gets it before to retry UInt32 contentSize = message.size() - fragment; // available ++itFrag; // Compute flags UInt8 flags = 0; if(fragment>0) flags |= MESSAGE_WITH_BEFOREPART; // fragmented if(itFrag!=message.fragments.end()) { flags |= MESSAGE_WITH_AFTERPART; contentSize = itFrag->first - fragment; } UInt32 size = contentSize+4; UInt32 availableToWrite(_band.availableToWrite()); if(!header && size>availableToWrite) { _band.flush(); header=true; } if(header) size+=headerSize(stage); if(size>availableToWrite) _band.flush(); // Write packet size-=3; // type + timestamp removed, before the "writeMessage" flush(_band.writeMessage(header ? 0x10 : 0x11,(UInt16)size) ,stage,flags,header,message,fragment,contentSize); header=false; --lostCount; ++lostStage; ++stage; } if(message.fragments.empty()) { if(message.repeatable) --_repeatable; if(_ackCount || _lostCount) { _qos.add(_lostCount / (_lostCount + _ackCount)); _ackCount=_lostCount=0; } delete *it; it=_messagesSent.erase(it); } else ++it; } if(lostCount>0 && packet.available()>0) ERROR("Some lost information received have not been yet sent on writer ",id); // rest messages repeatable? if(_repeatable==0) _trigger.stop(); else if(_stageAck>stageAckPrec || repeated) _trigger.reset(); }
void FlowWriter::beginTransaction() { if(_transaction) CRITIC("beginTransaction seems have been called without have call a endTransaction after") _transaction=true; }
/************************** *** MAIN **************************/ int main(int argc, char **argv) { /* ** INIT SIGNALS */ set_signals(); /* ** INIT / SETTINGS VARS */ client_count = 0; int port; /* ** ARGS MANAGEMENT */ if(argc != 3 || !is_number(argv[2])) { CRITIC("Can't launch with these arguments.", "\tUsage: ./executable <directory> <port>"); } port = atoi(argv[2]); if(port > 65535 || port < 1024) { CRITIC("Can't launch with this port.", "\tPort must be between 1024 and 65535."); } switch(check_directory(argv[1])) { case 0: strncpy(dir_path, argv[1], MAX_PATH - 1); if(dir_path[strlen(dir_path) - 1] != '/') strncat(dir_path, "/", 1); dir_path[MAX_PATH - 1] = '\0'; break; case 1: // Ask to create directory INFO("Directory does not exist, do you want to create it? (yes/no)"); char buffer[MAX_BUF]; fgets(buffer, MAX_BUF, stdin); // If user said yes if(strcmp(buffer, "YES\n") == 0 || strcmp(buffer, "yes\n") == 0) { // Create directory and set full path create_directory(argv[1]); strncpy(dir_path, argv[1], MAX_PATH - 1); if(dir_path[strlen(dir_path) - 1] != '/') strncat(dir_path, "/", 1); dir_path[MAX_PATH - 1] = '\0'; } else { CRITIC("Can't launch with this directory.", "\tDirectory must exists."); } break; case 2: CRITIC("ERRNO ON STAT", strerror(errno)); break; case 3: CRITIC("Can't launch with this directory.", "\tThe given path is not a directory."); break; case 4: CRITIC("Can't launch with this directory.", "\tYou don't have the required permissions."); default: CRITIC("Something impossible happened!", "Wrong switch value"); break; } // INIT MUTEX if(pthread_mutex_init(&client_count_mutex, NULL) != 0) { CRITIC("Can't create client mutex", "MUTEX INIT ERROR"); } if(pthread_mutex_init(&client_list_mutex, NULL) != 0) { CRITIC("Can't create list mutex", "MUTEX INIT ERROR"); } /* ** SERVER MANAGEMENT */ return start_server(port); } // int main(int, char**)
/************************** *** SERVER MANAGEMENT **************************/ int start_server(int port) { // Server socket int main_socket = socket(AF_INET, SOCK_STREAM, 0); // Set socket options to avoid waiting time int opt_val = 1; if(setsockopt(main_socket, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof(opt_val)) < 0) { CRITIC("Error while setting socket", strerror(errno)); } // Verify socket if(main_socket < 0) { CRITIC("Error while creating socket", strerror(errno)); } // Setting the sockaddr_in struct struct sockaddr_in serv_addr; serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = INADDR_ANY; serv_addr.sin_port = htons(port); // Trying to bind the socket to the interface if(bind(main_socket, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { CRITIC("Error while binding socket", strerror(errno)); } // Liten on socket if(listen(main_socket, MAX_PENDING) < 0) { CRITIC("Error while listening socket", strerror(errno)); } // Sockets set fd_set in_desc; // Timeout setting struct timeval timeout_set; timeout_set.tv_sec = TIMEOUT_V; timeout_set.tv_usec = 1000 * TIMEOUT_V; INFO("Server started"); while(server_listening) { // Setting the file desciptors set FD_ZERO(&in_desc); FD_SET(STDIN_FILENO, &in_desc); FD_SET(main_socket, &in_desc); // Select the socket to watch if(select(main_socket + 1, &in_desc , NULL , NULL , &timeout_set) < 0 && (errno != EINTR)) { if(errno == EINTR) { WARNING("Select interupted", "No error is server is disconnecting"); break; } else { CRITIC("Error while selecting sockets", strerror(errno)); } } if(!server_listening) break; // If server socket changed state if(FD_ISSET(main_socket, &in_desc)) { INFO("HERE"); // Creating new client struct client_s *new_client = malloc(sizeof(struct client_s)); new_client->client_addr_len = sizeof(struct sockaddr_in); // Accepting new client if ((new_client->client_socket = accept(main_socket, (struct sockaddr *)&new_client->client_addr, &new_client->client_addr_len)) < 0) { if(errno == EINTR) { WARNING("Accept interupted", "No error is server is disconnecting"); break; } else { CRITIC("Error while trying to accept new client", strerror(errno)); } } INFO("Accepting new client"); // Creating the client listening thread int ret; if((ret = pthread_create(&new_client->client_thread, NULL, client_thread, &new_client->client_socket)) != 0) { // In case of error if(ret == EAGAIN) { ERROR("Can't create new client thread", "Insufficient resources"); } else { ERROR("Can't create new client thread", "Unknown"); } if(close(new_client->client_socket) < 0) { ERROR("Can't close new client socket", strerror(errno)); } free(new_client); } else { // Adding the client to the list pthread_mutex_lock(&client_list_mutex); new_client->next = clients_list; new_client->prev = NULL; if(clients_list) { clients_list->prev = new_client; } clients_list = new_client; pthread_mutex_unlock(&client_list_mutex); pthread_mutex_lock(&client_count_mutex); ++client_count; pthread_mutex_unlock(&client_count_mutex); } } // If stdin changed state if(FD_ISSET(STDIN_FILENO, &in_desc)) { INFO("ECIT"); char buffer[MAX_BUF]; fgets(buffer, MAX_BUF, stdin); if(strcmp(buffer, "exit\n") == 0) { INFO("Server asked to quit"); server_listening = server_kill(); } } } INFO("Close main socket"); if(close(main_socket) < 0) { ERROR("Can't close server socket", strerror(errno)); } INFO("QUIT"); return EXIT_SUCCESS; } // int start_server(int)