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