1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2016, 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 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 39typedef struct 40{ 41 int _errno; 42 void *twentybytes; 43} libthreaddata_t; 44 45typedef 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 55int gLibId = -1; 56void *gLibHandle = (void *) NULL; 57rtag_t gAllocTag = (rtag_t) NULL; 58NXMutex_t *gLibLock = (NXMutex_t *) NULL; 59 60/* internal library function prototypes... */ 61int DisposeLibraryData(void *); 62void DisposeThreadData(void *); 63int GetOrSetUpData(int id, libdata_t **data, libthreaddata_t **threaddata); 64 65 66int _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 */ 135void _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 */ 152int _NonAppCheckUnload(void) 153{ 154 return 0; 155} 156 157int 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 280int 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 292void 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 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