/** * Utility for setting up a socket (or pair of sockets) from a text-based * description. * * Currently this is only used for UDP multicast. * * @param descr hold the information needed to create the socket(s). * @param logger should be used for reporting errors, printf-style. * @param logdat must be passed as first argument to logger(). * @param getbound is callback for getting already-bound sender socket, * should return -1 if none. * @param getbounddat is passed as first argument to getbound * @param socks will be filled in with the pair of socket file descriptors. * @returns 0 for success, -1 for error. */ int ccn_setup_socket(const struct ccn_sockdescr *descr, void (*logger)(void *, const char *, ...), void *logdat, int (*getbound)(void *, struct sockaddr *, socklen_t), void *getbounddat, struct ccn_sockets *socks) { int result = -1; char *cp = NULL; struct addrinfo hints = {0}; int res; struct addrinfo *mcast_source_addrinfo = NULL; struct addrinfo *addrinfo = NULL; struct addrinfo *laddrinfo = NULL; unsigned int if_index = 0; const int one = 1; int sock = -1; int close_protect = -1; GOT_HERE; socks->sending = socks->recving = -1; if (descr->ipproto > 0) hints.ai_protocol = descr->ipproto; if (descr->ipproto == IPPROTO_UDP) hints.ai_socktype = SOCK_DGRAM; else if (descr->ipproto == IPPROTO_TCP) hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_NUMERICHOST; if (descr->port == NULL || strspn(descr->port, "0123456789") != strlen(descr->port)) { LOGGIT(logdat, "must specify numeric port"); goto Finish; } GOT_HERE; if (descr->source_address != NULL) { res = getaddrinfo(descr->source_address, descr->port, &hints, &mcast_source_addrinfo); if (res != 0 || mcast_source_addrinfo == NULL) { LOGGIT(logdat, "getaddrinfo(\"%s\", ...): %s", descr->source_address, gai_strerror(res)); goto Finish; } hints.ai_family = mcast_source_addrinfo->ai_family; } GOT_HERE; if (descr->mcast_ttl >= 0) { if (descr->mcast_ttl < 1 || descr->mcast_ttl > 255) { // XXX - It could make sense to use ttl 0 if we're talking on a loopback interface and we leave IP_MULTICAST_LOOP on. LOGGIT(logdat, "mcast_ttl(%d) out of range", descr->mcast_ttl); goto Finish; } } GOT_HERE; if (descr->address == NULL) { LOGGIT(logdat, "must specify remote address"); goto Finish; } #ifdef IPV6_JOIN_GROUP cp = strchr(descr->address, '%'); GOT_HERE; if (cp != NULL) { cp++; errno = 0; if_index = atoi(cp); if (if_index == 0) { if_index = if_nametoindex(cp); if (if_index == 0 && errno != 0) { LOGGIT(logdat, "Invalid interface name %s", cp); goto Finish; } } } #endif GOT_HERE; res = getaddrinfo(descr->address, descr->port, &hints, &addrinfo); if (res != 0 || addrinfo == NULL) { LOGGIT(logdat, "getaddrinfo(\"%s\", ...): %s", descr->address, gai_strerror(res)); goto Finish; } sock = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); GOT_HERE; if (sock == -1) { LOGGIT(logdat, "socket: %s", strerror(errno)); goto Finish; } GOT_HERE; socks->recving = socks->sending = sock; if (mcast_source_addrinfo == NULL) { /* Try binding the port now to see if we need 2 sockets. */ hints.ai_family = addrinfo->ai_family; hints.ai_socktype = addrinfo->ai_socktype; hints.ai_flags = AI_PASSIVE; GOT_HERE; res = getaddrinfo(NULL, descr->port, &hints, &laddrinfo); if (res != 0) goto Finish; GOT_HERE; res = bind(socks->sending, laddrinfo->ai_addr, laddrinfo->ai_addrlen); if (res == -1 && getbound) { mcast_source_addrinfo = laddrinfo; laddrinfo = NULL; } } if (mcast_source_addrinfo != NULL) { /* * We have a specific interface to bind to for sending. * mcast_source_addrinfo is the unicast address of this interface. * Since we need to bind the recving side to the multicast address, * we need two sockets in this case. * * Our caller may choose to provide the sending side. */ socks->sending = -1; if (getbound) { GOT_HERE; socks->sending = getbound(getbounddat, mcast_source_addrinfo->ai_addr, mcast_source_addrinfo->ai_addrlen); if (socks->sending >= 0) { GOT_HERE; close_protect = socks->sending; } } if (socks->sending == -1) socks->sending = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); if (socks->sending == -1) { LOGGIT(logdat, "socket: %s", strerror(errno)); goto Finish; } res = setsockopt(socks->recving, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); if (res == -1) { LOGGIT(logdat, "setsockopt(recving, ..., SO_REUSEADDR, ...): %s", strerror(errno)); goto Finish; } /* bind the recving socket to the multicast address */ res = bind(socks->recving, addrinfo->ai_addr, addrinfo->ai_addrlen); if (res == -1) { LOGGIT(logdat, "bind(recving, ...): %s", strerror(errno)); goto Finish; } } GOT_HERE; res = set_multicast_socket_options(socks->recving, socks->sending, addrinfo, mcast_source_addrinfo, descr->mcast_ttl, if_index, logger, logdat); if (res < 0) goto Finish; if (mcast_source_addrinfo != NULL) { GOT_HERE; if (socks->sending != close_protect) { res = bind(socks->sending, mcast_source_addrinfo->ai_addr, mcast_source_addrinfo->ai_addrlen); if (res == -1) { LOGGIT(logdat, "bind(sending, ...): %s", strerror(errno)); goto Finish; } } } GOT_HERE; result = 0; Finish: if (addrinfo != NULL) freeaddrinfo(addrinfo); if (laddrinfo != NULL) freeaddrinfo(laddrinfo); if (mcast_source_addrinfo != NULL) freeaddrinfo(mcast_source_addrinfo); if (result != 0) { close(socks->recving); if (socks->sending != socks->recving && socks->sending != close_protect) close(socks->sending); socks->sending = socks->recving = -1; } return(result); }
static void restore(register Joblist_t* job, Sfio_t* buf, Sfio_t* att) { register char* s; register char* b; char* u; char* down; char* back; char* sep; int downlen; int localview; void* pos; Var_t* v; Sfio_t* opt; Sfio_t* tmp; Sfio_t* context; push(job); localview = state.localview; state.localview = state.mam.statix && !state.expandview && state.user && !(job->flags & CO_ALWAYS); if ((job->flags & CO_LOCALSTACK) || (job->target->dynamic & D_hasscope)) { register Rule_t* r; register List_t* p; job->flags |= CO_LOCALSTACK; pos = pushlocal(); opt = sfstropen(); if (job->target->dynamic & D_hasscope) for (p = job->prereqs; p; p = p->next) if ((r = p->rule)->dynamic & D_scope) { if (*r->name == '-') set(r->name, 1, opt); else parse(NiL, r->name, r->name, opt); } else if ((r->property & (P_make|P_local|P_use)) == (P_make|P_local) && r->action) parse(NiL, r->action, r->name, opt); } context = state.context; if (state.targetcontext && *(u = unbound(job->target)) != '/' && (s = strrchr(u, '/'))) { size_t n; int c; tmp = sfstropen(); downlen = s - u; *s = 0; sfprintf(tmp, "%s%c", u, 0); n = sfstrtell(tmp); c = '/'; do { if (u = strchr(u, '/')) u++; else c = 0; sfputr(tmp, "..", c); } while (c); *s = '/'; back = (down = sfstrbase(tmp)) + n; state.context = buf; buf = sfstropen(); state.localview++; } else state.context = 0; if (job->action) expand(buf, job->action); if (state.context) { s = sfstruse(buf); sep = strchr(s, '\n') ? "\n" : "; "; sfprintf(state.context, "{ cd %s%s", down, sep); while (b = strchr(s, MARK_CONTEXT)) { sfwrite(state.context, s, b - s); if (!(s = strchr(++b, MARK_CONTEXT))) error(PANIC, "unbalanced MARK_CONTEXT"); *s++ = 0; if (*b == '/' || (u = getbound(b)) && *u == '/') sfputr(state.context, b, -1); else if (*b) { if (strneq(b, down, downlen)) switch (*(b + downlen)) { case 0: sfputc(state.context, '.'); continue; case '/': sfputr(state.context, b + downlen + 1, -1); continue; } if (streq(b, ".")) sfputr(state.context, back, -1); else if (isspace(*b)) sfputr(state.context, b, -1); else sfprintf(state.context, "%s/%s", back, b); } } sfprintf(state.context, "%s%s}", s, sep); sfstrclose(tmp); sfstrclose(buf); } state.context = context; sfprintf(att, "label=%s", job->target->name); if ((v = getvar(CO_ENV_ATTRIBUTES)) && !(v->property & V_import)) sfprintf(att, ",%s", v->value); if (job->flags & CO_LOCALSTACK) { poplocal(pos); if (*(s = sfstruse(opt))) set(s, 1, NiL); sfclose(opt); } state.localview = localview; pop(job); }