Skip to content

Commit 966689c

Browse files
committed
daemon.c for testing C socket ipv6 / ipv4 compatibility
1 parent 81c434b commit 966689c

3 files changed

Lines changed: 112 additions & 2 deletions

File tree

internal/socket-testing/.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Ignore all files
2+
daemon
3+
daemon2
4+
*
5+
6+
# But not directories (so Git can check inside them)
7+
# !*/
8+
9+
# Except daemon.c (allow this specific file)
10+
!daemon.c

internal/socket-testing/daemon.c

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
#include <unistd.h>
5+
#include <sys/socket.h>
6+
#include <netinet/in.h>
7+
#include <arpa/inet.h>
8+
9+
#define PORT 8080
10+
#define BUFFER_SIZE 1024
11+
12+
int main() {
13+
int server_fd, new_socket;
14+
struct sockaddr_in6 address;
15+
int addrlen = sizeof(address);
16+
char buffer[BUFFER_SIZE] = {0};
17+
const char *http_response = "HTTP/1.1 200 OK\nContent-Type: text/plain\nContent-Length: 14\n\nHello, world!\n";
18+
19+
// Create an IPv6 socket
20+
if ((server_fd = socket(AF_INET6, SOCK_STREAM, 0)) == 0) {
21+
perror("socket failed");
22+
exit(EXIT_FAILURE);
23+
}
24+
25+
// Set SO_REUSEADDR to reuse the address immediately
26+
int opt = 1;
27+
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
28+
perror("setsockopt SO_REUSEADDR failed");
29+
close(server_fd);
30+
exit(EXIT_FAILURE);
31+
}
32+
33+
// Set IPV6_V6ONLY to 0 to allow dual-stack operation.
34+
// This is the crucial part for the test. If this is 0,
35+
// the IPv6 socket can also accept IPv4 connections.
36+
// If it were 1, it would only accept IPv6 connections.
37+
int v6only = 0;
38+
if (setsockopt(server_fd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only))) {
39+
perror("setsockopt IPV6_V6ONLY failed");
40+
close(server_fd);
41+
exit(EXIT_FAILURE);
42+
}
43+
int returned_v6only;
44+
socklen_t len = sizeof(returned_v6only);
45+
if (getsockopt(server_fd, IPPROTO_IPV6, IPV6_V6ONLY, &returned_v6only, &len) == 0) {
46+
printf("IPV6_V6ONLY is currently set to: %d\n", returned_v6only);
47+
} else {
48+
perror("getsockopt IPV6_V6ONLY failed");
49+
}
50+
51+
// Configure the server address
52+
// Use IN6ADDR_LOOPBACK_INIT to bind to [::1]
53+
memset(&address, 0, sizeof(address));
54+
address.sin6_family = AF_INET6;
55+
address.sin6_addr = in6addr_loopback; // This is the [::1] address
56+
address.sin6_port = htons(PORT);
57+
58+
// Bind the socket to the configured address
59+
if (bind(server_fd, (struct sockaddr *)&address, addrlen) < 0) {
60+
perror("bind failed");
61+
close(server_fd);
62+
exit(EXIT_FAILURE);
63+
}
64+
65+
// Start listening for incoming connections
66+
if (listen(server_fd, 3) < 0) {
67+
perror("listen failed");
68+
close(server_fd);
69+
exit(EXIT_FAILURE);
70+
}
71+
72+
printf("Server listening on [::1] port %d\n", PORT);
73+
printf("Test with curl: \n");
74+
printf(" curl -6 http://[::1]:%d\n", PORT);
75+
printf(" curl -4 http://127.0.0.1:%d\n\n", PORT);
76+
77+
while (1) {
78+
// Accept a new connection
79+
if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen)) < 0) {
80+
perror("accept failed");
81+
continue;
82+
}
83+
84+
// Read the incoming request
85+
read(new_socket, buffer, BUFFER_SIZE);
86+
printf("Request received:\n---\n%s\n---\n", buffer);
87+
88+
// Send the HTTP response
89+
write(new_socket, http_response, strlen(http_response));
90+
91+
// Close the client socket
92+
close(new_socket);
93+
}
94+
95+
// Close the server socket (unreachable in this infinite loop)
96+
close(server_fd);
97+
98+
return 0;
99+
}

multilistener/multilistener.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ type MultiListener struct {
3131

3232
type Addresses = []string
3333

34-
// net.Addr.Network() implementation
34+
// Network() implementation for net.Addr
3535
func (dl *MultiListener) Network() string {
3636
return "tcp+multi"
3737
}
38+
39+
// String() joins all addresses, comma separated, for logs & debug
3840
func (dl *MultiListener) String() string {
3941
if len(dl.listeners) < 1 {
4042
return ""
@@ -153,6 +155,5 @@ func (dl *MultiListener) Close() error {
153155

154156
// Addr returns the preferred (first) interface Addr
155157
func (dl *MultiListener) Addr() net.Addr {
156-
// Return one of the addresses for display
157158
return dl.listeners[0].Addr()
158159
}

0 commit comments

Comments
 (0)