2 * The contents of this file are subject to the Mozilla Public
3 * License Version 1.1 (the "License"); you may not use this file
4 * except in compliance with the License. You may obtain a copy of
5 * the License at http://www.mozilla.org/MPL/
7 * Software distributed under the License is distributed on an "AS
8 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
9 * implied. See the License for the specific language governing
10 * rights and limitations under the License.
12 * The Original Code is the Netscape security libraries.
14 * The Initial Developer of the Original Code is Netscape
15 * Communications Corporation. Portions created by Netscape are
16 * Copyright (C) 1994-2000 Netscape Communications Corporation. All
21 * Alternatively, the contents of this file may be used under the
22 * terms of the GNU General Public License Version 2 or later (the
23 * "GPL"), in which case the provisions of the GPL are applicable
24 * instead of those above. If you wish to allow use of your
25 * version of this file only under the terms of the GPL and not to
26 * allow others to use your version of this file under the MPL,
27 * indicate your decision by deleting the provisions above and
28 * replace them with the notice and other provisions required by
29 * the GPL. If you do not delete the provisions above, a recipient
30 * may use your version of this file under either the MPL or the
35 * secport.c - portability interfaces for security libraries
37 * This file abstracts out libc functionality that libsec depends on
39 * NOTE - These are not public interfaces
41 * $Id: secport.c,v 1.5 2004/10/27 20:36:36 dmitch Exp $
61 #endif /* THREADMARK */
63 #if defined(XP_UNIX) || defined(XP_MAC) || defined(XP_OS2) || defined(XP_BEOS)
69 #define SET_ERROR_CODE /* place holder for code to set PR error code. */
72 typedef struct threadmark_mark_str
{
73 struct threadmark_mark_str
*next
;
77 #endif /* THREADMARK */
79 /* The value of this magic must change each time PORTArenaPool changes. */
80 #define ARENAPOOL_MAGIC 0xB8AC9BDF
82 /* enable/disable mutex in PORTArenaPool */
83 #define ARENA_POOL_LOCK 0
85 typedef struct PORTArenaPool_str
{
92 PRThread
*marking_thread
;
93 threadmark_mark
*first_mark
;
98 /* count of allocation failures. */
99 unsigned long port_allocFailures
;
102 /* locations for registering Unicode conversion functions.
103 * XXX is this the appropriate location? or should they be
104 * moved to client/server specific locations?
106 PORTCharConversionFunc ucs4Utf8ConvertFunc
;
107 PORTCharConversionFunc ucs2Utf8ConvertFunc
;
108 PORTCharConversionWSwapFunc ucs2AsciiConvertFunc
;
109 #endif /* __APPLE__ */
112 PORT_Alloc(size_t bytes
)
116 /* Always allocate a non-zero amount of bytes */
117 rv
= (void *)PR_Malloc(bytes
? bytes
: 1);
119 ++port_allocFailures
;
120 PORT_SetError(SEC_ERROR_NO_MEMORY
);
126 PORT_Realloc(void *oldptr
, size_t bytes
)
130 rv
= (void *)PR_Realloc(oldptr
, bytes
);
132 ++port_allocFailures
;
133 PORT_SetError(SEC_ERROR_NO_MEMORY
);
139 PORT_ZAlloc(size_t bytes
)
143 /* Always allocate a non-zero amount of bytes */
144 rv
= (void *)PR_Calloc(1, bytes
? bytes
: 1);
146 ++port_allocFailures
;
147 PORT_SetError(SEC_ERROR_NO_MEMORY
);
161 PORT_ZFree(void *ptr
, size_t len
)
170 PORT_Strdup(const char *str
)
172 size_t len
= PORT_Strlen(str
)+1;
175 newstr
= (char *)PORT_Alloc(len
);
177 PORT_Memcpy(newstr
, str
, len
);
183 PORT_SetError(int value
)
185 PR_SetError(value
, 0);
192 return(PR_GetError());
195 /********************* Arena code follows *****************************/
198 PORT_NewArena(unsigned long chunksize
)
202 /* 64 bits cast: Safe. We only use chunksize 1024. */
203 PORT_Assert(chunksize
<=PR_UINT32_MAX
);
205 pool
= PORT_ZNew(PORTArenaPool
);
209 pool
->magic
= ARENAPOOL_MAGIC
;
211 pool
->lock
= PZ_NewLock(nssILockArena
);
213 ++port_allocFailures
;
218 PL_InitArenaPool(&pool
->arena
, "security", (PRUint32
) chunksize
, (PRUint32
)sizeof(double));
219 return(&pool
->arena
);
223 PORT_ArenaAlloc(PLArenaPool
*arena
, size_t size
)
227 PORTArenaPool
*pool
= (PORTArenaPool
*)arena
;
229 PORT_Assert(size
<=PR_UINT32_MAX
);
231 /* Is it one of ours? Assume so and check the magic */
232 if (ARENAPOOL_MAGIC
== pool
->magic
) {
236 /* Most likely one of ours. Is there a thread id? */
237 if (pool
->marking_thread
&&
238 pool
->marking_thread
!= PR_GetCurrentThread() ) {
239 /* Another thread holds a mark in this arena */
240 PZ_Unlock(pool
->lock
);
241 PORT_SetError(SEC_ERROR_NO_MEMORY
);
245 #endif /* THREADMARK */
246 #endif /* ARENA_POOL_LOCK */
247 PL_ARENA_ALLOCATE(p
, arena
, (PRUint32
)size
);
249 PZ_Unlock(pool
->lock
);
252 PL_ARENA_ALLOCATE(p
, arena
, (PRUint32
)size
);
256 ++port_allocFailures
;
257 PORT_SetError(SEC_ERROR_NO_MEMORY
);
264 PORT_ArenaZAlloc(PLArenaPool
*arena
, size_t size
)
266 void *p
= PORT_ArenaAlloc(arena
, size
);
269 PORT_Memset(p
, 0, size
);
275 /* XXX - need to zeroize!! - jsw */
277 PORT_FreeArena(PLArenaPool
*arena
, PRBool zero
)
279 PORTArenaPool
*pool
= (PORTArenaPool
*)arena
;
281 PRLock
* lock
= (PRLock
*)0;
283 size_t len
= sizeof *arena
;
284 extern const PRVersionDescription
* libVersionPoint(void);
286 static const PRVersionDescription
* pvd
;
288 static PRBool doFreeArenaPool
= PR_FALSE
;
290 if (ARENAPOOL_MAGIC
== pool
->magic
) {
298 /* dmitch - not needed */
300 /* Each of NSPR's DLLs has a function libVersionPoint().
301 ** We could do a lot of extra work to be sure we're calling the
302 ** one in the DLL that holds PR_FreeArenaPool, but instead we
303 ** rely on the fact that ALL NSPR DLLs in the same directory
304 ** must be from the same release, and we call which ever one we get.
306 /* no need for thread protection here */
307 pvd
= libVersionPoint();
308 if ((pvd
->vMajor
> 4) ||
309 (pvd
->vMajor
== 4 && pvd
->vMinor
> 1) ||
310 (pvd
->vMajor
== 4 && pvd
->vMinor
== 1 && pvd
->vPatch
>= 1)) {
311 const char *ev
= PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
312 if (!ev
) doFreeArenaPool
= PR_TRUE
;
316 if (doFreeArenaPool
) {
317 PL_FreeArenaPool(arena
);
319 PL_FinishArenaPool(arena
);
324 PZ_DestroyLock(lock
);
327 PORT_ZFree(arena
, len
);
331 PORT_ArenaGrow(PLArenaPool
*arena
, void *ptr
, size_t oldsize
, size_t newsize
)
333 PORTArenaPool
*pool
= (PORTArenaPool
*)arena
;
334 PORT_Assert(newsize
>= oldsize
);
335 PORT_Assert(oldsize
<= PR_UINT32_MAX
);
336 PORT_Assert(newsize
<= PR_UINT32_MAX
);
338 if (ARENAPOOL_MAGIC
== pool
->magic
) {
342 /* Do we do a THREADMARK check here? */
343 PL_ARENA_GROW(ptr
, arena
, (PRUint32
)oldsize
, (PRUint32
)( newsize
- oldsize
) );
345 PZ_Unlock(pool
->lock
);
348 PL_ARENA_GROW(ptr
, arena
, (PRUint32
)oldsize
, (PRUint32
)( newsize
- oldsize
) );
355 PORT_ArenaMark(PLArenaPool
*arena
)
357 #if ARENA_MARK_ENABLE
360 PORTArenaPool
*pool
= (PORTArenaPool
*)arena
;
361 if (ARENAPOOL_MAGIC
== pool
->magic
) {
365 threadmark_mark
*tm
, **pw
;
366 PRThread
* currentThread
= PR_GetCurrentThread();
368 if (! pool
->marking_thread
) {
370 pool
->marking_thread
= currentThread
;
371 } else if (currentThread
!= pool
->marking_thread
) {
372 PZ_Unlock(pool
->lock
);
373 PORT_SetError(SEC_ERROR_NO_MEMORY
);
378 result
= PL_ARENA_MARK(arena
);
379 PL_ARENA_ALLOCATE(tm
, arena
, sizeof(threadmark_mark
));
381 PZ_Unlock(pool
->lock
);
382 PORT_SetError(SEC_ERROR_NO_MEMORY
);
387 tm
->next
= (threadmark_mark
*)NULL
;
389 pw
= &pool
->first_mark
;
396 #else /* THREADMARK */
397 result
= PL_ARENA_MARK(arena
);
398 #endif /* THREADMARK */
399 PZ_Unlock(pool
->lock
);
401 /* a "pure" NSPR arena */
402 result
= PL_ARENA_MARK(arena
);
406 /* Some code in libsecurity_smime really checks for a nonzero
407 * return here, so... */
413 PORT_ArenaRelease(PLArenaPool
*arena
, void *mark
)
415 #if ARENA_MARK_ENABLE
416 PORTArenaPool
*pool
= (PORTArenaPool
*)arena
;
417 if (ARENAPOOL_MAGIC
== pool
->magic
) {
421 threadmark_mark
**pw
, *tm
;
423 if (PR_GetCurrentThread() != pool
->marking_thread
) {
424 PZ_Unlock(pool
->lock
);
425 PORT_SetError(SEC_ERROR_NO_MEMORY
);
427 return /* no error indication available */ ;
430 pw
= &pool
->first_mark
;
431 while( *pw
&& (mark
!= (*pw
)->mark
) ) {
437 PZ_Unlock(pool
->lock
);
438 PORT_SetError(SEC_ERROR_NO_MEMORY
);
440 return /* no error indication available */ ;
444 *pw
= (threadmark_mark
*)NULL
;
446 PL_ARENA_RELEASE(arena
, mark
);
448 if (! pool
->first_mark
) {
449 pool
->marking_thread
= (PRThread
*)NULL
;
452 #else /* THREADMARK */
453 PL_ARENA_RELEASE(arena
, mark
);
454 #endif /* THREADMARK */
455 PZ_Unlock(pool
->lock
);
457 PL_ARENA_RELEASE(arena
, mark
);
459 #endif /* ARENA_MARK_ENABLE */
463 PORT_ArenaUnmark(PLArenaPool
*arena
, void *mark
)
465 #if ARENA_MARK_ENABLE
467 PORTArenaPool
*pool
= (PORTArenaPool
*)arena
;
468 if (ARENAPOOL_MAGIC
== pool
->magic
) {
469 threadmark_mark
**pw
, *tm
;
473 if (PR_GetCurrentThread() != pool
->marking_thread
) {
474 PZ_Unlock(pool
->lock
);
475 PORT_SetError(SEC_ERROR_NO_MEMORY
);
477 return /* no error indication available */ ;
480 pw
= &pool
->first_mark
;
481 while( ((threadmark_mark
*)NULL
!= *pw
) && (mark
!= (*pw
)->mark
) ) {
485 if ((threadmark_mark
*)NULL
== *pw
) {
487 PZ_Unlock(pool
->lock
);
488 PORT_SetError(SEC_ERROR_NO_MEMORY
);
490 return /* no error indication available */ ;
494 *pw
= (threadmark_mark
*)NULL
;
496 if (! pool
->first_mark
) {
497 pool
->marking_thread
= (PRThread
*)NULL
;
500 PZ_Unlock(pool
->lock
);
502 #endif /* THREADMARK */
503 #endif /* ARENA_MARK_ENABLE */
507 PORT_ArenaStrdup(PLArenaPool
*arena
, const char *str
) {
508 size_t len
= PORT_Strlen(str
)+1;
511 newstr
= (char*)PORT_ArenaAlloc(arena
,len
);
513 PORT_Memcpy(newstr
,str
,len
);
518 /********************** end of arena functions ***********************/
522 /****************** unicode conversion functions ***********************/
524 * NOTE: These conversion functions all assume that the multibyte
525 * characters are going to be in NETWORK BYTE ORDER, not host byte
526 * order. This is because the only time we deal with UCS-2 and UCS-4
527 * are when the data was received from or is going to be sent out
528 * over the wire (in, e.g. certificates).
532 PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc
)
534 ucs4Utf8ConvertFunc
= convFunc
;
538 PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc
)
540 ucs2AsciiConvertFunc
= convFunc
;
544 PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc
)
546 ucs2Utf8ConvertFunc
= convFunc
;
550 /* dmitch - not needed */
552 PORT_UCS4_UTF8Conversion(PRBool toUnicode
, unsigned char *inBuf
,
553 unsigned int inBufLen
, unsigned char *outBuf
,
554 unsigned int maxOutBufLen
, unsigned int *outBufLen
)
556 if(!ucs4Utf8ConvertFunc
) {
557 return sec_port_ucs4_utf8_conversion_function(toUnicode
,
558 inBuf
, inBufLen
, outBuf
, maxOutBufLen
, outBufLen
);
561 return (*ucs4Utf8ConvertFunc
)(toUnicode
, inBuf
, inBufLen
, outBuf
,
562 maxOutBufLen
, outBufLen
);
566 PORT_UCS2_UTF8Conversion(PRBool toUnicode
, unsigned char *inBuf
,
567 unsigned int inBufLen
, unsigned char *outBuf
,
568 unsigned int maxOutBufLen
, unsigned int *outBufLen
)
570 if(!ucs2Utf8ConvertFunc
) {
571 return sec_port_ucs2_utf8_conversion_function(toUnicode
,
572 inBuf
, inBufLen
, outBuf
, maxOutBufLen
, outBufLen
);
575 return (*ucs2Utf8ConvertFunc
)(toUnicode
, inBuf
, inBufLen
, outBuf
,
576 maxOutBufLen
, outBufLen
);
578 //#endif /* __APPLE__ */
581 PORT_UCS2_ASCIIConversion(PRBool toUnicode
, unsigned char *inBuf
,
582 unsigned int inBufLen
, unsigned char *outBuf
,
583 unsigned int maxOutBufLen
, unsigned int *outBufLen
,
586 if(!ucs2AsciiConvertFunc
) {
590 return (*ucs2AsciiConvertFunc
)(toUnicode
, inBuf
, inBufLen
, outBuf
,
591 maxOutBufLen
, outBufLen
, swapBytes
);
595 /* Portable putenv. Creates/replaces an environment variable of the form
596 * envVarName=envValue
599 NSS_PutEnv(const char * envVarName
, const char * envValue
)
601 #if defined(XP_MAC) || defined(_WIN32_WCE)
604 SECStatus result
= SECSuccess
;
610 setOK
= SetEnvironmentVariable(envVarName
, envValue
);
617 encoded
= (char *)PORT_ZAlloc(strlen(envVarName
) + 2 + strlen(envValue
));
618 strcpy(encoded
, envVarName
);
619 strcat(encoded
, "=");
620 strcat(encoded
, envValue
);
622 putEnvFailed
= putenv(encoded
); /* adopt. */
631 #endif /* __APPLE__ */