aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2015-07-13 14:53:30 +0000
committerChristian Grothoff <christian@grothoff.org>2015-07-13 14:53:30 +0000
commit3104aa430ae360599dd54369a8cb1fd61f07894c (patch)
tree6b8d87ddc782d50e51d1107bb13597218b5e9a1f /src
parent13a3089d561ed7332da25a7c461cdcc633c6b855 (diff)
downloadgnunet-3104aa430ae360599dd54369a8cb1fd61f07894c.tar.gz
gnunet-3104aa430ae360599dd54369a8cb1fd61f07894c.zip
automatically clean up left-over Unix domain socket files when trying to bind (fixes #3723)
Diffstat (limited to 'src')
-rw-r--r--src/arm/gnunet-service-arm.c25
-rw-r--r--src/include/gnunet_network_lib.h15
-rw-r--r--src/util/network.c58
3 files changed, 84 insertions, 14 deletions
diff --git a/src/arm/gnunet-service-arm.c b/src/arm/gnunet-service-arm.c
index 0dffafeeb..a411546d7 100644
--- a/src/arm/gnunet-service-arm.c
+++ b/src/arm/gnunet-service-arm.c
@@ -603,7 +603,8 @@ accept_connection (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
603 * @param sl service entry for the service in question 603 * @param sl service entry for the service in question
604 */ 604 */
605static void 605static void
606create_listen_socket (struct sockaddr *sa, socklen_t addr_len, 606create_listen_socket (struct sockaddr *sa,
607 socklen_t addr_len,
607 struct ServiceList *sl) 608 struct ServiceList *sl)
608{ 609{
609 static int on = 1; 610 static int on = 1;
@@ -652,14 +653,18 @@ create_listen_socket (struct sockaddr *sa, socklen_t addr_len,
652 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK, 653 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR | GNUNET_ERROR_TYPE_BULK,
653 "setsockopt"); 654 "setsockopt");
654#endif 655#endif
655 656#ifndef WINDOWS
657 if (AF_UNIX == sa->sa_family)
658 GNUNET_NETWORK_unix_precheck ((struct sockaddr_un *) sa);
659#endif
656 if (GNUNET_OK != 660 if (GNUNET_OK !=
657 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len)) 661 GNUNET_NETWORK_socket_bind (sock, (const struct sockaddr *) sa, addr_len))
658 { 662 {
659 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, 663 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
660 _ 664 _("Unable to bind listening socket for service `%s' to address `%s': %s\n"),
661 ("Unable to bind listening socket for service `%s' to address `%s': %s\n"), 665 sl->name,
662 sl->name, GNUNET_a2s (sa, addr_len), STRERROR (errno)); 666 GNUNET_a2s (sa, addr_len),
667 STRERROR (errno));
663 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock)); 668 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (sock));
664 GNUNET_free (sa); 669 GNUNET_free (sa);
665 return; 670 return;
@@ -1394,11 +1399,11 @@ setup_service (void *cls,
1394 "FORCESTART")) 1399 "FORCESTART"))
1395 { 1400 {
1396 sl->force_start = GNUNET_YES; 1401 sl->force_start = GNUNET_YES;
1397 /* FIXME: we might like the pre-binding even for 1402 if (GNUNET_YES ==
1398 _certain_ services that have force_start set, 1403 GNUNET_CONFIGURATION_get_value_yesno (cfg,
1399 otherwise interdependencies may again force 1404 section,
1400 client's to retry connections during startup. */ 1405 "NOARMBIND"))
1401 return; 1406 return;
1402 } 1407 }
1403 else 1408 else
1404 { 1409 {
diff --git a/src/include/gnunet_network_lib.h b/src/include/gnunet_network_lib.h
index f70509830..83d820a5b 100644
--- a/src/include/gnunet_network_lib.h
+++ b/src/include/gnunet_network_lib.h
@@ -106,6 +106,21 @@ char *
106GNUNET_NETWORK_shorten_unixpath (char *unixpath); 106GNUNET_NETWORK_shorten_unixpath (char *unixpath);
107 107
108 108
109#ifndef WINDOWS
110/**
111 * If services crash, they can leave a unix domain socket file on the
112 * disk. This needs to be manually removed, because otherwise both
113 * bind() and connect() for the respective address will fail. In this
114 * function, we test if such a left-over file exists, and if so,
115 * remove it (unless there is a listening service at the address).
116 *
117 * @param un unix domain socket address to check
118 */
119void
120GNUNET_NETWORK_unix_precheck (const struct sockaddr_un *un);
121#endif
122
123
109/** 124/**
110 * Accept a new connection on a socket. Configure it for non-blocking 125 * Accept a new connection on a socket. Configure it for non-blocking
111 * IO and mark it as non-inheritable to child processes (set the 126 * IO and mark it as non-inheritable to child processes (set the
diff --git a/src/util/network.c b/src/util/network.c
index d141732c2..489966426 100644
--- a/src/util/network.c
+++ b/src/util/network.c
@@ -147,6 +147,53 @@ GNUNET_NETWORK_shorten_unixpath (char *unixpath)
147} 147}
148 148
149 149
150#ifndef WINDOWS
151/**
152 * If services crash, they can leave a unix domain socket file on the
153 * disk. This needs to be manually removed, because otherwise both
154 * bind() and connect() for the respective address will fail. In this
155 * function, we test if such a left-over file exists, and if so,
156 * remove it (unless there is a listening service at the address).
157 *
158 * @param un unix domain socket address to check
159 */
160void
161GNUNET_NETWORK_unix_precheck (const struct sockaddr_un *un)
162{
163 int s;
164 int eno;
165 struct stat sbuf;
166 int ret;
167
168 s = socket (AF_UNIX, SOCK_STREAM, 0);
169 ret = connect (s,
170 (struct sockaddr *) un,
171 sizeof (struct sockaddr_un));
172 eno = errno;
173 GNUNET_break (0 == close (s));
174 if (0 == ret)
175 return; /* another process is listening, do not remove! */
176 if (ECONNREFUSED != eno)
177 return; /* some other error, likely "no such file or directory" -- all well */
178 /* should unlink, but sanity checks first */
179 if (0 != stat (un->sun_path,
180 &sbuf))
181 return; /* failed to 'stat', likely does not exist after all */
182 if (S_IFSOCK != (S_IFMT & sbuf.st_mode))
183 return; /* refuse to unlink anything except sockets */
184 /* finally, really unlink */
185 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
186 "Removing left-over `%s' from previous exeuction\n",
187 un->sun_path);
188 if (0 != unlink (un->sun_path))
189 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_WARNING,
190 "unlink",
191 un->sun_path);
192}
193#endif
194
195
196
150#ifndef FD_COPY 197#ifndef FD_COPY
151#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set))) 198#define FD_COPY(s, d) (memcpy ((d), (s), sizeof (fd_set)))
152#endif 199#endif
@@ -447,6 +494,8 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
447#endif 494#endif
448#endif 495#endif
449#ifndef WINDOWS 496#ifndef WINDOWS
497 if (AF_UNIX == address->sa_family)
498 GNUNET_NETWORK_unix_precheck ((const struct sockaddr_un *) address);
450 { 499 {
451 const int on = 1; 500 const int on = 1;
452 501
@@ -459,8 +508,6 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
459 LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG, 508 LOG_STRERROR (GNUNET_ERROR_TYPE_DEBUG,
460 "setsockopt"); 509 "setsockopt");
461 } 510 }
462#endif
463#ifndef WINDOWS
464 { 511 {
465 /* set permissions of newly created non-abstract UNIX domain socket to 512 /* set permissions of newly created non-abstract UNIX domain socket to
466 "user-only"; applications can choose to relax this later */ 513 "user-only"; applications can choose to relax this later */
@@ -476,7 +523,10 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
476 old_mask = umask (S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH | S_IXOTH); 523 old_mask = umask (S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IROTH | S_IXOTH);
477#endif 524#endif
478 525
479 ret = bind (desc->fd, address, address_len); 526 ret = bind (desc->fd,
527 address,
528 address_len);
529
480#ifndef WINDOWS 530#ifndef WINDOWS
481 if (not_abstract) 531 if (not_abstract)
482 (void) umask (old_mask); 532 (void) umask (old_mask);
@@ -486,7 +536,7 @@ GNUNET_NETWORK_socket_bind (struct GNUNET_NETWORK_Handle *desc,
486 if (SOCKET_ERROR == ret) 536 if (SOCKET_ERROR == ret)
487 SetErrnoFromWinsockError (WSAGetLastError ()); 537 SetErrnoFromWinsockError (WSAGetLastError ());
488#endif 538#endif
489 if (ret != 0) 539 if (0 != ret)
490 return GNUNET_SYSERR; 540 return GNUNET_SYSERR;
491#ifndef MINGW 541#ifndef MINGW
492 desc->addr = GNUNET_malloc (address_len); 542 desc->addr = GNUNET_malloc (address_len);