Commit df53e41ddab49eafa2cf680774d9b1b0326d6e84

Thomas de Grivel 2024-07-21T15:20:19

make test_http OK

diff --git a/http/socket.c b/http/socket.c
index 2810973..a733470 100644
--- a/http/socket.c
+++ b/http/socket.c
@@ -11,10 +11,10 @@
  * THIS SOFTWARE.
  */
 #include <errno.h>
-#include <netdb.h>
-#include <netinet/in.h>
 #include <string.h>
 #include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
 #include <unistd.h>
 #include <libkc3/kc3.h>
 #include "socket.h"
@@ -49,65 +49,112 @@ p_socket socket_init_accept (p_socket s, p_socket listening)
   return s;
 }
 
-p_socket socket_init_listen (p_socket s, const s_str *host, u16 port)
+p_socket socket_init_connect (p_socket s, const s_str *host,
+                              const s_str *service)
 {
-  struct sockaddr        *addr;
-  struct sockaddr_in     *addr_inet;
-  struct sockaddr_in6    *addr_inet6;
-  socklen_t               addr_len;
-  struct sockaddr_storage addr_storage;
-  sw e;
-  struct hostent *hostent;
+  struct addrinfo hints = {0};
+  struct addrinfo *res;
+  struct addrinfo *res0;
+  s32 e;
+  const char *error_reason;
   t_socket tmp;
   assert(s);
   assert(host);
-  hostent = gethostbyname2(host->ptr.pchar, AF_INET);
-  if (! hostent)
-    hostent = gethostbyname2(host->ptr.pchar, AF_INET6);
-  if (! hostent) {
-    e = errno;
-    err_write_1("socket_init_listen: gethostbyname2: ");
-    err_puts(strerror(e));
-    assert(! "socket_init_listen: gethostbyname2");
+  hints.ai_family = AF_INET;
+  e = getaddrinfo(host->ptr.pchar, service->ptr.pchar, &hints, &res0);
+  if (e) {
+    err_write_1("socket_init_connect(");
+    err_write_1(host->ptr.pchar);
+    err_write_1(", ");
+    err_write_1(service->ptr.pchar);
+    err_write_1("): getaddrinfo: ");
+    err_puts(gai_strerror(e));
+    assert(! "socket_init_connect: getaddrinfo");
     return NULL;
   }
-  addr = (struct sockaddr *) &addr_storage;
-  addr_len = hostent->h_length;
-  memcpy(addr, hostent->h_addr_list[0], addr_len);
-  switch (addr->sa_family) {
-  case AF_INET:
-    addr_inet = (struct sockaddr_in *) addr;
-    addr_inet->sin_port = htons(port);
-    break;
-  case AF_INET6:
-    addr_inet6 = (struct sockaddr_in6 *) addr;
-    addr_inet6->sin6_port = htons(port);
-    break;
-  default:
-    err_puts("socket_init_listen: unknown address family");
-    assert(! "socket_init_listen: unknown address family");
-    return NULL;
+  e = 0;
+  tmp = -1;
+  res = res0;
+  while (res) {
+    tmp = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
+    if (tmp < 0) {
+      e = errno;
+      error_reason = "socket_init_connect: socket: ";
+      goto next;
+    }
+    if (connect(tmp, res->ai_addr, res->ai_addrlen) < 0) {
+      e = errno;
+      error_reason = "socket_init_connect: connect: ";
+      goto next;
+    }
+  next:
+    res = res->ai_next;
   }
-  tmp = socket(addr->sa_family, SOCK_STREAM, 0);
   if (tmp < 0) {
-    e = errno;
-    err_write_1("socket_init_listen: socket: ");
+    err_write_1(error_reason);
     err_puts(strerror(e));
-    assert(! "socket_init_listen: socket");
+    assert(! "socket_init_connect");
     return NULL;
   }
-  if (bind(tmp, addr, addr_len) < 0) {
-    e = errno;
-    err_write_1("socket_init_listen: bind: ");
-    err_puts(strerror(e));
-    assert(! "socket_init_listen: bind");
+  *s = tmp;
+  return s;
+}
+
+p_socket socket_init_listen (p_socket s, const s_str *host,
+                             const s_str *service)
+{
+  struct addrinfo hints = {0};
+  struct addrinfo *res;
+  struct addrinfo *res0;
+  s32 e;
+  const char *error_reason;
+  t_socket tmp;
+  assert(s);
+  assert(host);
+  hints.ai_family = AF_INET;
+  e = getaddrinfo(host->ptr.pchar, service->ptr.pchar, &hints, &res0);
+  if (e) {
+    err_write_1("socket_init_listen(");
+    err_write_1(host->ptr.pchar);
+    err_write_1(", ");
+    err_write_1(service->ptr.pchar);
+    err_write_1("): getaddrinfo: ");
+    err_puts(gai_strerror(e));
+    assert(! "socket_init_listen: getaddrinfo");
     return NULL;
   }
-  if (listen(tmp, SOMAXCONN) < 0) {
-    e = errno;
-    err_write_1("socket_init_listen: listen: ");
+  e = 0;
+  tmp = -1;
+  res = res0;
+  while (res) {
+    tmp = socket(res->ai_family, SOCK_STREAM, res->ai_protocol);
+    if (tmp < 0) {
+      e = errno;
+      error_reason = "socket_init_listen: socket: ";
+      goto next;
+    }
+    if (setsockopt(tmp, SOL_SOCKET, SO_REUSEADDR, &(int) {1},
+                   sizeof(int)) < 0) {
+      error_reason = "setsockopt(SO_REUSEADDR)";
+      goto next;
+    }
+    if (bind(tmp, res->ai_addr, res->ai_addrlen) < 0) {
+      e = errno;
+      error_reason = "socket_init_listen: bind: ";
+      goto next;
+    }
+    if (listen(tmp, SOMAXCONN) < 0) {
+      e = errno;
+      error_reason = "socket_init_listen: listen: ";
+      goto next;
+    }
+  next:
+    res = res->ai_next;
+  }
+  if (tmp < 0) {
+    err_write_1(error_reason);
     err_puts(strerror(e));
-    assert(! "socket_init_listen: listen");
+    assert(! "socket_init_listen");
     return NULL;
   }
   *s = tmp;
diff --git a/http/socket.h b/http/socket.h
index 26a03fc..09b7311 100644
--- a/http/socket.h
+++ b/http/socket.h
@@ -17,7 +17,8 @@
 
 /* Stack-allocation compatible functions. */
 p_socket socket_init_accept (p_socket s, p_socket listening);
-p_socket socket_init_listen (p_socket s, const s_str *host, u16 port);
+p_socket socket_init_listen (p_socket s, const s_str *host,
+                             const s_str *service);
 
 /* Operators. */
 void socket_close (p_socket s);
diff --git a/lib/kc3/0.1/http.kc3 b/lib/kc3/0.1/http.kc3
deleted file mode 100644
index cfdd4b2..0000000
--- a/lib/kc3/0.1/http.kc3
+++ /dev/null
@@ -1,14 +0,0 @@
-defmodule Socket do
-
-  defstruct [fd: (S32) 0]
-
-  dlopen(__DIR__ + "http.so")
-
-  def accept = cfn Socket "socket_init_accept" (Result, Socket)
-
-  def close = cfn Void "socket_close" (Socket)
-
-  # listen(host, port)
-  def listen = cfn Socket "socket_init_listen" (Result, Str, U16)
-
-end
diff --git a/lib/kc3/0.1/socket.kc3 b/lib/kc3/0.1/socket.kc3
index ad3a0c2..c380af3 100644
--- a/lib/kc3/0.1/socket.kc3
+++ b/lib/kc3/0.1/socket.kc3
@@ -8,6 +8,8 @@ defmodule Socket do
 
   def close = cfn Void "socket_close" (Socket)
 
-  def listen = cfn Socket "socket_init_listen" (Result, Str, U16)
+  def connect = cfn Socket "socket_init_connect" (Result, Str, Str)
+
+  def listen = cfn Socket "socket_init_listen" (Result, Str, Str)
 
 end
diff --git a/libkc3/cfn.c b/libkc3/cfn.c
index 8022e03..8205ccb 100644
--- a/libkc3/cfn.c
+++ b/libkc3/cfn.c
@@ -56,14 +56,20 @@ s_tag * cfn_apply (s_cfn *cfn, s_list *args, s_tag *dest)
   if (cfn->cif.rtype == &ffi_type_pointer) {
     /* make result point to result_pointer */
     if (! tag_to_ffi_pointer(&tmp, cfn->result_type,
-                             (void **) &result_pointer))
+                             (void **) &result_pointer)) {
+      err_puts("cfn_apply: tag_to_ffi_pointer 1");
+      assert(! "cfn_apply: tag_to_ffi_pointer 1");
       return NULL;
+    }
     result = &result_pointer;
   }
   else {
     /* make result point to tmp value */
-    if (! tag_to_ffi_pointer(&tmp, cfn->result_type, &result))
+    if (! tag_to_ffi_pointer(&tmp, cfn->result_type, &result)) {
+      err_puts("cfn_apply: tag_to_ffi_pointer 2");
+      assert(! "cfn_apply: tag_to_ffi_pointer 2");
       return NULL;
+    }
   }
   if (cfn->arity) {
     arg_pointers = alloc((cfn->arity + 1) * sizeof(void *));
@@ -81,22 +87,32 @@ s_tag * cfn_apply (s_cfn *cfn, s_list *args, s_tag *dest)
       if (cfn_arg_types->tag.data.sym == &g_sym_Result) {
         assert(cfn->cif.rtype == &ffi_type_pointer);
         cfn_tag_init(&tmp2, cfn->result_type);
-        if (! tag_to_ffi_pointer(&tmp2, cfn->result_type, arg_pointers + i))
+        if (! tag_to_ffi_pointer(&tmp2, cfn->result_type,
+                                 arg_pointers + i)) {
+          err_puts("cfn_apply: tag_to_ffi_pointer 3");
+          assert(! "cfn_apply: tag_to_ffi_pointer 3");
           goto ko;
+        }
         arg_values[i] = &arg_pointers[i];
         arg_pointer_result = arg_pointers[i];
       }
       else {
         if (cfn->cif.arg_types[i] == &ffi_type_pointer) {
           if (! tag_to_ffi_pointer(&a->tag, cfn_arg_types->tag.data.sym,
-                                   arg_pointers + i))
+                                   arg_pointers + i)) {
+            err_puts("cfn_apply: tag_to_ffi_pointer 4");
+            assert(! "cfn_apply: tag_to_ffi_pointer 4");
             goto ko;
+          }
           arg_values[i] = &arg_pointers[i];
         }
         else
           if (! tag_to_ffi_pointer(&a->tag, cfn_arg_types->tag.data.sym,
-                                   arg_values + i))
+                                   arg_values + i)) {
+            err_puts("cfn_apply: tag_to_ffi_pointer 5");
+            assert(! "cfn_apply: tag_to_ffi_pointer 5");
             goto ko;
+          }
         a = list_next(a);
       }
       cfn_arg_types = list_next(cfn_arg_types);
diff --git a/test/Makefile b/test/Makefile
index 3b81cb5..a0ee8c0 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -74,7 +74,7 @@ gdb_test_ekc3:
 	cd ekc3 && gdb ../../kc3s/.libs/kc3s_debug
 
 gdb_test_http:
-	cd http && gdb ../../kc3s/.libs/kc3s_debug
+	cd http && gdb ../../ikc3/.libs/ikc3_debug
 
 lldb_test: debug
 	if [ -f libkc3_test_debug.core ]; then lldb .libs/libkc3_test_debug libkc3_test_debug.core; else lldb .libs/libkc3_test_debug; fi
diff --git a/test/http/.ikc3_history b/test/http/.ikc3_history
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/http/.ikc3_history
diff --git a/test/http/server.kc3 b/test/http/server.kc3
index bc658e1..4c7599a 100644
--- a/test/http/server.kc3
+++ b/test/http/server.kc3
@@ -1,2 +1,12 @@
-server = Socket.listen("localhost", 8000)
-client = Socket.accept(server)
+quote server = Socket.listen("localhost", "8000")
+server = Socket.listen("localhost", "8000")
+quote client = Socket.connect("localhost", "8000")
+client = Socket.connect("localhost", "8000")
+quote server_client = Socket.accept(server)
+server_client = Socket.accept(server)
+quote Socket.close(client)
+Socket.close(client)
+quote Socket.close(server_client)
+Socket.close(server_client)
+quote Socket.close(server)
+Socket.close(server)
diff --git a/test/http/server.out.expected b/test/http/server.out.expected
index e69de29..d7cff23 100644
--- a/test/http/server.out.expected
+++ b/test/http/server.out.expected
@@ -0,0 +1,12 @@
+server = Socket.listen("localhost", "8000")
+%Socket{fd: 4}
+client = Socket.connect("localhost", "8000")
+%Socket{fd: 5}
+server_client = Socket.accept(server)
+%Socket{fd: 6}
+Socket.close(client)
+void
+Socket.close(server_client)
+void
+Socket.close(server)
+void
diff --git a/test/http/server.ret b/test/http/server.ret
index 897bdc8..573541a 100644
--- a/test/http/server.ret
+++ b/test/http/server.ret
@@ -1 +1 @@
-139
+0
diff --git a/test/http_test b/test/http_test
index 64f0d53..2254924 100755
--- a/test/http_test
+++ b/test/http_test
@@ -29,10 +29,10 @@ test_ok() {
 }
 
 if [ $# = 0 ]; then
-    if [ "x${EKC3_TEST_TARGETS}" = "x" ]; then
+    if [ "x${HTTP_TEST}" = "x" ]; then
         TARGETS="$(ls -1 *.kc3 | sed -e 's/[.]kc3$//')"
     else
-        TARGETS="${EKC3_TEST_TARGETS}"
+        TARGETS="${HTTP_TEST}"
     fi
 else
     TARGETS="$@"