Example #1
0
/** @brief Handle an "event" on the unicast file descriptors
 * If the event is on an already open client connection, it handle the message
 * If the event is on the master connection, it accepts the new connection
 * If the event is on a channel specific socket, it accepts the new connection and starts streaming
 *
 */
int unicast_handle_fd_event(unicast_parameters_t *unicast_vars, fds_t *fds, mumudvb_channel_t *channels, int number_of_channels, strength_parameters_t *strengthparams, auto_p_t *auto_p, void *cam_p, void *scam_vars)
{
	int iRet;
	//We look what happened for which connection
	int actual_fd;


	for(actual_fd=1;actual_fd<fds->pfdsnum;actual_fd++)
	{
		iRet=0;
		if((fds->pfds[actual_fd].revents&POLLHUP)&&(unicast_vars->fd_info[actual_fd].type==UNICAST_CLIENT))
		{
			log_message( log_module, MSG_DEBUG,"We've got a POLLHUP. Actual_fd %d socket %d we close the connection \n", actual_fd, fds->pfds[actual_fd].fd );
			unicast_close_connection(unicast_vars,fds,fds->pfds[actual_fd].fd);
			//We check if we hage to parse fds->pfds[actual_fd].revents (the last fd moved to the actual one)
			if(fds->pfds[actual_fd].revents)
				actual_fd--;//Yes, we force the loop to see it
		}
		if((fds->pfds[actual_fd].revents&POLLIN)||(fds->pfds[actual_fd].revents&POLLPRI))
		{
			if((unicast_vars->fd_info[actual_fd].type==UNICAST_MASTER)||
					(unicast_vars->fd_info[actual_fd].type==UNICAST_LISTEN_CHANNEL))
			{
				//Event on the master connection or listenin channel
				//New connection, we accept the connection
				log_message( log_module, MSG_FLOOD,"New client\n");
				int tempSocket;
				unicast_client_t *tempClient;
				//we accept the incoming connection
				tempClient=unicast_accept_connection(unicast_vars, fds->pfds[actual_fd].fd);

				if(tempClient!=NULL)
				{
					tempSocket=tempClient->Socket;
					fds->pfdsnum++;
					fds->pfds=realloc(fds->pfds,(fds->pfdsnum+1)*sizeof(struct pollfd));
					if (fds->pfds==NULL)
					{
						log_message( log_module, MSG_ERROR,"Problem with realloc : %s file : %s line %d\n",strerror(errno),__FILE__,__LINE__);
						set_interrupted(ERROR_MEMORY<<8);
						return -1;
					}
					//We poll the new socket
					fds->pfds[fds->pfdsnum-1].fd = tempSocket;
					fds->pfds[fds->pfdsnum-1].events = POLLIN | POLLPRI | POLLHUP; //We also poll the deconnections
					fds->pfds[fds->pfdsnum-1].revents = 0;
					fds->pfds[fds->pfdsnum].fd = 0;
					fds->pfds[fds->pfdsnum].events = POLLIN | POLLPRI;
					fds->pfds[fds->pfdsnum].revents = 0;

					//Information about the descriptor
					unicast_vars->fd_info=realloc(unicast_vars->fd_info,(fds->pfdsnum)*sizeof(unicast_fd_info_t));
					if (unicast_vars->fd_info==NULL)
					{
						log_message( log_module, MSG_ERROR,"Problem with realloc : %s file : %s line %d\n",strerror(errno),__FILE__,__LINE__);
						set_interrupted(ERROR_MEMORY<<8);
						return -1;
					}
					//client connection
					unicast_vars->fd_info[fds->pfdsnum-1].type=UNICAST_CLIENT;
					unicast_vars->fd_info[fds->pfdsnum-1].channel=-1;
					unicast_vars->fd_info[fds->pfdsnum-1].client=tempClient;


					log_message( log_module, MSG_FLOOD,"Number of clients : %d\n", unicast_vars->client_number);

					if(unicast_vars->fd_info[actual_fd].type==UNICAST_LISTEN_CHANNEL)
					{
						//Event on a channel connection, we open a new socket for this client and
						//we store the wanted channel for when we will get the GET
						log_message( log_module, MSG_DEBUG,"Connection on a channel socket the client  will get the channel %d\n", unicast_vars->fd_info[actual_fd].channel);
						tempClient->askedChannel=unicast_vars->fd_info[actual_fd].channel;
					}
				}
			}
			else if(unicast_vars->fd_info[actual_fd].type==UNICAST_CLIENT)
			{
				//Event on a client connectio i.e. the client asked something
				log_message( log_module, MSG_FLOOD,"New message for socket %d\n", fds->pfds[actual_fd].fd);
				iRet=unicast_handle_message(unicast_vars,unicast_vars->fd_info[actual_fd].client, channels, number_of_channels, strengthparams, auto_p, cam_p, scam_vars);
				if (iRet==-2 ) //iRet==-2 --> 0 received data or error, we close the connection
				{
					unicast_close_connection(unicast_vars,fds,fds->pfds[actual_fd].fd);
					//We check if we hage to parse fds->pfds[actual_fd].revents (the last fd moved to the actual one)
					if(fds->pfds[actual_fd].revents)
						actual_fd--;//Yes, we force the loop to see it again
				}
			}
			else
			{
				log_message( log_module, MSG_WARN,"File descriptor with bad type, please contact\n Debug information : actual_fd %d unicast_vars->fd_info[actual_fd].type %d\n",
						actual_fd, unicast_vars->fd_info[actual_fd].type);
			}
		}
	}
	return 0;

}
Example #2
0
/** @brief Send the buffer for the channel
 *
 * This function is called when a buffer for a channel is full and have to be sent to the clients
 *
 */
void unicast_data_send(mumudvb_channel_t *actual_channel, mumudvb_channel_t *channels, fds_t *fds, unicast_parameters_t *unicast_vars)
{
  if(actual_channel->clients)
  {
    unicast_client_t *actual_client;
    unicast_client_t *temp_client;
    int written_len;
    unsigned char *buffer;
    int buffer_len;
    int data_from_queue;
    int packets_left;
    struct timeval tv;

    actual_client=actual_channel->clients;
    while(actual_client!=NULL)
    {
      buffer=actual_channel->buf;
      buffer_len=actual_channel->nb_bytes;
      data_from_queue=0;
      if(actual_client->queue.packets_in_queue!=0)
      {
	//already some packets in the queue we enqueue the new one and try to send the queued ones
	data_from_queue=1;
	packets_left=UNICAST_MULTIPLE_QUEUE_SEND;
	if((actual_client->queue.data_bytes_in_queue+buffer_len)< unicast_vars->queue_max_size)
	  unicast_queue_add_data(&actual_client->queue, buffer, buffer_len );
	else
	{
	  if(!actual_client->queue.full)
	  {
	    actual_client->queue.full=1;
	    log_message( log_module, MSG_DETAIL,"The queue is full, we now throw away new packets for client %s:%d\n",
		        inet_ntoa(actual_client->SocketAddr.sin_addr),
		        actual_client->SocketAddr.sin_port);
	  }
	}
	buffer=unicast_queue_get_data(&actual_client->queue, &buffer_len);
      }
      else
	packets_left=1;

      while(packets_left>0)
      {
	//we send the data
	written_len=write(actual_client->Socket,buffer, buffer_len);
	//We check if all the data was successfully written
	if(written_len<buffer_len)
	{
	  //No !
	  packets_left=0; //we don't send more packets to this client
	  if(written_len==-1)
	  {
	    if(errno != actual_client->last_write_error)
	    {
	      log_message( log_module, MSG_DEBUG,"New error when writing to client %s:%d : %s\n",
			  inet_ntoa(actual_client->SocketAddr.sin_addr),
			  actual_client->SocketAddr.sin_port,
			  strerror(errno));
	      actual_client->last_write_error=errno;
	      written_len=0;
	    }
	  }
	  else
	  {
	    log_message( log_module, MSG_DEBUG,"Not all the data was written to %s:%d. Asked len : %d, written len %d\n",
			inet_ntoa(actual_client->SocketAddr.sin_addr),
			actual_client->SocketAddr.sin_port,
			actual_channel->nb_bytes,
			written_len);
	  }
	  if(!(unicast_vars->flush_on_eagain &&(errno==EAGAIN)))//Debug feature : we can drop data if eagain error
          {
            //No drop on eagain or no eagain
            if(!data_from_queue)
            {
              //We store the non sent data in the queue
              if((actual_client->queue.data_bytes_in_queue+buffer_len-written_len)< unicast_vars->queue_max_size)
              {
                unicast_queue_add_data(&actual_client->queue, buffer+written_len, buffer_len-written_len);
                log_message( log_module, MSG_DEBUG,"We start queuing packets ... \n");
              }
            }
            else if(written_len > 0)
            {
              unicast_queue_remove_data(&actual_client->queue);
              unicast_queue_add_data(&actual_client->queue, buffer+written_len, buffer_len-written_len);
              log_message( log_module, MSG_DEBUG,"We requeue the non sent data ... \n");
            }
          }else{
            //this is an EAGAIN error and we want to drop the data
            if(!data_from_queue)
            {
            //Not from the queue we dont do anything
              log_message( log_module, MSG_DEBUG,"We drop not from queue ... \n");
            }
            else
            {
            unicast_queue_clear(&actual_client->queue);
            log_message( log_module, MSG_DEBUG,"Eagain error we flush the queue ... \n");
            }
          }

	  if(!actual_client->consecutive_errors)
	  {
	    log_message( log_module, MSG_DETAIL,"Error when writing to client %s:%d : %s\n",
			inet_ntoa(actual_client->SocketAddr.sin_addr),
			actual_client->SocketAddr.sin_port,
			strerror(errno));
			gettimeofday (&tv, (struct timezone *) NULL);
			actual_client->first_error_time = tv.tv_sec;
			actual_client->consecutive_errors=1;
	  }
	  else
	  {
	    //We have errors, we check if we reached the timeout
	    gettimeofday (&tv, (struct timezone *) NULL);
	    if((unicast_vars->consecutive_errors_timeout > 0) && (tv.tv_sec - actual_client->first_error_time) > unicast_vars->consecutive_errors_timeout)
	    {
	      log_message( log_module, MSG_INFO,"Consecutive errors when writing to client %s:%d during too much time, we disconnect\n",
			  inet_ntoa(actual_client->SocketAddr.sin_addr),
			  actual_client->SocketAddr.sin_port);
			  temp_client=actual_client->chan_next;
			  unicast_close_connection(unicast_vars,fds,actual_client->Socket,channels);
			  actual_client=temp_client;
	    }
	  }
	}
	else
	{
	  //data successfully written
	  if (actual_client->consecutive_errors)
	  {
	    log_message( log_module, MSG_DETAIL,"We can write again to client %s:%d\n",
			inet_ntoa(actual_client->SocketAddr.sin_addr),
			actual_client->SocketAddr.sin_port);
	    actual_client->consecutive_errors=0;
	    actual_client->last_write_error=0;
	    if(data_from_queue)
	      log_message( log_module, MSG_DEBUG,"We start dequeuing packets Packets in queue: %d. Bytes in queue: %d\n",
			  actual_client->queue.packets_in_queue,
			  actual_client->queue.data_bytes_in_queue);
	  }
	  packets_left--;
	  if(data_from_queue)
	  {
	    //The data was successfully sent, we can dequeue it
	    unicast_queue_remove_data(&actual_client->queue);
	    if(actual_client->queue.packets_in_queue!=0)
	    {
	      //log_message( log_module, MSG_DEBUG,"Still packets in the queue,next one\n");
	      //still packets in the queue, we continue sending
	      if(packets_left)
		buffer=unicast_queue_get_data(&actual_client->queue, &buffer_len);
	    }
	    else //queue now empty
	    {
	      packets_left=0;
	      log_message( log_module, MSG_DEBUG,"The queue is now empty :) client %s:%d \n",
			  inet_ntoa(actual_client->SocketAddr.sin_addr),
		          actual_client->SocketAddr.sin_port);
	    }
	  }
	}
      }

      if(actual_client) //Can be null if the client was destroyed
	actual_client=actual_client->chan_next;
    }
  }
  
}