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;
+}