/// Check if one string starts with another
bool dStrStartsWith(const char* str1, const char* str2)
{
   return !dStrnicmp(str1, str2, dStrlen(str2));
}
bool AppMesh::isBillboardZAxis()
{
   return !dStrnicmp(getName(),"BBZ::",5) || !dStrnicmp(getName(),"BBZ_",4);
}
bool Net::stringToAddress(const char *addressString, NetAddress  *address)
{
   if(!dStrnicmp(addressString, "ipx:", 4))
      // ipx support deprecated
      return false;

   if(!dStrnicmp(addressString, "ip:", 3))
      addressString += 3;  // eat off the ip:

   sockaddr_in ipAddr;
   char remoteAddr[256];
   if(strlen(addressString) > 255)
      return false;

   dStrcpy(remoteAddr, addressString);

   char *portString = dStrchr(remoteAddr, ':');
   if(portString)
      *portString++ = '\0';

   if(!dStricmp(remoteAddr, "broadcast"))
      ipAddr.sin_addr.s_addr = htonl(INADDR_BROADCAST);
   else
   {
      ipAddr.sin_addr.s_addr = inet_addr(remoteAddr);

      if (ipAddr.sin_addr.s_addr == INADDR_NONE) // error
      {
         // On the Xbox, 'gethostbyname' does not exist so...
#ifndef TORQUE_OS_XENON
         struct hostent *hp;
         if((hp = gethostbyname(remoteAddr)) == 0)
            return false;
         else
            memcpy(&ipAddr.sin_addr.s_addr, hp->h_addr,  sizeof(in_addr));
#else
         // On the Xbox do XNetDnsLookup
         XNDNS *pxndns = NULL;
         HANDLE hEvent = CreateEvent(NULL, false, false, NULL);
         XNetDnsLookup(remoteAddr, hEvent, &pxndns);

         // Wait for event (passing NULL as a handle to XNetDnsLookup will NOT
         // cause it to behave synchronously, so do not remove the handle/wait
         while(pxndns->iStatus == WSAEINPROGRESS) 
            WaitForSingleObject(hEvent, INFINITE);

         bool foundAddr = pxndns->iStatus == 0 && pxndns->cina > 0;
         if(foundAddr)
         {
            // Lets just grab the first address returned, for now
            memcpy(&ipAddr.sin_addr, pxndns->aina,  sizeof(IN_ADDR));
         }

         XNetDnsRelease(pxndns);
         CloseHandle(hEvent);

         // If we didn't successfully resolve the DNS lookup, bail after the
         // handles are released
         if(!foundAddr)
            return false;
#endif
      }
   }
   if(portString)
      ipAddr.sin_port = htons(dAtoi(portString));
   else
      ipAddr.sin_port = htons(defaultPort);
   ipAddr.sin_family = AF_INET;
   IPSocketToNetAddress(&ipAddr, address);
   return true;
}
bool AppMesh::isBillboard()
{
   return !dStrnicmp(getName(),"BB::",4) || !dStrnicmp(getName(),"BB_",3) || isBillboardZAxis();
}
NetSocket Net::openConnectTo(const char *addressString)
{
   if(!dStrnicmp(addressString, "ipx:", 4))
      // ipx support deprecated
      return InvalidSocket;
   if(!dStrnicmp(addressString, "ip:", 3))
      addressString += 3;  // eat off the ip:
   char remoteAddr[256];
   dStrcpy(remoteAddr, addressString);

   char *portString = dStrchr(remoteAddr, ':');

   U16 port;
   if(portString)
   {
      *portString++ = 0;
      port = htons(dAtoi(portString));
   }
   else
      port = htons(defaultPort);

   if(!dStricmp(remoteAddr, "broadcast"))
      return InvalidSocket;

   if(Journal::IsPlaying())
   {
      U32 ret;
      Journal::Read(&ret);
      return NetSocket(ret);
   }
   NetSocket sock = openSocket();
   setBlocking(sock, false);

   sockaddr_in ipAddr;
   dMemset(&ipAddr, 0, sizeof(ipAddr));
   ipAddr.sin_addr.s_addr = inet_addr(remoteAddr);

   if(ipAddr.sin_addr.s_addr != INADDR_NONE)
   {
      ipAddr.sin_port = port;
      ipAddr.sin_family = AF_INET;
      if(::connect(sock, (struct sockaddr *)&ipAddr, sizeof(ipAddr)) ==  -1)
      {
         S32 err = getLastError();
         if(err != Net::WouldBlock)
         {
            Con::errorf("Error connecting %s: %s",
               addressString, strerror(err));
            ::closesocket(sock);
            sock = InvalidSocket;
         }
      }
      if(sock != InvalidSocket) 
      {
         // add this socket to our list of polled sockets
         addPolledSocket(sock, ConnectionPending);
      }
   }
   else
   {
      // need to do an asynchronous name lookup.  first, add the socket
      // to the polled list
      addPolledSocket(sock, NameLookupRequired, remoteAddr, port);
      // queue the lookup
      gNetAsync.queueLookup(remoteAddr, sock);
   }
   if(Journal::IsRecording())
      Journal::Write(U32(sock));
   return sock;
}