THRIFT-4878 - [c_glib] add unix domain socket support to ThriftSocket (#1807)
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c
index 6ea897c..1646374 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.c
@@ -23,6 +23,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <thrift/c_glib/thrift.h>
@@ -36,6 +37,7 @@
{
PROP_0,
PROP_THRIFT_SERVER_SOCKET_PORT,
+ PROP_THRIFT_SERVER_SOCKET_PATH,
PROP_THRIFT_SERVER_SOCKET_BACKLOG
};
@@ -48,17 +50,12 @@
thrift_server_socket_listen (ThriftServerTransport *transport, GError **error)
{
int enabled = 1; /* for setsockopt() */
- struct sockaddr_in pin;
ThriftServerSocket *tsocket = THRIFT_SERVER_SOCKET (transport);
- /* create a address structure */
- memset (&pin, 0, sizeof(pin));
- pin.sin_family = AF_INET;
- pin.sin_addr.s_addr = INADDR_ANY;
- pin.sin_port = htons(tsocket->port);
+ const int socket_domain = tsocket->path ? PF_UNIX : AF_INET;
/* create a socket */
- if ((tsocket->sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
+ if ((tsocket->sd = socket (socket_domain, SOCK_STREAM, 0)) == -1)
{
g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
THRIFT_SERVER_SOCKET_ERROR_SOCKET,
@@ -76,22 +73,60 @@
}
/* bind to the socket */
- if (bind(tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
+ if (tsocket->path)
{
- g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
- THRIFT_SERVER_SOCKET_ERROR_BIND,
- "failed to bind to port %d - %s",
- tsocket->port, strerror(errno));
- return FALSE;
+ /* create a socket structure */
+ struct sockaddr_un pin;
+ memset (&pin, 0, sizeof(pin));
+ pin.sun_family = AF_UNIX;
+ memcpy(pin.sun_path, tsocket->path, strlen(tsocket->path) + 1);
+
+ if (bind(tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_BIND,
+ "failed to bind to path %s",
+ tsocket->path, strerror(errno));
+ return FALSE;
+ }
+ }
+ else
+ {
+ /* create a address structure */
+ struct sockaddr_in pin;
+ memset (&pin, 0, sizeof(pin));
+ pin.sin_family = AF_INET;
+ pin.sin_addr.s_addr = INADDR_ANY;
+ pin.sin_port = htons(tsocket->port);
+
+ if (bind(tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_BIND,
+ "failed to bind to port %d - %s",
+ tsocket->port, strerror(errno));
+ return FALSE;
+ }
}
if (listen(tsocket->sd, tsocket->backlog) == -1)
{
- g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
- THRIFT_SERVER_SOCKET_ERROR_LISTEN,
- "failed to listen to port %d - %s",
- tsocket->port, strerror(errno));
- return FALSE;
+ if (tsocket->path)
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_BIND,
+ "failed to bind to path %s",
+ tsocket->path, strerror(errno));
+ return FALSE;
+ }
+ else
+ {
+ g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
+ THRIFT_SERVER_SOCKET_ERROR_LISTEN,
+ "failed to listen to port %d - %s",
+ tsocket->port, strerror(errno));
+ return FALSE;
+ }
}
return TRUE;
@@ -178,6 +213,9 @@
case PROP_THRIFT_SERVER_SOCKET_PORT:
g_value_set_uint (value, socket->port);
break;
+ case PROP_THRIFT_SERVER_SOCKET_PATH:
+ g_value_set_string (value, socket->path);
+ break;
case PROP_THRIFT_SERVER_SOCKET_BACKLOG:
g_value_set_uint (value, socket->backlog);
break;
@@ -199,6 +237,12 @@
case PROP_THRIFT_SERVER_SOCKET_PORT:
socket->port = g_value_get_uint (value);
break;
+ case PROP_THRIFT_SERVER_SOCKET_PATH:
+ if (socket->path) {
+ g_free(socket->path);
+ }
+ socket->path = g_strdup (g_value_get_string (value));
+ break;
case PROP_THRIFT_SERVER_SOCKET_BACKLOG:
socket->backlog = g_value_get_uint (value);
break;
@@ -232,6 +276,16 @@
PROP_THRIFT_SERVER_SOCKET_PORT,
param_spec);
+ param_spec = g_param_spec_string ("path",
+ "path (construct)",
+ "Set the path to listen to",
+ NULL, /* default value */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class,
+ PROP_THRIFT_SERVER_SOCKET_PATH,
+ param_spec);
+
param_spec = g_param_spec_uint ("backlog",
"backlog (construct)",
"Set the accept backlog",
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h
index fd04954..7710d51 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_server_socket.h
@@ -50,6 +50,7 @@
/* private */
guint port;
+ gchar *path;
gshort backlog;
int sd;
guint8 *buf;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
index 560c24e..b7b4139 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.c
@@ -23,6 +23,7 @@
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
+#include <sys/un.h>
#include <netinet/in.h>
#include <thrift/c_glib/thrift.h>
@@ -34,7 +35,8 @@
{
PROP_0,
PROP_THRIFT_SOCKET_HOSTNAME,
- PROP_THRIFT_SOCKET_PORT
+ PROP_THRIFT_SOCKET_PORT,
+ PROP_THRIFT_SOCKET_PATH
};
G_DEFINE_TYPE(ThriftSocket, thrift_socket, THRIFT_TYPE_TRANSPORT)
@@ -128,6 +130,35 @@
ThriftSocket *tsocket = THRIFT_SOCKET (transport);
g_return_val_if_fail (tsocket->sd == THRIFT_INVALID_SOCKET, FALSE);
+
+ if (tsocket->path) {
+ /* create a socket structure */
+ struct sockaddr_un pin;
+ memset (&pin, 0, sizeof(pin));
+ pin.sun_family = AF_UNIX;
+ memcpy(pin.sun_path, tsocket->path, strlen(tsocket->path) + 1);
+
+ /* create the socket */
+ if ((tsocket->sd = socket (PF_UNIX, SOCK_STREAM, 0)) == -1)
+ {
+ g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_SOCKET,
+ "failed to create socket for path %s: - %s",
+ tsocket->path,
+ strerror(errno));
+ return FALSE;
+ }
+
+ /* open a connection */
+ if (connect (tsocket->sd, (struct sockaddr *) &pin, sizeof(pin)) == -1)
+ {
+ thrift_socket_close(tsocket, NULL);
+ g_set_error (error, THRIFT_TRANSPORT_ERROR, THRIFT_TRANSPORT_ERROR_CONNECT,
+ "failed to connect to path %s: - %s",
+ tsocket->path, strerror(errno));
+ return FALSE;
+ }
+ return TRUE;
+ }
/* lookup the destination host */
#if defined(HAVE_GETHOSTBYNAME_R)
@@ -278,6 +309,10 @@
g_free (socket->hostname);
}
socket->hostname = NULL;
+ if (socket->path != NULL)
+ {
+ g_free (socket->path);
+ }
if (socket->sd != THRIFT_INVALID_SOCKET)
{
@@ -303,6 +338,9 @@
case PROP_THRIFT_SOCKET_PORT:
g_value_set_uint (value, socket->port);
break;
+ case PROP_THRIFT_SOCKET_PATH:
+ g_value_set_string (value, socket->path);
+ break;
}
}
@@ -326,6 +364,12 @@
case PROP_THRIFT_SOCKET_PORT:
socket->port = g_value_get_uint (value);
break;
+ case PROP_THRIFT_SOCKET_PATH:
+ if (socket->path) {
+ g_free(socket->path);
+ }
+ socket->path = g_strdup (g_value_get_string (value));
+ break;
}
}
@@ -361,6 +405,15 @@
g_object_class_install_property (gobject_class, PROP_THRIFT_SOCKET_PORT,
param_spec);
+ param_spec = g_param_spec_string ("path",
+ "path (construct)",
+ "Set the path of the remote host",
+ NULL, /* default value */
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_READWRITE);
+ g_object_class_install_property (gobject_class, PROP_THRIFT_SOCKET_PATH,
+ param_spec);
+
gobject_class->finalize = thrift_socket_finalize;
ttc->is_open = thrift_socket_is_open;
ttc->peek = thrift_socket_peek;
diff --git a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h
index 2f6f67d..c91f52f 100644
--- a/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h
+++ b/lib/c_glib/src/thrift/c_glib/transport/thrift_socket.h
@@ -51,6 +51,7 @@
/* private */
gchar *hostname;
guint port;
+ gchar *path;
int sd;
};
diff --git a/test/c_glib/src/test_client.c b/test/c_glib/src/test_client.c
index ef24ab7..7126a86 100644
--- a/test/c_glib/src/test_client.c
+++ b/test/c_glib/src/test_client.c
@@ -113,6 +113,7 @@
{
static gchar * host = NULL;
static gint port = 9090;
+ static gchar * path = NULL;
static gboolean ssl = FALSE;
static gchar * transport_option = NULL;
static gchar * protocol_option = NULL;
@@ -124,6 +125,8 @@
"Host to connect (=localhost)", NULL },
{ "port", 'p', 0, G_OPTION_ARG_INT, &port,
"Port number to connect (=9090)", NULL },
+ { "domain-socket", 0, 0, G_OPTION_ARG_STRING, &path,
+ "Unix socket domain path to connect", NULL },
{ "ssl", 's', 0, G_OPTION_ARG_NONE, &ssl,
"Enable SSL", NULL },
{ "transport", 't', 0, G_OPTION_ARG_STRING, &transport_option,
@@ -227,12 +230,20 @@
if (!options_valid)
return 254;
- printf ("Connecting (%s/%s) to: %s/%s:%d\n",
- transport_name,
- protocol_name,
- socket_name,
- host,
- port);
+ if (path) {
+ printf ("Connecting (%s/%s) to: %s/%s\n",
+ transport_name,
+ protocol_name,
+ socket_name,
+ path);
+ } else {
+ printf ("Connecting (%s/%s) to: %s/%s:%d\n",
+ transport_name,
+ protocol_name,
+ socket_name,
+ host,
+ port);
+ }
/* Install our SIGPIPE handler, which outputs an error message to
standard error before exiting so testers can know what
@@ -247,10 +258,16 @@
}
/* Establish all our connection objects */
- socket = g_object_new (socket_type,
- "hostname", host,
- "port", port,
- NULL);
+ if (path) {
+ socket = g_object_new (socket_type,
+ "path", path,
+ NULL);
+ } else {
+ socket = g_object_new (socket_type,
+ "hostname", host,
+ "port", port,
+ NULL);
+ }
if (ssl && !thrift_ssl_load_cert_from_file(THRIFT_SSL_SOCKET(socket), "../keys/CA.pem")) {
fprintf(stderr, "Unable to load validation certificate ../keys/CA.pem - did you run in the test/c_glib directory?\n");
@@ -336,7 +353,11 @@
gboolean first;
gint32 i, j;
- printf ("Test #%d, connect %s:%d\n", test_num + 1, host, port);
+ if (path) {
+ printf ("Test #%d, connect %s\n", test_num + 1, path);
+ } else {
+ printf ("Test #%d, connect %s:%d\n", test_num + 1, host, port);
+ }
gettimeofday (&time_start, NULL);
/* These test routines have been ported from the C++ test
diff --git a/test/c_glib/src/test_server.c b/test/c_glib/src/test_server.c
index 2d716ec..0819b8c 100644
--- a/test/c_glib/src/test_server.c
+++ b/test/c_glib/src/test_server.c
@@ -69,6 +69,7 @@
main (int argc, char **argv)
{
static gint port = 9090;
+ static gchar *path_option = NULL;
static gchar *server_type_option = NULL;
static gchar *transport_option = NULL;
static gchar *protocol_option = NULL;
@@ -79,6 +80,8 @@
GOptionEntry option_entries[] = {
{ "port", 0, 0, G_OPTION_ARG_INT, &port,
"Port number to connect (=9090)", NULL },
+ { "domain-socket", 0, 0, G_OPTION_ARG_STRING, &path_option,
+ "Unix socket domain path to connect", NULL },
{ "server-type", 0, 0, G_OPTION_ARG_STRING, &server_type_option,
"Type of server: simple (=simple)", NULL },
{ "transport", 0, 0, G_OPTION_ARG_STRING, &transport_option,
@@ -218,9 +221,15 @@
"handler", handler,
NULL);
}
- server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
- "port", port,
- NULL);
+ if (path_option) {
+ server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "path", path_option,
+ NULL);
+ } else {
+ server_transport = g_object_new (THRIFT_TYPE_SERVER_SOCKET,
+ "port", port,
+ NULL);
+ }
transport_factory = g_object_new (transport_factory_type,
NULL);
@@ -250,11 +259,19 @@
sigint_action.sa_flags = SA_RESETHAND;
sigaction (SIGINT, &sigint_action, NULL);
- printf ("Starting \"%s\" server (%s/%s) listen on: %d\n",
- server_name,
- transport_name,
- protocol_name,
- port);
+ if (path_option) {
+ printf ("Starting \"%s\" server (%s/%s) listen on: %s\n",
+ server_name,
+ transport_name,
+ protocol_name,
+ path_option);
+ } else {
+ printf ("Starting \"%s\" server (%s/%s) listen on: %d\n",
+ server_name,
+ transport_name,
+ protocol_name,
+ port);
+ }
fflush (stdout);
/* Serve clients until SIGINT is received (Ctrl-C is pressed) */
diff --git a/test/tests.json b/test/tests.json
index 851244e..6a41639 100644
--- a/test/tests.json
+++ b/test/tests.json
@@ -32,7 +32,8 @@
"framed"
],
"sockets": [
- "ip"
+ "ip",
+ "domain"
],
"protocols": [
"binary",