# 🌐 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` (mapare `ConnectionHandler* → 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 nu `poll()`/`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:**

1. **Module de Servicii** (`xClient`) — încărcate prin `loadClients()`:
   - Fiecare subclasează `xClient`
   - Exportă o funcție fabrică: `_gnuwinit_<nume>(configFile)`
   - Exemple: `mod.cservice`, `mod.ccontrol`, `mod.chanfix`

2. **Handlere de Comenzi Server** (`ServerCommandHandler`) — încărcate prin `loadCommandHandlers()`:
   - 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_LOADER` simplifică 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:

```cpp
// 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:

1. **`doShutdown()` — Iterare cu break prematur:** Buclele de cleanup iterează și fac `break` dacă containerul devine gol, dar sar elemente intermediare dacă mai sunt.
2. **`msg_B::parseBurstBans()`** — Vectorul de ban-uri este creat cu `st.size()` elemente goale *și* apoi se face `push_back`, rezultând elemente duplicate goale.
3. **`channelEventMap`** — Listele alocate cu `new` pentru evenimentele de canal trebuie dezalocate manual.
4. **Excepții negestionate** — Fără RAII, orice excepție între `new` și `delete` creează 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:

```bash
./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 serverului
- `cservice.example.conf.in` — Configurația CService
- `ccontrol.example.conf.in` — Configurația CControl
- Alte fișiere `.conf.in` pentru 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](https://gitlab.back.ro/underchat/gnuworld.git)

---

*Generat pe baza analizei codului sursă — Martie 2026*

