X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=net.c;h=312a68546f08bc5493699a9ae32d6a4b96164e13;hp=9309ac1f02dc63edcc7af2939686b10b6d9b0599;hb=de9a70360fcd3b5285d280ad1f229f679d453603;hpb=40de1dd2fdbb054444d585aa70e2d50166a66e07 diff --git a/net.c b/net.c index 9309ac1f..312a6854 100644 --- a/net.c +++ b/net.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005-2008 Andre Noll + * Copyright (C) 2005-2009 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ @@ -755,3 +755,142 @@ out: free(buf); return ret; } + +static int resolve(const char *hostname, unsigned short port, + struct sockaddr_in *addr) +{ + struct hostent *host; + + assert(hostname); + host = gethostbyname(hostname); + if (!host) + return -ERRNO_TO_PARA_ERROR(h_errno); + if (addr) { + memcpy(&addr->sin_addr, host->h_addr_list[0], host->h_length); + addr->sin_port = port; + } + return 1; +} + +/* + * Create an UDP socket. + * + * If the given address is a multicast adress, the socket will be set + * to use the multicast TTL ttl and sets the datagrams to loop back. + * + * \return The fd of the socket on success, negative on errors. + */ +static int create_udp_socket(struct sockaddr_in *addr, + unsigned short port, unsigned char ttl) +{ + int ret, fd, yes = 1; + + assert(addr); + ret = socket(PF_INET, SOCK_DGRAM, 0); + if (ret < 0) + return -ERRNO_TO_PARA_ERROR(errno); + fd = ret; + /* reuse addresses */ + ret = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); + if (ret < 0) { + ret = -ERRNO_TO_PARA_ERROR(errno); + goto err; + } + addr->sin_family = AF_INET; + addr->sin_port = htons(port); + /* set the TTL and turn on multicast loop */ + if (IN_MULTICAST(htonl(addr->sin_addr.s_addr))) { + unsigned char loop = 1; + ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, + sizeof(ttl)); + if (ret < 0) { + ret = -ERRNO_TO_PARA_ERROR(errno); + goto err; + } + ret = setsockopt(fd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, + sizeof(loop)); + if (ret < 0) { + ret = -ERRNO_TO_PARA_ERROR(errno); + goto err; + } + } + return fd; +err: + close(fd); + return ret; +} + +/** + * Create and connect a sending UDP socket. + * + * \param hostname Where to send to (name or IPv4 address). + * \param port The udp port to use. + * \param ttl Time to live (only relevant for multicast). + * + * \return The fd of the socket on success, negative on error. + */ +int create_udp_send_socket(char *hostname, unsigned short port, + unsigned char ttl) +{ + struct sockaddr_in addr; + int fd, ret = resolve(hostname, port, &addr); + + if (ret < 0) + return ret; + ret = create_udp_socket(&addr, port, ttl); + if (ret < 0) + return ret; + fd = ret; + ret = connect(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (ret >= 0) + return fd; + ret = -ERRNO_TO_PARA_ERROR(errno); + close(fd); + return ret; +} + +/** + * Create and bind a receiving UDP socket. + * + * Bind the created UDP socket to \a hostname, and add multicast membership if + * hostname is a multicast hostname. + * + * \param hostname Name or IPv4 address to receive from. + * \param port The udp port. + * + * \return The fd of the socket on success, negative on errors. + */ +int create_udp_recv_socket(char *hostname, unsigned short port) +{ + struct sockaddr_in addr; + int fd, ret = resolve(hostname, port, &addr); + + if (ret < 0) + memset(&addr.sin_addr, 0, sizeof(addr.sin_addr)); + ret = create_udp_socket(&addr, port, 1); + if (ret < 0) + return ret; + fd = ret; + ret = bind(fd, (struct sockaddr *)&addr, sizeof(addr)); + if (ret < 0) { + ret = -ERRNO_TO_PARA_ERROR(errno); + goto err; + } + /* Add multicast membership */ + if (IN_MULTICAST(htonl(addr.sin_addr.s_addr))) { + struct ip_mreq mreq; + + mreq.imr_multiaddr.s_addr = addr.sin_addr.s_addr; + mreq.imr_interface.s_addr = htonl(INADDR_ANY); + ret = setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, + &mreq, sizeof(mreq)); + if (ret < 0) { + ret = -ERRNO_TO_PARA_ERROR(errno); + goto err; + } + } + return fd; +err: + close(fd); + return ret; +}