# ๐Ÿ”„ FLUXURI DETALIATE - Underchat IRCD **Data**: 23 Februarie 2026 **Complement la**: ANALIZA_ARHITECTURA_SENIOR.md --- ## ๐Ÿ“Š DIAGRAMฤ‚ GENERALฤ‚ - DATA FLOW ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ CLIENT โ”‚ โ”‚ (IRC App) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ TCP/SSL โ”‚ Port 6667/6697 โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ LISTENER (s_bsd.c) โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ accept() โ†’ new socket โ”‚ โ”‚ โ”‚ โ”‚ set non-blocking โ”‚ โ”‚ โ”‚ โ”‚ add to LocalClientArray[] โ”‚ โ”‚ โ”‚ โ”‚ register with epoll โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ EVENT LOOP (ircd_events.c) โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ while(running) { โ”‚ โ”‚ โ”‚ โ”‚ epoll_wait() โ†’ events โ”‚ โ”‚ โ”‚ โ”‚ for each event: โ”‚ โ”‚ โ”‚ โ”‚ if EPOLLIN โ†’ READ โ”‚ โ”‚ โ”‚ โ”‚ if EPOLLOUT โ†’ WRITE โ”‚ โ”‚ โ”‚ โ”‚ if EPOLLERR โ†’ ERROR โ”‚ โ”‚ โ”‚ โ”‚ } โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ READ PATH WRITE PATH โ”‚ โ”‚ โ–ผ โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ READ HANDLER โ”‚ โ”‚ WRITE HANDLER โ”‚ โ”‚ (s_bsd.c) โ”‚ โ”‚ (send.c) โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ”‚ โ–ผ โ–ผ [Flow A] [Flow B] ``` --- ## ๐Ÿ”ต FLOW A: MESSAGE RECEIVING (Client โ†’ Server) ### Step 1: Socket Read **Fiศ™ier**: `ircd/s_bsd.c` - funcศ›ia `read_packet()` ```c // Pseudocod simplificat int read_packet(struct Client* cptr, int ready_to_read) { char readbuf[SERVER_TCP_WINDOW]; // 32KB buffer // 1. Read from socket length = recv(cli_fd(cptr), readbuf, sizeof(readbuf), 0); if (length <= 0) { // Connection closed or error return exit_client(cptr); } // 2. Append to client's receive buffer (DBuf) if (dbuf_put(&cli_recvQ(cptr), readbuf, length) < 0) { // Out of memory return exit_client_msg(cptr, "Buffer allocation error"); } // 3. Process complete messages while (has_complete_line(&cli_recvQ(cptr))) { dolen = dbuf_get(&cli_recvQ(cptr), readbuf, sizeof(readbuf)); if (IsServer(cptr)) server_dopacket(cptr, readbuf, dolen); else connect_dopacket(cptr, readbuf, dolen); } return 1; } ``` **Caracteristici**: - โœ… Non-blocking read - โœ… Buffering pentru mesaje incomplete - โœ… Procesare iterativฤƒ (multiple mesaje per read) - โš ๏ธ RISC: Fฤƒrฤƒ limitฤƒ pe dimensiunea DBuf --- ### Step 2: Packet Processing **Fiศ™ier**: `ircd/packet.c` - funcศ›ia `connect_dopacket()` ```c int connect_dopacket(struct Client *cptr, const char *buffer, int length) { const char* src = buffer; char* endp = cli_buffer(cptr) + cli_count(cptr); // Proceseazฤƒ byte cu byte while (length-- > 0) { *endp = *src++; // Detecteazฤƒ end-of-line if (IsEol(*endp)) { // CR sau LF if (endp == cli_buffer(cptr)) continue; // Skip LF/CR gol *endp = '\0'; // Null-terminate // โ˜… PARSE MESSAGE if (parse_client(cptr, cli_buffer(cptr), endp) == CPTR_KILLED) return CPTR_KILLED; // Reset buffer endp = cli_buffer(cptr); } else if (endp < cli_buffer(cptr) + BUFSIZE) { ++endp; } } cli_count(cptr) = endp - cli_buffer(cptr); return 1; } ``` **FLUX**: ``` Buffer: "PRIVMSG #test :Hello\r\nNICK newname\r" โ†“ Iteraศ›ie 1: Gฤƒseศ™te \r dupฤƒ "Hello" โ†’ parse_client("PRIVMSG #test :Hello") Iteraศ›ie 2: Gฤƒseศ™te \r dupฤƒ "newname" โ†’ parse_client("NICK newname") ``` --- ### Step 3: Message Parsing **Fiศ™ier**: `ircd/parse.c` - funcศ›ia `parse_client()` ```c int parse_client(struct Client *cptr, char *buffer, char *bufend) { struct Message* mptr; char* para[MAXPARA + 2]; // parametrii comenzii int paramcount; // 1. Extrage prefix (dacฤƒ existฤƒ) // Format: :prefix COMMAND param1 param2 :trailing if (*buffer == ':') { // Skip prefix pentru client messages while (*buffer != ' ' && *buffer) buffer++; } // 2. Extrage comanda char* command = buffer; while (*buffer != ' ' && *buffer) buffer++; *buffer++ = '\0'; // 3. Lookup รฎn trie mptr = find_command(command); // O(k) lookup if (!mptr) { // ERR_UNKNOWNCOMMAND return send_reply(cptr, ERR_UNKNOWNCOMMAND, command); } // 4. Extrage parametrii paramcount = parse_params(buffer, para, MAXPARA); // 5. Verificฤƒri if (mptr->parameters < paramcount) { return send_reply(cptr, ERR_NEEDMOREPARAMS, mptr->cmd); } // 6. โ˜… CALL HANDLER MessageHandler handler = mptr->handlers[cli_status(cptr)]; return (*handler)(cptr, cptr, paramcount, para); } ``` **Trie Lookup Example**: ``` Command: "PRIVMSG" msg_tree: 'P' โ†’ 'R' โ†’ 'I' โ†’ 'V' โ†’ 'M' โ†’ 'S' โ†’ 'G' โ†’ [Message*] โ†“ {MSG_PRIVATE, handlers[]} ``` --- ### Step 4: Handler Execution **Fiศ™ier**: `ircd/m_privmsg.c` - funcศ›ia `m_privmsg()` ```c int m_privmsg(struct Client* cptr, struct Client* sptr, int parc, char* parv[]) { // parv[0] = source nick (implicit) // parv[1] = target (nick or #channel) // parv[2] = message text // 1. Validare parametrii if (parc < 2 || EmptyString(parv[1])) { return send_reply(sptr, ERR_NORECIPIENT, "PRIVMSG"); } if (parc < 3 || EmptyString(parv[2])) { return send_reply(sptr, ERR_NOTEXTTOSEND); } char* target = parv[1]; char* text = parv[2]; // 2. Determine target type if (IsChannelName(target)) { // โ˜… CHANNEL MESSAGE struct Channel* chptr = FindChannel(target); if (!chptr) return send_reply(sptr, ERR_NOSUCHCHANNEL, target); if (!can_send_to_channel(sptr, chptr)) return send_reply(sptr, ERR_CANNOTSENDTOCHAN, target); // โ˜… BROADCAST la toศ›i membrii canalului sendcmdto_channel_butone(sptr, CMD_PRIVMSG, chptr, cli_from(sptr), "%s :%s", target, text); } else { // โ˜… PRIVATE MESSAGE struct Client* acptr = FindUser(target); if (!acptr) return send_reply(sptr, ERR_NOSUCHNICK, target); // โ˜… SEND direct sendcmdto_one(sptr, CMD_PRIVMSG, acptr, "%s :%s", target, text); } return 0; } ``` --- ## ๐ŸŸข FLOW B: MESSAGE SENDING (Server โ†’ Client) ### Step 1: Message Queue Addition **Fiศ™ier**: `ircd/send.c` - funcศ›ia `sendcmdto_one()` ```c void sendcmdto_one(struct Client *from, const char *cmd, struct Client *to, const char *pattern, ...) { va_list vl; struct MsgBuf *mb; // 1. Format message va_start(vl, pattern); mb = msgq_vmake(to, pattern, vl); va_end(vl); // 2. Prepend command and source // Format final: ":source COMMAND params\r\n" msgq_append(to, mb, ":%s %s", cli_name(from), cmd); // 3. Add to target's send queue msgq_add(&cli_sendQ(to), mb, 0); // 0 = normal priority // 4. Mark connection as having data to send if (MsgQLength(&cli_sendQ(to)) > 0) update_write(to); // Register for EPOLLOUT msgq_clean(mb); // Cleanup message buffer } ``` **Priority Queue**: ```c struct MsgQ { struct MsgQList prio; // Priority messages (server-to-server) struct MsgQList queue; // Normal messages (client) }; // Server messages โ†’ prio queue // Client messages โ†’ normal queue // Send order: prio first, then queue ``` --- ### Step 2: Write Readiness **Fiศ™ier**: `ircd/ircd_events.c` + `ircd/engine_epoll.c` ```c // Event loop detecteazฤƒ EPOLLOUT void engine_loop(struct Engine* eng) { struct epoll_event events[MAXEVENTS]; int nfds = epoll_wait(epoll_fd, events, MAXEVENTS, timeout); for (int i = 0; i < nfds; i++) { struct Socket* sock = events[i].data.ptr; struct Client* cptr = sock->s_data; if (events[i].events & EPOLLOUT) { // โ˜… Socket is writable event_generate(ET_WRITE, sock, 0); // Call registered callback (*sock->s_callback)(sock->s_events); } } } ``` --- ### Step 3: Message Flushing **Fiศ™ier**: `ircd/send.c` - funcศ›ia `send_queued()` ```c void send_queued(struct Client *to) { if (IsBlocked(to) || !can_send(to)) return; // Process send queue while (MsgQLength(&cli_sendQ(to)) > 0) { unsigned int len; // โ˜… DELIVER message len = deliver_it(to, &cli_sendQ(to)); if (len > 0) { // Successfully sent 'len' bytes msgq_delete(&cli_sendQ(to), len); cli_lastsq(to) = MsgQLength(&cli_sendQ(to)) / 1024; if (IsBlocked(to)) { // Socket buffer full, stop for now update_write(to); // Re-register for EPOLLOUT return; } } else { // Error or blocking if (IsDead(to)) exit_client(to, to, &me, cli_info(to)); return; } } // Send queue empty, no more EPOLLOUT needed update_write(to); } ``` --- ### Step 4: Actual Socket Write **Fiศ™ier**: `ircd/s_bsd.c` - funcศ›ia `deliver_it()` ```c unsigned int deliver_it(struct Client *cptr, struct MsgQ *mq) { struct iovec iov[IOV_MAX]; // Scatter-gather I/O unsigned int len; int count, bytes; // 1. Map MsgQ to iovec array count = msgq_mapiov(mq, iov, IOV_MAX, &len); // 2. Write with writev (zero-copy) bytes = writev(cli_fd(cptr), iov, count); if (bytes < 0) { if (errno == EWOULDBLOCK || errno == EAGAIN) { // Socket buffer full SetBlocked(cptr); return 0; } // Real error dead_link(cptr, "Write error"); return 0; } cli_sendB(cptr) += bytes; // Update statistics return bytes; } ``` **writev() Advantages**: ``` Instead of: send(fd, msg1, len1); send(fd, msg2, len2); send(fd, msg3, len3); Use: iov[0] = {msg1, len1}; iov[1] = {msg2, len2}; iov[2] = {msg3, len3}; writev(fd, iov, 3); // โ˜… Single syscall ``` --- ## ๐Ÿ”ด FLOW C: CHANNEL BROADCAST **Scenario**: User A sends message to #test (100 members) ```c // m_privmsg.c void sendcmdto_channel_butone(struct Client *from, const char *cmd, struct Channel *chptr, struct Client *one, const char *pattern, ...) { struct Membership *member; struct MsgBuf *mb; // 1. Format message once mb = msgq_make(NULL, pattern, ...); // 2. Iterate all channel members for (member = chptr->members; member; member = member->next_member) { struct Client *dest = member->user; // Skip sender and specified 'one' if (dest == from || dest == one) continue; // โ˜… Add to each member's sendQ msgq_add(&cli_sendQ(dest), mb, 0); // Mark as needing write if (MsgQLength(&cli_sendQ(dest)) > 0) update_write(dest); } msgq_clean(mb); } ``` **Performance Impact**: ``` O(N) where N = channel members For #test with 100 members: - 1 message format - 100 msgq_add() calls - 100 update_write() calls - Next event loop: 100ร— send_queued() Bottleneck: CPU-bound (single thread) ``` --- ## โšก FLOW D: SERVER-TO-SERVER (P10 Protocol) ### Message Format **P10 Numeric Encoding**: ``` Client format: :Nick!user@host PRIVMSG #test :Hello P10 format: ABCDE P #test :Hello Where: AB = Server numeric (2 chars) CDE = User numeric (3 chars) P = PRIVMSG token ``` **Encoding Table**: ```c // numnicks.c static const char convert2y[] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','[',']' }; // Base64-like: 64^3 = 262,144 possible users per server ``` ### Server Link Flow ``` Local Server (AA) Remote Server (BB) โ”‚ โ”‚ โ”‚ 1. CONNECT initiated โ”‚ โ”‚ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€> โ”‚ โ”‚ โ”‚ โ”‚ 2. PASS :password โ”‚ โ”‚ <โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ โ”‚ โ”‚ โ”‚ 3. SERVER name โ”‚ โ”‚ <โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ โ”‚ โ”‚ โ”‚ 4. BURST mode โ”‚ โ”‚ <โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• โ”‚ โ”‚ - All users โ”‚ โ”‚ - All channels โ”‚ โ”‚ - All modes โ”‚ โ”‚ โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•> โ”‚ โ”‚ โ”‚ โ”‚ 5. END_OF_BURST โ”‚ โ”‚ <โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ โ”‚ โ”‚ โ”‚ โ”‚ 6. Normal operation โ”‚ โ”‚ <โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•> โ”‚ ``` **BURST Example**: ``` // Server BB sends its state to AA N AliceUser 1 1234567890 alice alice.host +i B]AAAB ABAAA :Alice โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€ realname โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€ account โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€ user numeric โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€ modes โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€ hostname โ”‚ โ”‚ โ”‚ โ””โ”€ username โ”‚ โ”‚ โ””โ”€ timestamp โ”‚ โ””โ”€ hopcount โ””โ”€ NICK command (token: N) B #test 1234567890 ABAAA:o,ABAAB โ”‚ โ”‚ โ””โ”€ members (ABAAA is op, ABAAB normal) โ”‚ โ””โ”€ timestamp โ””โ”€ BURST command ``` --- ## ๐Ÿ›ก๏ธ FLOW E: FLOOD PROTECTION ### IPcheck Rate Limiting ```c // IPcheck.c - ip_registry_check_connect() int ip_registry_check_connect(const struct irc_in_addr *addr, time_t *next_target_out) { struct IPRegistryEntry *entry = ip_registry_find(addr); if (!entry) { // First connection from this IP entry = ip_registry_new_entry(); ip_registry_canonicalize(&entry->addr, addr); entry->connected = 1; entry->attempts = 1; entry->last_connect = NOW; ip_registry_add(entry); return 1; // โœ… ALLOW } // Check clone limit if (entry->connected >= IPCHECK_CLONE_LIMIT) { return 0; // โŒ REJECT: Too many clones } // Check connection rate time_t elapsed = CONNECTED_SINCE(entry->last_connect); if (elapsed < IPCHECK_CLONE_DELAY) { // Too fast if (entry->attempts++ > IPCHECK_CLONE_PERIOD) { return 0; // โŒ REJECT: Connection flood } } else { // Reset attempt counter entry->attempts = 1; } entry->connected++; entry->last_connect = NOW; return 1; // โœ… ALLOW } ``` **Decay Algorithm**: ``` Time: 0s 10s 20s 30s 40s Connect: โœ“ โœ“ โœ“ [decay] โœ“ Attempts: 1 2 3 1 2 If attempts > CLONE_PERIOD within CLONE_DELAY โ†’ REJECT ``` --- ### Target Rate Limiting ```c // IPcheck.c - ip_registry_check_target() int ip_registry_check_target(struct Client *sptr, void *target, const char *name) { struct IPRegistryEntry *entry = ip_registry_find(&cli_ip(sptr)); if (!entry->target) entry->target = allocate_targets(); // Update free targets (token bucket) unsigned int free_targets = entry->target->count + (CONNECTED_SINCE(entry->last_connect) / TARGET_DELAY); if (free_targets > STARTTARGETS) free_targets = STARTTARGETS; // Check if already talking to this target for (int i = 0; i < MAXTARGETS; i++) { if (entry->target->targets[i] == target_hash(target)) return 0; // โœ… Known target, no cost } // New target if (free_targets == 0) { // โŒ REJECT: No free targets send_reply(sptr, ERR_TARGETTOOFAST, name, TARGET_DELAY * (STARTTARGETS - free_targets)); return 1; } // Consume one target free_targets--; add_target(entry, target); return 0; // โœ… ALLOW } ``` **Example**: ``` User starts with 10 targets (STARTTARGETS) Sends PRIVMSG to: #channel1 โ†’ 9 targets left #channel2 โ†’ 8 targets left ... #channel10 โ†’ 0 targets left #channel11 โ†’ โŒ ERR_TARGETTOOFAST After TARGET_DELAY seconds: Targets regenerate: 0 โ†’ 1 โ†’ 2 โ†’ ... โ†’ 10 (max) ``` --- ## ๐Ÿ› FLOW F: ERROR HANDLING ### Socket Error Detection ```c // s_bsd.c - read_packet() int read_packet(struct Client* cptr, int ready) { int length = recv(cli_fd(cptr), readbuf, sizeof(readbuf), 0); if (length < 0) { // Error handling int err = errno; switch (err) { case EWOULDBLOCK: case EAGAIN: // Not actually ready (spurious wakeup) return 1; // OK, try later case ECONNRESET: // Connection reset by peer return exit_client_msg(cptr, cptr, &me, "Connection reset by peer"); case ETIMEDOUT: // Connection timed out return exit_client_msg(cptr, cptr, &me, "Connection timed out"); default: // Other error return exit_client_msg(cptr, cptr, &me, "Read error: %s", strerror(err)); } } if (length == 0) { // EOF (connection closed gracefully) return exit_client_msg(cptr, cptr, &me, "Connection closed"); } // Normal processing // ... } ``` --- ### Dead Link Marking ```c // send.c - dead_link() static void dead_link(struct Client *to, char *notice) { // โ˜… Don't exit immediately, mark for cleanup SetFlag(to, FLAG_DEADSOCKET); // Clear buffers to prevent further operations DBufClear(&cli_recvQ(to)); MsgQClear(&cli_sendQ(to)); client_drop_sendq(cli_connect(to)); // Save error message ircd_strncpy(cli_info(to), notice, REALLEN + 1); // Notify opers if (!IsUser(to) && !IsUnknown(to) && !HasFlag(to, FLAG_CLOSING)) sendto_opmask_butone(0, SNO_OLDSNO, "%s for %s", cli_info(to), cli_name(to)); } ``` **Main Loop Cleanup**: ```c // ircd.c - event_loop() while (running) { event_loop_iteration(); // Check for dead sockets for (i = 0; i <= HighestFd; i++) { cptr = LocalClientArray[i]; if (cptr && IsDead(cptr)) { exit_client(cptr, cptr, &me, cli_info(cptr)); } } } ``` --- ## ๐Ÿ“Š TIMING DIAGRAMS ### Normal PRIVMSG Latency ``` Time Event โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 0ms Client A: send("PRIVMSG #test :Hi\r\n") โ”‚ 0.1ms Server: recv() โ†’ DBuf โ†’ parse โ”‚ 0.2ms Server: Handler m_privmsg() โ”‚ โ”œโ”€ Validate โ”‚ โ”œโ”€ Find channel โ”‚ โ””โ”€ Broadcast โ”‚ 0.3ms Server: 100ร— msgq_add() (channel members) โ”‚ 0.4ms Server: update_write() ร— 100 โ”‚ [Next event loop iteration] โ”‚ 10ms Server: epoll_wait() โ†’ EPOLLOUT events โ”‚ 11ms Server: send_queued() โ†’ writev() ร— 100 โ”‚ 12ms Clients: recv() message โ”‚ TOTAL: ~12ms latency (local network) ``` --- ### SendQ Overflow Scenario ``` Time Event โ”€โ”€โ”€โ”€โ”€ โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ 0s Client A connected, sendQ = 0 KB โ”‚ 1s Server โ†’ Client: 100 messages โ”‚ sendQ = 50 KB โ”‚ Client not reading (slow network) โ”‚ 2s Server โ†’ Client: 100 more messages โ”‚ sendQ = 100 KB โ”‚ โš ๏ธ WARNING: High sendQ โ”‚ 3s Server โ†’ Client: 100 more messages โ”‚ sendQ = 150 KB โ”‚ โš ๏ธ CRITICAL: Very high sendQ โ”‚ 4s kill_highest_sendq() triggered โ”‚ โŒ Client A disconnected โ”‚ Reason: "SendQ exceeded" โ”‚ โœ… Memory freed, server stable ``` **Prevention**: ```c // Recommended: Per-client hard limit #define MAX_SENDQ_USER 65536 // 64KB if (MsgQLength(&cli_sendQ(to)) > MAX_SENDQ_USER) { dead_link(to, "SendQ exceeded"); return; } ``` --- ## ๐Ÿ” DEBUGGING FLOWS ### Debug Logging Example ```c // Enable with /SET DEBUG level Debug((DEBUG_INFO, "Client %s (%s) connected from %s", cli_name(cptr), cli_username(cptr), cli_sock_ip(cptr))); Debug((DEBUG_SEND, "Sending to %s: %s", cli_name(to), message)); Debug((DEBUG_ERROR, "Failed to send to %s: %s", cli_name(to), strerror(errno))); ``` **Output** (ircd.log): ``` [12:34:56] [INFO] Client Alice (alice) connected from 192.168.1.100 [12:34:57] [SEND] Sending to Alice: :server.test 001 Alice :Welcome [12:34:58] [ERROR] Failed to send to Bob: Connection reset by peer ``` --- ## ๐ŸŽฏ CRITICAL PATHS (Performance Hotspots) ### 1. Message Parsing (Most Frequent) **File**: `parse.c` **Frequency**: Every message received **Optimization**: - โœ… Trie lookup O(k) - โœ… Token-based P10 (shorter strings) - โŒ Still does byte-by-byte parsing ### 2. Channel Broadcast (Most Expensive) **File**: `send.c`, `channel.c` **Frequency**: Every channel message **Complexity**: O(N) where N = members **Optimization**: - โœ… writev() reduces syscalls - โœ… Message formatted once - โŒ No message coalescing for multiple broadcasts ### 3. Event Loop (Always Running) **File**: `ircd_events.c`, `engine_epoll.c` **Frequency**: Continuous **Optimization**: - โœ… epoll() scales to 10K+ connections - โœ… Edge-triggered mode reduces wakeups - โŒ Single-threaded CPU bottleneck --- ## ๐Ÿ“š REFERINศšE SUPLIMENTARE ### Command Flow Examples **USER Registration**: ``` Client โ†’ Server: NICK Alice Server โ†’ Client: (no response, waiting for USER) Client โ†’ Server: USER alice 0 * :Alice Smith Server โ†’ Client: :server 001 Alice :Welcome to IRC :server 002 Alice :Your host is server :server 003 Alice :This server was created... :server 004 Alice server version modes :server 005 Alice FEATURES :are supported (MOTD) :server 376 Alice :End of MOTD ``` **Channel JOIN**: ``` Client โ†’ Server: JOIN #test Server processing: 1. Validate channel name 2. Check if channel exists 3. Check bans/invite-only 4. Add user to channel 5. Broadcast JOIN to all members 6. Send channel topic 7. Send NAMES list Server โ†’ Client: :Alice!alice@host JOIN #test Server โ†’ Client: :server 332 Alice #test :Channel topic Server โ†’ Client: :server 333 Alice #test topic_setter 1234567890 Server โ†’ Client: :server 353 Alice = #test :@Alice Bob Carol Server โ†’ Client: :server 366 Alice #test :End of NAMES ``` --- *Document generat de Senior Software Architect - Complement la analiza principalฤƒ.*