[gimp/soc-2010-cage] Bug 623045 - script-fu: make server IPv6 aware
- From: Michael Muré <mmure src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/soc-2010-cage] Bug 623045 - script-fu: make server IPv6 aware
- Date: Wed, 30 Jun 2010 22:19:43 +0000 (UTC)
commit d9aa8288124afc6d94ded93120a4b23e580614cd
Author: Nils Philippsen <nils redhat com>
Date: Tue Jun 29 15:43:31 2010 +0200
Bug 623045 - script-fu: make server IPv6 aware
use getnameinfo() instead of inet_ntoa()
use two sockets for IPv4, IPv6
configure.ac | 8 +-
plug-ins/script-fu/script-fu-server.c | 141 +++++++++++++++++++++++++-------
plug-ins/script-fu/servertest.py | 76 ++++++++++++------
3 files changed, 166 insertions(+), 59 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 7dea7da..dd73b9c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -622,14 +622,14 @@ AC_CHECK_FUNC(rint, AC_DEFINE(HAVE_RINT, 1,
AC_DEFINE(HAVE_RINT)])])
-######################################################
-# Check for extra libs needed for inet_ntoa and socket
-######################################################
+########################################################
+# Check for extra libs needed for getnameinfo and socket
+########################################################
gimp_save_LIBS=$LIBS
LIBS=""
-AC_CHECK_FUNCS(inet_ntoa, , AC_CHECK_LIB(nsl, inet_ntoa))
+AC_CHECK_FUNCS(getnameinfo, , AC_CHECK_LIB(nsl, getnameinfo))
AC_CHECK_LIB(socket, socket)
SOCKET_LIBS="$LIBS"
diff --git a/plug-ins/script-fu/script-fu-server.c b/plug-ins/script-fu/script-fu-server.c
index 35585f6..c158fa0 100644
--- a/plug-ins/script-fu/script-fu-server.c
+++ b/plug-ins/script-fu/script-fu-server.c
@@ -136,7 +136,8 @@ static void server_start (gint port,
const gchar *logfile);
static gboolean execute_command (SFCommand *cmd);
static gint read_from_client (gint filedes);
-static gint make_socket (guint port);
+static gint make_socket (const struct addrinfo
+ *ai);
static void server_log (const gchar *format,
...) G_GNUC_PRINTF (1, 2);
static void server_quit (void);
@@ -150,7 +151,10 @@ static void print_socket_api_error (const gchar *api_name);
/*
* Local variables
*/
-static gint server_sock;
+static gint server_socks[2],
+ server_socks_used = 0;
+static const gint server_socks_len = sizeof (server_socks) /
+ sizeof (server_socks[0]);
static GList *command_queue = NULL;
static gint queue_length = 0;
static gint request_no = 0;
@@ -284,6 +288,7 @@ script_fu_server_listen (gint timeout)
struct timeval tv;
struct timeval *tvp = NULL;
SELECT_MASK fds;
+ gint sockno;
/* Set time struct */
if (timeout)
@@ -294,7 +299,10 @@ script_fu_server_listen (gint timeout)
}
FD_ZERO (&fds);
- FD_SET (server_sock, &fds);
+ for (sockno = 0; sockno < server_socks_used; sockno++)
+ {
+ FD_SET (server_socks[sockno], &fds);
+ }
g_hash_table_foreach (clients, script_fu_server_add_fd, &fds);
/* Block until input arrives on one or more active sockets
@@ -306,15 +314,25 @@ script_fu_server_listen (gint timeout)
return;
}
- /* Service the server socket if it has input pending. */
- if (FD_ISSET (server_sock, &fds))
+ /* Service the server sockets if any has input pending. */
+ for (sockno = 0; sockno < server_socks_used; sockno++)
{
- struct sockaddr_in clientname;
+ struct sockaddr_storage client;
+ struct sockaddr_in *client_in;
+ struct sockaddr_in6 *client_in6;
+ gchar clientname[NI_MAXHOST];
/* Connection request on original socket. */
- guint size = sizeof (clientname);
- gint new = accept (server_sock,
- (struct sockaddr *) &clientname, &size);
+ guint size = sizeof (client);
+ gint new;
+ guint portno;
+
+ if (! FD_ISSET (server_socks[sockno], &fds))
+ {
+ continue;
+ }
+
+ new = accept (server_socks[sockno], (struct sockaddr *) &client, &size);
if (new < 0)
{
@@ -323,13 +341,34 @@ script_fu_server_listen (gint timeout)
}
/* Associate the client address with the socket */
- g_hash_table_insert (clients,
- GINT_TO_POINTER (new),
- g_strdup (inet_ntoa (clientname.sin_addr)));
+
+ /* If all else fails ... */
+ strncpy (clientname, "(error during host address lookup)", NI_MAXHOST-1);
+
+ /* Lookup address */
+ (void) getnameinfo ((struct sockaddr *) &client, size, clientname,
+ sizeof (clientname), NULL, 0, NI_NUMERICHOST);
+
+ g_hash_table_insert (clients, GINT_TO_POINTER (new),
+ g_strdup (clientname));
+
+ /* Determine port number */
+ switch (client.ss_family)
+ {
+ case AF_INET:
+ client_in = (struct sockaddr_in *) &client;
+ portno = (guint) g_ntohs (client_in->sin_port);
+ break;
+ case AF_INET6:
+ client_in6 = (struct sockaddr_in6 *) &client;
+ portno = (guint) g_ntohs (client_in6->sin6_port);
+ break;
+ default:
+ portno = 0;
+ }
server_log ("Server: connect from host %s, port %d.\n",
- inet_ntoa (clientname.sin_addr),
- (unsigned int) ntohs (clientname.sin_port));
+ clientname, portno);
}
/* Service the client sockets. */
@@ -391,18 +430,46 @@ static void
server_start (gint port,
const gchar *logfile)
{
- const gchar *progress;
+ struct addrinfo *ai,
+ *ai_curr;
+ struct addrinfo hints;
+ gint e,
+ sockno;
+ gchar *port_s;
- /* First of all, create the socket and set it up to accept connections. */
- /* This may fail if there's a server running on this port already. */
- server_sock = make_socket (port);
+ const gchar *progress;
- if (listen (server_sock, 5) < 0)
+ memset (&hints, 0, sizeof (hints));
+ hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_STREAM;
+
+ port_s = g_strdup_printf ("%d", port);
+ e = getaddrinfo (NULL, port_s, &hints, &ai);
+ g_free (port_s);
+
+ if (e != 0)
{
- print_socket_api_error ("listen");
+ g_printerr ("getaddrinfo: %s", gai_strerror (e));
return;
}
+ for (ai_curr = ai, sockno = 0;
+ ai_curr != NULL && sockno < server_socks_len;
+ ai_curr = ai_curr->ai_next, sockno++)
+ {
+ /* Create the socket and set it up to accept connections. */
+ /* This may fail if there's a server running on this port already. */
+ server_socks[sockno] = make_socket (ai_curr);
+
+ if (listen (server_socks[sockno], 5) < 0)
+ {
+ print_socket_api_error ("listen");
+ return;
+ }
+ }
+
+ server_socks_used = sockno;
+
/* Setup up the server log file */
if (logfile && *logfile)
server_log_file = g_fopen (logfile, "a");
@@ -591,11 +658,10 @@ read_from_client (gint filedes)
}
static gint
-make_socket (guint port)
+make_socket (const struct addrinfo *ai)
{
- struct sockaddr_in name;
- gint sock;
- gint v = 1;
+ gint sock;
+ gint v = 1;
/* Win32 needs the winsock library initialized. */
#ifdef G_OS_WIN32
@@ -619,7 +685,7 @@ make_socket (guint port)
#endif
/* Create the socket. */
- sock = socket (PF_INET, SOCK_STREAM, 0);
+ sock = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
if (sock < 0)
{
print_socket_api_error ("socket");
@@ -628,12 +694,20 @@ make_socket (guint port)
setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &v, sizeof(v));
- /* Give the socket a name. */
- name.sin_family = AF_INET;
- name.sin_port = htons (port);
- name.sin_addr.s_addr = htonl (INADDR_ANY);
+#ifdef IPV6_V6ONLY
+ /* Only listen on IPv6 addresses, otherwise bind() will fail. */
+ if (ai->ai_family == AF_INET6)
+ {
+ v = 1;
+ if (setsockopt (sock, IPPROTO_IPV6, IPV6_V6ONLY, &v, sizeof(v)) < 0)
+ {
+ print_socket_api_error ("setsockopt");
+ gimp_quit();
+ }
+ }
+#endif
- if (bind (sock, (struct sockaddr *) &name, sizeof (name)) < 0)
+ if (bind (sock, ai->ai_addr, ai->ai_addrlen) < 0)
{
print_socket_api_error ("bind");
gimp_quit ();
@@ -671,7 +745,12 @@ script_fu_server_shutdown_fd (gpointer key,
static void
server_quit (void)
{
- CLOSESOCKET (server_sock);
+ gint sockno;
+
+ for (sockno = 0; sockno < server_socks_used; sockno++)
+ {
+ CLOSESOCKET (server_socks[sockno]);
+ }
if (clients)
{
diff --git a/plug-ins/script-fu/servertest.py b/plug-ins/script-fu/servertest.py
index b636557..5fb673a 100644
--- a/plug-ins/script-fu/servertest.py
+++ b/plug-ins/script-fu/servertest.py
@@ -2,38 +2,66 @@
import readline, socket, sys
-if len (sys.argv) == 1:
- HOST = 'localhost'
- PORT = 10008
-elif len (sys.argv) == 3:
- HOST = sys.argv[1]
- PORT = int (sys.argv[2])
-else:
- print >> sys.stderr, "Usage: %s <host> <port>" % sys.argv[0]
- print >> sys.stderr, " (if omitted connect to localhost, port 10008)"
- sys.exit ()
+if len(sys.argv) < 1 or len(sys.argv) > 3:
+ print >>sys.stderr, "Usage: %s <host> <port>" % sys.argv[0]
+ print >>sys.stderr, " (if omitted connect to localhost, port 10008)"
+ sys.exit(1)
+HOST = "localhost"
+PORT = 10008
-sock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
-sock.connect ((HOST, PORT))
+try:
+ HOST = sys.argv[1]
+ try:
+ PORT = int(sys.argv[2])
+ except IndexError:
+ pass
+except IndexError:
+ pass
+
+addresses = socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM)
+
+connected = False
+
+for addr in addresses:
+ (family, socktype, proto, canonname, sockaddr) = addr
+
+ numeric_addr = sockaddr[0]
+
+ if canonname:
+ print "Trying %s ('%s')." % (numeric_addr, canonname)
+ else:
+ print "Trying %s." % numeric_addr
+
+ try:
+ sock = socket.socket(family, socket.SOCK_STREAM)
+ sock.connect((HOST, PORT))
+ connected = True
+ break
+ except:
+ pass
+
+if not connected:
+ print "Failed."
+ sys.exit(1)
try:
- cmd = raw_input ("Script-Fu-Remote - Testclient\n> ")
+ cmd = raw_input("Script-Fu-Remote - Testclient\n> ")
- while len (cmd) > 0:
- sock.send ('G%c%c%s' % (len (cmd) / 256, len (cmd) % 256, cmd))
+ while len(cmd) > 0:
+ sock.send('G%c%c%s' % (len(cmd) / 256, len(cmd) % 256, cmd))
data = ""
- while len (data) < 4:
- data += sock.recv (4 - len (data))
+ while len(data) < 4:
+ data += sock.recv(4 - len(data))
- if len (data) >= 4:
+ if len(data) >= 4:
if data[0] == 'G':
- l = ord (data[2]) * 256 + ord (data[3])
+ l = ord(data[2]) * 256 + ord(data[3])
msg = ""
- while len (msg) < l:
- msg += sock.recv (l - len (msg))
- if ord (data[1]):
+ while len(msg) < l:
+ msg += sock.recv(l - len(msg))
+ if ord(data[1]):
print "(ERR):", msg
else:
print " (OK):", msg
@@ -41,9 +69,9 @@ try:
print "invalid magic: %s\n" % data
else:
print "short response: %s\n" % data
- cmd = raw_input ("> ")
+ cmd = raw_input("> ")
except EOFError:
print
-sock.close
+sock.close()
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]