Exemplo n.º 1
0
  bool SchedulerBase::CreateSignalChannel(int *outSigId, SignalCallback callback, void *userdata)
  {
    LogAssert(IsMainThread());

    if (!LogVerify(outSigId) || !LogVerify(callback))
      return false;

    *outSigId = -1;

    // Create a set of pipes
    int fdPipe[2];
    int flags;
    int ret = pipe(fdPipe);

    if (ret != 0)
    {
      gLog.ErrnoError(errno, "Unable to create pipe for signaling");
      return false;
    }

    FileDescriptor pipeRead(fdPipe[0]);
    FileDescriptor pipeWrite(fdPipe[1]);

    flags = fcntl(pipeRead, F_GETFL);
    flags = flags | O_NONBLOCK;
    if (-1 == fcntl(pipeRead, F_SETFL, flags))
    {
      gLog.LogError("Failed to set read pipe to non-blocking.");
      return false;
    }
    flags = fcntl(pipeWrite, F_GETFL);
    flags = flags | O_NONBLOCK;
    if (-1 == fcntl(pipeWrite, F_SETFL, flags))
    {
      gLog.LogError("Failed to set write pipe to non-blocking.");
      return false;
    }

    if (!watchSocket(pipeRead))
      return false;

    schedulerSignalItem item;

    item.callback = callback;
    item.userdata = userdata;
    item.fdWrite = pipeWrite;
    item.fdRead = pipeRead;

    m_signals[item.fdRead] = item;

    pipeWrite.Detach();
    pipeRead.Detach();

    *outSigId = item.fdWrite;

    gLog.Optional(Log::TimerDetail, "Created signal channel from %d to %d .", item.fdWrite, item.fdRead);

    return true;
  }
Exemplo n.º 2
0
  bool ReadWriteLock::UnLock()
  {
    if (!LogVerify(m_initialized))
      return false;

    if (!LogVerify(!pthread_rwlock_unlock(&m_Lock)))
      return false;

    return true;
  }
Exemplo n.º 3
0
  bool QuickLock::UnLock()
  {
    if (!LogVerify(m_initialized))
      return false;

    if (!LogVerify(!pthread_mutex_unlock(&m_Lock)))
      return false;

    return true;
  }
Exemplo n.º 4
0
  int AutoQuickLock::LockWait(WaitCondition &condition, uint32_t msTimeout)
  {
    if (!LogVerify(m_isLockedByMe))
      return -1;

    return m_quickLock->LockWait(condition, msTimeout);
  }
Exemplo n.º 5
0
 bool AutoQuickLock::UnLock()
 {
   if (!LogVerify(m_isLockedByMe))
     return false;
   m_isLockedByMe = false;
   return m_quickLock->UnLock();
 }
Exemplo n.º 6
0
 bool AutoReadWriteLock::UnLock()
 {
   if (!LogVerify(m_lockedByMeType != AutoReadWriteLock::None))
     return false;
   m_lockedByMeType = AutoReadWriteLock::None;
   return m_rwLock->UnLock();
 }
Exemplo n.º 7
0
  void AutoQuickLock::SignalAndUnlock(WaitCondition &condition)
  {
    if (!LogVerify(m_isLockedByMe))
      return;

    m_isLockedByMe = false;
    m_quickLock->SignalAndUnlock(condition);
  }
Exemplo n.º 8
0
 void QuickLock::Destroy()
 {
   if (m_initialized)
   {
     LogVerify(!pthread_mutex_destroy(&m_Lock));
     m_initialized = false;
   }
 }
Exemplo n.º 9
0
  void Beacon::SetDefMinTxInterval(uint32_t val)
  {
    LogAssert(m_scheduler->IsMainThread());
    if (!LogVerify(val != 0)) // v10/4.1
      return;

    m_initialSessionParams.desiredMinTx = val;
  }
Exemplo n.º 10
0
  void Beacon::SetDefMulti(uint8_t val)
  {
    LogAssert(m_scheduler->IsMainThread());
    if (!LogVerify(val != 0)) // v10/4.1
      return;

    m_initialSessionParams.detectMulti = val;
  }
Exemplo n.º 11
0
 void ReadWriteLock::Destroy()
 {
   if (m_initialized)
   {
     LogVerify(!pthread_rwlock_destroy(&m_Lock));
     m_initialized = false;
   }
 }
Exemplo n.º 12
0
 bool AutoQuickLock::Lock()
 {
   if (!LogVerify(!m_isLockedByMe))
     return true;
   // only call once
   if (!m_quickLock->Lock())
     return false;
   m_isLockedByMe = true;
   return true;
 }
Exemplo n.º 13
0
  void WaitCondition::Signal()
  {
    if (!m_initDone)
    {
      LogAssertFalse("signaling on uninitialized signal");
      return;
    }

    LogVerify(!pthread_cond_signal(&m_condition));
  }
Exemplo n.º 14
0
 bool AutoReadWriteLock::WriteLock()
 {
   if (!LogVerify(m_lockedByMeType == AutoReadWriteLock::None))
     return true;
   // only call once
   if (!m_rwLock->WriteLock())
     return false;
   m_lockedByMeType = AutoReadWriteLock::Write;
   return true;
 }
Exemplo n.º 15
0
  void Beacon::KillSession(Session *session)
  {

    if (!LogVerify(session))
      return;

    LogAssert(m_scheduler->IsMainThread());

    LogVerify(1 == m_discMap.erase(session->GetLocalDiscriminator()));
    LogVerify(1 == m_IdMap.erase(session->GetId()));
    LogVerify(1 == m_sourceMap.erase(SourceMapKey(session->GetRemoteAddress(), session->GetLocalAddress())));

    LogOptional(Log::Session, "Removed session %s to %s id=%d.",
                session->GetLocalAddress().ToString(),
                session->GetRemoteAddress().ToString(),
                session->GetId());

    delete session;
  }
Exemplo n.º 16
0
  bool SchedulerBase::SetSocketCallback(int socket, Scheduler::SocketCallback callback, void *userdata)
  {
    LogAssert(IsMainThread());

    if (!LogVerify(callback) || !LogVerify(socket != -1))
      return false;

    if (!watchSocket(socket))
      return false;

    schedulerSocketItem item;

    item.callback = callback;
    item.userdata = userdata;
    item.socket = socket;

    m_sockets[socket] = item;

    return true;
  }
Exemplo n.º 17
0
  void QuickLock::SignalAndUnlock(WaitCondition &condition)
  {
    if (!LogVerify(m_initialized))
      return;

    condition.Signal();

    // Unlocking after is safer, but may be more expensive. In the simple case it
    // could be unlocked before the signal. There are more complicated cases
    // involving multiple waiters with different expectations, where this could be a
    // problems. For now we err on the side of safety.
    UnLock();
  }
Exemplo n.º 18
0
  bool QuickLock::Create()
  {
    if (!LogVerify(!m_initialized))
      return false;

    if (pthread_mutex_init(&m_Lock, NULL))
    {
      LogAssertFalse("pthread_mutex_init failed");
      return false;
    }
    m_initialized = true;
    return true;
  }
Exemplo n.º 19
0
  bool ReadWriteLock::Create()
  {
    if (!LogVerify(!m_initialized))
      return false;

    if (pthread_rwlock_init(&m_Lock, NULL))
    {
      LogAssertFalse("pthread_rwlock_init failed");
      return false;
    }
    m_initialized = true;
    return true;
  }
Exemplo n.º 20
0
  bool WaitCondition::Init()
  {
    if (m_initDone)
    {
      LogAssertFalse("WaitCondition::Init called more than once.");
      return true;
    }

    if (LogVerify(!pthread_cond_init(&m_condition, NULL)))
      m_initDone = true;

    return m_initDone;
  }
Exemplo n.º 21
0
/**
 * This needs a  to match compare.
 *
 * @return size_t
 */
size_t sockAddrBase::hash() const
{

  /**
   * Invalid always hashes to a constant ... 0 seems as good as any?
   */
  if (!IsValid())
    return 0;
  else if (IsIPv4())
  {
    // May not be the 'best' hash, but it should work. We add DNSP_HASHINIT
    // So that address 0.0.0.0 does not collide with !IsValid().
    if (!m_allowPort)
      return getIPv4Storage()->sin_addr.s_addr + DNSP_HASHINIT;
    else
    {
      const sockaddr_in *storage = getIPv4Storage();
      return hashlittle(&storage->sin_port, sizeof(storage->sin_port), storage->sin_addr.s_addr + DNSP_HASHINIT);
    }
  }
  else
  {
    const sockaddr_in6 *storage = getIPv6Storage();

    // Below is to make sure that we can use hashword. This should never fail, but
    // without the 'if' some compilers issue a warning.
    if (!LogVerify((sizeof(in6_addr) % 4) == 0))
      return 0;

    // May not be the 'best' hash, but it should work.
    uint32_t port = m_allowPort ? storage->sin6_port : 0;
    uint32_t hash = hashword(reinterpret_cast<const uint32_t *>(&storage->sin6_addr),
                             sizeof(in6_addr) / 4, DNSP_HASHINIT + port);
    return (hash + storage->sin6_scope_id + storage->sin6_flowinfo);
  }
}
Exemplo n.º 22
0
  bool SchedulerBase::Run()
  {
    uint32_t iter=0;
    TimeSpec timeout;
    TimeSpec immediate;
    bool gotEvents;

    if (!LogVerify(IsMainThread()))
      return false;

    m_isStarted = true;

    // Start with a quick event check.
    timeout = immediate;
    while (true)
    {
      iter++;

      if (m_wantsShutdown)
        break;

      // 
      //  Get event, or timeout. 
      // 
      gLog.Optional(Log::TimerDetail, "checking events (%u)", iter);
      gotEvents = waitForEvents(timeout);

      // By default the next event check is immediately.
      timeout = immediate;  

      // 
      // High priority timers, if any, get handled now 
      // 
      while (!m_wantsShutdown && expireTimer(Timer::Priority::Hi))
      { //nothing
      }

      if (m_wantsShutdown)
        break;

      // 
      //  Handle any events.
      // 
      if (gotEvents)
      {
        int socketId;

        gLog.Optional(Log::TimerDetail, "Handling events (%u)", iter);


        while (-1 != (socketId = getNextSocketEvent()))
        {
          // we have a socket event .. is it a socket or a signal?

          SocketItemHashMap::iterator foundSocket;
          SignalItemHashMap::iterator foundSignal;

          if (m_sockets.end() != (foundSocket = m_sockets.find(socketId)))
          {
            if (LogVerify(foundSocket->second.callback != NULL))
              foundSocket->second.callback(socketId, foundSocket->second.userdata);
          }
          else if (m_signals.end() != (foundSignal = m_signals.find(socketId)))
          {
            if (LogVerify(foundSignal->second.callback != NULL))
            {
              // 'Drain' the pipe.
              char drain[128];
              int result;
              size_t reads = 0;

              while ( 0 < (result = ::read(socketId, drain, sizeof(drain))))
                reads++;

              if (reads == 0 && result < 0)
                gLog.LogError("Failed to read from pipe %d: %s", socketId, strerror(errno));
              else if (result == 0)
                gLog.LogError("Signaling pipe write end for %d closed", socketId);

              foundSignal->second.callback(foundSignal->second.fdWrite, foundSignal->second.userdata);
            }
          }
          else
          {
            gLog.Optional(Log::TimerDetail, "Socket (%d) signaled with no handler (%u).", socketId, iter);
          }

          if (m_wantsShutdown)
            break;
        }

        if (m_wantsShutdown)
          break;
      }

      // 
      //  Handle a low priority timer if there are no events.
      //  TODO: starvation is a potential problem for low priority timers.
      // 
      if (!gotEvents && !expireTimer(Timer::Priority::Low))
      {
        // No events and no more timers, so we are ready to sleep again. 
        timeout = getNextTimerTimeout();
      }

      if (m_wantsShutdown)
        break;
    } // while true

    return true;
  }
Exemplo n.º 23
0
 int QuickLock::LockWait(WaitCondition &condition, uint32_t msTimeout)
 {
   if (!LogVerify(m_initialized))
     return -1;
   return condition.Wait(&m_Lock, msTimeout);
 }
Exemplo n.º 24
0
 /**
  * Call from any thread to trigger handleSelfMessage on main thread.
  *
  *
  * @return bool
  */
 bool Beacon::triggerSelfMessage()
 {
   if (!LogVerify(m_selfSignalId != -1) || !LogVerify(m_scheduler))
     return false;
   return m_scheduler->Signal(m_selfSignalId);
 }
Exemplo n.º 25
0
  static bool doLoadScript(const char *path, const SockAddr &connectAddr)
  {
    ifstream file;
    string line;
    int lines = 0;
    vector<char> buffer;
    const char *seps = " \t";

    file.open(path);
    if (!file.is_open())
    {
      fprintf(stderr, "Failed to open file <%s> : %s\n", path, ErrnoToString());
      return false;
    }

    buffer.reserve(MaxCommandSize);
    while (getline(file, line), file.good())
    {
      size_t pos = 0;
      lines++;
      if (line.empty())
        continue;
      if (line[0] == '#')
        continue;

      // Parse the command line. This doe not currently handle quoted parameters. If
      // we ever have a command that takes, for example, a file name, then this will
      // need to be fixed.
      buffer.resize(0);
      pos = line.find_first_not_of(seps, 0);
      while (pos != string::npos)
      {
        size_t sepPos = line.find_first_of(seps, pos);
        LogVerify(sepPos != pos);
        size_t end = (sepPos == string::npos) ? line.length() : sepPos;
        size_t bufpos = buffer.size();
        buffer.resize(bufpos + end - pos);
        memcpy(&buffer[bufpos], &line[pos], end - pos);
        buffer.push_back('\0');
        if (sepPos == string::npos)
          break;
        pos = line.find_first_not_of(seps, end);
      }

      if (buffer.size() != 0)
      {
        fprintf(stdout, " Command <%s>\n", line.c_str());

        // buffer is double null terminated.
        buffer.push_back('\0');
        if (!SendData(&buffer.front(), buffer.size(), connectAddr, "   "))
          return false;
      }
    }

    if (!file.eof())
    {
      fprintf(stderr, "Failed to read from file <%s>. %d lines processed: %s\n", path, lines, ErrnoToString());
      return false;
    }

    file.close();
    return true;
  }
Exemplo n.º 26
0
const char* sockAddrBase::ToString(bool includePort /*true*/) const
{
  in_port_t port = includePort ? Port() : 0;

  if (IsIPv4())
  {
    if (port == 0)
      return Ip4ToString(getIPv4Storage()->sin_addr);
    else
      return Ip4ToString(getIPv4Storage()->sin_addr, port);
  }
  else if (IsIPv6())
  {
    const sockaddr_in6 *storage = getIPv6Storage();

    if (storage->sin6_scope_id == 0 && !port)
    {
      // Just IPv6 address
      char *buffer;
      size_t bufsize = GetSmallTLSBuffer(&buffer);
      if (!bufsize)
        return "<memerror>";
      if (!inet_ntop(AF_INET6, &storage->sin6_addr, buffer, bufsize))
        return "<Invalid Address>";
      return buffer;
    }
    else
    {
      // composite address
      char ifNameBuf[IF_NAMESIZE];
      char addrStrBuf[INET6_ADDRSTRLEN];
      const char *ifName = NULL;
      const char *addrStr = NULL;

      if (storage->sin6_scope_id)
      {
        ifName = if_indextoname(storage->sin6_scope_id, ifNameBuf);
        if (!ifName)
          ifName = "???";
      }

      addrStr = inet_ntop(AF_INET6, &storage->sin6_addr, addrStrBuf, sizeof(addrStrBuf));
      if (!addrStr)
        addrStr = "<Invalid IPv6>";

      if (port)
      {
        if (ifName)
          return FormatShortStr("[%s%%%s]:%d", addrStr, ifName, (int)port);
        else
          return FormatShortStr("[%s]:%d", addrStr, (int)port);
      }
      else
      {
        if (ifName)
          return FormatShortStr("%s%%%s", addrStr, ifName);
        else
        {
          LogVerify(false); // should never happen
          return FormatShortStr("%s", addrStr);
        }
      }
    }
  }
  else
    return "<Invalid Address>";
}
Exemplo n.º 27
0
 WaitCondition::~WaitCondition()
 {
   if (m_initDone)
     LogVerify(!pthread_cond_destroy(&m_condition));
 }
Exemplo n.º 28
0
  void Beacon::handleListenSocket(Socket &socket)
  {
    SockAddr sourceAddr;
    IpAddr destIpAddr, sourceIpAddr;
    uint8_t ttl;
    BfdPacket packet;
    bool found;
    Session *session = NULL;

    if (!m_packet.DoRecvMsg(socket))
    {
      gLog.ErrnoError(m_packet.GetLastError(), "Error receiving on BFD listen socket");
      return;
    }

    sourceAddr = m_packet.GetSrcAddress();
    if (!LogVerify(sourceAddr.IsValid()))
      return;
    sourceIpAddr = IpAddr(sourceAddr);

    destIpAddr = m_packet.GetDestAddress();
    if (!destIpAddr.IsValid())
    {
      gLog.LogError("Could not get destination address for packet from %s.", sourceAddr.ToString());
      return;
    }

    ttl = m_packet.GetTTLorHops(&found);
    if (!found)
    {
      gLog.LogError("Could not get ttl for packet from %s.", sourceAddr.ToString());
      return;
    }

    LogOptional(Log::Packet, "Received bfd packet %zu bytes from %s to %s", m_packet.GetDataSize(), sourceAddr.ToString(), destIpAddr.ToString());

    //
    // Check ip specific stuff. See draft-ietf-bfd-v4v6-1hop-11.txt
    //

    // Port
    if (m_strictPorts)
    {
      if (sourceAddr.Port() < bfd::MinSourcePort) // max port is max value, so no need to check
      {
        LogOptional(Log::Discard, "Discard packet: bad source port %s to %s", sourceAddr.ToString(), destIpAddr.ToString());
        return;
      }
    }

    // TTL assumes that all control packets are from neighbors.
    if (ttl != 255)
    {
      gLog.Optional(Log::Discard, "Discard packet: bad ttl/hops %hhu", ttl);
      return;
    }

    if (!Session::InitialProcessControlPacket(m_packet.GetData(), m_packet.GetDataSize(), packet))
    {
      gLog.Optional(Log::Discard, "Discard packet");
      return;
    }

    // We have a (partially) valid packet ... now find the correct session.
    if (packet.header.yourDisc != 0)
    {
      DiscMapIt found = m_discMap.find(packet.header.yourDisc);
      if (found == m_discMap.end())
      {
        if (gLog.LogTypeEnabled(Log::DiscardDetail))
          Session::LogPacketContents(packet, false, true, sourceAddr, destIpAddr);

        gLog.Optional(Log::Discard, "Discard packet: no session found for yourDisc <%u>.", packet.header.yourDisc);
        return;
      }
      session = found->second;
      if (session->GetRemoteAddress() != sourceIpAddr)
      {
        if (gLog.LogTypeEnabled(Log::DiscardDetail))
          Session::LogPacketContents(packet, false, true, sourceAddr, destIpAddr);

        LogOptional(Log::Discard, "Discard packet: mismatched yourDisc <%u> and ip <from %s to %s>.", packet.header.yourDisc, sourceAddr.ToString(), destIpAddr.ToString());
        return;
      }
    }
    else
    {
      // No discriminator
      session = findInSourceMap(sourceIpAddr, destIpAddr);
      if (NULL == session)
      {
        // No session yet .. create one !?
        if (!m_allowAnyPassiveIP && m_allowedPassiveIP.find(sourceIpAddr) == m_allowedPassiveIP.end())
        {
          if (gLog.LogTypeEnabled(Log::DiscardDetail))
            Session::LogPacketContents(packet, false, true, sourceAddr, destIpAddr);

          LogOptional(Log::Discard, "Ignoring unauthorized bfd packets from %s",  sourceAddr.ToString());
          return;
        }

        session = addSession(sourceIpAddr, destIpAddr);
        if (!session)
          return;
        if (!session->StartPassiveSession(sourceAddr, destIpAddr))
        {
          gLog.LogError("Failed to add new session for local %s to remote  %s id=%d.", destIpAddr.ToString(), sourceAddr.ToString(), session->GetId());
          KillSession(session);
        }
        LogOptional(Log::Session, "Added new session for local %s to remote  %s id=%d.", destIpAddr.ToString(), sourceAddr.ToString(), session->GetId());
      }
    }

    //
    //  We have a session that can handle the rest.
    //
    session->ProcessControlPacket(packet, sourceAddr.Port());
  }