login database and alternate character search tool

Posted by Gohan_TheDragonball on Fri 27 Apr 2007 07:35 AM — 35 posts, 131,192 views.

USA #0
I recently uploaded my modified version of the LAST command from smaug. basically i created a login database, and then built a FINDALTS function into the last command which will perform a search for possible alternate characters of the specified character. For the search it queries logins based on the day of the login and the ip address used, any other character that logged into the mud on that same day with the same ip address is flagged as a possible alternate character. it then displays all the names of the alt chars, along with how many different ip addresses were matched and how many total matches were found in the database. i would love to hear any comments on it for future improvement.

http://www.mudbytes.net/index.php?a=files&s=viewfile&fid=942
USA #1
I tried to install this snippet a few days ago and ran into some problems, so consider my feedback at http://www.mudbytes.net/index.php?a=comments&s=viewcomments&cid=76&c=100#p100 in response to your request, if you would. :)

It really looks like a great snippet, but even trying to fix the points I'd posted so that it'd compile, got the mud to crash complete with core dump as soon as anyone (including my admin character) successfully logged in, so for now I've gone back to Xorath's do_last replacement, but if I could understand how to make yours work for me, I'd far prefer it.
USA #2
what was xorath's do_last replacement, never heard of it.
USA #3
He called it Login History, but basically it was a replacement for the do_last function that saves the logon data to last.lst just like yours does and lets you search that file in-game by number of logons, character name (with or with specified number of logons), or "today".

Since it doesn't appear to already be posted to MudBytes yet, I'll go ahead and submit a copy there so you can see it. (Sorry, but I don't recall any more which site I downloaded it from originally.)
USA #4
lol ok that is what i had to begin with, i thought it came with my code many many years ago, but maybe i got it from a snippet site. but then i went it and completely modified it, so this is basically an upgraded version of that code, hope ya likes it, hope to hear any comments good or bad.
USA #5
Ah, so it was the inspiration, can't say that I'm surprised, it's been a busier day than I would've liked and I have not ahd a chance to retry your update yet.

I was wondering if it still supported the "last <searchname?> <character> #" syntax?

I did notice that your supplied syntax and help don't seem to cover all the options, nor exactly match one another. :(
USA #6
hmm i didn't post the right helpfile, i two different helpfiles, one for lower admins and one for upper admins. as for the other two options in the code: last month and last countips, those options are not used, because they are incomplete, or just useless. here is the upper admin helpfile:

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

Syntax: last <player name>
This option allows for one to see the last login of a specific
player.

Syntax: last <number>
This option allows for one to input a range and view the last
number of logins chosen.

Syntax: last searchname <name>
This option allows one to view 50 of the players logins ending
with the most recent login found.

Syntax: last findalts <main character name>
This option allows one to view all possible alternate characters
of the main character specified.

Syntax: last fromip <IP address>
This option allows one to view 50 of the most recent logins
from the given IP address.

This option also has one extra feature, it in a sense allows for
a wildcard. Lets say for example you want to see all ips starting
with 24.21.*.*, you would simple type last fromip 24.21.

Note the period at the end of 24.21., this is because if you were
to leave it out, an ip address like 154.24.212.234 might show up.

=============================================================================
USA #7
In that last findip <ip> option, is there anyway to have it search by string instead of number?

Since my system's setup such that by the time the IP address is being passed to the last struct (which may well be the cause of my logon crashes before with it) it's already been resolved to a host/domain name rather than still being considered an IP...
USA #8
umm it already searches by string, as d->host is a string already, which is what the ip is. if your mud is crashin then post a dump and we'll see what the prob be.
USA #9
It did before you updated the snippet, I was going to try it again today, but the lawn apparently needed mowing more urgently... *shrug*
USA #10
oh you know i never did rename that variable that you said time.h was having trouble with, only because it has no problem compiling on my server, really no idea what it does on yours, unless of course you already had time defined as a variable, since you did have xoraths snippet installed its a possibility.
USA #11
That's a minor enough detail, especially if I know about it in advance. ;)
USA #12
Ok, got the new updated version installed and here are the fixes that were still needed to get GCC to compile it:

Compiling o/imc.o....
In file included from imc.c:42:
mud.h:4786: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘int’
mud.h:4787: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘int’
mud.h:4788: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘char’
cc1: warnings being treated as errors
imc.c: In function ‘imclog’:
imc.c:230: warning: declaration of ‘format’ shadows a global declaration
mud.h:4789: warning: shadowed declaration is here
imc.c: In function ‘imcbug’:
imc.c:250: warning: declaration of ‘format’ shadows a global declaration
mud.h:4789: warning: shadowed declaration is here
imc.c: In function ‘imcformat_channel’:
imc.c:1005: warning: declaration of ‘format’ shadows a global declaration
mud.h:4789: warning: shadowed declaration is here
imc.c: In function ‘imc_act_string’:
imc.c:7356: warning: declaration of ‘format’ shadows a global declaration
mud.h:4789: warning: shadowed declaration is here
make[2]: *** [o/imc.o] Error 1

The above were resolved by adding a second set of () to the
char *get_monthname args( ( int month ) );
char *get_daysuffix args( ( int day ) );
bool exists_player args( ( char *name ) );
in mud.h and by moving the
char *format args( ( char *fmt, ... ) );
to save.c from mud.h with a
const
in front of it immediately after
bool exists, recurse = FALSE;

Compiling o/comm.o....
cc1: warnings being treated as errors
comm.c: In function ‘nanny’:
comm.c:2000: warning: declaration of ‘time’ shadows a global declaration
/usr/include/time.h:187: warning: shadowed declaration is here
make[1]: *** [o/comm.o] Error 1

Resolved by changing time to ltime

Compiling o/tables.o....
tables.c: In function ‘write_last_file’:
tables.c:3129: error: ‘fpReserve’ undeclared (first use in this function)
tables.c:3129: error: (Each undeclared identifier is reported only once
tables.c:3129: error: for each function it appears in.)
tables.c: In function ‘exists_player’:
tables.c:3301: error: storage size of ‘fst’ isn’t known
cc1: warnings being treated as errors
tables.c:3311: warning: implicit declaration of function ‘stat’
tables.c:3301: warning: unused variable ‘fst’
make[1]: *** [o/tables.o] Error 1

Resolved by commenting out the two fpReserve references in write_last_file and adding
#include <sys/stat.h>
to the other includes at the top of tables.c

o/comm.o: In function `nanny':
/home/muddev/src/comm.c:2961: undefined reference to `first_on'
/home/muddev/src/comm.c:2961: undefined reference to `first_on'
/home/muddev/src/comm.c:2961: undefined reference to `last_on'
/home/muddev/src/comm.c:2961: undefined reference to `last_on'
/home/muddev/src/comm.c:2961: undefined reference to `first_on'
/home/muddev/src/comm.c:2961: undefined reference to `last_on'
/home/muddev/src/comm.c:2961: undefined reference to `last_on'
o/db.o: In function `load_logons':
/home/muddev/src/db.c:940: undefined reference to `first_on'
/home/muddev/src/db.c:940: undefined reference to `first_on'
/home/muddev/src/db.c:940: undefined reference to `last_on'
/home/muddev/src/db.c:940: undefined reference to `last_on'
/home/muddev/src/db.c:940: undefined reference to `first_on'
/home/muddev/src/db.c:940: undefined reference to `last_on'
/home/muddev/src/db.c:940: undefined reference to `last_on'
o/save.o: In function `do_last':
/home/muddev/src/save.c:2230: undefined reference to `first_on'
/home/muddev/src/save.c:2290: undefined reference to `first_on'
/home/muddev/src/save.c:2322: undefined reference to `first_on'
/home/muddev/src/save.c:2329: undefined reference to `first_on'
/home/muddev/src/save.c:2352: undefined reference to `first_on'
o/save.o:/home/muddev/src/save.c:2370: more undefined references to `first_on' follow
o/tables.o: In function `write_last_file':
/home/muddev/src/tables.c:3153: undefined reference to `last_on'
/home/muddev/src/tables.c:3153: undefined reference to `last_on'
/home/muddev/src/tables.c:3153: undefined reference to `last_on'
/home/muddev/src/tables.c:3160: undefined reference to `first_on'
collect2: ld returned 1 exit status
make[1]: *** [smaug] Error 1

Resolved by adding:
LAST_DATA *first_on;
LAST_DATA *last_on;
to the beginning of db.c

After I got past all of those, I hotbooted the mud (which went fine) and then tried to log on one of my alts to see what would happen and the mud crashed with a core file which GDB reported:

#0 0x0810fcac in nanny (d=0x0, argument=0xbf9c4d35 "") at comm.c:2960
2960 newlogon->ip = str_dup(d->host);
(gdb) bt
#0 0x0810fcac in nanny (d=0x0, argument=0xbf9c4d35 "") at comm.c:2960
#1 0x0810a83f in game_loop () at comm.c:1010
#2 0x08109c9e in main (argc=6, argv=0xbf9c56a4) at comm.c:600

And that's where I'm at now.
Amended on Sat 05 May 2007 01:23 AM by Conner
USA #13
Ok, resolved the crash by changing
newlogon->ip = str_dup(d->host);
to
newlogon->ip = str_dup(ch->desc->host);
and it seems to be working now. :)

(Thanks to Kiasyn for helping me figure out the last two issues there.)

Btw, Zeno also tested this and says that he's not gotten most of the errors that I did, so I guess I'm far from stock.. *shrug*
USA #14
its wierd that you needed to use ch->desc->host as opposed to d->host, unless of course whatever your code does disposes d->host, i truthfully have no clue. as to the other things i updated the snippet accordingly. as for needing to move format out of mud.h, by the errors i would assume there is a global declaration already in place named format, since i removed all traces of imc from my code i would think thats why i never ran into that. as for the shadowed declaration of time i'm still stumped on that, so i'll just modify it in the snippet to maybe help avoid head scratching of future implementors. soooo other than alllll that, did ya get it to work and how did ya like it?
Amended on Sat 05 May 2007 05:18 AM by Gohan_TheDragonball
USA #15
As a matter of fact, yes, I did get it to work (took some reworking of my existing last.lst file to match the new format since I'd previously been using Xerves' snippet) and made some minor modifications already (made it so that "last month" takes a month and year argument, made fromip accept non-numeric argmuents, got rid of a . after the month display, added a header to the findalt display, and expanded the syntax message to include all the options) but it's great, I love it even compared to Xerves' snippet. I can't say what other changes I'm liable to make, but I'll keep you aware if you'd like. In any event, thanks very much for a great snippet. :)
USA #16
yeah sure any changes ya make that you feel i'd like to include please do keep me posted. i'm glad ya likes it, also glad ya already had a previous list to insert into the database.
USA #17
Strangely, it doesn't seem to be working for me. Or at least the "findalts" part.

There are characters with the same IP in the last.lst file, and fromip shows that fine. But doing "findalts" with the character that shares that IP with other characters says there are no alts, even though there are.

Next time you're on, check it out. I have no idea why it's not working.

[EDIT] His response is as follows:

Remove this part from both main and recursive.
                // Have we already done a search for the argument on this day?
                 if ( day == logon->day && month == logon->month && year == logon->year )
                 {
                     continue;
                 }

It was only finding one login per day, so if multiple IPs were on from the same char it would only check the first match.
Amended on Sun 06 May 2007 02:28 AM by Zeno
USA #18
now what i originally did was go day by day, pick the first login that day from that character, and do a search based on that logins ip address. once that search was done we skip to the next day and so forth. now this served a problem on zeno's due to the first login of the day of one character differed from every other login from that character that day. now what zeno posted was my simple fix, but be warned the computing time will suffer.

My mud has the limit of logins in the database, which is 20000.


Before fix:

<PL:(502,500,000)> <Gohan> timecmd last findalts gohan

Timing
Starting timer.
Possible Alts of Gohan:
----------------------------------------------------------
....Matches
----------------------------------------------------------
25 Total Possible Alts: 7 still exist, 18 are deleted.
Timing complete.
Timing took 0.823513 seconds.

After fix:


<PL:(502,500,000)> <Gohan> timecmd last findalts gohan

Timing
Starting timer.
Possible Alts of Gohan:
----------------------------------------------------------
....Matches
----------------------------------------------------------
25 Total Possible Alts: 7 still exist, 18 are deleted.
Timing complete.
Timing took 2.104752 seconds.


Now based on just a search for my alt chars, it really didn't improve it much, but on Zeno's it would have produced results in his scenario. The choice is yours!!!
USA #19
Wow, that's almost three times as long.. and it doesn't change the results?
USA #20
No, as we said it changes the results. The shorter time only checks the first login each day. So if there are 20 logins during the day on the same char, it won't check them all and won't be accurate.
USA #21
it really depends on the database its searching really, my db is at its max, the more logins you have the easier it will be to determine possible alternate characters based on the first match only. zeno had just barely started his db so it had very few references for a specific character, so the results were affected. i did many checks against multiple characters on my db, and the change really didn't seem to affect my results, except for the number of matches found and the number of different ip addresses found. also, and i am not sure about this, but zeno and probably you too conner have dns resolving, whereas i just use ip addresses, but that might affect it, if the players host doesn't resolve correctly and just defaults to the ip address instead. but again im not sure exactly what zeno has installed that shows stuff liek xerves.something.com instead of just an ip address.
USA #22
Hmm, I may have to try it to see what difference it produces on mine then, I currently do have DNS resolving enabled, though there are always a few that don't resolve as well. As for the size of the "database" mine currently shows:
last -1
There were 5018 logons (0 Unique IPs) -1, 0/0/0.

last countips
There were 1677 different IP addresses in the database.

But I had my last.lst file set to max out at 5000 before I installed this so it's slowly growing from that point (the last couple of days have been fairly slow).

Without this "fix" when I try the findalts using timecmd, I get:

timecmd last findalts conner
Timing
Starting timer.
Possible Alts of Conner:
----------------------------------------------------------
Character Name Matchs IPs Exists?
----------------------------------------------------------
....Matches
------------Recurssive Matches------------
....More Matches
----------------------------------------------------------
65 Total Possible Alts: 65 still exist, 0 are deleted.
Timing complete.
Timing took 0.335328 seconds.

Now, to be completely honest, 44 of those 65 are not my alts and it's not listing Conner as a match, but the other 21 are mine. However, of the ones it's listing, the reason they're matching are because they're either alts of Dragona (who has in the recent past used my machine on occassion) or of Zelose (who is Dragona's brother and we've had to logon as one of his characters once in the last eleven months (as far back as my last.lst goes) to fix a problem he was having, so it is guessing correctly based on what it's got to go off of.

Now, am I understanding correctly that, given the size of my last.lst file, this "fix" will make that same findalts take roughly a full second and will probably generate the same output because it's already getting it pretty close to accurate to begin with?
USA #23
yes, from what i can tell without the fix, the code is pretty accurate, granted i wouldn't know if i ever missed an alt due to not having this fix. i personally am not implementing this fix, as i feel the code as it is suits my needs and is accurate enough for me to make a fair estimate on a players possible alternate chars.
USA #24
When Dragona gets done using me for her current spring cleaning project, I'll give it a shot and see if it changes my results on the search, fortunately, for immortals at least, I track alts separately anyway, so I already have a list I can check to see if it's catching them all or not. I suspect that in my case it may not be because I've noticed that some folks here will logon with several alts more or less grouped, so they're not being logged on separately over different days so this fix may actually improve the accuracy of the search some. Either way, I'll post my results here as soon as I have them to post.
USA #25
Ok, on my dev port, before the "fix":

timecmd last findalts conner
Timing
Starting timer.
Possible Alts of Conner:
----------------------------------------------------------
Character Name Matchs IPs Exists?
----------------------------------------------------------
....Matches
------------Recurssive Matches------------
....More Matches
----------------------------------------------------------
21 Total Possible Alts: 15 still exist, 6 are deleted.
Timing complete.
Timing took 0.248079 seconds.

last countips
There were 67 different IP addresses in the database.

last -1
There were 1168 logons (0 Unique IPs) -1, 0/0/0.

After the "fix":

timecmd last findalts conner
Timing
Starting timer.
Possible Alts of Conner:
----------------------------------------------------------
Character Name Matchs IPs Exists?
----------------------------------------------------------
....Matches
------------Recurssive Matches------------
....More Matches
----------------------------------------------------------
21 Total Possible Alts: 15 still exist, 6 are deleted.
Timing complete.
Timing took 0.151553 seconds.

last countips
There were 67 different IP addresses in the database.

last -1
There were 1168 logons (0 Unique IPs) -1, 0/0/0.

So, at least on my development port, the only difference was that it took roughly 7x as long to run the command. Perhaps once I get today's portion of the family spring cleaning done, I'll try it again on my live mud to see if having the larger "database" makes more of a difference. *shrug*
USA #26
Before fix: Timing took 0.248079 seconds.
After fix: Timing took 0.151553 seconds.

Where exactly did you get 7x longer from your posted times? to me that looks like less time.
USA #27
You're right, I misread it as 0.024 for the first one. *L*

ok, same "test" on my live mud...
Before fix (since you pointed that out, I tried it twice in a row to see what the timing difference was, and it was significant):

timecmd last findalts conner
Timing
Starting timer.
Possible Alts of Conner:
----------------------------------------------------------
Character Name Matchs IPs Exists?
----------------------------------------------------------
....Matches
------------Recurssive Matches------------
....More Matches
----------------------------------------------------------
65 Total Possible Alts: 65 still exist, 0 are deleted.
Timing complete.
Timing took 0.924846 seconds.

timecmd last findalts conner
Timing
Starting timer.
Possible Alts of Conner:
----------------------------------------------------------
Character Name Matchs IPs Exists?
----------------------------------------------------------
....Matches
------------Recurssive Matches------------
....More Matches
----------------------------------------------------------
65 Total Possible Alts: 65 still exist, 0 are deleted.
Timing complete.
Timing took 0.238696 seconds.

last -1
There were 5054 logons (0 Unique IPs) -1, 0/0/0.

last countips
There were 1687 different IP addresses in the database.

After the fix:

timecmd last findalts conner
Timing
Starting timer.
Possible Alts of Conner:
----------------------------------------------------------
Character Name Matchs IPs Exists?
----------------------------------------------------------
....Matches
------------Recurssive Matches------------
....More Matches
----------------------------------------------------------
65 Total Possible Alts: 65 still exist, 0 are deleted.
Timing complete.
Timing took 0.327006 seconds.

last -1
There were 5054 logons (0 Unique IPs) -1, 0/0/0.

last countips
There were 1687 different IP addresses in the database.

Hmm, interesting results, this time there was a slight difference between the outputs, aside from the actual timing, the very first of the Matches on the list had 137 "Matchs" after the fix and only had 71 before but everything else was identical. I suppose for the meager difference in timing, I'll leave the "fix" in place (though maybe I'll add an e to the word "Matchs" since I'm noticing that I'd left one out) since, in theory this way is more accurate, but I'm not really seeing a significant difference here even in the time for the command to run. *shrug*
USA #28
Hmm, I just crashed my live mud by trying some other names (folks I know have a bunch of alts) to see how much the timing would change.. gdb shows:

#0 0x08123e75 in str_cmp (astr=0x1 <Address 0x1 out of bounds>,
bstr=0xdd7c1c8 "ts1-231.nmkt.auracom.net") at db.c:5591
5591 for( ; *astr || *bstr; astr++, bstr++ )
(gdb) bt
#0 0x08123e75 in str_cmp (astr=0x1 <Address 0x1 out of bounds>,
bstr=0xdd7c1c8 "ts1-231.nmkt.auracom.net") at db.c:5591
#1 0x081ca8d7 in do_last (ch=0xddf29d0, argument=0xbfc7d77a "rand")
at save.c:2541
#2 0x0816009b in interpret (ch=0xddf29d0, argument=0xbfc7d771 "findalts rand")
at interp.c:446
#3 0x0816102a in do_timecmd (ch=0xddf29d0,
argument=0xbfc7d76c "last findalts rand") at interp.c:850
#4 0x0816009b in interpret (ch=0xddf29d0,
argument=0xbfc7d76c "last findalts rand") at interp.c:446
#5 0x0810a868 in game_loop () at comm.c:1014
#6 0x08109c9e in main (argc=6, argv=0xbfc7e0d4) at comm.c:600

I'm not sure why astr would've been out of bounds though. :(
It worked for the first three names besides my own that I'd tried, and on the fourth one it dropped a core dump. :(
...
tried it again with just him and got the same results, so it's something about him. His character's name is Rand, could the code think it's looking up a random number because of that? :(
Australia Forum Administrator #29

5591 for( ; *astr || *bstr; astr++, bstr++ )
(gdb) bt
#0 0x08123e75 in str_cmp (astr=0x1 <Address 0x1 out of bounds>,


Looks like astr was NULL, as it is now 1 after adding 1 to it.
Australia Forum Administrator #30
Quote:

His character's name is Rand, could the code think it's looking up a random number because of that?


Hmmm - perhaps if I create a character called "Format c:" you would be in big trouble? Somehow I don't think so. (Or, Shutdown, or Reboot). ;)
Amended on Wed 09 May 2007 05:08 AM by Nick Gammon
USA #31
Let me get this out really quick, ROFL!!!!!! Ok now back to business, could you post what section of code surrounds line 2541 in save.c
USA #32
It was just a thought, Nick. *shrug* (It's a linux box, so I suspect that format c wouldn't mean anything even if it did work that way.) ;)

Sure, here you go (the bolded line is 2541 itself):

            if ( !str_cmp( logon->name, argument ) )
            {
/*		// Have we already done a search for the argument on this day?
		if ( day == logon->day && month == logon->month && year == logon->year )
		{
		    continue;
		} */
                day = logon->day;
                month = logon->month;
                year = logon->year;
                sprintf( ipstring, "%s", logon->ip );
                for ( logon_temp = first_on; logon_temp; logon_temp = logon_temp->next )
                {
                    if ( (logon_temp->day == day) && (logon_temp->month == month) &&
                                (logon_temp->year == year) && str_cmp( logon_temp->name, argument ) )
                    {
                        if ( !str_cmp(ipstring,logon_temp->ip) )
                        {
			    recorded = FALSE;
			    for ( tmp = 0; tmp <= alts; tmp++ )
			    {
				if ( !str_cmp( altsearch_table[tmp].name, logon_temp->name ) )
				{
				    bool ip_found = FALSE;
				    for ( tmp2 = 0; tmp2 < altsearch_table[tmp].dif_ips; tmp2++ )
				    {
					if ( !str_cmp( altsearch_table[tmp].ip[tmp2], logon_temp->ip ) )
					{
					    altsearch_table[tmp].ip_track[tmp2]++;
					    ip_found = TRUE;
					}
				    }
				    if ( !ip_found )
				    {
					altsearch_table[tmp].ip[altsearch_table[tmp].dif_ips] = STRALLOC(ipstring);
				    	altsearch_table[tmp].dif_ips++;
				    }
				    altsearch_table[tmp].total_matches++;
				    recorded = TRUE;
				}
			    }
			    if ( !recorded )
			    {
				alts++;
				altsearch_table[alts].name = STRALLOC(logon_temp->name);
				altsearch_table[alts].ip[0] = STRALLOC(ipstring);
				altsearch_table[alts].dif_ips++;
				altsearch_table[alts].total_matches++;
			    }
                        }
                    }
                }
            }
        }
Amended on Wed 09 May 2007 10:12 PM by Conner
USA #33
hmm ok i know whats probably wrong, you will want to change that section of code to such, the bold is the change:


			            for ( tmp2 = 0; tmp2 < altsearch_table[tmp].dif_ips; tmp2++ )
				    {
                                        if ( tmp2 >= MAX_IP_TRACK )
                                        {
                                            ip_found = TRUE;
                                            break;     
                                        }
					if ( !str_cmp( altsearch_table[tmp].ip[tmp2], logon_temp->ip ) )
					{
					    altsearch_table[tmp].ip_track[tmp2]++;
					    ip_found = TRUE;
					}
				    }


i am pretty sure it was an array out of bounds, hadn't run into it before so it never became an issue.
Amended on Thu 10 May 2007 06:06 AM by Gohan_TheDragonball
USA #34
Yup, that fixed it. Thanks! :)