Reading files from an extension

I inheirited an a Lotus Notes extension app, written with the C API. Overly simplistic configuration, and a little less stability and functionality that the users wanted, but it mostly worked.

So I’m updating the application. The big change is the configuration - before it was two NOTES.INI variables; now I want to move it to an independent configuration file.

The configuration code works just fine on its own. I plug the new config code in, and the Domino server crashes. This is not good, and it’s early enough in the process that I’m completely clueless as to what’s wrong.

Here’s the psuedo-code:

if not launched by nserver.exe, return

do

get location of config file

load config file

fopen file

parse file

while !configLoaded

=========

There’s other stuff, but it crashes here.

Any clues?

Subject: Reading files from an extension

do you really think, that someone could find a bug? in your pseudo-code:)

be more specific, so you might get an answer.

how does it crash?

in which line?

what’s involved within this line (variables, values, calls)?

post relevant code snippets.

does the configuration take that much lines (you said there are two)? i thing for extmgrs notes.ini is the right place for configuration-settings…

have you tried to debug it?

and: what’s that funny loop around loading configuration? such loop should be avoided. try to use synchronization stuff (waitforsingleobject or whatever its called). remember that once within your extmgr, domino does only resume startup if you leave MainEntryPoint…

Markus Seitz

markus.seitz@icodex.com

Subject: RE: Reading files from an extension

Re: p-codeWell, I was hoping - the crash is so dramatic that I figure it has to be something basic. The crash is reported by NSD, which dumps a boatload of what I’m sure would be highly useful information - IF I actually understood/could translate even a 1/3 of the stuff in there.

Re: configuration stuff

  1. The code has to run on both Wintel and *nix, so I’m trying to avoid the sychronization functions since they’re very platform specific. I may not have a choice here though.

  2. The entire purpose of this exercise is to move the configuration out of Notes.ini. In fact, it’s an actual requirement. And no, I can’t get it changed.

Re: Debugging

Oh yeah. Unhappily, I’m lacking a development environment on the test machine, so I’m reduced to console printfs. So the best I can tell you is that the code bombs somewhere after the first printf (in the config loop), and before the second printf marking the loop exit. The code all seems innocuous to me, but I’m obviously missing something. I’ll see what I can do about code snippets.

Re: Resume

Hmm… does that mean that if I want to place an extension “on hold” (using an infiloop, for instance) that the entire server start-up freezes?

Subject: RE: Reading files from an extension

you don’t need a development environment, if you take some time you can try to setup remote debugging.

if you like you can send me the nsd-file and code-snippets by mail, i’ll have a look.

nsd really contains valueable information, most valueable for the lucky ones that have the source:) but there’s still a lot that us others can benefit from, e.g. you can even tell which database was involved (if so) in a crash, what dll(lib) or exe crash appeared…

extmgrs are loaded on a per-process basis, you figured out yet how to skip other tasks, but there are still many threads within a single process (e.g. one thread for each user session on server). this thread’s locked if you don’t return.

mainentrypoint, where you do your config stuff, is called for server/client process at startup, so server won’t continue launching.

p.s: you can use sleep (unix?) / Sleep (win32) instead of busy waiting…

Markus Seitz

markus.seitz@icodex.com

Subject: RE: Reading files from an extension

Well, I can’t get you the NSD (various reasons, don’t ask). But I can give you code snippets. I’ve stripped variable declaration, initialization, and error handling for brevity’s sake.

here’s the config loop code snippet:


do

{

memset(g_configFilePath, 0, sizeof(g_configFilePath));

if ( OSGetEnvironmentString(g_configFileVariable, strPath, MAX_PATH-1) != FALSE )

{

strncpy(g_configFilePath, strPath, strlen(strPath));

}

else

{

strncpy(g_configFilePath, g_defaultConfigFile, strlen(g_defaultConfigFile));

}

configLoaded = loadConfigFile(g_configFilePath, &g_configuration);

/* DEBUG PRINTF #1 HERE */

if ( !configLoaded )

{

_sleep(g_initialConfigWait);

}

}while (!configLoaded);

/* DEBUG PRINTF #2 HERE; never reached */


And here’s loadConfigFile(filePath,config):

======================

if ( (configFile = fopen(filePath, “r”)) != NULL )

{

if ( scanForConfigSection(configFile, SECTION_HEADER) )

{

   tempConfig = (ConfigVariables_t *)calloc(1, sizeof(ConfigVariables_t));

   while ( !feof(configFile) )

   {

   fgets(line, LINE_LEN, configFile);

   whichKey = matchKeys(line, g_listOfConfigKeys);

   switch (whichKey):

   {

       /* Key handling stuff, assigning values of members of tempConfig. Some involve callocs. If we find at least one of every key, we're good to continue */

   }

   }

}

if ( success )

{

   if ( config != NULL )

   {

       destroyConfigVariables(config);

   }

   config = tempConfig;

} else {

   destroyConfigVariables(tempConfig);

}

}

=============================

As for remote debugging, I don’t think that’s doable - the test machines are on a separate, air-gapped, network from any machine with a dev environment.

Subject: RE: Reading files from an extension

hard to tell, that’s not too much information:)

when is success set?

if you don’t find any section in configfile your nevertheless calling destroyConfigVariables(tempConfig). don’t know what this does, but if you don’t set tempConfig initial to null and check in destroyConfigVariables, that’ll for shure crash.

but since i don’t know anything about that functions…

try to avoid treating strings as memory, that’s not neccessary (using memset,…).

if you’ve got a c++ compiler/linker (hope so), you should always use exception handling. that’ll not only work for c++ classes that raise exceptions, but also for things like using nullpointers, zero division. in your case a try/catch(…) around mainentrypoint & exthandler will at least avoid server-crash.

and have a look at nsd-report, search for fatal and tell me what are the last functions called and what lib/dll.

why don’t you try to debug that thing on your client? maybe you can setup config-file as it’s done on server?

Markus Seitz

markus.seitz@icodex.com

Subject: RE: Reading files from an extension

Sorry about the success return - it got elided when I abstracted the key/variable handling code. It’s in there. In fact, I’m almost certain the problem’s not in loadConfigFile(). I beat the stuffing out of that using CppUnit. (It’s always possible I missed a test case, of course.)

DestroyConfigVariables is a safe wrapper around a free. tempConfig is initializaed to NULL. At that point, it should be either NULL or valid. I’ll double-check.

The problem with using try/catch is that I’m trying not to mix the two languages (i.e. stay purely C).

Subject: RE: Reading files from an extension

I’m not sure whether to be annoyed or not.

Repeat after me: “Always check your assumptions.”

The problem was in the loadConfigFile() code. I had missed a test case. I inadvertently managed to dereference a point (god knows where) before the beginning of my buffer.

At this point the problem should be solved, but I have yet to confirm it through testing.

Thanks for your help.

Subject: Your loadConfigFile(filePath,config) does not return True or False, So loop never ends.

put at end: if ( success )

{

   if ( config != NULL )

   {

       destroyConfigVariables(config);

   }

   config = tempConfig;

} else {

   destroyConfigVariables(tempConfig);

}

loadConfigFile = success;