This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH v5] Make bindresvport() function to multithread-safe
- From: Peng Haitao <penght at cn dot fujitsu dot com>
- To: libc-alpha at sourceware dot org
- Date: Tue, 16 Oct 2012 17:06:54 +0800
- Subject: [PATCH v5] Make bindresvport() function to multithread-safe
bindresvport() uses a static variable port which is not protected.
It is not safe when in multithread circumstance.
bindresvport() select a port number from the range 512 to 1023, when in
multithread circumstance, the port may be 1024. So the static variable
should add __thread.
Signed-off-by: Peng Haitao <penght@cn.fujitsu.com>
---
ChangeLog | 7 +++
sunrpc/bindrsvprt.c | 3 +-
sysdeps/unix/sysv/linux/bindrsvprt.c | 86 ++++++++++++++++++++++++++++++++++++
sysdeps/unix/sysv/linux/bindrsvprt.h | 33 ++++++++++++++
4 files changed, 128 insertions(+), 1 deletion(-)
create mode 100644 sysdeps/unix/sysv/linux/bindrsvprt.c
create mode 100644 sysdeps/unix/sysv/linux/bindrsvprt.h
diff --git a/ChangeLog b/ChangeLog
index 8e83c46..d0619ed 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2012-10-16 Peng Haitao <penght@cn.fujitsu.com>
+
+ [BZ #13763]
+ * sysdeps/unix/sysv/linux/bindrsvprt.h: New file.
+ * sysdeps/unix/sysv/linux/bindrsvprt.c: New file.
+ * sunrpc/bindrsvprt.c: Add __thread when define static's port.
+
2012-10-16 Florian Weimer <fweimer@redhat.com>
[BZ #14700]
diff --git a/sunrpc/bindrsvprt.c b/sunrpc/bindrsvprt.c
index d493c9f..4cc9004 100644
--- a/sunrpc/bindrsvprt.c
+++ b/sunrpc/bindrsvprt.c
@@ -1,5 +1,6 @@
/*
* Copyright (c) 2010, Oracle America, Inc.
+ * Copyright (C) 2012 Free Software Foundation, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
@@ -42,7 +43,7 @@
int
bindresvport (int sd, struct sockaddr_in *sin)
{
- static short port;
+ static __thread short port;
struct sockaddr_in myaddr;
int i;
diff --git a/sysdeps/unix/sysv/linux/bindrsvprt.c b/sysdeps/unix/sysv/linux/bindrsvprt.c
new file mode 100644
index 0000000..2ead49f
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bindrsvprt.c
@@ -0,0 +1,86 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <bindrsvprt.h>
+
+/*
+ * Bind a socket to a privileged IP port
+ */
+int
+bindresvport (int sd, struct sockaddr_in *sin)
+{
+ static __thread short port;
+ struct sockaddr_in myaddr;
+ int i;
+
+#define STARTPORT 600
+#define LOWPORT 512
+#define ENDPORT (IPPORT_RESERVED - 1)
+#define NPORTS (ENDPORT - STARTPORT + 1)
+ static short startport = STARTPORT;
+
+ if (sin == (struct sockaddr_in *) 0)
+ {
+ sin = &myaddr;
+ __bzero (sin, sizeof (*sin));
+ sin->sin_family = AF_INET;
+ }
+ else if (sin->sin_family != AF_INET)
+ {
+ __set_errno (EAFNOSUPPORT);
+ return -1;
+ }
+
+ if (port == 0)
+ {
+ port = ( __get_unique_id () % NPORTS) + STARTPORT;
+ }
+
+ /* Initialize to make gcc happy. */
+ int res = -1;
+
+ int nports = ENDPORT - startport + 1;
+ int endport = ENDPORT;
+ again:
+ for (i = 0; i < nports; ++i)
+ {
+ sin->sin_port = htons (port++);
+ if (port > endport)
+ port = startport;
+ res = __bind (sd, sin, sizeof (struct sockaddr_in));
+ if (res >= 0 || errno != EADDRINUSE)
+ break;
+ }
+
+ if (i == nports && startport != LOWPORT)
+ {
+ startport = LOWPORT;
+ endport = STARTPORT - 1;
+ nports = STARTPORT - LOWPORT;
+ port = LOWPORT + port % (STARTPORT - LOWPORT);
+ goto again;
+ }
+
+ return res;
+}
+libc_hidden_def (bindresvport)
diff --git a/sysdeps/unix/sysv/linux/bindrsvprt.h b/sysdeps/unix/sysv/linux/bindrsvprt.h
new file mode 100644
index 0000000..2295236
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/bindrsvprt.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2012 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#ifdef INTERNAL_SYSCALL
+#define __get_unique_id() \
+ ({ \
+ INTERNAL_SYSCALL_DECL (err); \
+ short __port; \
+ __port = INTERNAL_SYSCALL (gettid, err, 0); \
+ __port; \
+ })
+#else
+#define __get_unique_id() \
+ ({ \
+ short __port; \
+ __port = INLINE_SYSCALL (gettid, 0); \
+ __port; \
+ })
+#endif /* INTERNAL_SYSCALL */
--
1.7.11.4