1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23#ifdef NETWARE /* Novell NetWare */ 24 25#include <stdlib.h> 26 27#ifdef __NOVELL_LIBC__ 28/* For native LibC-based NLM we need to register as a real lib. */ 29#include <errno.h> 30#include <string.h> 31#include <library.h> 32#include <netware.h> 33#include <screen.h> 34#include <nks/thread.h> 35#include <nks/synch.h> 36 37 38typedef struct 39{ 40 int _errno; 41 void *twentybytes; 42} libthreaddata_t; 43 44typedef struct 45{ 46 int x; 47 int y; 48 int z; 49 void *tenbytes; 50 NXKey_t perthreadkey; /* if -1, no key obtained... */ 51 NXMutex_t *lock; 52} libdata_t; 53 54int gLibId = -1; 55void *gLibHandle = (void *) NULL; 56rtag_t gAllocTag = (rtag_t) NULL; 57NXMutex_t *gLibLock = (NXMutex_t *) NULL; 58 59/* internal library function prototypes... */ 60int DisposeLibraryData ( void * ); 61void DisposeThreadData ( void * ); 62int GetOrSetUpData ( int id, libdata_t **data, libthreaddata_t **threaddata ); 63 64 65int _NonAppStart( void *NLMHandle, 66 void *errorScreen, 67 const char *cmdLine, 68 const char *loadDirPath, 69 size_t uninitializedDataLength, 70 void *NLMFileHandle, 71 int (*readRoutineP)( int conn, 72 void *fileHandle, size_t offset, 73 size_t nbytes, 74 size_t *bytesRead, 75 void *buffer ), 76 size_t customDataOffset, 77 size_t customDataSize, 78 int messageCount, 79 const char **messages ) 80{ 81 NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0); 82 83#ifndef __GNUC__ 84#pragma unused(cmdLine) 85#pragma unused(loadDirPath) 86#pragma unused(uninitializedDataLength) 87#pragma unused(NLMFileHandle) 88#pragma unused(readRoutineP) 89#pragma unused(customDataOffset) 90#pragma unused(customDataSize) 91#pragma unused(messageCount) 92#pragma unused(messages) 93#endif 94 95/* 96** Here we process our command line, post errors (to the error screen), 97** perform initializations and anything else we need to do before being able 98** to accept calls into us. If we succeed, we return non-zero and the NetWare 99** Loader will leave us up, otherwise we fail to load and get dumped. 100*/ 101 gAllocTag = AllocateResourceTag(NLMHandle, 102 "<library-name> memory allocations", 103 AllocSignature); 104 105 if(!gAllocTag) { 106 OutputToScreen(errorScreen, "Unable to allocate resource tag for " 107 "library memory allocations.\n"); 108 return -1; 109 } 110 111 gLibId = register_library(DisposeLibraryData); 112 113 if(gLibId < -1) { 114 OutputToScreen(errorScreen, "Unable to register library with kernel.\n"); 115 return -1; 116 } 117 118 gLibHandle = NLMHandle; 119 120 gLibLock = NXMutexAlloc(0, 0, &liblock); 121 122 if(!gLibLock) { 123 OutputToScreen(errorScreen, "Unable to allocate library data lock.\n"); 124 return -1; 125 } 126 127 return 0; 128} 129 130/* 131** Here we clean up any resources we allocated. Resource tags is a big part 132** of what we created, but NetWare doesn't ask us to free those. 133*/ 134void _NonAppStop( void ) 135{ 136 (void) unregister_library(gLibId); 137 NXMutexFree(gLibLock); 138} 139 140/* 141** This function cannot be the first in the file for if the file is linked 142** first, then the check-unload function's offset will be nlmname.nlm+0 143** which is how to tell that there isn't one. When the check function is 144** first in the linked objects, it is ambiguous. For this reason, we will 145** put it inside this file after the stop function. 146** 147** Here we check to see if it's alright to ourselves to be unloaded. If not, 148** we return a non-zero value. Right now, there isn't any reason not to allow 149** it. 150*/ 151int _NonAppCheckUnload( void ) 152{ 153 return 0; 154} 155 156int GetOrSetUpData(int id, libdata_t **appData, 157 libthreaddata_t **threadData ) 158{ 159 int err; 160 libdata_t *app_data; 161 libthreaddata_t *thread_data; 162 NXKey_t key; 163 NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0); 164 165 err = 0; 166 thread_data = (libthreaddata_t *) NULL; 167 168/* 169** Attempt to get our data for the application calling us. This is where we 170** store whatever application-specific information we need to carry in support 171** of calling applications. 172*/ 173 app_data = (libdata_t *) get_app_data(id); 174 175 if(!app_data) { 176/* 177** This application hasn't called us before; set up application AND per-thread 178** data. Of course, just in case a thread from this same application is calling 179** us simultaneously, we better lock our application data-creation mutex. We 180** also need to recheck for data after we acquire the lock because WE might be 181** that other thread that was too late to create the data and the first thread 182** in will have created it. 183*/ 184 NXLock(gLibLock); 185 186 if(!(app_data = (libdata_t *) get_app_data(id))) { 187 app_data = malloc(sizeof(libdata_t)); 188 189 if(app_data) { 190 memset(app_data, 0, sizeof(libdata_t)); 191 192 app_data->tenbytes = malloc(10); 193 app_data->lock = NXMutexAlloc(0, 0, &liblock); 194 195 if(!app_data->tenbytes || !app_data->lock) { 196 if(app_data->lock) 197 NXMutexFree(app_data->lock); 198 199 free(app_data); 200 app_data = (libdata_t *) NULL; 201 err = ENOMEM; 202 } 203 204 if(app_data) { 205/* 206** Here we burn in the application data that we were trying to get by calling 207** get_app_data(). Next time we call the first function, we'll get this data 208** we're just now setting. We also go on here to establish the per-thread data 209** for the calling thread, something we'll have to do on each application 210** thread the first time it calls us. 211*/ 212 err = set_app_data(gLibId, app_data); 213 214 if(err) { 215 free(app_data); 216 app_data = (libdata_t *) NULL; 217 err = ENOMEM; 218 } 219 else { 220 /* create key for thread-specific data... */ 221 err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key); 222 223 if(err) /* (no more keys left?) */ 224 key = -1; 225 226 app_data->perthreadkey = key; 227 } 228 } 229 } 230 } 231 232 NXUnlock(gLibLock); 233 } 234 235 if(app_data) { 236 key = app_data->perthreadkey; 237 238 if(key != -1 /* couldn't create a key? no thread data */ 239 && !(err = NXKeyGetValue(key, (void **) &thread_data)) 240 && !thread_data) { 241/* 242** Allocate the per-thread data for the calling thread. Regardless of whether 243** there was already application data or not, this may be the first call by a 244** a new thread. The fact that we allocation 20 bytes on a pointer is not very 245** important, this just helps to demonstrate that we can have arbitrarily 246** complex per-thread data. 247*/ 248 thread_data = malloc(sizeof(libthreaddata_t)); 249 250 if(thread_data) { 251 thread_data->_errno = 0; 252 thread_data->twentybytes = malloc(20); 253 254 if(!thread_data->twentybytes) { 255 free(thread_data); 256 thread_data = (libthreaddata_t *) NULL; 257 err = ENOMEM; 258 } 259 260 if((err = NXKeySetValue(key, thread_data))) { 261 free(thread_data->twentybytes); 262 free(thread_data); 263 thread_data = (libthreaddata_t *) NULL; 264 } 265 } 266 } 267 } 268 269 if(appData) 270 *appData = app_data; 271 272 if(threadData) 273 *threadData = thread_data; 274 275 return err; 276} 277 278int DisposeLibraryData( void *data ) 279{ 280 if(data) { 281 void *tenbytes = ((libdata_t *) data)->tenbytes; 282 283 if(tenbytes) 284 free(tenbytes); 285 286 free(data); 287 } 288 289 return 0; 290} 291 292void DisposeThreadData( void *data ) 293{ 294 if(data) { 295 void *twentybytes = ((libthreaddata_t *) data)->twentybytes; 296 297 if(twentybytes) 298 free(twentybytes); 299 300 free(data); 301 } 302} 303 304#else /* __NOVELL_LIBC__ */ 305/* For native CLib-based NLM seems we can do a bit more simple. */ 306#include <nwthread.h> 307 308int main ( void ) 309{ 310 /* initialize any globals here... */ 311 312 /* do this if any global initializing was done 313 SynchronizeStart(); 314 */ 315 ExitThread (TSR_THREAD, 0); 316 return 0; 317} 318 319#endif /* __NOVELL_LIBC__ */ 320 321#else /* NETWARE */ 322 323#ifdef __POCC__ 324# pragma warn(disable:2024) /* Disable warning #2024: Empty input file */ 325#endif 326 327#endif /* NETWARE */ 328