/* * 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 struct Peer peers[PEERS_MAX]; static struct pollfd pfd[PEERS_MAX + 1]; static size_t remove_schedule[PEERS_MAX]; const char *host; int port; void ircd(void) { size_t i, schedulei, connected, pid; 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); for (connected = 0;;schedulei = 0) { pfd[connected] = (struct pollfd){ .fd = sfd, .events = POLLIN }; for (i = 0; i < connected; ++i) pfd[i] = (struct pollfd) { .fd = peers[i].fd, .events = POLLIN, }; res = poll(pfd, (passed = connected) + 1, -1); if (res == -1) err(1, "poll()"); if (pfd[connected].revents & POLLIN) { client = accept(sfd, (void *)&clientaddr, &(int){sizeof(clientaddr)}); if (client == -1) { warn("accept(sfd)"); } else if (connected == PEERS_MAX) { /* * TODO: maybe send 005 or smth? */ close(client); } else { peers[connected++] = (struct Peer){ .fd = client }; strlcpy( peers[connected - 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])) remove_schedule[schedulei++] = i; } for (i = 0; i < schedulei; ++i) { pid = remove_schedule[i]; /* TODO: announce_quit(&peers[pid]); */ writef(peers[pid].fd, "ERROR :Closing Link: %s", peers[pid].host); close(peers[pid].fd); peers[pid] = peers[--connected]; } schedulei = 0; } }