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