blob: 6ea897c9110127b3530fe1f69ff626a293113830 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include <errno.h>
#include <netdb.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <thrift/c_glib/thrift.h>
#include <thrift/c_glib/transport/thrift_socket.h>
#include <thrift/c_glib/transport/thrift_transport.h>
#include <thrift/c_glib/transport/thrift_server_transport.h>
#include <thrift/c_glib/transport/thrift_server_socket.h>
/* object properties */
enum _ThriftServerSocketProperties
{
PROP_0,
PROP_THRIFT_SERVER_SOCKET_PORT,
PROP_THRIFT_SERVER_SOCKET_BACKLOG
};
/* define the GError domain string */
#define THRIFT_SERVER_SOCKET_ERROR_DOMAIN "thrift-server-socket-error-quark"
G_DEFINE_TYPE(ThriftServerSocket, thrift_server_socket, THRIFT_TYPE_SERVER_TRANSPORT)
gboolean
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);
/* create a socket */
if ((tsocket->sd = socket (AF_INET, SOCK_STREAM, 0)) == -1)
{
g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
THRIFT_SERVER_SOCKET_ERROR_SOCKET,
"failed to create socket - %s", strerror (errno));
return FALSE;
}
if (setsockopt(tsocket->sd, SOL_SOCKET, SO_REUSEADDR, &enabled,
sizeof(enabled)) == -1)
{
g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
THRIFT_SERVER_SOCKET_ERROR_SETSOCKOPT,
"unable to set SO_REUSEADDR - %s", strerror(errno));
return FALSE;
}
/* bind to the socket */
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;
}
return TRUE;
}
ThriftTransport *
thrift_server_socket_accept (ThriftServerTransport *transport, GError **error)
{
int sd = THRIFT_INVALID_SOCKET;
guint addrlen = 0;
struct sockaddr_in address;
ThriftSocket *socket = NULL;
ThriftServerSocket *tsocket = THRIFT_SERVER_SOCKET (transport);
if ((sd = accept(tsocket->sd, (struct sockaddr *) &address, &addrlen)) == -1)
{
g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
THRIFT_SERVER_SOCKET_ERROR_ACCEPT,
"failed to accept connection - %s",
strerror(errno));
return FALSE;
}
socket = g_object_new (THRIFT_TYPE_SOCKET, NULL);
socket->sd = sd;
return THRIFT_TRANSPORT(socket);
}
gboolean
thrift_server_socket_close (ThriftServerTransport *transport, GError **error)
{
ThriftServerSocket *tsocket = THRIFT_SERVER_SOCKET (transport);
if (close (tsocket->sd) == -1)
{
g_set_error (error, THRIFT_SERVER_SOCKET_ERROR,
THRIFT_SERVER_SOCKET_ERROR_CLOSE,
"unable to close socket - %s", strerror(errno));
return FALSE;
}
tsocket->sd = THRIFT_INVALID_SOCKET;
return TRUE;
}
/* define the GError domain for this implementation */
GQuark
thrift_server_socket_error_quark (void)
{
return g_quark_from_static_string(THRIFT_SERVER_SOCKET_ERROR_DOMAIN);
}
/* initializes the instance */
static void
thrift_server_socket_init (ThriftServerSocket *socket)
{
socket->sd = THRIFT_INVALID_SOCKET;
}
/* destructor */
static void
thrift_server_socket_finalize (GObject *object)
{
ThriftServerSocket *socket = THRIFT_SERVER_SOCKET (object);
if (socket->sd != THRIFT_INVALID_SOCKET)
{
close (socket->sd);
}
socket->sd = THRIFT_INVALID_SOCKET;
}
/* property accessor */
void
thrift_server_socket_get_property (GObject *object, guint property_id,
GValue *value, GParamSpec *pspec)
{
ThriftServerSocket *socket = THRIFT_SERVER_SOCKET (object);
switch (property_id)
{
case PROP_THRIFT_SERVER_SOCKET_PORT:
g_value_set_uint (value, socket->port);
break;
case PROP_THRIFT_SERVER_SOCKET_BACKLOG:
g_value_set_uint (value, socket->backlog);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* property mutator */
void
thrift_server_socket_set_property (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
{
ThriftServerSocket *socket = THRIFT_SERVER_SOCKET (object);
switch (property_id)
{
case PROP_THRIFT_SERVER_SOCKET_PORT:
socket->port = g_value_get_uint (value);
break;
case PROP_THRIFT_SERVER_SOCKET_BACKLOG:
socket->backlog = g_value_get_uint (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* initializes the class */
static void
thrift_server_socket_class_init (ThriftServerSocketClass *cls)
{
ThriftServerTransportClass *tstc = THRIFT_SERVER_TRANSPORT_CLASS (cls);
GObjectClass *gobject_class = G_OBJECT_CLASS (cls);
GParamSpec *param_spec = NULL;
/* setup accessors and mutators */
gobject_class->get_property = thrift_server_socket_get_property;
gobject_class->set_property = thrift_server_socket_set_property;
param_spec = g_param_spec_uint ("port",
"port (construct)",
"Set the port to listen to",
0, /* min */
65535, /* max */
9090, /* default by convention */
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_THRIFT_SERVER_SOCKET_PORT,
param_spec);
param_spec = g_param_spec_uint ("backlog",
"backlog (construct)",
"Set the accept backlog",
0, /* max */
65534, /* max */
1024, /* default */
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_READWRITE);
g_object_class_install_property (gobject_class,
PROP_THRIFT_SERVER_SOCKET_BACKLOG,
param_spec);
gobject_class->finalize = thrift_server_socket_finalize;
tstc->listen = thrift_server_socket_listen;
tstc->accept = thrift_server_socket_accept;
tstc->close = thrift_server_socket_close;
}