shithub: snippets

Download patch

ref: 42506c4e867c90c174617163fcfc2c08f0246a49
parent: 0cd57b4514cb22dc3304f523680a1679e6e0479b
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Sun Jun 26 18:01:18 EDT 2022

dial: dial(2) for POSIX

--- a/README.md
+++ b/README.md
@@ -6,6 +6,7 @@
 
 * `atomics9*` a set of atomics for Plan 9
 * `c_builtins*` a few __builtin_* for Plan 9, useful for porting other software
+* `dial.c` dial(2) (with "proto!hostname!port" support) for POSIX
 * `kbd.[ch]` API to handle keyboard on lower level, with all modifiers accessible, on Plan 9
 * `lrint.c` lrint* implementation
 * `msr.c` MSR reading tool
--- /dev/null
+++ b/dial.c
@@ -1,0 +1,50 @@
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <unistd.h>
+
+int
+dial(const char *s)
+{
+	struct addrinfo *r, *a, hint = {.ai_flags = AI_ADDRCONFIG, .ai_family = AF_UNSPEC, 0};
+	char host[128], *port;
+	int e, f;
+
+	if(strncmp(s, "udp!", 4) == 0){
+		hint.ai_socktype = SOCK_DGRAM;
+		hint.ai_protocol = IPPROTO_UDP;
+	}else if(strncmp(s, "tcp!", 4) == 0){
+		hint.ai_socktype = SOCK_STREAM;
+		hint.ai_protocol = IPPROTO_TCP;
+	}else{
+		fprintf(stderr, "invalid dial string: %s\n", s);
+		return -1;
+	}
+	if((port = strchr(s+4, '!')) == NULL){
+		fprintf(stderr, "invalid dial string: %s\n", s);
+		return -1;
+	}
+	if(snprintf(host, sizeof(host), "%.*s", (int)(port-s-4), s+4) >= (int)sizeof(host)){
+		fprintf(stderr, "host name too large: %s\n", s);
+		return -1;
+	}
+	port++;
+	if((e = getaddrinfo(host, port, &hint, &r)) != 0){
+		fprintf(stderr, "%s: %s\n", gai_strerror(e), s);
+		return -1;
+	}
+	f = -1;
+	for(a = r; a != NULL; a = a->ai_next){
+		if((f = socket(a->ai_family, a->ai_socktype, a->ai_protocol)) < 0)
+			continue;
+		if(connect(f, a->ai_addr, a->ai_addrlen) == 0)
+			break;
+		close(f);
+		f = -1;
+	}
+	freeaddrinfo(r);
+
+	return f;
+}