summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Vogelgesang <matthias.vogelgesang@kit.edu>2016-12-16 15:12:21 +0100
committerMatthias Vogelgesang <matthias.vogelgesang@kit.edu>2016-12-16 15:23:41 +0100
commitcb27d4d80e98cb7cb97cfd0bfe0eade67565a762 (patch)
treea06f3a1c29a7b63bdd31a9a66ac9025a1fca1404
parentb925ab14dfc7d8600c0dd2f2bbcb4639bb40c26e (diff)
downloaduca-net-cb27d4d80e98cb7cb97cfd0bfe0eade67565a762.tar.gz
uca-net-cb27d4d80e98cb7cb97cfd0bfe0eade67565a762.tar.bz2
uca-net-cb27d4d80e98cb7cb97cfd0bfe0eade67565a762.tar.xz
uca-net-cb27d4d80e98cb7cb97cfd0bfe0eade67565a762.zip
Fix #3: use one socket connect per request
Previously all requests shared the same connection which meant that the client had to wait that a request finished until it could issue another request. Otherwise, replies could end up for the wrong request causing all kinds of problems. This synchronous request-reply model could not be kept because of inherent asynchronicity of certain mechanisms (e.g. grab + software trigger). This change removes the always-open socket connection and replaces it with a new connection per request. Due to the OS multiplexing, replies cannot be mistaken.
-rw-r--r--uca-net-camera.c94
-rw-r--r--uca-net-protocol.h1
-rw-r--r--ucad.c59
3 files changed, 66 insertions, 88 deletions
diff --git a/uca-net-camera.c b/uca-net-camera.c
index daf177f..9750758 100644
--- a/uca-net-camera.c
+++ b/uca-net-camera.c
@@ -49,11 +49,11 @@ static GParamSpec *net_properties[N_PROPERTIES] = { NULL, };
struct _UcaNetCameraPrivate {
GError *construct_error;
gchar *host;
- GSocketConnection *connection;
GSocketClient *client;
gsize size;
};
+
static gboolean
send_default_message (GSocketConnection *connection, UcaNetMessageType type, GError **error)
{
@@ -94,13 +94,23 @@ handle_default_reply (GSocketConnection *connection, UcaNetMessageType type, GEr
return FALSE;
}
+static GSocketConnection *
+connect_socket (UcaNetCameraPrivate *priv, GError **error)
+{
+ return g_socket_client_connect_to_host (priv->client, priv->host, UCA_NET_DEFAULT_PORT, NULL, error);
+}
+
static void
-request_call (GSocketConnection *connection, UcaNetMessageType type, GError **error)
+request_call (UcaNetCameraPrivate *priv, UcaNetMessageType type, GError **error)
{
- if (!send_default_message (connection, type, error))
- return;
+ GSocketConnection *connection;
+
+ connection = connect_socket (priv, error);
- handle_default_reply (connection, type, error);
+ if (send_default_message (connection, type, error))
+ handle_default_reply (connection, type, error);
+
+ g_object_unref (connection);
}
static void
@@ -122,8 +132,7 @@ uca_net_camera_start_recording (UcaCamera *camera,
priv = UCA_NET_CAMERA_GET_PRIVATE (camera);
priv->size = width * height * (bits > 8 ? 2 : 1);
-
- request_call (priv->connection, UCA_NET_MESSAGE_START_RECORDING, error);
+ request_call (priv, UCA_NET_MESSAGE_START_RECORDING, error);
}
static void
@@ -131,7 +140,7 @@ uca_net_camera_stop_recording (UcaCamera *camera,
GError **error)
{
g_return_if_fail (UCA_IS_NET_CAMERA (camera));
- request_call (UCA_NET_CAMERA_GET_PRIVATE (camera)->connection, UCA_NET_MESSAGE_STOP_RECORDING, error);
+ request_call (UCA_NET_CAMERA_GET_PRIVATE (camera), UCA_NET_MESSAGE_STOP_RECORDING, error);
}
static void
@@ -139,7 +148,7 @@ uca_net_camera_start_readout (UcaCamera *camera,
GError **error)
{
g_return_if_fail (UCA_IS_NET_CAMERA (camera));
- request_call (UCA_NET_CAMERA_GET_PRIVATE (camera)->connection, UCA_NET_MESSAGE_START_READOUT, error);
+ request_call (UCA_NET_CAMERA_GET_PRIVATE (camera), UCA_NET_MESSAGE_START_READOUT, error);
}
static void
@@ -147,7 +156,7 @@ uca_net_camera_stop_readout (UcaCamera *camera,
GError **error)
{
g_return_if_fail (UCA_IS_NET_CAMERA (camera));
- request_call (UCA_NET_CAMERA_GET_PRIVATE (camera)->connection, UCA_NET_MESSAGE_STOP_READOUT, error);
+ request_call (UCA_NET_CAMERA_GET_PRIVATE (camera), UCA_NET_MESSAGE_STOP_READOUT, error);
}
static void
@@ -158,6 +167,7 @@ uca_net_camera_write (UcaCamera *camera,
GError **error)
{
UcaNetCameraPrivate *priv;
+ GSocketConnection *connection;
GOutputStream *output;
gssize bytes_left;
gchar *buffer;
@@ -166,7 +176,8 @@ uca_net_camera_write (UcaCamera *camera,
g_return_if_fail (UCA_IS_NET_CAMERA (camera));
priv = UCA_NET_CAMERA_GET_PRIVATE (camera);
- output = g_io_stream_get_output_stream (G_IO_STREAM (priv->connection));
+ connection = connect_socket (priv, error);
+ output = g_io_stream_get_output_stream (G_IO_STREAM (connection));
request.size = size;
strncpy (request.name, name, sizeof (request.name));
@@ -187,7 +198,8 @@ uca_net_camera_write (UcaCamera *camera,
bytes_left -= written;
}
- handle_default_reply (priv->connection, UCA_NET_MESSAGE_WRITE, error);
+ handle_default_reply (connection, UCA_NET_MESSAGE_WRITE, error);
+ g_object_unref (connection);
}
static gboolean
@@ -196,6 +208,7 @@ uca_net_camera_grab (UcaCamera *camera,
GError **error)
{
UcaNetCameraPrivate *priv;
+ GSocketConnection *connection;
GInputStream *input;
GOutputStream *output;
gsize bytes_left;
@@ -204,17 +217,19 @@ uca_net_camera_grab (UcaCamera *camera,
g_return_val_if_fail (UCA_IS_NET_CAMERA (camera), FALSE);
priv = UCA_NET_CAMERA_GET_PRIVATE (camera);
- input = g_io_stream_get_input_stream (G_IO_STREAM (priv->connection));
- output = g_io_stream_get_output_stream (G_IO_STREAM (priv->connection));
+ connection = connect_socket (priv, error);
+ input = g_io_stream_get_input_stream (G_IO_STREAM (connection));
+ output = g_io_stream_get_output_stream (G_IO_STREAM (connection));
request.size = priv->size;
/* request */
if (!g_output_stream_write_all (output, &request, sizeof (request), NULL, NULL, error)) {
+ g_object_unref (connection);
return FALSE;
}
/* error reply */
- if (handle_default_reply (priv->connection, UCA_NET_MESSAGE_GRAB, error)) {
+ if (handle_default_reply (connection, UCA_NET_MESSAGE_GRAB, error)) {
bytes_left = priv->size;
while (bytes_left > 0) {
@@ -230,9 +245,11 @@ uca_net_camera_grab (UcaCamera *camera,
bytes_left -= read;
}
+ g_object_unref (connection);
return TRUE;
}
+ g_object_unref (connection);
return FALSE;
}
@@ -241,7 +258,7 @@ uca_net_camera_trigger (UcaCamera *camera,
GError **error)
{
g_return_if_fail (UCA_IS_NET_CAMERA (camera));
- request_call (UCA_NET_CAMERA_GET_PRIVATE (camera)->connection, UCA_NET_MESSAGE_TRIGGER, error);
+ request_call (UCA_NET_CAMERA_GET_PRIVATE (camera), UCA_NET_MESSAGE_TRIGGER, error);
}
static gboolean
@@ -283,6 +300,7 @@ uca_net_camera_set_property (GObject *object,
GParamSpec *pspec)
{
UcaNetCameraPrivate *priv;
+ GSocketConnection *connection;
const gchar *name;
GError *error = NULL;
@@ -296,10 +314,13 @@ uca_net_camera_set_property (GObject *object,
}
/* handle remote props */
+ connection = connect_socket (priv, &error);
name = g_param_spec_get_name (pspec);
- if (!request_set_property (priv->connection, name, value, &error))
+ if (!request_set_property (connection, name, value, &error))
g_warning ("Could not set property: %s", error->message);
+
+ g_object_unref (connection);
}
static gboolean
@@ -369,6 +390,7 @@ uca_net_camera_get_property (GObject *object,
GParamSpec *pspec)
{
UcaNetCameraPrivate *priv;
+ GSocketConnection *connection;
const gchar *name;
GError *error = NULL;
@@ -381,35 +403,19 @@ uca_net_camera_get_property (GObject *object,
}
/* handle remote props */
+ connection = connect_socket (priv, &error);
name = g_param_spec_get_name (pspec);
- if (!request_get_property (priv->connection, name, value, &error))
+ if (!request_get_property (connection, name, value, &error))
g_warning ("Could not get property: %s", error->message);
+
+ g_object_unref (connection);
}
static void
uca_net_camera_dispose (GObject *object)
{
- UcaNetCameraPrivate *priv;
-
- priv = UCA_NET_CAMERA_GET_PRIVATE (object);
-
- if (priv->connection != NULL) {
- GOutputStream *output;
- GError *error = NULL;
- UcaNetMessageDefault request = { .type = UCA_NET_MESSAGE_CLOSE_CONNECTION };
-
- output = g_io_stream_get_output_stream (G_IO_STREAM (priv->connection));
-
- if (!g_output_stream_write_all (output, &request, sizeof (request), NULL, NULL, &error)) {
- g_warning ("Could not close connection: %s", error->message);
- g_error_free (error);
- }
-
- g_object_unref (priv->connection);
- }
-
- g_object_unref (priv->client);
+ g_object_unref (UCA_NET_CAMERA_GET_PRIVATE (object)->client);
G_OBJECT_CLASS (uca_net_camera_parent_class)->dispose (object);
}
@@ -516,6 +522,7 @@ static void
uca_net_camera_constructed (GObject *object)
{
UcaNetCameraPrivate *priv;
+ GSocketConnection *connection;
priv = UCA_NET_CAMERA_GET_PRIVATE (object);
@@ -526,13 +533,14 @@ uca_net_camera_constructed (GObject *object)
priv->host = env != NULL ? g_strdup (env) : g_strdup ("localhost");
}
- priv->connection = g_socket_client_connect_to_host (priv->client, priv->host, UCA_NET_DEFAULT_PORT, NULL, &priv->construct_error);
+ connection = connect_socket (priv, &priv->construct_error);
- if (priv->connection != NULL) {
+ if (connection != NULL) {
/* ask for additional camera properties */
- if (send_default_message (priv->connection, UCA_NET_MESSAGE_GET_PROPERTIES, &priv->construct_error))
- read_get_properties_reply (object, g_io_stream_get_input_stream (G_IO_STREAM (priv->connection)),
- &priv->construct_error);
+ if (send_default_message (connection, UCA_NET_MESSAGE_GET_PROPERTIES, &priv->construct_error))
+ read_get_properties_reply (object, g_io_stream_get_input_stream (G_IO_STREAM (connection)), &priv->construct_error);
+
+ g_object_unref (connection);
}
}
diff --git a/uca-net-protocol.h b/uca-net-protocol.h
index de05aac..4a1b5b6 100644
--- a/uca-net-protocol.h
+++ b/uca-net-protocol.h
@@ -15,7 +15,6 @@ typedef enum {
UCA_NET_MESSAGE_TRIGGER,
UCA_NET_MESSAGE_GRAB,
UCA_NET_MESSAGE_WRITE,
- UCA_NET_MESSAGE_CLOSE_CONNECTION,
} UcaNetMessageType;
typedef struct {
diff --git a/ucad.c b/ucad.c
index 4d46bca..b66124e 100644
--- a/ucad.c
+++ b/ucad.c
@@ -333,12 +333,14 @@ handle_write_request_cleanup:
g_free (buffer);
}
-static void
-serve_connection (GSocketConnection *connection, UcaCamera *camera)
+static gboolean
+run_callback (GSocketService *service, GSocketConnection *connection, GObject *source, gpointer user_data)
{
GInputStream *input;
+ UcaCamera *camera;
+ UcaNetMessageDefault *message;
gchar *buffer;
- gboolean active;
+ GError *error = NULL;
HandlerTable table[] = {
{ UCA_NET_MESSAGE_GET_PROPERTIES, handle_get_properties_request },
@@ -354,34 +356,23 @@ serve_connection (GSocketConnection *connection, UcaCamera *camera)
{ UCA_NET_MESSAGE_INVALID, NULL }
};
+ camera = UCA_CAMERA (user_data);
buffer = g_malloc0 (4096);
input = g_io_stream_get_input_stream (G_IO_STREAM (connection));
- active = TRUE;
-
- while (active) {
- UcaNetMessageDefault *message;
- GError *error = NULL;
- /* looks dangerous */
- g_input_stream_read (input, buffer, 4096, NULL, &error);
- message = (UcaNetMessageDefault *) buffer;
+ /* looks dangerous */
+ g_input_stream_read (input, buffer, 4096, NULL, &error);
+ message = (UcaNetMessageDefault *) buffer;
#if (GLIB_CHECK_VERSION (2, 36, 0))
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE)) {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_BROKEN_PIPE)) {
#else
- if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED)) {
+ if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_FAILED)) {
#endif
- g_error_free (error);
- error = NULL;
- active = FALSE;
- break;
- }
-
- if (message->type == UCA_NET_MESSAGE_CLOSE_CONNECTION) {
- active = FALSE;
- break;
- }
-
+ g_error_free (error);
+ error = NULL;
+ }
+ else {
for (guint i = 0; table[i].type != UCA_NET_MESSAGE_INVALID; i++) {
if (table[i].type == message->type)
table[i].handler (connection, camera, buffer, &error);
@@ -390,30 +381,10 @@ serve_connection (GSocketConnection *connection, UcaCamera *camera)
if (error != NULL) {
g_warning ("Error handling requests: %s", error->message);
g_error_free (error);
- active = FALSE;
}
}
g_free (buffer);
-}
-
-static gboolean
-run_callback (GSocketService *service, GSocketConnection *connection, GObject *source, gpointer user_data)
-{
- GInetSocketAddress *sock_address;
- GInetAddress *address;
- gchar *address_string;
-
- sock_address = G_INET_SOCKET_ADDRESS (g_socket_connection_get_remote_address (connection, NULL));
- address = g_inet_socket_address_get_address (sock_address);
- address_string = g_inet_address_to_string (address);
- g_message ("Connection accepted from %s:%u", address_string, g_inet_socket_address_get_port (sock_address));
-
- g_free (address_string);
- g_object_unref (sock_address);
-
- serve_connection (connection, UCA_CAMERA (user_data));
-
return FALSE;
}