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