Logo Search packages:      
Sourcecode: sbnc version File versions  Download package

void CCore::StartMainLoop ( void   ) 

StartMainLoop

Executes shroudBNC's main loop.

Definition at line 252 of file Core.cpp.

References BuildPath(), CSocketEvents::Destroy(), CIRCConnection::Destroy(), CSocketEvents::Error(), Fatal(), CVector< Type >::GetLength(), CVector< Type >::GetList(), CTimer::GetNextCall(), GetStatus(), InitializeAdditionalListeners(), CConnection::IsLocked(), CIRCConnection::Kill(), LoadModule(), Log(), m_Args, m_Config, m_DnsQueries, m_ListenerV6, m_LoadingModules, m_OtherSockets, m_PollFds, m_SSLClientContext, m_SSLContext, m_SSLListenerV6, m_Users, CSocketEvents::Read(), CConfig::ReadString(), CConnection::ShouldDestroy(), CSocketEvents::Write(), and WritePidFile().

                              {
      unsigned int i;

      time(&g_CurrentTime);

      int argc = m_Args.GetLength();
      char **argv = m_Args.GetList();

      int Port = CacheGetInteger(m_ConfigCache, port);
#ifdef USESSL
      int SSLPort = CacheGetInteger(m_ConfigCache, sslport);

      if (Port == 0 && SSLPort == 0) {
#else
      if (Port == 0) {
#endif
            Port = 9000;
      }

      const char *BindIp = CacheGetString(m_ConfigCache, ip);

      if (m_Listener == NULL) {
            if (Port != 0) {
                  safe_box_t ListenerBox;

                  ListenerBox = safe_put_box(NULL, "Listener");

                  m_Listener = new CClientListener(Port, ListenerBox, BindIp, AF_INET);
            } else {
                  m_Listener = NULL;
            }
      }

      if (m_ListenerV6 == NULL) {
            if (Port != 0) {
                  safe_box_t ListenerBox;

                  ListenerBox = safe_put_box(NULL, "ListenerV6");

                  m_ListenerV6 = new CClientListener(Port, ListenerBox, BindIp, AF_INET6);

                  if (m_ListenerV6->IsValid() == false) {
                        delete m_ListenerV6;

                        m_ListenerV6 = NULL;
                  }
            } else {
                  m_ListenerV6 = NULL;
            }
      }

#ifdef USESSL
      if (m_SSLListener == NULL) {
            if (SSLPort != 0) {
                  safe_box_t ListenerBox;

                  ListenerBox = safe_put_box(NULL, "ListenerSSL");

                  m_SSLListener = new CClientListener(SSLPort, ListenerBox, BindIp, AF_INET, true);
            } else {
                  m_SSLListener = NULL;
            }
      }

      if (m_SSLListenerV6 == NULL) {
            if (SSLPort != 0) {
                  safe_box_t ListenerBox;

                  ListenerBox = safe_put_box(NULL, "ListenerSSLV6");

                  m_SSLListenerV6 = new CClientListener(SSLPort, ListenerBox, BindIp, AF_INET6, true);

                  if (m_SSLListenerV6->IsValid() == false) {
                        delete m_SSLListenerV6;

                        m_SSLListenerV6 = NULL;
                  }
            } else {
                  m_SSLListenerV6 = NULL;
            }
      }

      SSL_library_init();
      SSL_load_error_strings();

      SSL_METHOD *SSLMethod = SSLv23_method();

      m_SSLContext = SSL_CTX_new(SSLMethod);
      SSL_CTX_set_safe_passwd_cb(m_SSLContext);

      m_SSLClientContext = SSL_CTX_new(SSLMethod);
      SSL_CTX_set_safe_passwd_cb(m_SSLClientContext);

      SSL_CTX_set_mode(m_SSLContext, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
      SSL_CTX_set_mode(m_SSLClientContext, SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);

      g_SSLCustomIndex = SSL_get_ex_new_index(0, (void *)"CConnection*", NULL, NULL, NULL);

      if (!SSL_CTX_use_PrivateKey_file(m_SSLContext, BuildPath("sbnc.key"), SSL_FILETYPE_PEM)) {
            if (SSLPort != 0) {
                  Log("Could not load private key (sbnc.key).");
                  ERR_print_errors_fp(stdout);
                  return;
            } else {
                  SSL_CTX_free(m_SSLContext);
                  m_SSLContext = NULL;
            }
      } else {
            SSL_CTX_set_verify(m_SSLContext, SSL_VERIFY_PEER, SSLVerifyCertificate);
      }

      if (!SSL_CTX_use_certificate_chain_file(m_SSLContext, BuildPath("sbnc.crt"))) {
            if (SSLPort != 0) {
                  Log("Could not load public key (sbnc.crt).");
                  ERR_print_errors_fp(stdout);
                  return;
            } else {
                  SSL_CTX_free(m_SSLContext);
                  m_SSLContext = NULL;
            }
      } else {
            SSL_CTX_set_verify(m_SSLClientContext, SSL_VERIFY_PEER, SSLVerifyCertificate);
      }
#endif

      if (Port != 0 && m_Listener != NULL && m_Listener->IsValid()) {
            Log("Created main listener.");
      } else if (Port != 0) {
            Log("Could not create listener port");
            return;
      }

#ifdef USESSL
      if (SSLPort != 0 && m_SSLListener != NULL && m_SSLListener->IsValid()) {
            Log("Created ssl listener.");
      } else if (SSLPort != 0) {
            Log("Could not create ssl listener port");
            return;
      }
#endif

      InitializeAdditionalListeners();

      Log("Starting main loop.");

      WritePidFile();

      /* Note: We need to load the modules after using fork() as otherwise tcl cannot be cleanly unloaded */
      m_LoadingModules = true;

#ifdef _MSC_VER
#ifndef _DEBUG
      LoadModule("bnctcl.dll");
#else
      LoadModule("..\\bnctcl\\Debug\\bnctcl.dll");
#endif
#else
      LoadModule("./libbnctcl.la");
#endif

      char *Out;

      i = 0;
      while (true) {
            asprintf(&Out, "system.modules.mod%d", i++);

            CHECK_ALLOC_RESULT(Out, asprintf) {
                  Fatal();
            } CHECK_ALLOC_RESULT_END;

            const char *File = m_Config->ReadString(Out);

            free(Out);

            if (File != NULL) {
                  LoadModule(File);
            } else {
                  break;
            }
      }

      m_LoadingModules = false;

      i = 0;
      while (hash_t<CUser *> *User = m_Users.Iterate(i++)) {
            User->Value->LoadEvent();
      }

      int m_ShutdownLoop = 5;

      time_t Last = 0;
      time_t LastCheck = 0;

      while (GetStatus() == STATUS_RUN || GetStatus() == STATUS_PAUSE || --m_ShutdownLoop) {
            time_t Now, Best = 0, SleepInterval = 0;

#if defined(_WIN32) && defined(_DEBUG)
            DWORD TickCount = GetTickCount();
#endif

            time(&Now);

            i = 0;
            while (hash_t<CUser *> *UserHash = m_Users.Iterate(i++)) {
                  CIRCConnection *IRC;

                  if ((IRC = UserHash->Value->GetIRCConnection()) != NULL) {
                        if (GetStatus() != STATUS_RUN && GetStatus() != STATUS_PAUSE && IRC->IsLocked() == false) {
                              Log("Closing connection for user %s", UserHash->Name);
                              IRC->Kill("Shutting down.");

                              UserHash->Value->SetIRCConnection(NULL);
                        }

                        if (IRC->ShouldDestroy()) {
                              IRC->Destroy();
                        }
                  }
            }

            CUser::RescheduleReconnectTimer();

            time(&Now);

            if (g_CurrentTime - 5 > Now) {
                  Log("Time warp detected: %d seconds", Now - g_CurrentTime);
            }

            g_CurrentTime = Now;

            Best = CTimer::GetNextCall();

            if (Best <= g_CurrentTime) {
#ifdef _DEBUG
                  if (g_CurrentTime - 1 > Best) {
#else
                  if (g_CurrentTime - 5 > Best) {
#endif
                        Log("Time warp detected: %d seconds", g_CurrentTime - Best);
                  }

                  CTimer::CallTimers();

                  Best = CTimer::GetNextCall();
            }

            SleepInterval = Best - g_CurrentTime;

            for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) {
                  if (SocketCursor->PollFd->fd == INVALID_SOCKET) {
                        continue;
                  }

                  if (SocketCursor->Events->ShouldDestroy()) {
                        SocketCursor->Events->Destroy();
                  } else {
                        SocketCursor->PollFd->events = POLLIN | POLLERR;

                        if (SocketCursor->Events->HasQueuedData()) {
                              SocketCursor->PollFd->events |= POLLOUT;
                        }
                  }
            }

            if (SleepInterval <= 0 || (GetStatus() != STATUS_RUN && GetStatus() != STATUS_PAUSE)) {
                  SleepInterval = 1;
            }

            timeval interval = { SleepInterval, 0 };

            if (GetStatus() != STATUS_RUN && GetStatus() != STATUS_PAUSE && SleepInterval > 3) {
                  interval.tv_sec = 3;
            }

            for (unsigned int i = 0; i < m_DnsQueries.GetLength(); i++) {
                  ares_channel Channel = m_DnsQueries[i]->GetChannel();

                  if (Channel != NULL) {
                        ares_fds(Channel);
                        ares_timeout(Channel, NULL, &interval);
                  }
            }

            time(&Last);

#ifdef _DEBUG
            //safe_printf("poll: %d seconds\n", SleepInterval);
#endif

#if defined(_WIN32) && defined(_DEBUG)
            DWORD TimeDiff = GetTickCount();
#endif

            int ready = safe_poll(m_PollFds.GetList(), m_PollFds.GetLength(), interval.tv_sec * 1000);

#if defined(_WIN32) && defined(_DEBUG)
            TickCount += GetTickCount() - TimeDiff;
#endif

            time(&g_CurrentTime);

            for (unsigned int i = 0; i < m_DnsQueries.GetLength(); i++) {
                  ares_channel Channel = m_DnsQueries[i]->GetChannel();

                  ares_process(Channel);

                  m_DnsQueries[i]->Cleanup();
            }

            if (ready > 0) {
                  for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) {
                        pollfd *PollFd = SocketCursor->PollFd;
                        CSocketEvents *Events = SocketCursor->Events;

                        if (PollFd->fd != INVALID_SOCKET) {
                              if (PollFd->revents & (POLLERR|POLLHUP|POLLNVAL)) {
                                    int ErrorCode;
                                    socklen_t ErrorCodeLength = sizeof(ErrorCode);

                                    ErrorCode = 0;

                                    if (safe_getsockopt(PollFd->fd, SOL_SOCKET, SO_ERROR, (char *)&ErrorCode, &ErrorCodeLength) != -1) {
                                          if (ErrorCode != 0) {
                                                Events->Error(ErrorCode);
                                          }
                                    }

                                    if (ErrorCode == 0) {
                                          Events->Error(-1);
                                    }

                                    Events->Destroy();

                                    continue;
                              }

                              if (PollFd->revents & (POLLIN|POLLPRI)) {
                                    int Code;
                                    if ((Code = Events->Read()) != 0) {
                                          Events->Error(Code);
                                          Events->Destroy();

                                          continue;
                                    }
                              }

                              if (PollFd->revents & POLLOUT) {
                                    Events->Write();
                              }
                        }
                  }
            } else if (ready == -1) {
#ifndef _WIN32
                  if (safe_errno() != EBADF && safe_errno() != 0) {
#else
                  if (safe_errno() != WSAENOTSOCK) {
#endif
                        continue;
                  }

                  link_t<socket_t> *Current = m_OtherSockets.GetHead();

                  m_OtherSockets.Lock();

                  for (CListCursor<socket_t> SocketCursor(&m_OtherSockets); SocketCursor.IsValid(); SocketCursor.Proceed()) {
                        if (SocketCursor->PollFd->fd == INVALID_SOCKET) {
                              continue;
                        }

                        pollfd pfd;
                        pfd.fd = SocketCursor->PollFd->fd;
                        pfd.events = POLLIN | POLLOUT | POLLERR;

                        int code = safe_poll(&pfd, 1, 0);

                        if (code == -1) {
                              SocketCursor->Events->Error(-1);
                              SocketCursor->Events->Destroy();
                        }
                  }
            }

#if defined(_WIN32) && defined(_DEBUG)
            DWORD Ticks = GetTickCount() - TickCount;

            if (Ticks > 50) {
                  safe_printf("Spent %d msec in the main loop.\n", Ticks);
            }
#endif
      }

#ifdef USESSL
      SSL_CTX_free(m_SSLContext);
      SSL_CTX_free(m_SSLClientContext);
#endif
}


Generated by  Doxygen 1.6.0   Back to index