/* * 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