1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2018, 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 app_data = (libdata_t *) get_app_data(id); 188 if(!app_data) { 189 app_data = calloc(1, sizeof(libdata_t)); 190 191 if(app_data) { 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 free(app_data->tenbytes); 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 207 * by calling get_app_data(). Next time we call the first function, 208 * we'll get this data we're just now setting. We also go on here to 209 * establish the per-thread data for the calling thread, something 210 * we'll have to do on each application thread the first time 211 * it calls us. 212 */ 213 err = set_app_data(gLibId, app_data); 214 215 if(err) { 216 if(app_data->lock) 217 NXMutexFree(app_data->lock); 218 free(app_data->tenbytes); 219 free(app_data); 220 app_data = (libdata_t *) NULL; 221 err = ENOMEM; 222 } 223 else { 224 /* create key for thread-specific data... */ 225 err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key); 226 227 if(err) /* (no more keys left?) */ 228 key = -1; 229 230 app_data->perthreadkey = key; 231 } 232 } 233 } 234 } 235 236 NXUnlock(gLibLock); 237 } 238 239 if(app_data) { 240 key = app_data->perthreadkey; 241 242 if(key != -1 /* couldn't create a key? no thread data */ 243 && !(err = NXKeyGetValue(key, (void **) &thread_data)) 244 && !thread_data) { 245 /* 246 * Allocate the per-thread data for the calling thread. Regardless of 247 * whether there was already application data or not, this may be the 248 * first call by a new thread. The fact that we allocation 20 bytes on 249 * a pointer is not very important, this just helps to demonstrate that 250 * we can have arbitrarily complex per-thread data. 251 */ 252 thread_data = malloc(sizeof(libthreaddata_t)); 253 254 if(thread_data) { 255 thread_data->_errno = 0; 256 thread_data->twentybytes = malloc(20); 257 258 if(!thread_data->twentybytes) { 259 free(thread_data); 260 thread_data = (libthreaddata_t *) NULL; 261 err = ENOMEM; 262 } 263 264 err = NXKeySetValue(key, thread_data); 265 if(err) { 266 free(thread_data->twentybytes); 267 free(thread_data); 268 thread_data = (libthreaddata_t *) NULL; 269 } 270 } 271 } 272 } 273 274 if(appData) 275 *appData = app_data; 276 277 if(threadData) 278 *threadData = thread_data; 279 280 return err; 281 } 282 283 int DisposeLibraryData(void *data) 284 { 285 if(data) { 286 void *tenbytes = ((libdata_t *) data)->tenbytes; 287 288 free(tenbytes); 289 free(data); 290 } 291 292 return 0; 293 } 294 295 void DisposeThreadData(void *data) 296 { 297 if(data) { 298 void *twentybytes = ((libthreaddata_t *) data)->twentybytes; 299 300 free(twentybytes); 301 free(data); 302 } 303 } 304 305 #else /* __NOVELL_LIBC__ */ 306 /* For native CLib-based NLM seems we can do a bit more simple. */ 307 #include <nwthread.h> 308 309 int main(void) 310 { 311 /* initialize any globals here... */ 312 313 /* do this if any global initializing was done 314 SynchronizeStart(); 315 */ 316 ExitThread(TSR_THREAD, 0); 317 return 0; 318 } 319 320 #endif /* __NOVELL_LIBC__ */ 321 322 #else /* NETWARE */ 323 324 #ifdef __POCC__ 325 # pragma warn(disable:2024) /* Disable warning #2024: Empty input file */ 326 #endif 327 328 #endif /* NETWARE */ 329