/* * Copyright (c) 2026 Nakidai Perumenei * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ #include "ircd.h" #include #include #include #include #include #include #include #include #include static struct pollfd pfd[PEERS_MAX + 1]; struct Peer peers[PEERS_MAX]; size_t peers_c; const char *host; int port; void ircd(void) { size_t i, j, k; struct sockaddr_in addr, clientaddr; int res, sfd, client; nfds_t passed; ssize_t recvd; addr.sin_family = PF_INET; addr.sin_port = htons(port); res = inet_pton(AF_INET, host, &addr.sin_addr); if (res == -1) err(1, "inet_pton()"); sfd = socket(AF_INET, SOCK_STREAM, 0); if (sfd == -1) err(1, "socket()"); res = setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)); if (res == -1) err(1, "setsockopt(SO_REUSEADDR)"); res = bind(sfd, (void *)&addr, sizeof(addr)); if (res == -1) err(1, "bind()"); res = listen(sfd, 128); if (res == -1) err(1, "listen()"); signal(SIGPIPE, SIG_IGN); loop: pfd[peers_c] = (struct pollfd){ .fd = sfd, .events = POLLIN }; for (i = 0; i < peers_c; ++i) pfd[i] = (struct pollfd) { .fd = peers[i].fd, .events = POLLIN, }; res = poll(pfd, (passed = peers_c) + 1, -1); if (res == -1) err(1, "poll()"); if (pfd[peers_c].revents & POLLIN) { client = accept(sfd, (void *)&clientaddr, &(int){sizeof(clientaddr)}); if (client == -1) { warn("accept(%d)", sfd); } else if (peers_c == PEERS_MAX) { /* * TODO: maybe send 005 or smth? */ close(client); } else { peers[peers_c++] = (struct Peer){ .fd = client }; strlcpy( peers[peers_c - 1].host, inet_ntoa(clientaddr.sin_addr), sizeof(peers->host) ); } } for (i = 0; i < passed; ++i) { if (!(pfd[i].revents & POLLIN)) continue; recvd = read( peers[i].fd, peers[i].buf + peers[i].recvd, sizeof(peers[i].buf) - peers[i].recvd ); peers[i].recvd += recvd; if (recvd == -1 || !recvd || handle(&peers[i])) peers[i].flags |= DELETE; } for (i = 0; i < peers_c; ++i) { if (!(peers[i].flags & DELETE)) continue; if (!peers[i].type) goto skip; writef( peers[i].fd, ":%s!%s@%s QUIT", getnick(&peers[i]), peers[i].user, peers[i].host ); for (j = 0; j < peers[i].channels_c; ++j) { channel_exit(peers[i].channels[j], &peers[i]); for (k = 0; k < peers[i].channels[j]->users_c; ++k) peers[i].channels[j]->users[k]->flags |= ANNOUNCE; } for (j = 0; j < peers_c; ++j) if (peers[j].flags & ANNOUNCE) { writef( peers[j].fd, "%s!%s@%s QUIT", getnick(&peers[i]), peers[i].user, peers[i].host ); peers[j].flags &= ~ANNOUNCE; } skip: writef(peers[i].fd, "ERROR :Closing Link: %s", peers[i].host); close(peers[i].fd); peers[i] = peers[--peers_c]; i = 0; } goto loop; }