Merge lp:~schuster/mysql-proxy/remove_unix_socket into lp:mysql-proxy

Proposed by Michael Schuster
Status: Merged
Merged at revision: 1081
Proposed branch: lp:~schuster/mysql-proxy/remove_unix_socket
Merge into: lp:mysql-proxy
Diff against target: 231 lines (+130/-5)
4 files modified
src/network-address.c (+28/-1)
src/network-address.h (+1/-1)
src/network-socket.c (+1/-0)
tests/unit/t_network_socket.c (+100/-3)
To merge this branch: bzr merge lp:~schuster/mysql-proxy/remove_unix_socket
Reviewer Review Type Date Requested Status
Jan Kneschke (community) Approve
Review via email: mp+23652@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Jan Kneschke (jan-kneschke) wrote :

Am 19.04.2010 um 08:48 schrieb Michael Schuster:

> Michael Schuster has proposed merging lp:~schuster/mysql-proxy/remove_unix_socket into lp:mysql-proxy.
>
> Requested reviews:
> MySQL Proxy Developers (mysql-proxy-developers)
>
> --
> https://code.launchpad.net/~schuster/mysql-proxy/remove_unix_socket/+merge/23652
> Your team MySQL Proxy Developers is subscribed to branch lp:mysql-proxy.
> === modified file 'src/network-address.c'
> --- src/network-address.c 2010-04-07 12:44:32 +0000
> +++ src/network-address.c 2010-04-19 06:48:19 +0000
> @@ -45,6 +45,8 @@
> #include <string.h>
> #include <errno.h>
> #include <fcntl.h>
> +#include <glib.h>
> +#include <glib/gstdio.h>
>
> #include "network-address.h"
> #include "glib-ext.h"
> @@ -63,10 +65,33 @@
> }
>
> void network_address_free(network_address *addr) {
> +
> if (!addr) return;
>
> +#ifndef WIN32
> + /*
> + * if the name we're freeing starts with a '/', we're
> + * looking at a unix socket which needs to be removed
> + */
> + if (addr->fail_errno == 0 && addr->name != NULL &&
> + addr->name->str != NULL) {
> + gchar *name;
> + int ret;
> +
> + name = addr->name->str;
> + if (name[0] == '/' && g_access(name, 0) == 0) {
> + ret = g_remove(name);

Only try to remove it if we can to hide the error-msg (aka noise) for it ?

> +
> + if (ret == 0)
> + g_debug("%s removing socket %s successful",
> + G_STRLOC, name);
> + else
> + g_debug("%s removing socket %s failed: %s (%d)",
> + G_STRLOC, name, strerror(errno));

... in that case the g_debug() is perhaps better a g_critical() ?

> + }
> + }
> +#endif /* WIN32 */
> +
> g_string_free(addr->name, TRUE);
> -
> g_free(addr);
> }
>
>
> === modified file 'src/network-address.h'
> --- src/network-address.h 2010-04-06 14:26:51 +0000
> +++ src/network-address.h 2010-04-19 06:48:19 +0000
> @@ -63,8 +63,8 @@
> } addr;
>
> GString *name;
> -
> network_socklen_t len;
> + int fail_errno; /* != 0: don't remove ... I guess */
> } network_address;
>
> NETWORK_API network_address *network_address_new(void);
>
> === modified file 'src/network-socket.c'
> --- src/network-socket.c 2010-04-06 14:26:51 +0000
> +++ src/network-socket.c 2010-04-19 06:48:19 +0000
> @@ -397,6 +397,7 @@
> G_STRLOC,
> con->dst->name->str,
> g_strerror(errno), errno);
> + con->dst->fail_errno = errno; /* if a unix socket, this tells us "don't remove" */
> return NETWORK_SOCKET_ERROR;
> }
>
>

Revision history for this message
Michael Schuster (schuster) wrote :

On 04/19/10 09:39, Jan Kneschke wrote:
> Am 19.04.2010 um 08:48 schrieb Michael Schuster:
>
>> Michael Schuster has proposed merging lp:~schuster/mysql-proxy/remove_unix_socket into lp:mysql-proxy.
>>
>> Requested reviews:
>> MySQL Proxy Developers (mysql-proxy-developers)
>>
>> --
>> https://code.launchpad.net/~schuster/mysql-proxy/remove_unix_socket/+merge/23652
>> Your team MySQL Proxy Developers is subscribed to branch lp:mysql-proxy.
>> === modified file 'src/network-address.c'
>> --- src/network-address.c 2010-04-07 12:44:32 +0000
>> +++ src/network-address.c 2010-04-19 06:48:19 +0000
>> @@ -45,6 +45,8 @@
>> #include <string.h>
>> #include <errno.h>
>> #include <fcntl.h>
>> +#include <glib.h>
>> +#include <glib/gstdio.h>
>>
>> #include "network-address.h"
>> #include "glib-ext.h"
>> @@ -63,10 +65,33 @@
>> }
>>
>> void network_address_free(network_address *addr) {
>> +
>> if (!addr) return;
>>
>> +#ifndef WIN32
>> + /*
>> + * if the name we're freeing starts with a '/', we're
>> + * looking at a unix socket which needs to be removed
>> + */
>> + if (addr->fail_errno == 0 && addr->name != NULL &&
>> + addr->name->str != NULL) {
>> + gchar *name;
>> + int ret;
>> +
>> + name = addr->name->str;
>> + if (name[0] == '/' && g_access(name, 0) == 0) {
>> + ret = g_remove(name);
>
> Only try to remove it if we can to hide the error-msg (aka noise) for it ?

sorry, don't understand the question :-(

>> +
>> + if (ret == 0)
>> + g_debug("%s removing socket %s successful",
>> + G_STRLOC, name);
>> + else
>> + g_debug("%s removing socket %s failed: %s (%d)",
>> + G_STRLOC, name, strerror(errno));
>
> ... in that case the g_debug() is perhaps better a g_critical() ?

ok.

Michael

1049. By Michael Schuster

change warning level for failure to remove socket

Revision history for this message
Jan Kneschke (jan-kneschke) wrote :

Am 19.04.2010 um 10:45 schrieb Michael Schuster:

> On 04/19/10 09:39, Jan Kneschke wrote:
>> Am 19.04.2010 um 08:48 schrieb Michael Schuster:
>>
>>> Michael Schuster has proposed merging lp:~schuster/mysql-proxy/remove_unix_socket into lp:mysql-proxy.
>>>
>>> Requested reviews:
>>> MySQL Proxy Developers (mysql-proxy-developers)
>>>
>>> --
>>> https://code.launchpad.net/~schuster/mysql-proxy/remove_unix_socket/+merge/23652
>>> Your team MySQL Proxy Developers is subscribed to branch lp:mysql-proxy.
>>> === modified file 'src/network-address.c'
>>> --- src/network-address.c 2010-04-07 12:44:32 +0000
>>> +++ src/network-address.c 2010-04-19 06:48:19 +0000
>>> @@ -45,6 +45,8 @@
>>> #include <string.h>
>>> #include <errno.h>
>>> #include <fcntl.h>
>>> +#include <glib.h>
>>> +#include <glib/gstdio.h>
>>>
>>> #include "network-address.h"
>>> #include "glib-ext.h"
>>> @@ -63,10 +65,33 @@
>>> }
>>>
>>> void network_address_free(network_address *addr) {
>>> +
>>> if (!addr) return;
>>>
>>> +#ifndef WIN32
>>> + /*
>>> + * if the name we're freeing starts with a '/', we're
>>> + * looking at a unix socket which needs to be removed
>>> + */
>>> + if (addr->fail_errno == 0 && addr->name != NULL &&
>>> + addr->name->str != NULL) {
>>> + gchar *name;
>>> + int ret;
>>> +
>>> + name = addr->name->str;
>>> + if (name[0] == '/' && g_access(name, 0) == 0) {
>>> + ret = g_remove(name);
>>
>> Only try to remove it if we can to hide the error-msg (aka noise) for it ?
>
> sorry, don't understand the question :-(

I tried to figure out the reason for the g_access() and assumed it is to check if the g_remove() could succeed without a permission problem.

Problem with access() is that it creates a race-condition before the the permission check and the g_remove(). Instead just unlink() it and check for the 'errno != EPERM' to see if we can't delete the socket as we drop the privileges.

>>> +
>>> + if (ret == 0)
>>> + g_debug("%s removing socket %s successful",
>>> + G_STRLOC, name);
>>> + else
>>> + g_debug("%s removing socket %s failed: %s (%d)",
>>> + G_STRLOC, name, strerror(errno));
>>
>> ... in that case the g_debug() is perhaps better a g_critical() ?
>
> ok.

The whole patch does unlink() any file that is set as address. In the case of a network_socket_new() + network_address_set_address() + network_socket_connect() + network_socket_free() the socket-file should not be unlinked as it we didn't listen() on it.

Instead of ->fail_errno use a gboolean to track if you want to unlink the socket file on free and only set it to true in the case of a successful network_socket_bind().

> Michael
> --
> https://code.launchpad.net/~schuster/mysql-proxy/remove_unix_socket/+merge/23652
> Your team MySQL Proxy Developers is subscribed to branch lp:mysql-proxy.

Revision history for this message
Jan Kneschke (jan-kneschke) wrote :

A test-case to verify that we don't unlink() socket-files we havn't bound

1=== modified file 'tests/unit/t_network_address.c'
2--- tests/unit/t_network_address.c revid:michael.schuster@oracle.com-20100423113047-u7cepgr9b32hgxag
3+++ tests/unit/t_network_address.c 2010-04-28 07:07:30 +0000
4@@ -21,9 +21,14 @@
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8+#include <fcntl.h>
9
10 #include <glib.h>
11
12+#ifndef _WIN32
13+#include <unistd.h>
14+#endif
15+
16 #include "network-socket.h"
17
18 #if GLIB_CHECK_VERSION(2, 16, 0)
19@@ -80,6 +85,38 @@
20 network_address_free(addr);
21 }
22
23+/**
24+ * test if we decode the port number correctly
25+ */
26+void t_network_address_free_unix_socket() {
27+ network_address *addr;
28+ int fd;
29+
30+#define TESTFILE "/tmp/mysql-proxy-t_network_address_free_unix_socket.sock"
31+ unlink(TESTFILE); /* remove the file if a previous test-run failed */
32+
33+ /* create the test-file */
34+ fd = open(TESTFILE, O_RDONLY | O_CREAT | O_EXCL, 0600);
35+ if (fd != -1) close(fd);
36+
37+ g_assert_cmpint(fd, >, 0); /* creating the file should have succeeded */
38+
39+ addr = network_address_new();
40+ network_address_set_address(addr, TESTFILE);
41+
42+ network_address_free(addr); /* the free shouldn't remove the file as we didn't call bind() on it */
43+
44+ /* file should still be there */
45+ fd = open(TESTFILE, O_RDONLY);
46+ if (fd != -1) close(fd);
47+
48+ g_assert_cmpint(fd, >, 0);
49+
50+ unlink(TESTFILE); /* cleanup */
51+#undef TESTFILE
52+}
53+
54+
55
56 int main(int argc, char **argv) {
57 g_test_init(&argc, &argv, NULL);
58@@ -88,6 +125,7 @@
59 g_test_add_func("/core/network_address_new", t_network_address_new);
60 g_test_add_func("/core/network_address_set", t_network_address_set);
61 g_test_add_func("/core/network_address_resolve", t_network_address_resolve);
62+ g_test_add_func("/core/network_address_free_unix_socket", t_network_address_free_unix_socket);
63
64 return g_test_run();
65 }
1050. By Michael Schuster

remove unix socket at shutdown: remove race window, make logic for "remove the once we created only" better

1051. By Michael Schuster

add check for local socket removal to "is local" testcase

1052. By Michael Schuster

make sure socket is removed if assertion fails: add sig handler for SIGARBT

Revision history for this message
Jan Kneschke (jan-kneschke) wrote :

* remove the commented lines:

  /* printf("debug: socket name is %s (addr: %p)\n", pp->sockname, pp); */
  /* g_test_add_func("/core/network_socket_is_local_unix", t_network_socket_is_local_unix);*/

* stay with the existing coding style (no line-break after function declarations)
* The signal-handler for SIGABRT is installed for _all_ tests of this test-suite. Instead it should be added in the setup and turned back into SIG_DFL in teardown.
* void t_network_socket_is_local_unix() is about the ..._is_local() function. Comments are missing to describe that it also tests for 'socket is removed after successful bind() only'. It would have been better to have seperate test that only tests that.

Revision history for this message
Jan Kneschke (jan-kneschke) wrote :

g_debug("%s removing socket %s successful", ... is missing a colon after the first %s

Revision history for this message
Jan Kneschke (jan-kneschke) :
review: Needs Fixing
Revision history for this message
Michael Schuster (schuster) wrote :

Jan,

thx for review, comments in-line.

On 04.05.10 13:50, Jan Kneschke wrote:
> * remove the commented lines:
>
> /* printf("debug: socket name is %s (addr: %p)\n", pp->sockname, pp); */
> /* g_test_add_func("/core/network_socket_is_local_unix", t_network_socket_is_local_unix);*/

done

> * stay with the existing coding style (no line-break after function declarations)

ack, done.

> * The signal-handler for SIGABRT is installed for _all_ tests of this test-suite. Instead it should be added in the setup and turned back into SIG_DFL in teardown.

done

> * void t_network_socket_is_local_unix() is about the ..._is_local() function. Comments are missing to describe that it also tests for 'socket is removed after successful bind() only'. It would have been better to have seperate test that only tests that.

ack

> g_debug("%s removing socket %s successful", ... is missing a colon after the first %s

this is now gone.

Michael
--
Michael Schuster http://blogs.sun.com/recursion
Recursion, n.: see 'Recursion'

1053. By Michael Schuster

fix diversion

Revision history for this message
Jan Kneschke (jan-kneschke) wrote :

approved. will merge it to trunk

review: Approve
Revision history for this message
Jan Kneschke (jan-kneschke) wrote :

65 === modified file 'src/network-socket.c'
66 --- src/network-socket.c 2010-05-03 14:26:32 +0000
67 +++ src/network-socket.c 2010-05-10 11:52:26 +0000
...

In static network_socket_retval_t network_socket_write_send(network_socket *con, int send_chunks) is

76 @@ -660,6 +661,7 @@
77 }
78 }
79
80 + con->dst->can_unlink_socket = TRUE;
81 return NETWORK_SOCKET_SUCCESS;
82 }

which would mean:

"unlink socket after successful write" which isn't what we want. Seems to a broken merge. The rest looks good.

review: Needs Fixing
1054. By Michael Schuster

mismerge fixed

Revision history for this message
Jan Kneschke (jan-kneschke) :
review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/network-address.c'
2--- src/network-address.c 2010-04-07 12:44:32 +0000
3+++ src/network-address.c 2010-05-10 12:15:45 +0000
4@@ -45,6 +45,8 @@
5 #include <string.h>
6 #include <errno.h>
7 #include <fcntl.h>
8+#include <glib.h>
9+#include <glib/gstdio.h>
10
11 #include "network-address.h"
12 #include "glib-ext.h"
13@@ -63,10 +65,35 @@
14 }
15
16 void network_address_free(network_address *addr) {
17+
18 if (!addr) return;
19
20+#ifndef WIN32
21+ /*
22+ * if the name we're freeing starts with a '/', we're
23+ * looking at a unix socket which needs to be removed
24+ */
25+ if (addr->can_unlink_socket == TRUE && addr->name != NULL &&
26+ addr->name->str != NULL) {
27+ gchar *name;
28+ int ret;
29+
30+ name = addr->name->str;
31+ if (name[0] == '/') {
32+ ret = g_remove(name);
33+ if (ret == 0) {
34+ g_debug("%s: removing socket %s successful",
35+ G_STRLOC, name);
36+ } else {
37+ if (errno != EPERM && errno != EACCES)
38+ g_critical("%s: removing socket %s failed: %s (%d)",
39+ G_STRLOC, name, strerror(errno));
40+ }
41+ }
42+ }
43+#endif /* WIN32 */
44+
45 g_string_free(addr->name, TRUE);
46-
47 g_free(addr);
48 }
49
50
51=== modified file 'src/network-address.h'
52--- src/network-address.h 2010-04-06 14:26:51 +0000
53+++ src/network-address.h 2010-05-10 12:15:45 +0000
54@@ -63,8 +63,8 @@
55 } addr;
56
57 GString *name;
58-
59 network_socklen_t len;
60+ gboolean can_unlink_socket; /* set TRUE *only* after successful bind */
61 } network_address;
62
63 NETWORK_API network_address *network_address_new(void);
64
65=== modified file 'src/network-socket.c'
66--- src/network-socket.c 2010-05-03 14:26:32 +0000
67+++ src/network-socket.c 2010-05-10 12:15:45 +0000
68@@ -431,6 +431,7 @@
69 }
70 }
71
72+ con->dst->can_unlink_socket = TRUE;
73 return NETWORK_SOCKET_SUCCESS;
74 }
75
76
77=== modified file 'tests/unit/t_network_socket.c'
78--- tests/unit/t_network_socket.c 2010-04-07 12:44:32 +0000
79+++ tests/unit/t_network_socket.c 2010-05-10 12:15:45 +0000
80@@ -23,6 +23,12 @@
81 #include <string.h>
82 #include <errno.h>
83
84+#ifndef WIN32
85+#include <unistd.h>
86+#include <stdlib.h>
87+#include <fcntl.h>
88+#endif /* WIN32 */
89+
90 #include <glib.h>
91 #include <glib/gstdio.h> /* for g_unlink */
92
93@@ -31,6 +37,17 @@
94 #if GLIB_CHECK_VERSION(2, 16, 0)
95 #define C(x) x, sizeof(x) - 1
96
97+#ifndef WIN32
98+#define LOCAL_SOCK "/tmp/mysql-proxy-test.socket"
99+
100+typedef struct {
101+ char sockname[sizeof(LOCAL_SOCK) + 10];
102+} local_unix_t;
103+
104+static local_unix_t *pp = NULL;
105+static local_unix_t local_test_arg;
106+#endif /* WIN32 */
107+
108 void test_network_socket_new() {
109 network_socket *sock;
110
111@@ -295,6 +312,8 @@
112 network_socket_free(server);
113 }
114
115+#ifndef WIN32
116+
117 /**
118 * test if _is_local() works on unix-domain sockets
119 *
120@@ -314,6 +333,7 @@
121 c_sock = network_socket_new();
122 network_address_set_address(c_sock->dst, "/tmp/mysql-proxy-test.socket");
123
124+
125 /* hack together a network_socket_accept() which we don't have in this tree yet */
126 g_assert_cmpint(NETWORK_SOCKET_SUCCESS, ==, network_socket_bind(s_sock));
127
128@@ -331,6 +351,76 @@
129 g_unlink("/tmp/mysql-proxy-test.socket");
130 }
131
132+void t_network_localsocket_setup(local_unix_t *p) {
133+ g_assert(p != NULL);
134+ snprintf(p->sockname, sizeof(p->sockname), LOCAL_SOCK ".%d", (int)getpid());
135+ pp = p;
136+}
137+
138+void t_network_localsocket_teardown(local_unix_t *p) {
139+ g_assert(p != NULL);
140+ if (p->sockname[0] != '\0') {
141+ (void) g_unlink(p->sockname);
142+ p->sockname[0] = '\0';
143+ }
144+ pp = NULL;
145+}
146+
147+void exitfunc(int sig) {
148+ if (pp != NULL && pp->sockname[0] != '\0')
149+ (void) g_unlink(pp->sockname);
150+
151+ abort();
152+}
153+
154+/**
155+ * test if local sockets are removed at shutdown
156+ * this is an extension of _is_local_unix(), therefore looks much like it;
157+ * just in case, we leave all tests from that function in as well.
158+ */
159+void t_network_socket_rem_local_unix(local_unix_t *p) {
160+ network_socket *s_sock; /* the server side socket, listening for requests */
161+ network_socket *c_sock; /* the client side socket, that connects */
162+ network_socket *a_sock; /* the server side, accepted socket */
163+
164+ /*
165+ * if an assertion fails, we receive the ABORT signal. We need to
166+ * close the unix socket in that case too. The regular teardown function
167+ * is not called in this case, so we install our own handler.
168+ */
169+ signal(SIGABRT, exitfunc);
170+ g_test_bug("42220");
171+ g_log_set_always_fatal(G_LOG_FATAL_MASK); /* gtest modifies the fatal-mask */
172+
173+ s_sock = network_socket_new();
174+ network_address_set_address(s_sock->dst, p->sockname);
175+
176+ c_sock = network_socket_new();
177+ network_address_set_address(c_sock->dst, p->sockname);
178+
179+ g_assert_cmpint(NETWORK_SOCKET_SUCCESS, ==, network_socket_bind(s_sock));
180+
181+ g_assert_cmpint(g_access(p->sockname, 0), ==, 0);
182+
183+ g_assert_cmpint(NETWORK_SOCKET_SUCCESS, ==, network_socket_connect(c_sock));
184+
185+ a_sock = network_socket_accept(s_sock);
186+ g_assert(a_sock);
187+
188+ g_assert_cmpint(TRUE, ==, network_address_is_local(s_sock->dst, a_sock->dst));
189+
190+ network_socket_free(a_sock);
191+ g_assert_cmpint(g_access(p->sockname, 0), ==, 0);
192+ network_socket_free(c_sock);
193+ g_assert_cmpint(g_access(p->sockname, 0), ==, 0);
194+ network_socket_free(s_sock);
195+ g_assert_cmpint(g_access(p->sockname, 0), ==, -1);
196+
197+ /* re-establish default signal disposition */
198+ signal(SIGABRT, SIG_DFL);
199+}
200+
201+#endif /* WIN32 */
202
203 int main(int argc, char **argv) {
204 g_test_init(&argc, &argv, NULL);
205@@ -342,7 +432,14 @@
206 g_test_add_func("/core/network_queue_append", test_network_queue_append);
207 g_test_add_func("/core/network_queue_peek_string", test_network_queue_peek_string);
208 g_test_add_func("/core/network_queue_pop_string", test_network_queue_pop_string);
209- g_test_add_func("/core/network_socket_is_local_unix", t_network_socket_is_local_unix);
210+#ifndef WIN32
211+ g_test_add_func("/core/network_socket_is_local_unix",t_network_socket_is_local_unix);
212+
213+ g_test_add("/core/network_socket_rem_local_unix", local_unix_t,
214+ &local_test_arg,
215+ t_network_localsocket_setup, t_network_socket_rem_local_unix,
216+ t_network_localsocket_teardown);
217+#endif /* WIN32 */
218 #if 0
219 /**
220 * disabled for now until we fixed the _to_read() on HP/UX and AIX (and MacOS X)
221@@ -354,8 +451,8 @@
222
223 return g_test_run();
224 }
225-#else
226+#else /* GLIB_CHECK_VERSION */
227 int main() {
228 return 77;
229 }
230-#endif
231+#endif /* GLIB_CHECK_VERSION */

Subscribers

People subscribed via source and target branches