Пример #1
0
//Starts the server and listens for connections
void Server::start(){

	//check if directory exists
	//If it doesn't , try to create the directory

	char temp[1024];

	//Get address info purposes
	struct sockaddr_storage otherAddr, otherAddr2;		//Connectors address information
	socklen_t otherAddrLen, otherAddrLen2;
	int rv;
	int i;

	//Socket purposes
	int newfd;
	int newfd2;

	//port numbers
	unsigned short dataPort;

	//Handling child processes
	struct sigaction sa;

	//Char buffers
	char buffer[DATA_SIZE];

	//String vector
	vector<string> tokens;

	//extra string(s)
	string errMsg = INVCOM;


	//Copy the string into character array
	//since chdir() takes char * as argument
	strncpy( temp, rootDir.c_str() , sizeof(temp) );
	temp[ sizeof(temp) - 1 ] = 0;

	//Check if directory is valid
	//If no directory create one
	if( !validDir(temp) ){

		if( mkdir(temp, 0777) != 0 ){
			perror("mkdir");
			exit(1);
		}

	}

	//change directory
	//call chdir()
	if(chdir(temp) != 0){
		//If chdir fails
		perror("chdir");
		exit(1);
	}

	if ( !getPWD() ){
		cout << "Unable to get cwd" << endl;
		exit(1);
	}

	//We have now changed the program's pwd to root directory 
	//Now create a socket and bind to the control port and start listening
	//for connections

	cs = controlSock = createSocket( controlPort);
	if(verbose)
		cout << "Control socket created" << endl;

	ds = dataSock = createSocket("0");
	if(verbose)
		cout << "Data socket created" << endl;

	dataPort = getPort(dataSock);

	//Now we have successfully created the socket 
	//and bound it to the control port
	//Start listening for connections
	//Entering the listening loop

	if ( listen (controlSock , BACKLOG) != 0 ) {
		perror("listen");
		close(controlSock);
		exit(1);
	}

	if( listen(dataSock , BACKLOG) != 0 ){
		perror("listen");
		close(dataSock);
		exit(1);
	}

	//handle dead processes
	sa.sa_handler = sigchldHandler;		//read all dead processes
	sigemptyset( &sa.sa_mask );
	sa.sa_flags = SA_RESTART;
	if( sigaction( SIGCHLD, &sa , NULL ) == -1 ){
		perror("sigaction");
		exit(1);
	}

	//Handle user interrupts
	signal(SIGINT, userIntHandler);

	cout << "Waiting for connections ... " << endl;

	while(1){

		otherAddrLen = sizeof ( otherAddr) ;
		newfd = accept ( controlSock , (struct sockaddr *) &otherAddr , &otherAddrLen );
		cout << "Connection from " << getIPFromAddr(&otherAddr) << ":" << getPortFromAddr(&otherAddr) << endl;
		commsock = newfd;

		send(newfd, (unsigned short *)&dataPort, 2, 0);

		otherAddrLen2 = sizeof otherAddr2;
		newfd2 = accept(dataSock, (struct sockaddr *) &otherAddr2, &otherAddrLen2 );
		datacommsock = newfd2;
		cout << "Connection to data socket from client port " << getPortFromAddr(&otherAddr2) << endl;

		if( fork() == 0 ){
			//The code in this block is executed by the child process
			close(controlSock);  //Child doesn't require the control socket
			close(dataSock);

			if(verbose){
				cout << "Closing listener sockets" << endl;
				cout << "Child process created for communication with client" << endl;
			}

			if (dup2( newfd , 0 ) != 0 ){
				perror("dup2");
				exit(1);
			}

			do{
				
				if(fgets( buffer, DATA_SIZE, stdin ) == NULL){
					close(newfd);
					exit(1);
				}

				//Remove carriage return and new line characters
				for(rv = 0; rv < DATA_SIZE ; rv++){

					if(buffer[rv] == '\r'){
						buffer[rv] = 0;
						break;
					}

					if(buffer[rv] == '\n'){
						buffer[rv] = 0;
						break;
					}
				}
				
				//Read buffer and find what command it is
				//Call the corresponding method

				string s(buffer);		//convert the character array into string
				if(verbose){
					cout << "Received command " + s << endl;
				}

				istringstream iss(s);

				//copy the tokens into the string vector
				copy( istream_iterator<string>(iss),
				 istream_iterator<string>() ,
				 back_inserter<vector<string> >(tokens) );


				//Copied the tokens into tokens
				rv = tokens.size();
				if(rv > 0){
					//If there is atleast one word
					if(tokens[0].compare("ls") == 0){
						//The client requested a file listing
						ls(s, newfd2);
					}
					else if(tokens[0].compare("quit") == 0){
						//The client closed the connection
						break;
					}
					else if(tokens[0].compare("cd") == 0){
						//The client requested a directory change
						if(rv == 2){
							cd(tokens[1], newfd2);
						}
						else{
							sendMessage( errMsg.c_str() , errMsg.length() , ERROR, NF, dataSock );
						}
					}
					else if( tokens[0].compare("pwd") == 0 ){
						//Client requested a pwd
						PWD(newfd2);
					}
					else if(tokens[0].compare("get") == 0){
						string temp="";
						for(i=1; i < rv;i++){
							temp = temp + tokens[i] + " ";
						}
						temp = temp.substr(0, temp.length()-1 );
						getFile(temp, newfd2);
					}
					else if(tokens[0].compare("put") == 0){
						string temp="";
						for(i=1; i < rv;i++){
							temp = temp + tokens[i] + " ";
						}
						temp = temp.substr(0, temp.length()-1 );
						putFile(temp, newfd2);
					}
					else{
						sendMessage( errMsg.c_str() , errMsg.length() , ERROR, NF, newfd2 );
					}
				}

				tokens.clear();		//clear the tokens

			}while (1);

			//The client closed the connection
			//So, close the socket and quit the child process
			close(newfd);		
			close(newfd2);	
			cout << "Connection closed" << endl;
			exit(1);
		}
		close(newfd);

	}

	close(controlSock);
	

}
int main(int argc, char** argv)
{
  // create master socket in core OS and return file descriptor
  int masterFD = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

  // socket settings
  struct sockaddr_in sAddr;
  sAddr.sin_family = AF_INET;
  sAddr.sin_port = htons(12345);
  sAddr.sin_addr.s_addr = htonl(INADDR_ANY);
  bind(masterFD, (struct sockaddr *)(&sAddr), sizeof(sAddr));

  // nonblock socket - do not wait all data
  // read any and continue
  set_nonblock(masterFD);

  //listen as server ip and port from settings
  listen(masterFD, SOMAXCONN);

  std::cout << "master begin listen with FD = " << masterFD << std::endl;

  // create poll in OS core and return file descriptor
  // poll for correct work with slave socket`s
  int EPollFD = epoll_create1(0);

  struct epoll_event Event;
  Event.data.fd = masterFD;
  Event.events = EPOLLIN;// catch read event, all unread data generate new event

  // register Event listener in control
  epoll_ctl(EPollFD,EPOLL_CTL_ADD,masterFD,&Event);

  std::map<unsigned int,std::string> slaveSockets;

  while (true)
  {
    struct epoll_event Events[MaxReceivedEvents];

    // receive N events
    int N = -1;
    std::cout << "begin wait event..." << std::endl;
    // if N < 0 - core signal error - repeat wait
    while(true){
      N = epoll_wait(EPollFD,Events,MaxReceivedEvents,-1);
      if (N >= 0)
        break;
    }

    std::cout << "wait terminated..." << std::endl;


    for (int i = 0; i < N; ++i)
    {
      // new connection
      if (Events[i].data.fd == masterFD){
        //slave ip
        struct sockaddr_in slaveAddr; socklen_t slaveAddrSize = sizeof(slaveAddr);

        //register new connection
        int slaveFD = accept(masterFD, (sockaddr*)&slaveAddr, &slaveAddrSize);
        set_nonblock(slaveFD);

        struct epoll_event Event;
        Event.data.fd = slaveFD;
        Event.events = EPOLLIN;// catch read event, all unread data generate new event

        // register slave Event listener in control
        epoll_ctl(EPollFD,EPOLL_CTL_ADD,slaveFD,&Event);

        char * ip = getIPFromAddr(slaveAddr);

        //save to chat list
        slaveSockets.insert(std::pair<unsigned int,std::string> (slaveFD, ip));

        std::cout << "slave connected with FD = " << slaveFD
            << " AND slAddr = " << ip // << " || "
            //<< slaveAddr.sin_addr << " || "
            //<< slaveAddr.sin_port
            << std::endl;
      } else
      // read data
      {
        auto receiver = slaveSockets.find(Events[i].data.fd);
        if (receiver == slaveSockets.end()){
          continue;
        }

        static char Buffer[MaxMessageLength];

        int reciveResult = recv(Events[i].data.fd,Buffer,MaxMessageLength,MSG_NOSIGNAL);
        //connection closed
        if ((reciveResult == 0) && (errno != EAGAIN)){
          //close connection
          shutdown(Events[i].data.fd,SHUT_RDWR);
          close(Events[i].data.fd);
          //delete from listener
          slaveSockets.erase(Events[i].data.fd);

          std::cout << "slave disconnected with FD = " << Events[i].data.fd << std::endl;
        } else
        //read data from slave
        if (reciveResult > 0){
          int authorLength = receiver->second.length() + 4;
          char* ResBuffer = new char[reciveResult + authorLength];
          strcpy(ResBuffer,receiver->second.c_str());
          strcat(ResBuffer," || ");

          std::cout << "server receive message from slave with FD = " << Events[i].data.fd
              << " || message = " << Buffer
              << " || author = " << ResBuffer
              << std::endl;

          strcat(ResBuffer,Buffer);
          
          std::cout << "resultBuffer" << ResBuffer << std::endl;

          //translate message to all listener
          for (auto it = slaveSockets.begin(); it != slaveSockets.end();++it){
            if (it->first != (unsigned int)Events[i].data.fd){
              send(it->first,ResBuffer,reciveResult + authorLength,MSG_NOSIGNAL);
            }
          }
          delete [] ResBuffer;
        }
      }
    }
  }
  return 0;
}