From e9e826f4fb415c4225ff5934fe42572ffa3b5ebc Mon Sep 17 00:00:00 2001 From: Gerrit Renker Date: Thu, 25 Feb 2010 17:05:45 +0100 Subject: [PATCH] 05_dccp-supported-ccid-lookup.diff This adds a self-contained function to return the space-separated list of CCIDs available on the para_server. Visible via 'para_client si'. Since feature negotiation for CCIDs is supported only from v2.6.30-rc1 (released 7th April 2009), a more recent kernel (>= 2.6.30) is needed to support this feature, as well as subsequent per-connection use of CCIDs. Note: This patch still uses a hardcoded upper bound (DCCP_MAX_HOST_CCIDS), support dynamically detecting the number of CCIDs will be in 2.6.33. --- dccp_send.c | 26 +++++++++++++++++++++++++- net.c | 27 +++++++++++++++++++++++++++ net.h | 7 +++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/dccp_send.c b/dccp_send.c index d2f81dd9..94719f04 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -104,9 +104,33 @@ static int dccp_com_allow(struct sender_command_data *scd) return 1; } +/** + * Return list of available CCIDs or warning, in static buffer. + */ +static const char *dccp_list_available_ccids(void) +{ + uint8_t ccids[DCCP_MAX_HOST_CCIDS]; + uint8_t nccids = sizeof(ccids), i, len; + /* Worst case length: n * 3 digits + n-1 spaces + '\0' */ + static char list[DCCP_MAX_HOST_CCIDS * 4]; + + if (dccp_available_ccids(ccids, &nccids) == NULL) { + snprintf(list, sizeof(list), "Unable to query available CCIDs"); + } else { + for (i = len = 0; i < nccids; i++) + len += snprintf(list + len, sizeof(list) - len, + "%s%d", i ? " " : "", ccids[i]); + } + return list; +} + static char *dccp_info(void) { - return get_sender_info(dss, "dccp"); + char *info = get_sender_info(dss, "dccp"); + char *ret = make_message("%s" "\tsupported ccids: %s\n", + info, dccp_list_available_ccids()); + free(info); + return ret; } /** diff --git a/net.c b/net.c index 6ab96215..b83ab8c6 100644 --- a/net.c +++ b/net.c @@ -661,6 +661,33 @@ int para_accept(int fd, void *addr, socklen_t size) return new_fd < 0? -ERRNO_TO_PARA_ERROR(errno) : new_fd; } +/** + * Probe the list of DCCP CCIDs supported locally by the host. + * \param ccids Array to be filled in. + * \param nccids Length of \a ccids. + * \return Pointer to \a ccids, NULL on failure. + * + * NB: This feature is only available on Linux > 2.6.30; on older kernels + * ENOPROTOOPT ("Protocol not available") will be returned. + */ +const uint8_t *dccp_available_ccids(uint8_t *ccids, uint8_t *nccids) +{ + int fd = makesock(AF_UNSPEC, IPPROTO_DCCP, 0, NULL, 0); + + if (fd < 0) + return NULL; + + if (getsockopt(fd, SOL_DCCP, DCCP_SOCKOPT_AVAILABLE_CCIDS, + ccids, (socklen_t *)nccids) < 0) { + PARA_ERROR_LOG("No DCCP_SOCKOPT_AVAILABLE_CCIDS: %s\n", + strerror(errno)); + *nccids = 0; + } + close(fd); + + return *nccids ? ccids : NULL; +} + /** * Prepare a structure for \p AF_UNIX socket addresses. * diff --git a/net.h b/net.h index 88b8d431..66bf8755 100644 --- a/net.h +++ b/net.h @@ -100,3 +100,10 @@ int create_remote_socket(const char *name); int recv_cred_buffer(int, char *, size_t); ssize_t send_cred_buffer(int, char*); int recv_pattern(int fd, const char *pattern, size_t bufsize); + +/** + * Functions and definitions to support \p IPPROTO_DCCP + */ +/** Hardcoded maximum number of separate CCID modules compiled into a host */ +#define DCCP_MAX_HOST_CCIDS 20 +extern const uint8_t *dccp_available_ccids(uint8_t *ccids, uint8_t *nccids); -- 2.30.2