|
|
||
|---|---|---|
| .idea | ||
| autom4te.cache | ||
| bin | ||
| contrib | ||
| db | ||
| doc | ||
| include | ||
| lib | ||
| libgnuworld | ||
| libircu | ||
| libltdl | ||
| mod.ccontrol | ||
| mod.chanfix | ||
| mod.clientExample | ||
| mod.cloner | ||
| mod.cservice | ||
| mod.dronescan | ||
| mod.gnutest | ||
| mod.nickserv | ||
| mod.openchanfix | ||
| mod.scanner | ||
| mod.snoop | ||
| mod.stats | ||
| src | ||
| test | ||
| tools | ||
| AUTHORS | ||
| COPYING | ||
| ChangeLog | ||
| Credits | ||
| INSTALL | ||
| INSTALL-NEW-Website.txt | ||
| INSTALL-NEW-gnuworld.txt | ||
| INSTALL-NEW-ircd.txt | ||
| INSTALL-Useful-ToKnow.txt | ||
| LICENSE | ||
| Makefile.am | ||
| Makefile.in | ||
| NEWS | ||
| README | ||
| README-DO-UPDATES.txt | ||
| README-Database-backup.txt | ||
| README-Good-ToKnow.txt | ||
| README-NEW-Features.txt | ||
| README.md | ||
| TODO | ||
| ac_cxx_namespaces.m4 | ||
| aclocal.m4 | ||
| autogen.sh | ||
| ax_boost_thread.m4 | ||
| config-h.in | ||
| config.guess | ||
| config.sub | ||
| configure | ||
| configure.ac | ||
| debug.log | ||
| depcomp | ||
| install-sh | ||
| ltconfig | ||
| ltmain.sh | ||
| missing | ||
| mkinstalldirs | ||
README.md
🌐 GNUWorld — Servicii IRC pentru Undernet/P10
Prezentare Generală
GNUWorld este un cadru (framework) de servicii IRC scris în C++, proiectat pentru rețele bazate pe protocolul P10 (ircu/Undernet). Arhitectura este modulară, permițând încărcarea dinamică a clienților de servicii (CService, CControl, ChanFix, DroneScan etc.) prin intermediul bibliotecii libtool (lt_dlopen).
Proiectul este o adaptare și extensie a GNUWorld original, personalizat pentru nevoile rețelei Underchat.
📐 Arhitectura Generală
Ierarhia de Clase Principale
NetworkTarget ← Clasa de bază (adresare numerică P10 base64: YY + XXX)
├── iClient ← Utilizator de rețea (nick, user, host, moduri, canale)
├── iServer ← Server de rețea (uplink, stare burst, flag-uri)
├── xClient (+ TimerHandler) ← Client de servicii (bază pentru module: cservice, ccontrol etc.)
└── xServer (+ ConnectionManager ← Serverul principal — inima sistemului
+ ConnectionHandler
+ NetworkTarget)
Channel ← Canal IRC (moduri, utilizatori, ban-uri)
ChannelUser ← Asociere utilizator-canal (op, voice, half-op)
xNetwork ← Container global — stochează toți clienții, serverele și canalele
Componentele Cheie
| Componentă | Locație | Descriere |
|---|---|---|
| xServer | include/server.h, src/server.cc, src/main.cc |
Serverul principal — bucla de evenimente, gestionarea conexiunii, rutarea mesajelor |
| xClient | include/client.h |
Clasa de bază pentru toate modulele de servicii |
| xNetwork | include/Network.h, src/Network.cc |
Containerul global al rețelei — tabele pentru clienți, servere, canale |
| ConnectionManager | libgnuworld/ConnectionManager.h, libgnuworld/ConnectionManager.cc |
Gestionarea conexiunilor I/O prin select() |
| iClient / iServer | include/iClient.h, include/iServer.h |
Reprezentarea entităților de rețea |
| Channel / ChannelUser | include/Channel.h, include/ChannelUser.h |
Reprezentarea canalelor și a utilizatorilor din canale |
| Baza de Date | db/gnuworldDB.h, db/pgsqlDB.h |
Strat abstract cu implementare PostgreSQL |
🔄 Bucla Principală de Evenimente
Punctul de intrare este main() din src/main.cc, care instanțiază xServer și apelează run() → mainLoop().
Fluxul mainLoop() (din src/main.cc, linia 335):
┌─────────────────────────────────────────────┐
│ while( keepRunning ) │
│ │
│ 1. Verifică reconectarea (dacă e cazul) │
│ 2. Verifică dacă este ultima iterație │
│ 3. Calculează timeout-ul pe baza timerelor │
│ 4. ConnectionManager::Poll(seconds) │
│ └─> select() pe toate socket-urile │
│ └─> handleRead() / handleWrite() │
│ └─> OnRead() → Process() → dispatch │
│ 5. CheckTimers() — execută timerele │
│ 6. Verifică semnalele (Signal::getSignal) │
│ 7. PostSignal() către module │
│ │
│ La ieșire: doShutdown() │
└─────────────────────────────────────────────┘
Multiplexarea I/O — select()
ConnectionManager::Poll() (din libgnuworld/ConnectionManager.cc, linia 559) folosește apelul select() clasic:
- Iterează prin
handlerMap(mapareConnectionHandler* → set<Connection*>) - Configurează
fd_set(readfds / writefds) pentru fiecare conexiune - Apelează
::select(1 + highestFD, &readfds, &writefds, 0, &to) - Procesează rezultatele: citire, scriere, conexiuni noi, timeout-uri
⚠️ Observație: Se folosește
select()și nupoll()/epoll(). Aceasta este o limitare pentru rețele foarte mari (limita FD_SETSIZE, de obicei 1024).
🔗 Procesarea BURST și Sincronizarea cu Rețeaua
Sincronizarea cu rețeaua urmează protocolul P10 complet:
Secvența de Burst:
1. msg_Server → Creează iServer pentru uplink, pornește burst-ul
2. msg_S → Adaugă servere noi (EVT_NETJOIN)
3. msg_N → Adaugă clienți de rețea (iClient) în timpul burst-ului
4. msg_B → BURST canale: moduri, utilizatori (base64), ban-uri
(libircu/msg_B.cc — 541 linii, parser complex)
5. msg_EB → End of Burst:
├─ setUseHoldBuffer(false) — eliberează bufferul reținut
├─ BurstClients() — trimite clienții de servicii
├─ BurstChannels() — trimite canalele serviciilor
├─ setBursting(false)
├─ PostEvent(EVT_BURST_CMPLT)
├─ Trimite EB + EA
└─ WriteBurstBuffer() — golește datele reținute
6. msg_EA → End of Burst Acknowledge — confirmă sincronizarea
Mecanismul burstHoldBuffer:
În timpul burst-ului, Write() redirecționează datele într-un burstHoldBuffer separat (variabila useHoldBuffer). Aceasta previne trimiterea prematură de date către rețea înainte ca sincronizarea să fie completă. După msg_EB, datele sunt transferate în bufferul normal de ieșire prin WriteBurstBuffer().
🧩 Sistemul de Module (Pluginuri)
Încărcare Dinamică
Modulele sunt încărcate prin libtool (lt_dlopen) folosind clasa template moduleLoader<> din include/moduleLoader.h.
Două tipuri de module:
-
Module de Servicii (
xClient) — încărcate prinloadClients():- Fiecare subclasează
xClient - Exportă o funcție fabrică:
_gnuwinit_<nume>(configFile) - Exemple:
mod.cservice,mod.ccontrol,mod.chanfix
- Fiecare subclasează
-
Handlere de Comenzi Server (
ServerCommandHandler) — încărcate prinloadCommandHandlers():- Fiecare procesează un mesaj P10 specific (B, N, Q, M, J, etc.)
- Exportă:
_gnuwinit_<msg_X>(xServer*) - Locație:
libircu/msg_*.cc(~42 de handlere) - Macrourile
CREATE_HANDLER/CREATE_LOADERsimplifică declararea
Handlere P10 Disponibile (libircu/)
| Token | Handler | Descriere |
|---|---|---|
B |
msg_B |
BURST — sincronizare canale |
N |
msg_N |
NICK — client nou / schimbare nick |
S |
msg_S |
SERVER — server nou |
J |
msg_J |
JOIN — intrare în canal |
L |
msg_L |
PART — ieșire din canal |
Q |
msg_Q |
QUIT — deconectare client |
M |
msg_M |
MODE — schimbare moduri |
P |
msg_P |
PRIVMSG — mesaj privat |
K |
msg_K |
KICK — eliminare din canal |
G / GL |
msg_G / msg_GL |
GLINE — ban global |
EB |
msg_EB |
End of Burst |
EA |
msg_EA |
End of Burst Acknowledge |
SQ |
msg_SQ |
SQUIT — deconectare server |
AC |
msg_AC |
ACCOUNT — autentificare |
T |
msg_T |
TOPIC |
CM |
msg_CM |
CLEARMODE |
W |
msg_W |
WHOIS |
I |
msg_I |
INVITE |
XQ / XR |
msg_XQ / msg_XR |
Interogări/Răspunsuri extinse |
📊 Sistemul de Evenimente
Evenimente de Rețea (definite în include/events.h):
| Eveniment | Descriere |
|---|---|
EVT_NICK |
Client nou conectat |
EVT_QUIT |
Client deconectat |
EVT_KILL |
Client eliminat (kill) |
EVT_CHNICK |
Schimbare de nick |
EVT_OPER |
Operator IRC |
EVT_NETJOIN |
Server nou conectat |
EVT_NETBREAK |
Server deconectat (netsplit) |
EVT_BURST_CMPLT |
Burst complet |
EVT_BURST_ACK |
Confirmare burst |
EVT_GLINE / EVT_REMGLINE |
Adăugare/Ștergere GLINE |
EVT_ACCOUNT |
Autentificare cont |
Evenimente de Canal:
| Eveniment | Descriere |
|---|---|
EVT_JOIN |
Intrare în canal |
EVT_PART |
Ieșire din canal |
EVT_KICK |
Eliminare din canal |
EVT_TOPIC |
Schimbare topic |
EVT_CREATE |
Canal creat |
Modulele se înregistrează prin RegisterEvent() / RegisterChannelEvent() și primesc notificări prin OnEvent() / OnChannelEvent().
🗄️ Baza de Date
Arhitectura:
gnuworldDB (abstract) ← db/gnuworldDB.h — Interfață abstractă (Exec, isConnected)
└── pgsqlDB ← db/pgsqlDB.h — Implementare PostgreSQL (libpq)
Modele SQL per Modul (exemplu: mod.cservice):
| Clasă | Fișier | Descriere |
|---|---|---|
sqlUser |
mod.cservice/sqlUser.h |
Utilizator CService |
sqlChannel |
mod.cservice/sqlChannel.h |
Canal înregistrat |
sqlLevel |
mod.cservice/sqlLevel.h |
Nivel de acces utilizator-canal |
sqlBan |
mod.cservice/sqlBan.h |
Ban pe canal |
Scripturile SQL de inițializare se găsesc în directorul doc/ (cservice.sql, ccontrol.sql, etc.).
⚠️ Gestionarea Memoriei — Probleme Identificate
Folosire exclusivă de new/delete brut
Codul nu utilizează deloc smart pointers (std::unique_ptr, std::shared_ptr). Toate alocările sunt manuale:
// Exemple de alocare tipice:
iClient* theClient = new (std::nothrow) iClient(...);
Channel* theChan = new (std::nothrow) Channel(...);
ChannelUser* chanUser = new (std::nothrow) ChannelUser(theClient);
Zone Critice de Dealocare:
| Locație | Ce se dezalocă |
|---|---|
xServer::doShutdown() |
Clienți locali, clienți de rețea, canale, servere, gline-uri, timere |
xNetwork::removeClient() |
ChannelUser asociați, canale goale |
xNetwork::removeServer() |
Toți clienții de pe serverul eliminat |
msg_Q::Execute() |
iClient la QUIT |
msg_B::Execute() |
Channel + ChannelUser la BURST (cu verificare de erori) |
Potențiale Scurgeri de Memorie:
doShutdown()— Iterare cu break prematur: Buclele de cleanup iterează și facbreakdacă containerul devine gol, dar sar elemente intermediare dacă mai sunt.msg_B::parseBurstBans()— Vectorul de ban-uri este creat cust.size()elemente goale și apoi se facepush_back, rezultând elemente duplicate goale.channelEventMap— Listele alocate cunewpentru evenimentele de canal trebuie dezalocate manual.- Excepții negestionate — Fără RAII, orice excepție între
newșideletecreează o scurgere.
📁 Structura Directoarelor
underchat-gnuworld/
├── src/ ← Codul sursă principal (main.cc, server.cc, Network.cc)
├── include/ ← Fișierele header principale
├── libircu/ ← Handlere protocol P10 (msg_*.cc — ~42 fișiere)
├── libgnuworld/ ← Biblioteci auxiliare (ConnectionManager, ELog, EConfig, Buffer)
├── db/ ← Stratul de bază de date (abstract + PostgreSQL)
├── mod.cservice/ ← Modulul CService (X) — managementul canalelor
├── mod.ccontrol/ ← Modulul CControl — administrare rețea
├── mod.chanfix/ ← Modulul ChanFix — reparare canale
├── mod.dronescan/ ← Modulul DroneScan — detectare boți
├── mod.nickserv/ ← Modulul NickServ — servicii de nick
├── mod.openchanfix/ ← Modulul OpenChanFix
├── mod.scanner/ ← Modulul Scanner
├── mod.snoop/ ← Modulul Snoop — monitorizare
├── mod.stats/ ← Modulul Stats — statistici
├── mod.cloner/ ← Modulul Cloner (testare)
├── mod.gnutest/ ← Modulul de test
├── mod.clientExample/ ← Exemplu de modul client
├── bin/ ← Fișiere de configurare (.conf, .sh)
├── doc/ ← Documentație și scripturi SQL
├── contrib/ ← Utilitare auxiliare
├── test/ ← Teste
└── tools/ ← Unelte de dezvoltare
⚙️ Compilare și Instalare
Cerințe:
- Compilator C++ (GCC / G++ — standard pre-C++11)
- PostgreSQL (libpq-dev)
- libtool (pentru încărcarea dinamică a modulelor)
- autotools (autoconf, automake)
Pași de compilare:
./autogen.sh
./configure
make
make install
Configurare:
Fișierele de configurare se găsesc în directorul bin/:
GNUWorld.example.conf.in— Configurația principală a serveruluicservice.example.conf.in— Configurația CServiceccontrol.example.conf.in— Configurația CControl- Alte fișiere
.conf.inpentru fiecare modul
🔧 Recomandări de Modernizare
| Zonă | Starea Curentă | Recomandare |
|---|---|---|
| Multiplexare I/O | select() |
Migrare la epoll() (Linux) sau kqueue() (BSD) |
| Gestionare Memorie | new/delete brut |
Adoptare std::unique_ptr / std::shared_ptr (RAII) |
| Standard C++ | Pre-C++11 | Migrare la C++17 minim |
| Încărcare Module | libtool (lt_dlopen) |
dlopen() nativ sau C++20 modules |
| Bază de Date | PostgreSQL sincron | Query-uri asincrone (PQsendQuery) |
| Parsare Stringuri | StringTokenizer propriu |
std::string_view + std::regex |
| Logging | ELog propriu / log4cplus opțional |
Standardizare pe spdlog sau similar |
| Testare | Minimală | Adăugare teste unitare (Google Test / Catch2) |
📜 Licență
Acest proiect este distribuit sub licența GNU General Public License v2 (GPL-2.0).
🤝 Contribuții
Proiect menținut de echipa Underchat. Contribuțiile sunt binevenite prin intermediul serverului Gitea:
🔗 Repository: https://gitlab.back.ro/underchat/gnuworld.git
Generat pe baza analizei codului sursă — Martie 2026