X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=net.c;h=1b142a3cd4a25b87fe2e31c86caaf32e4be5f51e;hp=49026db0ec91a7b4a1d3d0917723720eb8d0ba30;hb=c998e827328c7989986e4fb91048e7f427f722a8;hpb=b307a25ed895caa33684302b502e9e0e70dc78b7 diff --git a/net.c b/net.c index 49026db0..1b142a3c 100644 --- a/net.c +++ b/net.c @@ -1,17 +1,18 @@ /* - * Copyright (C) 2005-2011 Andre Noll + * Copyright (C) 2005 Andre Noll * * Licensed under the GPL v2. For licencing details see COPYING. */ /** \file net.c Networking-related helper functions. */ -/* - * Since glibc 2.8, the _GNU_SOURCE feature test macro must be defined in order - * to obtain the definition of the ucred structure. - */ -#define _GNU_SOURCE +#include "para.h" +#include +#include +#include +#include +#include #include /* At least NetBSD needs these. */ @@ -27,7 +28,6 @@ #include -#include "para.h" #include "error.h" #include "net.h" #include "string.h" @@ -43,7 +43,7 @@ * \param netmask Value of the netmask part in \a cidr or the * default of 32 if not specified. * - * \return Pointer to \a addr if succesful, NULL on error. + * \return Pointer to \a addr if successful, NULL on error. * \sa RFC 4632 */ char *parse_cidr(const char *cidr, @@ -142,9 +142,9 @@ static bool host_string_ok(const char *host) * \param hostlen The maximum length of \a host. * \param port To return the port number (if any) of \a url. * - * \return Pointer to \a host, or NULL if failed. - * If NULL is returned, \a host and \a portnum are undefined. If no - * port number was present in \a url, \a portnum is set to -1. + * \return Pointer to \a host, or \p NULL if failed. If \p NULL is returned, + * \a host and \a port are undefined. If no port number was present in \a url, + * \a port is set to -1. * * \sa RFC 3986, 3.2.2/3.2.3 */ @@ -168,16 +168,16 @@ char *parse_url(const char *url, if (*o++ != ']' || (*o != '\0' && *o != ':')) goto failed; } else { - for (; (*c = *o == ':'? '\0' : *o); c++, o++) - if (c == end) + for (; (*c = *o == ':'? '\0' : *o); c++, o++) { + if (c == end && o[1]) goto failed; + } } if (*o == ':') if (para_atoi32(++o, port) < 0 || *port < 0 || *port > 0xffff) goto failed; - if (host_string_ok(host)) return host; failed: @@ -203,7 +203,7 @@ const char *stringify_port(int port, const char *transport) struct servent *se = getservbyport(htons(port), transport); if (se == NULL) - snprintf(service, sizeof(service), "%u", port); + snprintf(service, sizeof(service), "%d", port); else snprintf(service, sizeof(service), "%s", se->s_name); } @@ -264,6 +264,12 @@ struct flowopts { struct list_head sockopts; }; +/** + * Allocate and initialize a flowopt queue. + * + * \return A new structure to be passed to \ref flowopt_add(). It is + * automatically deallocated in \ref makesock(). + */ struct flowopts *flowopt_new(void) { struct flowopts *new = para_malloc(sizeof(*new)); @@ -305,14 +311,6 @@ void flowopt_add(struct flowopts *fo, int lev, int opt, list_add_tail(&new->node, &fo->sockopts); } -void flowopt_add_bool(struct flowopts *fo, int lev, int opt, - const char *optname, bool on_or_off) -{ - int on = on_or_off; /* kernel takes 'int' */ - - flowopt_add(fo, lev, opt, optname, &on, sizeof(on)); -} - /** Set the entire bunch of pre-connection options at once. */ static void flowopt_setopts(int sockfd, struct flowopts *fo) { @@ -330,7 +328,14 @@ static void flowopt_setopts(int sockfd, struct flowopts *fo) } } -static void flowopt_cleanup(struct flowopts *fo) +/** + * Deallocate all resources of a flowopts structure. + * + * \param fo A pointer as returned from flowopt_new(). + * + * It's OK to pass \p NULL here in which case the function does nothing. + */ +void flowopt_cleanup(struct flowopts *fo) { struct pre_conn_opt *cur, *next; @@ -346,137 +351,148 @@ static void flowopt_cleanup(struct flowopts *fo) } /** - * Resolve IPv4/IPv6 address and create a ready-to-use active or passive socket. + * Resolve an IPv4/IPv6 address. * * \param l4type The layer-4 type (\p IPPROTO_xxx). - * \param passive Whether this is a passive (1) or active (0) socket. + * \param passive Whether \p AI_PASSIVE should be included as hint. * \param host Remote or local hostname or IPv/6 address string. - * \param port_number Decimal port number. - * \param fo Socket options to be set before making the connection. + * \param port_number Used to set the port in each returned address structure. + * \param result addrinfo structures are returned here. * - * This creates a ready-made IPv4/v6 socket structure after looking up the - * necessary parameters. The interpretation of \a host depends on the value of - * \a passive: - * - on a passive socket host is interpreted as an interface IPv4/6 address - * (can be left NULL); - * - on an active socket, \a host is the peer DNS name or IPv4/6 address - * to connect to; - * - \a port_number is in either case the numeric port number (not service - * string). - * - * Furthermore, bind(2) is called on passive sockets, and connect(2) on active - * sockets. The algorithm tries all possible address combinations until it - * succeeds. If \a fo is supplied, options are set and cleanup is performed. - * - * \return This function returns 1 on success and \a -E_ADDRESS_LOOKUP when no - * matching connection could be set up (with details in the error log). - * - * \sa ipv6(7), getaddrinfo(3), bind(2), connect(2). + * The interpretation of \a host depends on the value of \a passive. On a + * passive socket host is interpreted as an interface IPv4/6 address (can be + * left NULL). On an active socket, \a host is the peer DNS name or IPv4/6 + * address to connect to. + * + * \return Standard. + * + * \sa getaddrinfo(3). */ -int makesock(unsigned l4type, bool passive, - const char *host, uint16_t port_number, - struct flowopts *fo) +int lookup_address(unsigned l4type, bool passive, const char *host, + int port_number, struct addrinfo **result) { - struct addrinfo *local = NULL, *src = NULL, *remote = NULL, - *dst = NULL, hints; - unsigned int l3type = AF_UNSPEC; - int rc, on = 1, sockfd = -1, - socktype = sock_type(l4type); + int ret; char port[6]; /* port number has at most 5 digits */ + struct addrinfo *addr = NULL, hints; - sprintf(port, "%u", port_number); + *result = NULL; + sprintf(port, "%u", port_number & 0xffff); /* Set up address hint structure */ memset(&hints, 0, sizeof(hints)); - hints.ai_family = l3type; - hints.ai_socktype = socktype; - /* + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = sock_type(l4type); + /* * 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; - if (l3type == AF_INET6) - /* use v4-mapped-v6 if no v6 addresses found */ - hints.ai_flags |= AI_V4MAPPED | AI_ALL; - if (passive && host == NULL) hints.ai_flags |= AI_PASSIVE; - /* Obtain local/remote address information */ - if ((rc = getaddrinfo(host, port, &hints, passive ? &local : &remote))) { - PARA_ERROR_LOG("can not resolve %s address %s#%s: %s.\n", - layer4_name(l4type), - host? host : (passive? "[loopback]" : "[localhost]"), - port, gai_strerror(rc)); - rc = -E_ADDRESS_LOOKUP; - goto out; + ret = getaddrinfo(host, port, &hints, &addr); + if (ret != 0) { + PARA_ERROR_LOG("can not resolve %s address %s#%s: %s\n", + layer4_name(l4type), + host? host : (passive? "[loopback]" : "[localhost]"), + port, gai_strerror(ret)); + return -E_ADDRESS_LOOKUP; } + *result = addr; + return 1; +} - /* Iterate over all src/dst combination, exhausting dst first */ - for (src = local, dst = remote; src != NULL || dst != NULL; /* no op */ ) { - if (src && dst && src->ai_family == AF_INET - && dst->ai_family == AF_INET6) - goto get_next_dst; /* v4 -> v6 is not possible */ - - sockfd = socket(src ? src->ai_family : dst->ai_family, - socktype, l4type); - if (sockfd < 0) - goto get_next_dst; +/** + * Create an active or passive socket. + * + * \param l4type \p IPPROTO_TCP, \p IPPROTO_UDP, or \p IPPROTO_DCCP. + * \param passive Whether to call bind(2) or connect(2). + * \param ai Address information as obtained from \ref lookup_address(). + * \param fo Socket options to be set before making the connection. + * + * bind(2) is called on passive sockets, and connect(2) on active sockets. The + * algorithm tries all possible address combinations until it succeeds. If \a + * fo is supplied, options are set but cleanup must be performed in the caller. + * + * \return File descriptor on success, \p E_MAKESOCK on errors. + * + * \sa \ref lookup_address(), \ref makesock(), ip(7), ipv6(7), bind(2), + * connect(2). + */ +int makesock_addrinfo(unsigned l4type, bool passive, struct addrinfo *ai, + struct flowopts *fo) +{ + int ret = -E_MAKESOCK, on = 1; + for (; ai; ai = ai->ai_next) { + int fd; + ret = socket(ai->ai_family, sock_type(l4type), l4type); + if (ret < 0) + continue; + fd = ret; + flowopt_setopts(fd, fo); + if (!passive) { + if (connect(fd, ai->ai_addr, ai->ai_addrlen) == 0) + return fd; + close(fd); + continue; + } /* * Reuse the address on passive sockets to avoid failure on * restart (protocols using listen()) and when creating * multiple listener instances (UDP multicast). */ - if (passive && setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, - &on, sizeof(on)) == -1) { - rc = errno; - close(sockfd); - PARA_ERROR_LOG("can not set SO_REUSEADDR: %s\n", - strerror(rc)); - rc = -ERRNO_TO_PARA_ERROR(rc); - break; - } - flowopt_setopts(sockfd, fo); - - if (src) { - if (bind(sockfd, src->ai_addr, src->ai_addrlen) < 0) { - close(sockfd); - goto get_next_src; - } - if (!dst) /* bind-only completed successfully */ - break; + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, + sizeof(on)) == -1) { + close(fd); + continue; } - - if (dst && connect(sockfd, dst->ai_addr, dst->ai_addrlen) == 0) - break; /* connection completed successfully */ - close(sockfd); -get_next_dst: - if (dst && (dst = dst->ai_next)) + if (bind(fd, ai->ai_addr, ai->ai_addrlen) < 0) { + close(fd); continue; -get_next_src: - if (src && (src = src->ai_next)) /* restart inner loop */ - dst = remote; + } + return fd; } -out: - if (local) - freeaddrinfo(local); - if (remote) - freeaddrinfo(remote); - flowopt_cleanup(fo); - - if (src == NULL && dst == NULL) { - if (rc >= 0) - rc = -E_MAKESOCK; - PARA_ERROR_LOG("can not create %s socket %s#%s.\n", - layer4_name(l4type), host? host : (passive? - "[loopback]" : "[localhost]"), port); - return rc; + return -E_MAKESOCK; +} + +/** + * Resolve IPv4/IPv6 address and create a ready-to-use active or passive socket. + * + * \param l4type The layer-4 type (\p IPPROTO_xxx). + * \param passive Whether this is a passive or active socket. + * \param host Passed to \ref lookup_address(). + * \param port_number Passed to \ref lookup_address(). + * \param fo Passed to \ref makesock_addrinfo(). + * + * This creates a ready-made IPv4/v6 socket structure after looking up the + * necessary parameters. The function first calls \ref lookup_address() and + * passes the address information to makesock_addrinfo() to create and + * initialize the socket. + * + * \return The newly created file descriptor on success, a negative error code + * on failure. + * + * \sa \ref lookup_address(), \ref makesock_addrinfo(). + */ +int makesock(unsigned l4type, bool passive, const char *host, uint16_t port_number, + struct flowopts *fo) +{ + struct addrinfo *ai; + int ret = lookup_address(l4type, passive, host, port_number, &ai); + + if (ret >= 0) + ret = makesock_addrinfo(l4type, passive, ai, fo); + if (ai) + freeaddrinfo(ai); + if (ret < 0) { + PARA_ERROR_LOG("can not create %s socket %s#%d.\n", + layer4_name(l4type), host? host : (passive? + "[loopback]" : "[localhost]"), port_number); } - return sockfd; + return ret; } /** @@ -580,7 +596,7 @@ static inline int estimated_header_overhead(const int af_type) * * \param sockfd The socket file descriptor. * - * The socket must be connected. See RFC 1122, 3.3.3. If the protocol familiy + * The socket must be connected. See RFC 1122, 3.3.3. If the protocol family * could not be determined, \p AF_INET is assumed. * * \return The maximum message size of the address family type. @@ -601,11 +617,9 @@ int generic_max_transport_msg_size(int sockfd) } /** - * Look up the local or remote side of a connected socket structure. + * Look up the remote side of a connected socket structure. * * \param fd The socket descriptor of the connected socket. - * \param getname Either \p getsockname() for local, or \p getpeername() for - * remote side. * * \return A static character string identifying hostname and port of the * chosen side in numeric host:port format. @@ -613,7 +627,7 @@ int generic_max_transport_msg_size(int sockfd) * \sa getsockname(2), getpeername(2), parse_url(), getnameinfo(3), * services(5), nsswitch.conf(5). */ -static char *__get_sock_name(int fd, typeof(getsockname) getname) +char *remote_name(int fd) { struct sockaddr_storage ss; const struct sockaddr *sa; @@ -622,7 +636,7 @@ static char *__get_sock_name(int fd, typeof(getsockname) getname) static char output[sizeof(hbuf) + sizeof(sbuf) + 4]; int ret; - if (getname(fd, (struct sockaddr *)&ss, &sslen) < 0) { + if (getpeername(fd, (struct sockaddr *)&ss, &sslen) < 0) { PARA_ERROR_LOG("can not determine address from fd %d: %s\n", fd, strerror(errno)); snprintf(output, sizeof(output), "(unknown)"); @@ -642,104 +656,47 @@ static char *__get_sock_name(int fd, typeof(getsockname) getname) return output; } -/** - * Look up the local side of a connected socket structure. - * - * \param sockfd The file descriptor of the socket. - * - * \return A pointer to a static buffer containing hostname an port. This - * buffer must not be freed by the caller. - * - * \sa remote_name(). - */ -char *local_name(int sockfd) -{ - return __get_sock_name(sockfd, getsockname); -} - -/** - * Look up the remote side of a connected socket structure. - * - * \param sockfd The file descriptor of the socket. - * - * \return Analogous to the return value of \ref local_name() but for the - * remote side. - * - * \sa local_name(). - */ -char *remote_name(int sockfd) -{ - return __get_sock_name(sockfd, getpeername); -} - /** * Extract IPv4 or IPv6-mapped-IPv4 address from sockaddr_storage. - * \param ss Container of IPv4/6 address - * \return Extracted IPv4 address (different from 0) or 0 if unsuccessful. * - * \sa RFC 3493 + * \param ss Container of IPv4/6 address. + * \param ia Extracted IPv4 address (different from 0) or 0 if unsuccessful. + * + * \sa RFC 3493. */ -struct in_addr extract_v4_addr(const struct sockaddr_storage *ss) +void extract_v4_addr(const struct sockaddr_storage *ss, struct in_addr *ia) { - struct in_addr ia = {.s_addr = 0}; const struct sockaddr *sa = normalize_ip_address(ss); + memset(ia, 0, sizeof(*ia)); if (sa->sa_family == AF_INET) - ia = ((struct sockaddr_in *)sa)->sin_addr; - return ia; -} - -/** - * Send a binary buffer. - * - * \param fd The file descriptor. - * \param buf The buffer to be sent. - * \param len The length of \a buf. - * - * Send out the buffer and try to resend the remaining part in case of short - * writes. - * - * \return Standard. - */ -int send_bin_buffer(int fd, const char *buf, size_t len) -{ - if (!len) - PARA_CRIT_LOG("len == 0\n"); - return write_all(fd, buf, &len); -} - -/** - * Send a \p NULL-terminated buffer. - * - * \param fd The file descriptor. - * \param buf The null-terminated buffer to be send. - * - * This is equivalent to send_bin_buffer(fd, buf, strlen(buf)). - * - * \return Standard. - */ -int send_buffer(int fd, const char *buf) -{ - return send_bin_buffer(fd, buf, strlen(buf)); + *ia = ((struct sockaddr_in *)sa)->sin_addr; } /** - * Send a buffer given by a format string. + * Compare the address part of IPv4/6 addresses. * - * \param fd The file descriptor. - * \param fmt A format string. + * \param sa1 First address. + * \param sa2 Second address. * - * \return Standard. + * \return True iff the IP address of \a sa1 and \a sa2 match. */ -__printf_2_3 int send_va_buffer(int fd, const char *fmt, ...) +bool sockaddr_equal(const struct sockaddr *sa1, const struct sockaddr *sa2) { - char *msg; - int ret; - - PARA_VSPRINTF(fmt, msg); - ret = send_buffer(fd, msg); - free(msg); - return ret; + if (!sa1 || !sa2) + return false; + if (sa1->sa_family != sa2->sa_family) + return false; + if (sa1->sa_family == AF_INET) { + struct sockaddr_in *a1 = (typeof(a1))sa1, + *a2 = (typeof (a2))sa2; + return a1->sin_addr.s_addr == a2->sin_addr.s_addr; + } else if (sa1->sa_family == AF_INET6) { + struct sockaddr_in6 *a1 = (typeof(a1))sa1, + *a2 = (typeof (a2))sa2; + return !memcmp(a1, a2, sizeof(*a1)); + } else + return false; } /** @@ -872,52 +829,66 @@ int dccp_available_ccids(uint8_t **ccid_array) * \return Positive on success, \p -E_NAME_TOO_LONG if \a name is longer * than \p UNIX_PATH_MAX. */ -static int init_unix_addr(struct sockaddr_un *u, const char *name) +static int init_unix_addr(struct sockaddr_un *u, const char *name, + bool abstract) { - if (strlen(name) >= UNIX_PATH_MAX) + if (strlen(name) + abstract >= UNIX_PATH_MAX) return -E_NAME_TOO_LONG; memset(u->sun_path, 0, UNIX_PATH_MAX); u->sun_family = PF_UNIX; - strcpy(u->sun_path, name); + strcpy(u->sun_path + abstract, name); return 1; } /** - * Prepare, create, and bind a socket for local communication. + * Create a socket for local communication and listen on it. * * \param name The socket pathname. - * \param unix_addr Pointer to the \p AF_UNIX socket structure. - * \param mode The desired mode of the socket. + * \param mode The desired permissions of the socket. + * + * This function creates a passive local socket for sequenced, reliable, + * two-way, connection-based byte streams. The socket file descriptor is set to + * nonblocking mode and listen(2) is called to prepare the socket for + * accepting incoming connection requests. * - * This function creates a local socket for sequenced, reliable, - * two-way, connection-based byte streams. + * If mode is zero, an abstract socket (a non-portable Linux extension) is + * created. In this case the socket name has no connection with filesystem + * pathnames. * - * \return The file descriptor, on success, negative on errors. + * \return The file descriptor on success, negative error code on failure. * - * \sa socket(2) - * \sa bind(2) - * \sa chmod(2) + * \sa socket(2), \sa bind(2), \sa chmod(2), listen(2), unix(7). */ -int create_local_socket(const char *name, struct sockaddr_un *unix_addr, - mode_t mode) +int create_local_socket(const char *name, mode_t mode) { + struct sockaddr_un unix_addr; int fd, ret; + bool abstract = mode == 0; - ret = init_unix_addr(unix_addr, name); + ret = init_unix_addr(&unix_addr, name, abstract); if (ret < 0) return ret; ret = socket(PF_UNIX, SOCK_STREAM, 0); if (ret < 0) return -ERRNO_TO_PARA_ERROR(errno); fd = ret; - ret = bind(fd, (struct sockaddr *) unix_addr, UNIX_PATH_MAX); + ret = mark_fd_nonblocking(fd); + if (ret < 0) + goto err; + ret = bind(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)); if (ret < 0) { ret = -ERRNO_TO_PARA_ERROR(errno); goto err; } - ret = -E_CHMOD; - if (chmod(name, mode) < 0) + if (!abstract) { + ret = -E_CHMOD; + if (chmod(name, mode) < 0) + goto err; + } + if (listen(fd , 5) < 0) { + ret = -ERRNO_TO_PARA_ERROR(errno); goto err; + } return fd; err: close(fd); @@ -943,17 +914,22 @@ int connect_local_socket(const char *name) int fd, ret; PARA_DEBUG_LOG("connecting to %s\n", name); - ret = init_unix_addr(&unix_addr, name); - if (ret < 0) - return ret; fd = socket(PF_UNIX, SOCK_STREAM, 0); if (fd < 0) return -ERRNO_TO_PARA_ERROR(errno); - if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) == -1) { - ret = -ERRNO_TO_PARA_ERROR(errno); + /* first try (linux-only) abstract socket */ + ret = init_unix_addr(&unix_addr, name, true); + if (ret < 0) goto err; - } - return fd; + if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) != -1) + return fd; + /* next try pathname socket */ + ret = init_unix_addr(&unix_addr, name, false); + if (ret < 0) + goto err; + if (connect(fd, (struct sockaddr *)&unix_addr, sizeof(unix_addr)) != -1) + return fd; + ret = -ERRNO_TO_PARA_ERROR(errno); err: close(fd); return ret; @@ -962,23 +938,25 @@ err: #ifndef HAVE_UCRED ssize_t send_cred_buffer(int sock, char *buf) { - return send_buffer(sock, buf); + return write_buffer(sock, buf); } int recv_cred_buffer(int fd, char *buf, size_t size) { return recv_buffer(fd, buf, size) > 0? 1 : -E_RECVMSG; } #else /* HAVE_UCRED */ + /** - * Send \p NULL-terminated buffer and Unix credentials of the current process. + * Send a buffer and the credentials of the current process to a socket. * - * \param sock The socket file descriptor. - * \param buf The buffer to be sent. + * \param sock The file descriptor of the sending socket. + * \param buf The zero-terminated buffer to send. * - * \return On success, this call returns the number of characters sent. On - * error, \p -E_SENDMSG is returned. + * \return On success, this call returns the number of bytes sent. On errors, + * \p -E_SENDMSG is returned. * - * \sa sendmsg(2), okir's Black Hats Manual. + * \sa \ref recv_cred_buffer, sendmsg(2), socket(7), unix(7), okir's Black Hats + * Manual. */ ssize_t send_cred_buffer(int sock, char *buf) { @@ -991,7 +969,7 @@ ssize_t send_cred_buffer(int sock, char *buf) /* Response data */ iov.iov_base = buf; - iov.iov_len = strlen(buf); + iov.iov_len = strlen(buf); c.pid = getpid(); c.uid = getuid(); c.gid = getgid(); @@ -1009,7 +987,7 @@ ssize_t send_cred_buffer(int sock, char *buf) *(struct ucred *)CMSG_DATA(cmsg) = c; msg.msg_controllen = cmsg->cmsg_len; ret = sendmsg(sock, &msg, 0); - if (ret < 0) + if (ret < 0) ret = -E_SENDMSG; return ret; } @@ -1025,17 +1003,17 @@ static void dispose_fds(int *fds, unsigned num) /** * Receive a buffer and the Unix credentials of the sending process. * - * \param fd the socket file descriptor. - * \param buf the buffer to store the message. - * \param size the size of \a buffer. + * \param fd The file descriptor of the receiving socket. + * \param buf The buffer to store the received message. + * \param size The length of \a buf in bytes. * - * \return negative on errors, the user id on success. + * \return Negative on errors, the user id of the sending process on success. * - * \sa recvmsg(2), okir's Black Hats Manual. + * \sa \ref send_cred_buffer and the references given there. */ int recv_cred_buffer(int fd, char *buf, size_t size) { - char control[255]; + char control[255] __a_aligned(8); struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; @@ -1064,7 +1042,7 @@ int recv_cred_buffer(int fd, char *buf, size_t size) } else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { - dispose_fds((int *) CMSG_DATA(cmsg), + dispose_fds((int *)CMSG_DATA(cmsg), (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int)); }