/*
- * Copyright (C) 2005-2008 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 2005-2009 Andre Noll <maan@systemlinux.org>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
/* Set up address hint structure */
memset(&hints, 0, sizeof(hints));
hints.ai_family = l3type;
- /* getaddrinfo does not really work well with SOCK_DCCP */
- if (socktype == SOCK_DGRAM || socktype == SOCK_STREAM)
- hints.ai_socktype = socktype;
+ hints.ai_socktype = socktype;
+ /*
+ * getaddrinfo does not support SOCK_DCCP, so for the sake of lookup
+ * (and only then) pretend to be UDP.
+ */
+ if (l4type == IPPROTO_DCCP)
+ hints.ai_socktype = SOCK_DGRAM;
/* only use addresses available on the host */
hints.ai_flags = AI_ADDRCONFIG;
*
* \return Positive if \a pattern was received, negative otherwise.
*
- * This function creates a buffer of size \a bufsize and tries
- * to receive at most \a bufsize bytes from file descriptor \a fd.
- * If at least \p strlen(\a pattern) bytes were received, the beginning of
- * the received buffer is compared with \a pattern, ignoring case.
+ * This function tries to receive at most \a bufsize bytes from file descriptor
+ * \a fd. If at least \p strlen(\a pattern) bytes were received, the beginning
+ * of the received buffer is compared with \a pattern, ignoring case.
*
* \sa recv_buffer(), \sa strncasecmp(3).
*/
{
size_t len = strlen(pattern);
char *buf = para_malloc(bufsize + 1);
- int ret = -E_RECV_PATTERN, n = recv_buffer(fd, buf, bufsize);
+ int ret = -E_RECV_PATTERN, n = recv_buffer(fd, buf, bufsize + 1);
if (n < len)
goto 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;
+}