From 30debe533c0537e49febeefe135ea069d7fbe2f2 Mon Sep 17 00:00:00 2001 From: "nelsonb%netscape.com" Date: Fri, 8 Jun 2001 02:56:31 +0000 Subject: Portable POSIX-like unnamed semaphores that work in process-shared memory. --- security/nss/lib/ssl/sslmutex.c | 385 ++++++++++++++++++++++++++++++++++++++++ security/nss/lib/ssl/sslmutex.h | 101 +++++++++++ 2 files changed, 486 insertions(+) create mode 100644 security/nss/lib/ssl/sslmutex.c create mode 100644 security/nss/lib/ssl/sslmutex.h (limited to 'security') diff --git a/security/nss/lib/ssl/sslmutex.c b/security/nss/lib/ssl/sslmutex.c new file mode 100644 index 000000000..7c021ffd7 --- /dev/null +++ b/security/nss/lib/ssl/sslmutex.c @@ -0,0 +1,385 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2001 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ + +#include "sslmutex.h" +#include "prerr.h" + +#if defined(LINUX) || defined(AIX) + +#include +#include +#include +#include +#include "unix_err.h" + +#define SSL_MUTEX_MAGIC 0xfeedfd +#define NONBLOCKING_POSTS 1 /* maybe this is faster */ + +#if NONBLOCKING_POSTS + +#ifndef FNONBLOCK +#define FNONBLOCK O_NONBLOCK +#endif + +static int +setNonBlocking(int fd, int nonBlocking) +{ + int flags; + int err; + + flags = fcntl(fd, F_GETFL, 0); + if (0 > flags) + return flags; + if (nonBlocking) + flags |= FNONBLOCK; + else + flags &= ~FNONBLOCK; + err = fcntl(fd, F_SETFL, flags); + return err; +} +#endif + +SECStatus +sslMutex_Init(sslMutex *pMutex, int shared) +{ + int err; + int mPipes[3]; + char c = 1; + + memset(pMutex, -1, sizeof *pMutex); + err = pipe(mPipes); + if (err) { + return err; + } + /* close-on-exec is false by default */ + if (!shared) { + err = fcntl(mPipes[0], F_SETFD, FD_CLOEXEC); + if (err) + goto loser; + + err = fcntl(mPipes[1], F_SETFD, FD_CLOEXEC); + if (err) + goto loser; + } + +#if NONBLOCKING_POSTS + err = setNonBlocking(mPipes[1], 1); + if (err) + goto loser; +#endif + + + do { + err = write(mPipes[1], &c, 1); + } while (err < 0 && (errno == EINTR || errno == EAGAIN)); + if (0 > err) + goto loser; + + mPipes[2] = SSL_MUTEX_MAGIC; + + memcpy(pMutex, mPipes, sizeof mPipes); + return SECSuccess; + +loser: + nss_MD_unix_map_default_error(errno); + close(mPipes[0]); + close(mPipes[1]); + return SECFailure; +} + +SECStatus +sslMutex_Destroy(sslMutex *pMutex) +{ + int * mPipes = (int *)pMutex; + if (mPipes[2] != SSL_MUTEX_MAGIC) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + close(mPipes[0]); + close(mPipes[1]); + memset(pMutex, -1, sizeof *pMutex); + return SECSuccess; +} + +SECStatus +sslMutex_Unlock(sslMutex *pMutex) +{ + int * mPipes = (int *)pMutex; + int cc; + char c = 1; + + if (mPipes[2] != SSL_MUTEX_MAGIC) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + do { + cc = write(mPipes[1], &c, 1); + } while (cc < 0 && (errno == EINTR || errno == EAGAIN)); + if (cc == 1) + return SECSuccess; + if (cc < 0) + nss_MD_unix_map_default_error(errno); + else + PORT_SetError(PR_UNKNOWN_ERROR); + return SECFailure; +} + +SECStatus +sslMutex_Lock(sslMutex *pMutex) +{ + int * mPipes = (int *)pMutex; + int cc; + char c; + + if (mPipes[2] != SSL_MUTEX_MAGIC) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + do { + cc = read(mPipes[0], &c, 1); + } while (cc < 0 && errno == EINTR); + if (cc == 1) + return SECSuccess; + if (cc < 0) + nss_MD_unix_map_default_error(errno); + else + PORT_SetError(PR_UNKNOWN_ERROR); + return SECFailure; +} + +#elif defined(WIN32) + +#include "win32err.h" + +/* The presence of the TRUE element in this struct makes the semaphore + * inheritable. The NULL means use process's default security descriptor. + */ + +SECStatus +sslMutex_Init(sslMutex *pMutex, int shared) +{ + + HANDLE hMutex; + SECURITY_ATTRIBUTES attributes = + { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE }; + + PR_ASSERT(pMutex != 0 && (*pMutex == 0 || *pMutex == INVALID_HANDLE_VALUE)); + if (!pMutex || ((hMutex = *pMutex) != 0 && hMutex != INVALID_HANDLE_VALUE)) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + attributes.bInheritHandle = (shared ? TRUE : FALSE); + hMutex = CreateMutex(&attributes, FALSE, NULL); + if (hMutex == NULL) { + hMutex = INVALID_HANDLE_VALUE; + nss_MD_win32_map_default_error(GetLastError()); + return SECFailure; + } + *pMutex = hMutex; + return SECSuccess; +} + +int +sslMutex_Destroy(sslMutex *pMutex) +{ + HANDLE hMutex; + int rv; + + PR_ASSERT(pMutex != 0 && *pMutex != 0 && *pMutex != INVALID_HANDLE_VALUE); + if (!pMutex || (hMutex = *pMutex) == 0 || hMutex == INVALID_HANDLE_VALUE) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + rv = CloseHandle(hMutex); /* ignore error */ + if (rv) { + *pMutex = hMutex = INVALID_HANDLE_VALUE; + return SECSuccess; + } + nss_MD_win32_map_default_error(GetLastError()); + return SECFailure; +} + +int +sslMutex_Unlock(sslMutex *pMutex) +{ + BOOL success = FALSE; + HANDLE hMutex; + + PR_ASSERT(pMutex != 0 && *pMutex != 0 && *pMutex != INVALID_HANDLE_VALUE); + if (!pMutex || (hMutex = *pMutex) == 0 || hMutex == INVALID_HANDLE_VALUE) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + success = ReleaseMutex(hMutex); + if (!success) { + nss_MD_win32_map_default_error(GetLastError()); + return SECFailure; + } + return SECSuccess; +} + +int +sslMutex_Lock(sslMutex *pMutex) +{ + HANDLE hMutex; + DWORD event; + DWORD lastError; + SECStatus rv; + + PR_ASSERT(pMutex != 0 && *pMutex != 0 && *pMutex != INVALID_HANDLE_VALUE); + if (!pMutex || (hMutex = *pMutex) == 0 || hMutex == INVALID_HANDLE_VALUE) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; /* what else ? */ + } + event = WaitForSingleObject(hMutex, INFINITE); + switch (event) { + case WAIT_OBJECT_0: + case WAIT_ABANDONED: + rv = SECSuccess; + break; + + case WAIT_TIMEOUT: + case WAIT_IO_COMPLETION: + default: /* should never happen. nothing we can do. */ + PR_ASSERT(!("WaitForSingleObject returned invalid value.")); + PORT_SetError(PR_UNKNOWN_ERROR); + rv = SECFailure; + break; + + case WAIT_FAILED: /* failure returns this */ + rv = SECFailure; + lastError = GetLastError(); /* for debugging */ + nss_MD_win32_map_default_error(lastError); + break; + } + return rv; +} + +#elif defined(XP_UNIX) + +#include +#include "unix_err.h" + +SECStatus +sslMutex_Init(sslMutex *pMutex, int shared) +{ + int rv; + do { + rv = sem_init(pMutex, shared, 1); + } while (rv < 0 && errno == EINTR); + if (rv < 0) { + nss_MD_unix_map_default_error(errno); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +sslMutex_Destroy(sslMutex *pMutex) +{ + int rv; + do { + rv = sem_destroy(pMutex); + } while (rv < 0 && errno == EINTR); + if (rv < 0) { + nss_MD_unix_map_default_error(errno); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +sslMutex_Unlock(sslMutex *pMutex) +{ + int rv; + do { + rv = sem_post(pMutex); + } while (rv < 0 && errno == EINTR); + if (rv < 0) { + nss_MD_unix_map_default_error(errno); + return SECFailure; + } + return SECSuccess; +} + +SECStatus +sslMutex_Lock(sslMutex *pMutex) +{ + int rv; + do { + rv = sem_wait(pMutex); + } while (rv < 0 && errno == EINTR); + if (rv < 0) { + nss_MD_unix_map_default_error(errno); + return SECFailure; + } + return SECSuccess; +} + +#else + +SECStatus +sslMutex_Init(sslMutex *pMutex, int shared) +{ + PORT_Assert(!("sslMutex_Init not implemented!")); + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return SECFailure; +} + +SECStatus +sslMutex_Destroy(sslMutex *pMutex) +{ + PORT_Assert(!("sslMutex_Destroy not implemented!")); + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return SECFailure; +} + +SECStatus +sslMutex_Unlock(sslMutex *pMutex) +{ + PORT_Assert(!("sslMutex_Unlock not implemented!")); + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return SECFailure; +} + +SECStatus +sslMutex_Lock(sslMutex *pMutex) +{ + PORT_Assert(!("sslMutex_Lock not implemented!")); + PORT_SetError(PR_NOT_IMPLEMENTED_ERROR); + return SECFailure; +} + +#endif diff --git a/security/nss/lib/ssl/sslmutex.h b/security/nss/lib/ssl/sslmutex.h new file mode 100644 index 000000000..a02c48cf5 --- /dev/null +++ b/security/nss/lib/ssl/sslmutex.h @@ -0,0 +1,101 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (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.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 2001 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ +#ifndef __SSLMUTEX_H_ +#define __SSLMUTEX_H_ 1 + +/* What SSL really wants is portable process-shared unnamed mutexes in + * shared memory, that have the property that if the process that holds + * them dies, they are released automatically, and that (unlike fcntl + * record locking) lock to the thread, not to the process. + * NSPR doesn't provide that. + * Windows has mutexes that meet that description, but they're not portable. + * POSIX mutexes are not automatically released when the holder dies, + * and other processes/threads cannot release the mutex on behalf of the + * dead holder. + * POSIX semaphores can be used to accomplish this on systems that implement + * process-shared unnamed POSIX semaphores, because a watchdog thread can + * discover and release semaphores that were held by a dead process. + * On systems that do not support process-shared POSIX unnamed semaphores, + * they can be emulated using pipes. + * The performance cost of doing that is not yet measured. + * + * So, this API looks a lot like POSIX pthread mutexes. + */ + +#if defined(WIN32) + +#include +typedef HANDLE sslMutex; +typedef int sslPID; + +#elif defined(LINUX) || defined(AIX) + +#include + +typedef struct { int ps[3]; } sslMutex; +typedef pid_t sslPID; + +#elif defined(XP_UNIX) /* other types of Unix */ + +#include /* for pid_t */ +#include /* for sem_t, and sem_* functions */ + +typedef sem_t sslMutex; +typedef pid_t sslPID; + +#else + +/* what platform is this ?? */ + +typedef int sslMutex; +typedef int sslPID; + +#endif + +#include "seccomon.h" + +SEC_BEGIN_PROTOS + +extern SECStatus sslMutex_Init(sslMutex *sem, int shared); + +extern SECStatus sslMutex_Destroy(sslMutex *sem); + +extern SECStatus sslMutex_Unlock(sslMutex *sem); + +extern SECStatus sslMutex_Lock(sslMutex *sem); + +SEC_END_PROTOS + +#endif -- cgit v1.2.1