00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <stdlib.h>
00021 #include <stdarg.h>
00022 #include <errno.h>
00023 #include <string.h>
00024 #include <signal.h>
00025 #include <sys/types.h>
00026 #include <sys/time.h>
00027 #include <sys/socket.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030 #include <net/if.h>
00031 #include <netdb.h>
00032 #include <unistd.h>
00033
00034 #include <ccn/sockcreate.h>
00035
00036 #if defined(NEED_GETADDRINFO_COMPAT)
00037 #include "getaddrinfo.h"
00038 #include "dummyin6.h"
00039 #endif
00040
00041 #define LOGGIT if (logger) (*logger)
00042 #define GOT_HERE LOGGIT(logdat, "at ccn_sockcreate.c:%d", __LINE__);
00043
00044
00045 static int
00046 set_multicast_socket_options(int socket_r, int socket_w,
00047 struct addrinfo *ai,
00048 struct addrinfo *localif_for_mcast_addrinfo,
00049 int multicastttl,
00050 int ifindex,
00051 void (*logger)(void *, const char *, ...),
00052 void *logdat)
00053 {
00054 struct addrinfo hints;
00055 struct ip_mreq mreq;
00056 #ifdef IPV6_JOIN_GROUP
00057 struct ipv6_mreq mreq6;
00058 #endif
00059 unsigned char csockopt;
00060 unsigned int isockopt;
00061 int res;
00062
00063 memset((void *)&hints, 0, sizeof(hints));
00064 memset((void *)&mreq, 0, sizeof(mreq));
00065 #ifdef IPV6_JOIN_GROUP
00066 memset((void *)&mreq6, 0, sizeof(mreq6));
00067 #endif
00068
00069 if (ai->ai_family == PF_INET && IN_MULTICAST(ntohl(((struct sockaddr_in *)(ai->ai_addr))->sin_addr.s_addr))) {
00070 LOGGIT(logdat, "IPv4 multicast");
00071 #ifdef IP_ADD_MEMBERSHIP
00072 memcpy((void *)&mreq.imr_multiaddr, &((struct sockaddr_in *)ai->ai_addr)->sin_addr, sizeof(mreq.imr_multiaddr));
00073 if (localif_for_mcast_addrinfo != NULL) {
00074 memcpy((void *)&mreq.imr_interface.s_addr, &((struct sockaddr_in *)localif_for_mcast_addrinfo->ai_addr)->sin_addr, sizeof(mreq.imr_interface.s_addr));
00075 }
00076 res = setsockopt(socket_r, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq));
00077 if (res == -1) {
00078 LOGGIT(logdat, "setsockopt(..., IP_ADD_MEMBERSHIP, ...): %s", strerror(errno));
00079 return(-1);
00080 }
00081 #endif
00082 #ifdef IP_MULTICAST_LOOP
00083 csockopt = 0;
00084 res = setsockopt(socket_w, IPPROTO_IP, IP_MULTICAST_LOOP, &csockopt, sizeof(csockopt));
00085 if (res == -1) {
00086 LOGGIT(logdat, "setsockopt(..., IP_MULTICAST_LOOP, ...): %s", strerror(errno));
00087 return(-1);
00088 }
00089 #endif
00090 #ifdef IP_MULTICAST_TTL
00091 if (multicastttl > 0) {
00092 csockopt = multicastttl;
00093 res = setsockopt(socket_w, IPPROTO_IP, IP_MULTICAST_TTL, &csockopt, sizeof(csockopt));
00094 if (res == -1) {
00095 LOGGIT(logdat, "setsockopt(..., IP_MULTICAST_TTL, ...): %s", strerror(errno));
00096 return(-1);
00097 }
00098 }
00099 #endif
00100 #ifdef IP_MULTICAST_IF
00101 if (localif_for_mcast_addrinfo != NULL) {
00102 struct in_addr ifaddr = { 0 };
00103 ifaddr = ((struct sockaddr_in *)localif_for_mcast_addrinfo->ai_addr)->sin_addr;
00104 res = setsockopt(socket_w, IPPROTO_IP, IP_MULTICAST_IF, &ifaddr, sizeof(ifaddr));
00105 if (res == -1) {
00106 LOGGIT(logdat, "setsockopt(..., IP_MULTICAST_IF, ...): %s", strerror(errno));
00107 return(-1);
00108 }
00109 }
00110 #endif
00111 } else if (ai->ai_family == PF_INET6 && IN6_IS_ADDR_MULTICAST((&((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr))) {
00112 LOGGIT(logdat, "IPv6 multicast");
00113 #ifdef IPV6_JOIN_GROUP
00114 memcpy((void *)&mreq6.ipv6mr_multiaddr, &((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr, sizeof(mreq6.ipv6mr_multiaddr));
00115 if (ifindex > 0) {
00116 mreq6.ipv6mr_interface = ifindex;
00117 }
00118 res = setsockopt(socket_r, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq6, sizeof(mreq6));
00119 if (res == -1) {
00120 LOGGIT(logdat, "setsockopt(..., IPV6_JOIN_GROUP, ...): %s", strerror(errno));
00121 return(-1);
00122 }
00123 #endif
00124 #ifdef IPV6_MULTICAST_LOOP
00125 isockopt = 0;
00126 res = setsockopt(socket_w, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &isockopt, sizeof(isockopt));
00127 if (res == -1) {
00128 LOGGIT(logdat, "setsockopt(..., IPV6_MULTICAST_LOOP, ...): %s", strerror(errno));
00129 return(-1);
00130 }
00131 #endif
00132 #ifdef IPV6_MULTICAST_HOPS
00133 if (multicastttl > 0) {
00134 isockopt = multicastttl;
00135 res = setsockopt(socket_w, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &isockopt, sizeof(isockopt));
00136 if (res == -1) {
00137 LOGGIT(logdat, "setsockopt(..., IPV6_MULTICAST_LOOP, ...): %s", strerror(errno));
00138 return(-1);
00139 }
00140 }
00141 #endif
00142 #ifdef IP6_MULTICAST_IF
00143 if (ifindex > 0) {
00144 isockopt = ifindex;
00145 res = setsockopt(socket_w, IPPROTO_IPV6, IP6_MULTICAST_IF, &isockopt, sizeof(isockopt));
00146 if (res == -1) {
00147 LOGGIT(logdat, "setsockopt(..., IP6_MULTICAST_IF, ...): %s", strerror(errno));
00148 return(-1);
00149 }
00150 }
00151 #endif
00152 }
00153 return(0);
00154 }
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 int
00172 ccn_setup_socket(const struct ccn_sockdescr *descr,
00173 void (*logger)(void *, const char *, ...),
00174 void *logdat,
00175 int (*getbound)(void *, struct sockaddr *, socklen_t),
00176 void *getbounddat,
00177 struct ccn_sockets *socks)
00178 {
00179 int result = -1;
00180 char *cp = NULL;
00181 struct addrinfo hints = {0};
00182 int res;
00183 struct addrinfo *mcast_source_addrinfo = NULL;
00184 struct addrinfo *addrinfo = NULL;
00185 struct addrinfo *laddrinfo = NULL;
00186 unsigned int if_index = 0;
00187 const int one = 1;
00188 int sock = -1;
00189 int close_protect = -1;
00190
00191 GOT_HERE;
00192 socks->sending = socks->recving = -1;
00193 if (descr->ipproto > 0)
00194 hints.ai_protocol = descr->ipproto;
00195 if (descr->ipproto == IPPROTO_UDP)
00196 hints.ai_socktype = SOCK_DGRAM;
00197 else if (descr->ipproto == IPPROTO_TCP)
00198 hints.ai_socktype = SOCK_STREAM;
00199 hints.ai_flags = AI_NUMERICHOST;
00200 if (descr->port == NULL ||
00201 strspn(descr->port, "0123456789") != strlen(descr->port)) {
00202 LOGGIT(logdat, "must specify numeric port");
00203 goto Finish;
00204 }
00205 GOT_HERE;
00206 if (descr->source_address != NULL) {
00207 res = getaddrinfo(descr->source_address, descr->port,
00208 &hints, &mcast_source_addrinfo);
00209 if (res != 0 || mcast_source_addrinfo == NULL) {
00210 LOGGIT(logdat, "getaddrinfo(\"%s\", ...): %s",
00211 descr->source_address, gai_strerror(res));
00212 goto Finish;
00213 }
00214 hints.ai_family = mcast_source_addrinfo->ai_family;
00215 }
00216 GOT_HERE;
00217 if (descr->mcast_ttl >= 0) {
00218 if (descr->mcast_ttl < 1 || descr->mcast_ttl > 255) {
00219
00220 LOGGIT(logdat, "mcast_ttl(%d) out of range", descr->mcast_ttl);
00221 goto Finish;
00222 }
00223 }
00224 GOT_HERE;
00225 if (descr->address == NULL) {
00226 LOGGIT(logdat, "must specify remote address");
00227 goto Finish;
00228 }
00229 #ifdef IPV6_JOIN_GROUP
00230 cp = strchr(descr->address, '%');
00231 GOT_HERE;
00232 if (cp != NULL) {
00233 cp++;
00234 errno = 0;
00235 if_index = atoi(cp);
00236 if (if_index == 0) {
00237 if_index = if_nametoindex(cp);
00238 if (if_index == 0 && errno != 0) {
00239 LOGGIT(logdat, "Invalid interface name %s", cp);
00240 goto Finish;
00241 }
00242 }
00243 }
00244 #endif
00245 GOT_HERE;
00246 res = getaddrinfo(descr->address, descr->port,
00247 &hints, &addrinfo);
00248 if (res != 0 || addrinfo == NULL) {
00249 LOGGIT(logdat, "getaddrinfo(\"%s\", ...): %s",
00250 descr->address, gai_strerror(res));
00251 goto Finish;
00252 }
00253 sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
00254 GOT_HERE;
00255 if (sock == -1) {
00256 LOGGIT(logdat, "socket: %s", strerror(errno));
00257 goto Finish;
00258 }
00259 GOT_HERE;
00260 socks->recving = socks->sending = sock;
00261 if (mcast_source_addrinfo == NULL) {
00262
00263 hints.ai_family = addrinfo->ai_family;
00264 hints.ai_socktype = addrinfo->ai_socktype;
00265 hints.ai_flags = AI_PASSIVE;
00266 GOT_HERE;
00267 res = getaddrinfo(NULL, descr->port, &hints, &laddrinfo);
00268 if (res != 0)
00269 goto Finish;
00270 GOT_HERE;
00271 res = bind(socks->sending, laddrinfo->ai_addr, laddrinfo->ai_addrlen);
00272 if (res == -1 && getbound) {
00273 mcast_source_addrinfo = laddrinfo;
00274 laddrinfo = NULL;
00275 }
00276 }
00277 if (mcast_source_addrinfo != NULL) {
00278
00279
00280
00281
00282
00283
00284
00285
00286 socks->sending = -1;
00287 if (getbound) {
00288 GOT_HERE;
00289 socks->sending = getbound(getbounddat,
00290 mcast_source_addrinfo->ai_addr,
00291 mcast_source_addrinfo->ai_addrlen);
00292 if (socks->sending >= 0) {
00293 GOT_HERE;
00294 close_protect = socks->sending;
00295 }
00296 }
00297 if (socks->sending == -1)
00298 socks->sending = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol);
00299 if (socks->sending == -1) {
00300 LOGGIT(logdat, "socket: %s", strerror(errno));
00301 goto Finish;
00302 }
00303 res = setsockopt(socks->recving, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
00304 if (res == -1) {
00305 LOGGIT(logdat, "setsockopt(recving, ..., SO_REUSEADDR, ...): %s", strerror(errno));
00306 goto Finish;
00307 }
00308
00309 res = bind(socks->recving, addrinfo->ai_addr, addrinfo->ai_addrlen);
00310 if (res == -1) {
00311 LOGGIT(logdat, "bind(recving, ...): %s", strerror(errno));
00312 goto Finish;
00313 }
00314 }
00315 GOT_HERE;
00316 res = set_multicast_socket_options(socks->recving, socks->sending,
00317 addrinfo,
00318 mcast_source_addrinfo,
00319 descr->mcast_ttl,
00320 if_index,
00321 logger,
00322 logdat);
00323 if (res < 0)
00324 goto Finish;
00325 if (mcast_source_addrinfo != NULL) {
00326 GOT_HERE;
00327 if (socks->sending != close_protect) {
00328 res = bind(socks->sending,
00329 mcast_source_addrinfo->ai_addr,
00330 mcast_source_addrinfo->ai_addrlen);
00331 if (res == -1) {
00332 LOGGIT(logdat, "bind(sending, ...): %s", strerror(errno));
00333 goto Finish;
00334 }
00335 }
00336 }
00337 GOT_HERE;
00338 result = 0;
00339
00340 Finish:
00341 if (addrinfo != NULL)
00342 freeaddrinfo(addrinfo);
00343 if (laddrinfo != NULL)
00344 freeaddrinfo(laddrinfo);
00345 if (mcast_source_addrinfo != NULL)
00346 freeaddrinfo(mcast_source_addrinfo);
00347 if (result != 0) {
00348 close(socks->recving);
00349 if (socks->sending != socks->recving && socks->sending != close_protect)
00350 close(socks->sending);
00351 socks->sending = socks->recving = -1;
00352 }
00353 return(result);
00354 }