123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462 |
- /* This file is part of Netsukuku
- * (c) Copyright 2005 Andrea Lo Pumo aka AlpT <alpt@freaknet.org>
- *
- * This source code 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 source code 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.
- * Please refer to the GNU Public License for more details.
- *
- * You should have received a copy of the GNU Public License along with
- * this source code; if not, write to:
- * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
- #include "includes.h"
-
- #include "common.h"
- #include "inet.h"
- #include "request.h"
- #include "if.h"
- #include "pkts.h"
- #include "bmap.h"
- #include "daemon.h"
- #include "netsukuku.h"
- #include "accept.h"
-
- extern int errno;
-
- /*
- * prepare_listen_socket:
- * It creates a new socket of the desired `family' and binds it to the
- * specified `port'. It sets also the reuseaddr and NONBLOCK
- * socket options, because this new socket shall be used to listen() and
- * accept().
- * If `dev' is not null, the socket will be binded to the device named
- * `dev'->dev_name with the SO_BINDTODEVICE socket option.
- * The created socket is returned.
- */
- int prepare_listen_socket(int family, int socktype, u_short port,
- interface *dev)
- {
- struct addrinfo hints, *ai, *aitop;
- char strport[NI_MAXSERV];
- int err, s;
-
- setzero(&hints, sizeof(struct addrinfo));
- hints.ai_family=family;
- hints.ai_socktype=socktype;
- hints.ai_flags=AI_PASSIVE;
- snprintf(strport, NI_MAXSERV, "%u", port);
-
- err=getaddrinfo(NULL, strport, &hints, &aitop);
- if(err) {
- error("Getaddrinfo error: %s", gai_strerror(err));
- return -1;
- }
-
- for (ai = aitop; ai; ai = ai->ai_next) {
- if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
- continue;
-
- s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
- if (s == -1)
- /* Maybe we can use another socket...*/
- continue;
-
- /* Bind the created socket to the device named dev->dev_name */
- if(dev && (set_bindtodevice_sk(s, dev->dev_name) < 0)) {
- inet_close(&s);
- continue;
- }
-
- if(set_reuseaddr_sk(s) < 0) {
- inet_close(&s);
- continue;
- }
-
- /* Let's bind it! */
- if(bind(s, ai->ai_addr, ai->ai_addrlen) < 0) {
- error("Cannot bind the port %d: %s. Trying another "
- "socket...", port, strerror(errno));
- inet_close(&s);
- continue;
- }
- freeaddrinfo(aitop);
- return s;
- }
-
- error("Cannot open inbound socket on port %d: %s", port, strerror(errno));
- freeaddrinfo(aitop);
- return -1;
- }
-
-
- /*
- * sockets_all_ifs
- *
- * creates a socket for each interface which is in the `ifs' array.
- * The array has `ifs_n' members.
- * Each created socket is stored in the `dev_sk' array, which has `ifs_n'#
- * members.
- * The created socket will be bound to the relative interface.
- * In `max_sk_idx' is stored the index of the `dev_sk' array, which has the
- * biggest dev_sk.
- *
- * On error 0 is returned, otherwise the number of utilised interfaces is
- * returned.
- * If the error is fatal, a negative value is returned.
- */
- int sockets_all_ifs(int family, int socktype, u_short port,
- interface *ifs, int ifs_n,
- int *dev_sk, int *max_sk_idx)
- {
- int i, n, e=0;
-
- *max_sk_idx=0;
-
- for(i=0, n=0; i<ifs_n; i++) {
- dev_sk[i] = prepare_listen_socket(family, socktype, port,
- &ifs[i]);
-
- if(dev_sk[i] < 0) {
- error("Cannot create a socket on the %s interface! "
- "Ignoring it", ifs[i].dev_name);
- dev_sk[i]=0;
- e++;
- continue;
- }
-
- if(dev_sk[i] >= dev_sk[*max_sk_idx])
- *max_sk_idx=i;
-
- n++;
- }
-
- if(e == ifs_n)
- return -1;
-
- return n;
- }
-
- /*
- * udp_exec_pkt: passes the received udp packet to pkt_exec().
- * `passed_argv' is a pointer to a udp_exec_pkt_argv struct
- */
- void *udp_exec_pkt(void *passed_argv)
- {
- struct udp_exec_pkt_argv argv;
-
- PACKET rpkt;
- const char *ntop;
-
- memcpy(&argv, passed_argv, sizeof(struct udp_exec_pkt_argv));
- memcpy(&rpkt, argv.recv_pkt, sizeof(PACKET));
-
- if(argv.flags & UDP_THREAD_FOR_EACH_PKT)
- pthread_mutex_unlock(&udp_exec_lock);
-
- /* Drop any packet we sent in broadcast */
- if(!memcmp(rpkt.from.data, me.cur_ip.data, MAX_IP_SZ)) {
- pkt_free(&rpkt, 0);
- return 0;
- }
-
- if(add_accept(rpkt.from, 1)) {
- ntop=inet_to_str(rpkt.from);
- debug(DBG_NORMAL, "ACPT: dropped UDP pkt from %s: "
- "Accept table full.", ntop);
- return 0;
- }
-
- pkt_exec(rpkt, argv.acpt_idx);
- pkt_free(&rpkt, 0);
-
- return 0;
- }
-
- /*
- * udp_daemon: Takes care of receiving udp packets.
- * `passed_argv' is a pointer to a udp_daemon_argv struct
- */
- void *udp_daemon(void *passed_argv)
- {
- struct udp_daemon_argv argv;
- struct udp_exec_pkt_argv exec_pkt_argv;
-
- interface *ifs;
- int max_sk_idx, dev_sk[me.cur_ifs_n];
-
- PACKET rpkt;
- fd_set fdset;
- int ret, i, err;
- u_short udp_port;
-
- pthread_t thread;
- pthread_attr_t t_attr;
-
- #ifdef DEBUG
- int select_errors=0;
- #endif
-
- memcpy(&argv, passed_argv, sizeof(struct udp_daemon_argv));
- udp_port=argv.port;
- setzero(&exec_pkt_argv, sizeof(struct udp_exec_pkt_argv));
-
- if(argv.flags & UDP_THREAD_FOR_EACH_PKT) {
- pthread_attr_init(&t_attr);
- pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_DETACHED);
- exec_pkt_argv.flags|=UDP_THREAD_FOR_EACH_PKT;
- }
-
- debug(DBG_SOFT, "Preparing the udp listening socket on port %d", udp_port);
-
- err=sockets_all_ifs(my_family, SOCK_DGRAM, udp_port, me.cur_ifs,
- me.cur_ifs_n, dev_sk, &max_sk_idx);
- if(!err)
- return NULL;
- else if(err < 0)
- fatal("Creation of the %s daemon aborted. "
- "Is there another ntkd running?", "udp");
-
- debug(DBG_NORMAL, "Udp daemon on port %d up & running", udp_port);
- pthread_mutex_unlock(&udp_daemon_lock);
-
- pthread_mutex_init(&udp_exec_lock, 0);
-
- for(;;) {
- FD_ZERO(&fdset);
-
- if(!me.cur_ifs_n) {
- /* All the devices have been removed while ntkd was
- * running, sleep well */
- sleep(1);
- continue;
- }
-
- for(i=0; i < me.cur_ifs_n; i++)
- if(dev_sk[i])
- FD_SET(dev_sk[i], &fdset);
-
- ret=select(dev_sk[max_sk_idx]+1, &fdset, NULL, NULL, NULL);
- if(sigterm_timestamp)
- /* NetsukukuD has been closed */
- break;
- if (ret < 0) {
- #ifdef DEBUG
- if(select_errors > 20)
- break;
- select_errors++;
- #endif
- error("daemon_udp: select error: %s", strerror(errno));
- continue;
- }
-
- for(i=0; i < me.cur_ifs_n; i++) {
- ifs=&me.cur_ifs[i];
- if(!dev_sk[i])
- continue;
-
- if(!FD_ISSET(dev_sk[i], &fdset))
- continue;
-
- setzero(&rpkt, sizeof(PACKET));
- pkt_addsk(&rpkt, my_family, dev_sk[i], SKT_UDP);
- pkt_add_dev(&rpkt, ifs, 0);
- rpkt.flags=MSG_WAITALL;
- pkt_addport(&rpkt, udp_port);
-
- if(pkt_recv(&rpkt) < 0) {
- pkt_free(&rpkt, 0);
- continue;
- }
-
- exec_pkt_argv.acpt_idx=accept_idx;
- exec_pkt_argv.acpt_sidx=accept_sidx;
-
- if(argv.flags & UDP_THREAD_FOR_EACH_PKT) {
- exec_pkt_argv.recv_pkt=&rpkt;
- pthread_mutex_lock(&udp_exec_lock);
- pthread_create(&thread, &t_attr, udp_exec_pkt,
- &exec_pkt_argv);
- pthread_mutex_lock(&udp_exec_lock);
- pthread_mutex_unlock(&udp_exec_lock);
- } else {
- exec_pkt_argv.recv_pkt=&rpkt;
- udp_exec_pkt(&exec_pkt_argv);
- }
- }
- }
-
- destroy_accept_tbl();
- return NULL;
- }
-
- void *tcp_recv_loop(void *recv_pkt)
- {
- PACKET rpkt;
- int acpt_idx, acpt_sidx;
-
- acpt_idx=accept_idx;
- acpt_sidx=accept_sidx;
- memcpy(&rpkt, recv_pkt, sizeof(PACKET));
- pthread_mutex_unlock(&tcp_exec_lock);
-
- #if 0
- add_accept_pid(getpid(), acpt_idx, acpt_sidx);
- #endif
-
- while( pkt_recv(&rpkt) != -1 ) {
- if(pkt_exec(rpkt, acpt_idx) < 0) {
- goto close;
- break;
- } else
- pkt_free(&rpkt, 0);
- }
-
- close:
- pkt_free(&rpkt, 1);
- close_accept(acpt_idx, acpt_sidx);
-
- return NULL;
- }
-
- void *tcp_daemon(void *door)
- {
- pthread_t thread;
- pthread_attr_t t_attr;
-
- PACKET rpkt;
- struct sockaddr_storage addr;
- socklen_t addrlen = sizeof addr;
- inet_prefix ip;
-
- fd_set fdset;
- int fd, ret, err, i;
-
- interface *ifs;
- int max_sk_idx, dev_sk[me.cur_ifs_n];
-
- u_short tcp_port=*(u_short *)door;
- const char *ntop;
-
- pthread_attr_init(&t_attr);
- pthread_attr_setdetachstate(&t_attr, PTHREAD_CREATE_DETACHED);
-
- debug(DBG_SOFT, "Preparing the tcp listening socket on port %d", tcp_port);
-
- err=sockets_all_ifs(my_family, SOCK_STREAM, tcp_port, me.cur_ifs,
- me.cur_ifs_n, dev_sk, &max_sk_idx);
- if(!err)
- return NULL;
- else if(err < 0)
- fatal("Creation of the %s daemon aborted. "
- "Is there another ntkd running?", "tcp");
-
- pthread_mutex_init(&tcp_exec_lock, 0);
-
- for(i=0; i<me.cur_ifs_n; i++) {
- if(!dev_sk[i])
- continue;
- /*
- * While we are accepting the connections we keep the socket non
- * blocking.
- */
- if(set_nonblock_sk(dev_sk[i])) {
- pthread_mutex_unlock(&tcp_daemon_lock);
- return NULL;
- }
-
- /* Shhh, it's listening... */
- if(listen(dev_sk[i], 5) == -1) {
- inet_close(&dev_sk[i]);
- pthread_mutex_unlock(&tcp_daemon_lock);
- return NULL;
- }
- }
-
- debug(DBG_NORMAL, "Tcp daemon on port %d up & running", tcp_port);
- pthread_mutex_unlock(&tcp_daemon_lock);
- for(;;) {
- FD_ZERO(&fdset);
-
- if(!me.cur_ifs_n) {
- /* All the devices have been removed while ntkd was
- * running, sleep well */
- sleep(1);
- continue;
- }
-
- for(i=0; i < me.cur_ifs_n; i++)
- if(dev_sk[i])
- FD_SET(dev_sk[i], &fdset);
-
- ret=select(dev_sk[max_sk_idx]+1, &fdset, NULL, NULL, NULL);
- if(sigterm_timestamp)
- /* NetsukukuD has been closed */
- break;
- if(ret < 0 && errno != EINTR)
- error("daemon_tcp: select error: %s", strerror(errno));
- if(ret < 0)
- continue;
-
- for(i=0; i < me.cur_ifs_n; i++) {
- ifs=&me.cur_ifs[i];
- if(!dev_sk[i])
- continue;
-
- if(!FD_ISSET(dev_sk[i], &fdset))
- continue;
-
- fd=accept(dev_sk[i], (struct sockaddr *)&addr, &addrlen);
- if(fd == -1) {
- if (errno != EINTR && errno != EWOULDBLOCK)
- error("daemon_tcp: accept(): %s", strerror(errno));
- continue;
- }
-
- setzero(&rpkt, sizeof(PACKET));
- pkt_addsk(&rpkt, my_family, fd, SKT_TCP);
- pkt_add_dev(&rpkt, ifs, 0);
- rpkt.flags=MSG_WAITALL;
- pkt_addport(&rpkt, tcp_port);
-
- ntop=0;
- sockaddr_to_inet((struct sockaddr *)&addr, &ip, 0);
- pkt_addfrom(&rpkt, &ip);
- if(server_opt.dbg_lvl)
- ntop=inet_to_str(ip);
-
- if((ret=add_accept(ip, 0))) {
- debug(DBG_NORMAL, "ACPT: drop connection with %s: "
- "Accept table full.", ntop);
-
- /* Omg, we cannot take it anymore, go away: ACK_NEGATIVE */
- pkt_err(rpkt, ret, 1);
- inet_close(&fd);
- continue;
- } else {
- /*
- * Ok, the connection is good, send back the
- * ACK_AFFERMATIVE.
- */
- pkt_addto(&rpkt, &rpkt.from);
- send_rq(&rpkt, 0, ACK_AFFERMATIVE, 0, 0, 0, 0);
- }
-
- if(unset_nonblock_sk(fd))
- continue;
-
- pthread_mutex_lock(&tcp_exec_lock);
- err=pthread_create(&thread, &t_attr, tcp_recv_loop, (void *)&rpkt);
- pthread_detach(thread);
- pthread_mutex_lock(&tcp_exec_lock);
- pthread_mutex_unlock(&tcp_exec_lock);
- }
- }
- return NULL;
- }
|