aboutsummaryrefslogtreecommitdiffstats
path: root/src/libmdsclient/address.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/libmdsclient/address.c94
1 files changed, 91 insertions, 3 deletions
diff --git a/src/libmdsclient/address.c b/src/libmdsclient/address.c
index 3a7aba3..0bb347a 100644
--- a/src/libmdsclient/address.c
+++ b/src/libmdsclient/address.c
@@ -17,9 +17,76 @@
*/
#include "address.h"
+#include <stddef.h>
+#include <sys/socket.h>
#include <sys/un.h>
#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <libmdsserver/config.h>
+
+
+
+/**
+ * Check whether a string is a radix-10 non-negative integer
+ *
+ * @param str The string
+ * @return Whether a string is a radix-10 non-negative integer
+ */
+__attribute__((nonnull))
+static int is_pzinteger(const char* restrict str)
+{
+ for (; *str; str++)
+ if (('0' > *str) || (*str > '9'))
+ return 0;
+ return 1;
+}
+
+
+/**
+ * Set the socket adress, with the address family `AF_UNIX`
+ *
+ * @param out_address Output paramter for the socket address
+ * @param pathlen Pointer to a variable where the length of the pathname will be stored
+ * @param format Formatting string for the pathname (should end with "%zn")
+ * @param ... Formatting arguments for the pathname (should end with `pathlen`)
+ * @return Zero on success, -1 on error, `errno`
+ * will have been set accordinly on error
+ *
+ * @throws ENOMEM Out of memory. Possibly, the application hit the
+ * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2).
+ * @throws ENAMETOOLONG The filename of the target socket is too long
+ */
+__attribute__((nonnull, format(gnu_printf, 3, 4)))
+static int set_af_unix(struct sockaddr** restrict out_address, ssize_t* pathlen, const char* format, ...)
+#define set_af_unix(a, f, ...) ((set_af_unix)(a, &pathlen, f "%zn", __VA_ARGS__, &pathlen))
+{
+ struct sockaddr_un* address;
+ size_t maxlen;
+ va_list args;
+
+ address = malloc(sizeof(struct sockaddr_un));
+ *out_address = (struct sockaddr*)address;
+ if (address == NULL)
+ return -1;
+
+ maxlen = sizeof(address->sun_path) / sizeof(address->sun_path[0]);
+
+ va_start(args, format);
+
+ address->sun_family = AF_UNIX;
+ vsnprintf(address->sun_path, maxlen, format, args);
+
+ va_end(args);
+
+ if ((size_t)*pathlen > maxlen)
+ return errno = ENAMETOOLONG, -1;
+
+ return 0;
+}
/**
@@ -30,17 +97,38 @@
* @return Zero on success, even if parsing failed, -1 on error,
* `errno` will have been set accordinly on error
*
- * @throws ENOMEM Out of memory. Possibly, the application hit the
- * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2).
+ * @throws ENOMEM Out of memory. Possibly, the application hit the
+ * RLIMIT_AS or RLIMIT_DATA limit described in getrlimit(2).
+ * @throws ENAMETOOLONG The filename of the target socket is too long
*/
int libmds_parse_display_adress(const char* restrict display, libmds_display_address_t* restrict address)
{
+ ssize_t pathlen;
+
address->domain = -1;
address->type = -1;
address->protocol = -1;
address->address = NULL;
address->address_len = 0;
- return (void) display, 0; /* TODO */
+ if (strchr(display, ':') == NULL)
+ return 0;
+
+ if (*display == ':')
+ {
+ address->domain = PF_UNIX;
+ address->type = SOCK_STREAM;
+ address->protocol = 0;
+ address->address_len = sizeof(struct sockaddr_un);
+
+ if (strstr(display, ":file:") == display)
+ return set_af_unix(&(address->address), "%s", display + 6);
+ else if (display[1] && is_pzinteger(display + 1))
+ return set_af_unix(&(address->address), "%s/%s.socket",
+ MDS_RUNTIME_ROOT_DIRECTORY, display + 1);
+ return 0;
+ }
+
+ return 0;
}