/* * tinychat.c: mini chat * * Copyright 2020 Renzo Davoli - Virtual Square Team * University of Bologna - Italy * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * */ #define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <netinet/in.h> #include <poll.h> #include <arpa/inet.h> #include <picoxnet.h> #include <nlinline+.h> NLINLINE_LIBMULTI(picox_) #define MAXFD 10 #define BUFSIZE 1024 static void perror_exit(char *s) { perror(s); exit(1); } int main(int arg, char *argv[]) { #define VDENET argv[1] #define IPADDR argv[2] #define PREFIX argv[3] #define PORT argv[4] unsigned long prefix = strtoul(PREFIX, NULL, 10); unsigned long port = strtoul(PORT, NULL, 10); struct picox *mystack = picox_newstack(VDENET); int ifindex = picox_if_nametoindex(mystack, "vde0"); uint8_t ipaddr[16]; struct pollfd pfd[MAXFD] = { [0 ... MAXFD-1] = {-1, POLLIN, 0} }; char buf[BUFSIZE]; if (picox_linksetupdown(mystack, ifindex, 1) < 0) perror_exit("link up"); // is IPADDR (argv[2]) a IPv6 address? if (inet_pton(AF_INET6, IPADDR, ipaddr) == 1) { struct sockaddr_in6 servaddr = { .sin6_family = AF_INET6, .sin6_port = htons(port), .sin6_addr = in6addr_any}; if (picox_ipaddr_add(mystack, AF_INET6, ipaddr, prefix, ifindex) < 0) perror_exit(IPADDR); pfd[0].fd = picox_msocket(mystack, AF_INET6, SOCK_STREAM, 0); if (picox_bind(pfd[0].fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) perror_exit("bind"); // is IPADDR (argv[2]) a IPv4 address? } else if (inet_pton(AF_INET, IPADDR, ipaddr) == 1) { struct sockaddr_in servaddr = { .sin_family = AF_INET, .sin_port = htons(port), .sin_addr.s_addr = htonl(INADDR_ANY)}; if (picox_ipaddr_add(mystack, AF_INET, ipaddr, prefix, ifindex) < 0) perror_exit(IPADDR); pfd[0].fd = picox_msocket(mystack, AF_INET, SOCK_STREAM, 0); if (picox_bind(pfd[0].fd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0) perror_exit("bind"); } else { errno = EPROTO; perror_exit("error"); } picox_listen (pfd[0].fd, 5); for ( ; ; ) { int i; if (poll(pfd, MAXFD, -1) < 0) break; // pfd[0].fd is the socket for accept if (pfd[0].revents) { int connfd; connfd = picox_accept (pfd[0].fd, NULL, NULL); for (i = 1; i < MAXFD; i++) { if (pfd[i].fd == -1) break; } if ( i < MAXFD) pfd[i].fd = connfd; else picox_close(connfd); } // pfd[i].fd, i > 0, connected sockets for (i = 1; i < MAXFD; i++) { if (pfd[i].revents) { int n = picox_read(pfd[i].fd, buf, BUFSIZE); if (n <= 0) { picox_close(pfd[i].fd); pfd[i].fd = -1; } else { int j; // copy the message to all the other connected sockets for (j = 1; j < n; j++) { if (i != j && pfd[j].fd != -1) picox_write(pfd[j].fd, buf, n); } } } } } picox_close(pfd[0].fd); picox_delstack(mystack); }