Esempio n. 1
0
void
VoodooDispatcher::ProcessMessages( VoodooMessageHeader *first,
                                   size_t               total_length )
{
     D_DEBUG_AT( Voodoo_Dispatcher, "VoodooDispatcher::%s( %p, first %p, total_length "_ZU" )\n",
                 __func__, this, first, total_length );

     D_MAGIC_ASSERT( this, VoodooDispatcher );

     VoodooMessageHeader *header = first;
     size_t               offset = 0;
     size_t               aligned;

     while (offset < total_length) {
          /* Get the message header. */
          header  = (VoodooMessageHeader *)((char*) first + offset);
          aligned = VOODOO_MSG_ALIGN( header->size );

          D_DEBUG_AT( Voodoo_Dispatcher, "  -> Next message has %d ("_ZU") bytes and is of type %d... (offset "_ZU"/"_ZU")\n",
                      header->size, aligned, header->type, offset, total_length );

          D_ASSERT( header->size >= (int) sizeof(VoodooMessageHeader) );
          D_ASSERT( header->size <= MAX_MSG_SIZE );

          D_ASSERT( offset + aligned <= total_length );

          switch (header->type) {
               case VMSG_SUPER:
                    manager->handle_super( (VoodooSuperMessage*) header );
                    break;

               case VMSG_REQUEST:
                    manager->handle_request( (VoodooRequestMessage*) header );
                    break;

               case VMSG_RESPONSE:
                    manager->handle_response( (VoodooResponseMessage*) header );
                    break;

               case VMSG_DISCOVER:
                    manager->handle_discover( header );
                    break;

               case VMSG_SENDINFO: // should only be received by TCP fake player, not manager
                    D_BUG( "received SENDINFO" );
                    break;

               default:
                    D_BUG( "invalid message type %d", header->type );
                    break;
          }

          offset += aligned;
     }

     D_ASSERT( offset == total_length );
}
Esempio n. 2
0
VoodooPacket *
VoodooConnectionLink::GetPacket( size_t length )
{
     D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionLink::%s( %p, length "_ZU" )\n", __func__, this, length );

     D_MAGIC_ASSERT( this, VoodooConnection );
     D_ASSERT( length >= (int) sizeof(VoodooMessageHeader) );
     D_ASSUME( length <= MAX_MSG_SIZE );

     if (length > MAX_MSG_SIZE) {
          D_WARN( _ZU" exceeds maximum message size of %d", length, MAX_MSG_SIZE );
          return NULL;
     }

     size_t aligned = VOODOO_MSG_ALIGN( length );


     Packets *packets = (Packets*) direct_tls_get( output.tls );

     if (!packets) {
          packets = new Packets( this );

          direct_tls_set( output.tls, packets );
     }

     VoodooPacket *packet = packets->active;

     if (packet) {
          if (packet->append( aligned ))
               return packet;

          Flush( packet );
     }

     packet = packets->Get();
     if (packet) {
          if (packet->sending) {
               direct_mutex_lock( &output.lock );

               while (packet->sending)
                    direct_waitqueue_wait( &output.wait, &output.lock );

               direct_mutex_unlock( &output.lock );
          }
          packet->reset( aligned );
     }

     return packet;
}
Esempio n. 3
0
static DirectResult
manager_lock_output( VoodooManager  *manager,
                     int             length,
                     void          **ret_ptr )
{
     int aligned;

     D_MAGIC_ASSERT( manager, VoodooManager );
     D_ASSERT( length >= sizeof(VoodooMessageHeader) );
     D_ASSUME( length <= MAX_MSG_SIZE );
     D_ASSERT( ret_ptr != NULL );

     if (length > MAX_MSG_SIZE) {
          D_WARN( "%d exceeds maximum message size of %d", length, MAX_MSG_SIZE );
          return DR_LIMITEXCEEDED;
     }

     aligned = VOODOO_MSG_ALIGN( length );

     pthread_mutex_lock( &manager->output.lock );

     while (manager->output.end + aligned > OUT_BUF_MAX) {
          pthread_cond_broadcast( &manager->output.wait );

          pthread_cond_wait( &manager->output.wait, &manager->output.lock );

          if (manager->quit) {
               pthread_mutex_lock( &manager->output.lock );
               return DR_DESTROYED;
          }
     }

     *ret_ptr = manager->output.buffer + manager->output.end;

     manager->output.end += aligned;

     return DR_OK;
}
Esempio n. 4
0
void *
VoodooConnectionPacket::io_loop()
{
     D_DEBUG_AT( Voodoo_Connection, "VoodooConnectionPacket::%s( %p )\n", __func__, this );

     while (!stop) {
          D_MAGIC_ASSERT( this, VoodooConnection );

          if (input.start == input.max) {
               input.start = 0;
               input.end   = 0;
               input.last  = 0;
               input.max   = VOODOO_CONNECTION_LINK_INPUT_BUF_MAX;
          }

          if (!stop) {
               DirectResult  ret;
               VoodooChunk   chunks[2];
               VoodooChunk  *chunk_read  = NULL;
               VoodooChunk  *chunk_write = NULL;
               size_t        last        = input.last;
               VoodooPacket *packet      = NULL;

               std::vector<VoodooChunk> chunks_write;
               std::vector<VoodooChunk> chunks_read;

               if (!output.sending) {
                    direct_mutex_lock( &output.lock );

                    if (output.packets) {
                         VoodooPacket *packet = (VoodooPacket*) output.packets;

                         D_ASSERT( packet->sending );

                         if (voodoo_config->compression_min && packet->size() >= voodoo_config->compression_min) {
                              output.sending = VoodooPacket::Compressed( packet );

                              if (output.sending->flags() & VPHF_COMPRESSED) {
                                   D_DEBUG_AT( Voodoo_Output, "  -> Compressed %u to %u bytes... (packet %p)\n",
                                               output.sending->uncompressed(), output.sending->size(), packet );

                                   output.sending->sending = true;

                                   packet->sending = false;

                                   direct_list_remove( &output.packets, &packet->link );

                                   direct_waitqueue_broadcast( &output.wait );
                              }
                         }
                         else
                              output.sending = packet;

                         output.sent = 0;
                    }

                    direct_mutex_unlock( &output.lock );
               }

               if (output.sending) {
                    packet = output.sending;

                    D_ASSERT( packet->sending );

                    chunk_write = &chunks[1];

                    chunk_write->ptr    = (char*) packet->data_header() + output.sent;
                    chunk_write->length = VOODOO_MSG_ALIGN(packet->size() + sizeof(VoodooPacketHeader)) - output.sent;
                    chunk_write->done   = 0;

                    chunks_write.push_back( chunks[1] );

                    chunk_write = chunks_write.data();
               }

               if (input.end < input.max && manager->DispatchReady()) {
                    chunk_read = &chunks[0];

                    chunk_read->ptr    = input.buffer + input.end;
                    chunk_read->length = input.max - input.end;
                    chunk_read->done   = 0;

                    chunks_read.push_back( chunks[0] );

                    chunk_read = chunks_read.data();
               }


               ret = link->SendReceive( link,
                                        chunks_write.data(), chunks_write.size(),
                                        chunks_read.data(), chunks_read.size() );
               switch (ret) {
                    case DR_OK:
                         if (chunk_write && chunk_write->done) {
                              D_DEBUG_AT( Voodoo_Output, "  -> Sent "_ZD"/"_ZD" bytes... (packet %p)\n", chunk_write->done, chunk_write->length, packet );

                              output.sent += chunk_write->done;

                              if (output.sent == VOODOO_MSG_ALIGN(packet->size() + sizeof(VoodooPacketHeader))) {
                                   output.sending = NULL;

                                   if (packet->flags() & VPHF_COMPRESSED) {
                                        packet->sending = false;

                                        D_FREE( packet );
                                   }
                                   else {
                                        direct_mutex_lock( &output.lock );

                                        packet->sending = false;

                                        direct_list_remove( &output.packets, &packet->link );

                                        direct_mutex_unlock( &output.lock );

                                        direct_waitqueue_broadcast( &output.wait );
                                   }
                              }
                         }
                         break;

                    case DR_TIMEOUT:
                         //D_DEBUG_AT( Voodoo_Connection, "  -> timeout\n" );
                         break;

                    case DR_INTERRUPTED:
                         D_DEBUG_AT( Voodoo_Connection, "  -> interrupted\n" );
                         break;

                    default:
                         if (ret == DR_IO)
                              D_DEBUG_AT( Voodoo_Connection, "  -> Connection closed!\n" );
                         else
                              D_DERROR( ret, "Voodoo/ConnectionPacket: Could not receive data!\n" );

                         goto disconnect;
               }


               if (chunk_read && chunk_read->done) {
                    D_DEBUG_AT( Voodoo_Input, "  -> Received "_ZD" bytes...\n", chunk_read->done );

                    input.end += (size_t) chunk_read->done;

                    do {
                         VoodooPacketHeader *header;
                         size_t              aligned;

                         D_DEBUG_AT( Voodoo_Input, "  -> last = %zu\n", last );

                         /* Get the packet header. */
                         header  = (VoodooPacketHeader *)(input.buffer + last);
                         D_DEBUG_AT( Voodoo_Input, "  -> header = %p\n", header );
                         D_DEBUG_AT( Voodoo_Input, "  -> header->size = %u\n", header->size );
                         aligned = VOODOO_MSG_ALIGN( header->size );

                         D_DEBUG_AT( Voodoo_Input, "  -> Next packet has %u ("_ZU") -> %u bytes (flags 0x%04x)...\n",
                                     header->size, aligned, header->uncompressed, header->flags );

                         if (input.end - last >= sizeof(VoodooPacketHeader)) {
                              if (header->uncompressed < (int) sizeof(VoodooMessageHeader)) {
                                   D_DERROR( ret, "Voodoo/ConnectionPacket: Data error, uncompressed %d < min %zu!\n", header->uncompressed, sizeof(VoodooPacketHeader) );

                                   goto disconnect;
                              }

                              if (header->uncompressed > VOODOO_PACKET_MAX) {
                                   D_DERROR( ret, "Voodoo/ConnectionPacket: Data error, uncompressed %d > max %d!\n", header->uncompressed, VOODOO_PACKET_MAX );

                                   goto disconnect;
                              }
                         }

                         if (sizeof(VoodooPacketHeader) + aligned > input.end - last) {
                              D_DEBUG_AT( Voodoo_Input, "  -> ...fetching tail of message.\n" );

                              /* Extend the buffer if the message doesn't fit into the default boundary. */
                              if (sizeof(VoodooPacketHeader) + aligned > input.max - last)
                                   input.max = last + sizeof(VoodooPacketHeader) + aligned;

                              break;
                         }

                         last += sizeof(VoodooPacketHeader) + aligned;
                    } while (last < input.end);

                    if (last != input.last) {
                         input.last = last;

                         D_DEBUG_AT( Voodoo_Input, "  { START "_ZD", LAST "_ZD", END "_ZD", MAX "_ZD" }\n",
                                     input.start, input.last, input.end, input.max );

                         while (input.start < input.last) {
                              /* Get the packet header. */
                              VoodooPacketHeader *header = (VoodooPacketHeader *)(input.buffer + input.start);

                              VoodooPacket *p;

                              D_ASSERT( header->uncompressed <= VOODOO_PACKET_MAX );

                              if (header->flags & VPHF_COMPRESSED) {
                                   size_t uncompressed = direct_fastlz_decompress( header + 1, header->size, tmp, header->uncompressed );

                                   D_DEBUG_AT( Voodoo_Input, "  -> Uncompressed "_ZU" bytes (%u compressed)\n", uncompressed, header->size );

                                   (void) uncompressed;

                                   D_ASSERT( uncompressed == header->uncompressed );

                                   // FIXME: don't copy, but read into packet directly, maybe call manager->GetPacket() at the top of this loop
                                   p = VoodooPacket::Copy( header->uncompressed, VPHF_NONE,
                                                           header->uncompressed, tmp );
                              }
                              else {
                                   // FIXME: don't copy, but read into packet directly, maybe call manager->GetPacket() at the top of this loop
                                   p = VoodooPacket::Copy( header->uncompressed, VPHF_NONE,
                                                           header->uncompressed, header + 1 );
                              }

                              manager->DispatchPacket( p );

                              input.start += VOODOO_MSG_ALIGN(header->size) + sizeof(VoodooPacketHeader);
                         }
                    }
               }
          }
     }

     return NULL;


disconnect:
     closed = true;

     manager->handle_disconnect();

     return NULL;
}
Esempio n. 5
0
static inline int
calc_blocks( VoodooMessageBlockType type, va_list args )
{
     int size = 4;  /* for the terminating VMBT_NONE */

     while (type != VMBT_NONE) {
          u32 arg;
          s32 in;
          void *ptr;
          int   len = 0;

          switch (type) {
               case VMBT_ID:
                    len = 4;
                    arg = va_arg( args, u32 );

                    D_DEBUG( "Voodoo/Message: + ID %u\n", arg );
                    break;

               case VMBT_INT:
                    len = 4;
                    in  = va_arg( args, s32 );

                    D_DEBUG( "Voodoo/Message: + INT %d\n", in );
                    break;

               case VMBT_UINT:
                    len = 4;
                    arg = va_arg( args, u32 );

                    D_DEBUG( "Voodoo/Message: + UINT %u\n", arg );
                    break;

               case VMBT_DATA:
                    len = va_arg( args, int );
                    ptr = va_arg( args, void * );

                    D_ASSERT( len > 0 );
                    D_ASSERT( ptr != NULL );

                    D_DEBUG( "Voodoo/Message: + DATA at %p with length %d\n", ptr, len );
                    break;

               case VMBT_ODATA:
                    len = va_arg( args, int );
                    ptr = va_arg( args, void * );

                    D_ASSERT( len > 0 );

                    D_DEBUG( "Voodoo/Message: + ODATA at %p with length %d\n", ptr, len );

                    if (!ptr)
                         len = 0;
                    break;

               case VMBT_STRING:
                    ptr = va_arg( args, char * );
                    len = strlen( ptr ) + 1;

                    D_ASSERT( ptr != NULL );

                    D_DEBUG( "Voodoo/Message: + STRING '%s' at %p with length %d\n", (char*) ptr, ptr, len );
                    break;

               default:
                    D_BREAK( "unknown message block type" );
          }

          size += 8 + VOODOO_MSG_ALIGN(len);

          type = va_arg( args, VoodooMessageBlockType );
     }

     return size;
}
Esempio n. 6
0
static void *
manager_dispatch_loop( DirectThread *thread, void *arg )
{
     VoodooManager *manager = arg;

     /* Lock the input buffer. */
     pthread_mutex_lock( &manager->input.lock );

     while (!manager->quit) {
          VoodooMessageHeader *header;
          int                  aligned;

          D_MAGIC_ASSERT( manager, VoodooManager );

          D_DEBUG( "Voodoo/Dispatch: START %d, END %d, MAX %d\n",
                   manager->input.start, manager->input.end, manager->input.max );

          /* Wait for at least four bytes which contain the length of the message. */
          while (manager->input.end - manager->input.start < 4) {
               D_DEBUG( "Voodoo/Dispatch: Waiting for messages...\n" );

               pthread_cond_wait( &manager->input.wait, &manager->input.lock );

               if (manager->quit)
                    break;
          }

          if (manager->quit)
               break;

          /* Get the message header. */
          header  = (VoodooMessageHeader *)(manager->input.buffer + manager->input.start);
          aligned = VOODOO_MSG_ALIGN( header->size );

          D_DEBUG( "Voodoo/Dispatch: Next message has %d (%d) bytes and is of type %d...\n",
                   header->size, aligned, header->type );

          D_ASSERT( header->size >= sizeof(VoodooMessageHeader) );
          D_ASSERT( header->size <= MAX_MSG_SIZE );

          /* Extend the buffer if the message doesn't fit into the default boundary. */
          if (aligned > manager->input.max - manager->input.start) {
               D_ASSERT( manager->input.max == IN_BUF_MAX );

               D_DEBUG( "Voodoo/Dispatch: ...fetching tail of message.\n" );

               manager->input.max = manager->input.start + aligned;

               pthread_cond_broadcast( &manager->input.wait );
          }

          /* Wait until the complete message is received. */
          while (aligned > manager->input.end - manager->input.start) {
               pthread_cond_wait( &manager->input.wait, &manager->input.lock );

               if (manager->quit)
                    break;
          }

          if (manager->quit)
               break;

          /* Unlock the input buffer. */
          pthread_mutex_unlock( &manager->input.lock );

          switch (header->type) {
               case VMSG_SUPER:
                    handle_super( manager, (VoodooSuperMessage*) header );
                    break;

               case VMSG_REQUEST:
                    handle_request( manager, (VoodooRequestMessage*) header );
                    break;

               case VMSG_RESPONSE:
                    handle_response( manager, (VoodooResponseMessage*) header );
                    break;

               default:
                    D_BUG( "invalid message type %d", header->type );
                    break;
          }

          /* Lock the input buffer. */
          pthread_mutex_lock( &manager->input.lock );

          manager->input.start += aligned;

          if (manager->input.start == manager->input.end) {
               if (manager->input.start == manager->input.max)
                    pthread_cond_broadcast( &manager->input.wait );

               manager->input.start = manager->input.end = 0;

               manager->input.max = IN_BUF_MAX;
          }
     }

     /* Unlock the input buffer. */
     pthread_mutex_unlock( &manager->input.lock );

     return NULL;
}