Today I learned that it isn't possible to bind to the same port on both IPv4 and IPv6 in GIO:
#include <glib.h>
#include <gio/gio.h>
#include <stdlib.h>
#include <stdio.h>
int main(int argc, const char ** argv) {
char * valid;
unsigned long int port;
GError * err = NULL;
GSocketFamily gfamily = G_SOCKET_FAMILY_IPV4;
GSocket * sockets[2];
GInetAddress * giaddress;
GSocketAddress * gsaddress;
int i;
g_type_init();
if(argc == 1) {
fprintf(stderr, "Usage: %s port\n", argv[0]);
return 1;
}
port = strtoul(argv[1], &valid, 10);
if(port == 0 || port > 0xFFFF || *valid != 0) {
fprintf(stderr, "Invalid port: %s\n", argv[1]);
return 1;
}
while(gfamily != G_SOCKET_FAMILY_INVALID) {
i = (gfamily == G_SOCKET_FAMILY_IPV4) ? 0 : 1;
printf("Family: %d, port: %lu\n", gfamily, port);
sockets[i] = g_socket_new(gfamily, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_TCP, &err);
if(sockets[i] == NULL || err != NULL) {
fprintf(stderr, "Failed to create server socket: %s\n", err->message);
g_error_free(err);
if(sockets[i] != NULL)
g_object_unref(sockets[i]);
return 2;
}
giaddress = g_inet_address_new_any(gfamily);
gsaddress = g_inet_socket_address_new(giaddress, port);
if(!g_socket_bind(sockets[i], gsaddress, TRUE, &err) || err != NULL) {
fprintf(stderr, "Failed to bind to port: %s\n", err->message);
g_error_free(err);
if(sockets[i] != NULL)
g_object_unref(sockets[i]);
if(gsaddress != NULL)
g_object_unref(gsaddress);
return 2;
}
if(!g_socket_listen(sockets[i], &err) || err != NULL) {
fprintf(stderr, "Failed to listen on socket: %s\n", err->message);
g_error_free(err);
if(sockets[i] != NULL)
g_object_unref(sockets[i]);
if(gsaddress != NULL)
g_object_unref(gsaddress);
return 2;
}
gfamily = (gfamily == G_SOCKET_FAMILY_IPV4) ? G_SOCKET_FAMILY_IPV6 : G_SOCKET_FAMILY_INVALID;
}
for(i = 0; i < 2; i++)
g_object_unref(sockets[i]);
return 0;
}
Typical output:
% ./gfail 3000
Family: 2, port: 3000
Family: 10, port: 3000
Failed to bind to port: Error binding to address: Address already in use
Weird.
No comments:
Post a Comment