Exemplo n.º 1
0
/**
 * 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);
}
Exemplo n.º 2
0
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);
}