ccnr_net.c

Go to the documentation of this file.
00001 /**
00002  * @file ccnr_net.c
00003  * 
00004  * Part of ccnr -  CCNx Repository Daemon.
00005  *
00006  */
00007 
00008 /*
00009  * Copyright (C) 2011 Palo Alto Research Center, Inc.
00010  *
00011  * This work is free software; you can redistribute it and/or modify it under
00012  * the terms of the GNU General Public License version 2 as published by the
00013  * Free Software Foundation.
00014  * This work is distributed in the hope that it will be useful, but WITHOUT ANY
00015  * WARRANTY; without even the implied warranty of MERCHANTABILITY or
00016  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
00017  * for more details. You should have received a copy of the GNU General Public
00018  * License along with this program; if not, write to the
00019  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022  
00023 #include <errno.h>
00024 #include <fcntl.h>
00025 #include <limits.h>
00026 #include <netdb.h>
00027 #include <poll.h>
00028 #include <signal.h>
00029 #include <stddef.h>
00030 #include <stdint.h>
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <time.h>
00035 #include <unistd.h>
00036 #include <arpa/inet.h>
00037 #include <sys/time.h>
00038 #include <sys/socket.h>
00039 #include <sys/stat.h>
00040 #include <sys/types.h>
00041 #include <sys/un.h>
00042 #include <netinet/in.h>
00043 
00044 #include "ccnr_private.h"
00045 
00046 #include "ccnr_net.h"
00047 
00048 #include "ccnr_io.h"
00049 #include "ccnr_msg.h"
00050 
00051 PUBLIC char *
00052 r_net_get_local_sockname(void)
00053 {
00054     struct sockaddr_un sa;
00055     ccn_setup_sockaddr_un(NULL, &sa);
00056     return(strdup(sa.sun_path));
00057 }
00058 
00059 PUBLIC void
00060 r_net_setsockopt_v6only(struct ccnr_handle *h, int fd)
00061 {
00062     int yes = 1;
00063     int res = 0;
00064 #ifdef IPV6_V6ONLY
00065     res = setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes));
00066 #endif
00067     if (res == -1)
00068         ccnr_msg(h, "warning - could not set IPV6_V6ONLY on fd %d: %s",
00069                  fd, strerror(errno));
00070 }
00071 
00072 static const char *
00073 af_name(int family)
00074 {
00075     switch (family) {
00076         case AF_INET:
00077             return("ipv4");
00078         case AF_INET6:
00079             return("ipv6");
00080         default:
00081             return("");
00082     }
00083 }
00084 
00085 PUBLIC int
00086 r_net_listen_on_wildcards(struct ccnr_handle *h)
00087 {
00088     int fd;
00089     int res;
00090     int whichpf;
00091     struct addrinfo hints = {0};
00092     struct addrinfo *addrinfo = NULL;
00093     struct addrinfo *a;
00094     
00095     if (h->portstr == NULL || h->portstr[0] == 0)
00096         return(-1);
00097     hints.ai_socktype = SOCK_STREAM;
00098     hints.ai_flags = AI_PASSIVE;
00099     for (whichpf = 0; whichpf < 2; whichpf++) {
00100         hints.ai_family = whichpf ? PF_INET6 : PF_INET;
00101         res = getaddrinfo(NULL, h->portstr, &hints, &addrinfo);
00102         if (res == 0) {
00103             for (a = addrinfo; a != NULL; a = a->ai_next) {
00104                 fd = socket(a->ai_family, SOCK_STREAM, 0);
00105                 if (fd != -1) {
00106                     int yes = 1;
00107                     // XXX - perhaps we should not set reuseaddr
00108                     setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
00109                     if (a->ai_family == AF_INET6)
00110                         r_net_setsockopt_v6only(h, fd);
00111                     res = bind(fd, a->ai_addr, a->ai_addrlen);
00112                     if (res != 0) {
00113                         close(fd);
00114                         continue;
00115                     }
00116                     res = listen(fd, 30);
00117                     if (res == -1) {
00118                         close(fd);
00119                         continue;
00120                     }
00121                     r_io_record_fd(h, fd,
00122                                       a->ai_addr, a->ai_addrlen,
00123                                       CCNR_FACE_PASSIVE);
00124                     if (CCNSHOULDLOG(h, listen_on, CCNL_INFO))
00125                         ccnr_msg(h, "accepting %s status connections on fd %d",
00126                                  af_name(a->ai_family), fd);
00127                 }
00128             }
00129             freeaddrinfo(addrinfo);
00130         }
00131     }
00132     return(0);
00133 }
00134 
00135 PUBLIC int
00136 r_net_listen_on_address(struct ccnr_handle *h, const char *addr)
00137 {
00138     int fd;
00139     int res;
00140     struct addrinfo hints = {0};
00141     struct addrinfo *addrinfo = NULL;
00142     struct addrinfo *a;
00143     int ok = 0;
00144     
00145     if (CCNSHOULDLOG(h, listen_on_addr, CCNL_FINE))
00146         ccnr_msg(h, "listen_on %s", addr);
00147     hints.ai_socktype = SOCK_DGRAM;
00148     hints.ai_flags = AI_PASSIVE;
00149     res = getaddrinfo(addr, h->portstr, &hints, &addrinfo);
00150     if (res == 0) {
00151         for (a = addrinfo; a != NULL; a = a->ai_next) {
00152             fd = socket(a->ai_family, SOCK_STREAM, 0);
00153             if (fd != -1) {
00154                 int yes = 1;
00155                 setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
00156                 if (a->ai_family == AF_INET6)
00157                     r_net_setsockopt_v6only(h, fd);
00158                 res = bind(fd, a->ai_addr, a->ai_addrlen);
00159                 if (res != 0) {
00160                     close(fd);
00161                     continue;
00162                 }
00163                 res = listen(fd, 30);
00164                 if (res == -1) {
00165                     close(fd);
00166                     continue;
00167                 }
00168                 r_io_record_fd(h, fd,
00169                                   a->ai_addr, a->ai_addrlen,
00170                                   CCNR_FACE_PASSIVE);
00171                 if (CCNSHOULDLOG(h, listen_on, CCNL_INFO))
00172                     ccnr_msg(h, "accepting %s status connections on fd %d",
00173                              af_name(a->ai_family), fd);
00174                 ok++;
00175             }
00176         }
00177         freeaddrinfo(addrinfo);
00178     }
00179     return(ok > 0 ? 0 : -1);
00180 }
00181 
00182 PUBLIC int
00183 r_net_listen_on(struct ccnr_handle *h, const char *addrs)
00184 {
00185     unsigned char ch;
00186     unsigned char dlm;
00187     int res = 0;
00188     int i;
00189     struct ccn_charbuf *addr = NULL;
00190     
00191     if (h->portstr == NULL || h->portstr[0] == 0)
00192         return(-1);
00193     if (addrs == NULL || !*addrs || 0 == strcmp(addrs, "*"))
00194         return(r_net_listen_on_wildcards(h));
00195     addr = ccn_charbuf_create();
00196     for (i = 0, ch = addrs[i]; addrs[i] != 0;) {
00197         addr->length = 0;
00198         dlm = 0;
00199         if (ch == '[') {
00200             dlm = ']';
00201             ch = addrs[++i];
00202         }
00203         for (; ch > ' ' && ch != ',' && ch != ';' && ch != dlm; ch = addrs[++i])
00204             ccn_charbuf_append_value(addr, ch, 1);
00205         if (ch && ch == dlm)
00206             ch = addrs[++i];
00207         if (addr->length > 0) {
00208             res |= r_net_listen_on_address(h, ccn_charbuf_as_string(addr));
00209         }
00210         while ((0 < ch && ch <= ' ') || ch == ',' || ch == ';')
00211             ch = addrs[++i];
00212     }
00213     ccn_charbuf_destroy(&addr);
00214     return(res);
00215 }

Generated on Thu Feb 16 00:43:58 2012 for Content-Centric Networking in C by  doxygen 1.5.6