mirror of
				https://git.proxmox.com/git/mirror_frr
				synced 2025-11-04 03:13:44 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			223 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			223 lines
		
	
	
		
			5.0 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
Copyright (c) 2007, 2008 by Juliusz Chroboczek
 | 
						|
 | 
						|
Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
						|
of this software and associated documentation files (the "Software"), to deal
 | 
						|
in the Software without restriction, including without limitation the rights
 | 
						|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
						|
copies of the Software, and to permit persons to whom the Software is
 | 
						|
furnished to do so, subject to the following conditions:
 | 
						|
 | 
						|
The above copyright notice and this permission notice shall be included in
 | 
						|
all copies or substantial portions of the Software.
 | 
						|
 | 
						|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
						|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
						|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | 
						|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
						|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
						|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 | 
						|
THE SOFTWARE.
 | 
						|
*/
 | 
						|
 | 
						|
#ifdef HAVE_CONFIG_H
 | 
						|
#include "config.h"
 | 
						|
#endif
 | 
						|
 | 
						|
#include <unistd.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <string.h>
 | 
						|
#include <sys/ioctl.h>
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/uio.h>
 | 
						|
#include <sys/socket.h>
 | 
						|
#include <netinet/in.h>
 | 
						|
#include <netinet/in_systm.h>
 | 
						|
#include <netinet/ip.h>
 | 
						|
#include <arpa/inet.h>
 | 
						|
#include <errno.h>
 | 
						|
 | 
						|
#include "babeld.h"
 | 
						|
#include "util.h"
 | 
						|
#include "net.h"
 | 
						|
#include "sockopt.h"
 | 
						|
 | 
						|
int
 | 
						|
babel_socket(int port)
 | 
						|
{
 | 
						|
    struct sockaddr_in6 sin6;
 | 
						|
    int s, rc;
 | 
						|
    int saved_errno;
 | 
						|
    int one = 1, zero = 0;
 | 
						|
 | 
						|
    s = socket(PF_INET6, SOCK_DGRAM, 0);
 | 
						|
    if(s < 0)
 | 
						|
        return -1;
 | 
						|
 | 
						|
    rc = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
 | 
						|
                    &zero, sizeof(zero));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = setsockopt(s, IPPROTO_IPV6, IPV6_UNICAST_HOPS,
 | 
						|
                    &one, sizeof(one));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS,
 | 
						|
                    &one, sizeof(one));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    setsockopt_ipv6_tclass (s, IPTOS_PREC_INTERNETCONTROL);
 | 
						|
 | 
						|
    rc = fcntl(s, F_GETFL, 0);
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = fcntl(s, F_GETFD, 0);
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    memset(&sin6, 0, sizeof(sin6));
 | 
						|
    sin6.sin6_family = AF_INET6;
 | 
						|
    sin6.sin6_port = htons(port);
 | 
						|
    rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    return s;
 | 
						|
 | 
						|
 fail:
 | 
						|
    saved_errno = errno;
 | 
						|
    close(s);
 | 
						|
    errno = saved_errno;
 | 
						|
    return -1;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
babel_recv(int s, void *buf, int buflen, struct sockaddr *sin, int slen)
 | 
						|
{
 | 
						|
    struct iovec iovec;
 | 
						|
    struct msghdr msg;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    memset(&msg, 0, sizeof(msg));
 | 
						|
    iovec.iov_base = buf;
 | 
						|
    iovec.iov_len = buflen;
 | 
						|
    msg.msg_name = sin;
 | 
						|
    msg.msg_namelen = slen;
 | 
						|
    msg.msg_iov = &iovec;
 | 
						|
    msg.msg_iovlen = 1;
 | 
						|
 | 
						|
    rc = recvmsg(s, &msg, 0);
 | 
						|
    return rc;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
babel_send(int s,
 | 
						|
           void *buf1, int buflen1, void *buf2, int buflen2,
 | 
						|
           struct sockaddr *sin, int slen)
 | 
						|
{
 | 
						|
    struct iovec iovec[2];
 | 
						|
    struct msghdr msg;
 | 
						|
    int rc;
 | 
						|
 | 
						|
    iovec[0].iov_base = buf1;
 | 
						|
    iovec[0].iov_len = buflen1;
 | 
						|
    iovec[1].iov_base = buf2;
 | 
						|
    iovec[1].iov_len = buflen2;
 | 
						|
    memset(&msg, 0, sizeof(msg));
 | 
						|
    msg.msg_name = sin;
 | 
						|
    msg.msg_namelen = slen;
 | 
						|
    msg.msg_iov = iovec;
 | 
						|
    msg.msg_iovlen = 2;
 | 
						|
 | 
						|
 again:
 | 
						|
    rc = sendmsg(s, &msg, 0);
 | 
						|
    if(rc < 0) {
 | 
						|
        if(errno == EINTR)
 | 
						|
            goto again;
 | 
						|
        else if(errno == EAGAIN) {
 | 
						|
            int rc2;
 | 
						|
            rc2 = wait_for_fd(1, s, 5);
 | 
						|
            if(rc2 > 0)
 | 
						|
                goto again;
 | 
						|
            errno = EAGAIN;
 | 
						|
        }
 | 
						|
    }
 | 
						|
    return rc;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
tcp_server_socket(int port, int local)
 | 
						|
{
 | 
						|
    struct sockaddr_in6 sin6;
 | 
						|
    int s, rc, saved_errno;
 | 
						|
    int one = 1;
 | 
						|
 | 
						|
    s = socket(PF_INET6, SOCK_STREAM, 0);
 | 
						|
    if(s < 0)
 | 
						|
        return -1;
 | 
						|
 | 
						|
    rc = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = fcntl(s, F_GETFL, 0);
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = fcntl(s, F_SETFL, (rc | O_NONBLOCK));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = fcntl(s, F_GETFD, 0);
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = fcntl(s, F_SETFD, rc | FD_CLOEXEC);
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    memset(&sin6, 0, sizeof(sin6));
 | 
						|
    sin6.sin6_family = AF_INET6;
 | 
						|
    sin6.sin6_port = htons(port);
 | 
						|
    if(local) {
 | 
						|
        rc = inet_pton(AF_INET6, "::1", &sin6.sin6_addr);
 | 
						|
        if(rc < 0)
 | 
						|
            goto fail;
 | 
						|
    }
 | 
						|
    rc = bind(s, (struct sockaddr*)&sin6, sizeof(sin6));
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    rc = listen(s, 2);
 | 
						|
    if(rc < 0)
 | 
						|
        goto fail;
 | 
						|
 | 
						|
    return s;
 | 
						|
 | 
						|
 fail:
 | 
						|
    saved_errno = errno;
 | 
						|
    close(s);
 | 
						|
    errno = saved_errno;
 | 
						|
    return -1;
 | 
						|
}
 |