Next Previous Contents

4. Running CircleMUD

4.1 I typed ``autorun'' but then my terminal just froze.

autorun is a script which automatically runs, logs, and reboots the game for long-term runs. You should run autorun in the background by typing ``./autorun &'' -- the MUD will start running in the background and you'll get the normal UNIX prompt back immediately (see section 4.3). The game will then run unattended until you explicitly shut it down.

On some systems, you may need to prepend ``nohup'' to the autorun command since some systems will kill off any processes left running when you leave the shell.

4.2 I typed ``bin/circle'' and got lots of boot messages, but then it said ``Entering game loop'' and froze.

It is not frozen, it is just waiting for people to connect. You have to run the MUD in the background by typing ``bin/circle &'' and then use telnet to connect to the game (see next section).

4.3 Okay, I think the MUD is running but why don't I get a login prompt?

In order to play the MUD, you must connect to it using the telnet command, i.e. ``telnet localhost 4000''.

4.4 How come I get this error when running my mud: ``Error reading board: No such file or directory''

This is not a bad thing, all it means is that you have some boards on the mud and that it can't find the file for them. Since it can't find the file, the mud will just create the file on the fly and use that, so the next time something is posted to the board, the files will exist. However, if you did have files for the boards and you are suddenly getting this error, it means that the board files have been deleted or something similar.

4.5 I just got this SIGPIPE, what is it and what Can I Do About It?

Often it appears that other people send your system SIGPIPEs when their connection is closed, in fact, it is not the person sending the SIGPIPE, it is your system. The SIGPIPE is generated when your program attempts to write to descriptor which has no one listening to it. This occurs if the character is sent a message by the mud after connecting, but before the socket is flagged with an exception or reads 0 bytes. By default, CircleMUD ignores these SIGPIPEs, with the line my_signal(SIGPIPE, SIG_IGN) in signal_setup(). Where most people see the problems with SIGPIPE is while debugging with GDB. By default, GDB responds to a SIGPIPE by stoping the program, printing that a SIGPIPE was received, and passing it to the program. You can change the action taken by GDB by using the `handle' command. To stop the program from stoping at SIGPIPE, you would give GDB the command `handle SIGPIPE nostop'

4.6 When I run Circle under Linux, it tells me ``gethostbyaddr: connection refused'' when the MUD boots, and then dies. Why?

You need to make sure you have Networking and TCP/IP support compiled into your Linux kernel, even if you aren't actually connected to the Internet. The easiest way to do this if you're using Slackware is to install one of Slackware's precompiled networking kernels. Also, make sure to install Slackware's `N' series of disks which contains other networking support files.

If Slackware's precompiled kernel isn't available you'll have to compile the kernel yourself. First make sure the kernel source is installed in /usr/src/linux (see section 3.1.4) and follow the instructions in /usr/src/linux/README. When you do `make config' it will ask you a series of questions about which kernel features you want; make sure to answer ``Y'' to ``Networking support'' and ``TCP/IP support''.

4.7 When I run Circle under Windows 95, it tells me ``Winsock error #10047'' when the MUD boots, and then dies. Why?

You need to configure TCP/IP networking from the Network Control Panel, even if you are not connected to the Internet. From the Network Control Panel, select ``Add Protocol'', and under the vendor ``Microsoft'', choose ``TCP/IP''. It may ask you to insert the Windows 95 CDROM in order to copy the drivers onto your hard drive.

4.8 When I run Circle under Windows 95, players can't rent---their equipment is just dropped on the ground, syslogs don't work, so what is the problem?

The reason that objects aren't saved when your players quit is that certain unzip programs are buggy and don't completely recreate the MUD's directory structure (in particular, it doesn't create directories which have no files in them.) This is fixed in Circle 3.0 patchlevel 12 and above. Before patchlevel 12, you can fix it simply by manually creating the needed directories:

        CD \Circle30bpl11
        cd lib\plrobjs
        mkdir A-E
        mkdir F-J
        mkdir K-O
        mkdir P-T
        mkdir U-Z
        mkdir ZZZ
Object saving should then work. The syslogs are a different story; no data is written to the system logs because the code currently is configured simply to write all errors to the standard error file descriptor (stderr), and Windows doesn't seem to let you redirect stderr to a file the same way UNIX does. pl12 allows you to direct logs to a specific file instead.

4.9 When someone logs on to my Windows 95 MUD, the console screen gives: ``gethostbyaddr: No such file or directory''

This means the MUD can't resolve the IP address of the connecting player's source site innto a hostname. You probably don't have DNS correctly configured in the Windows Network Control Panel menu (under configuration of the TCP protocol). Make sure you have the IP address of your ISP's DNS server listed.

4.10 My Mud crashed and my connection got closed. What can I do?

Just because your connection got closed from the mud (for example, if you get too much information sent to you and the telnet session gets closed), this doesn't always mean that the game itself crashed. Before reporting something as a crash bug, make sure that the game itself crashed, and above all, try to duplicate the circumstances before reporting it as a crash bug. You can also try using gdb to find out why the mud is crashing if it gives you a core dump.

4.11 Ok, so how do I use ``gdb''?

GDB has some online help, though it is not the best. It does at least give a summary of commands and what they're supposed to do. What follows is Sammy's short intro to gdb with some bughunting notes following it:

If you've got a core file, go to your top circle directory and type:

> gdb bin/circle lib/core

If you want to hunt bugs in real time (causing bugs to find the cause as opposed to checking a core to see why the mud crashed earlier) use:

> gdb bin/circle

If you're working with a core, gdb should show you where the crash occurred. If you get an actual line that failed, you've got it made. If not, the included message should help. If you're working in real time, now's the time to crash the mud so you can see what gdb catches.

When you've got the crash info, you can type ``where'' to see which function called the crash function, which function called that one, and so on all the way up to ``main()''.

I should explain about ``context'' You may type ``print ch'' which you would expect to show you the ch variable, but if you're in a function that doesn't get a ch passed to it (real_mobile, etc), you can't see ch because it's not in that context. To change contexts (the function levels you saw with where) type ``up'' to go up. You start at the bottom, but once you go up, and up, and up, you can always go back ``down''. You may be able to go up a couple functions to see a function with ch in it, if finding out who caused the crash is useful (it normally isn't).

The ``print'' command is probably the single most useful command, and lets you print any variable, and arithmetic expressions (makes a nice calculator if you know C math). Any of the following are valid and sometimes useful:

print ch (fast way to see if ch is a valid pointer, 0 if it's not)
print *ch (prints the contents of ch, rather than the pointer address)
print ch->player.name (same as GET_NAME(ch))
print world[ch->in_room].number (vnum of the room the char is in)
etc..

Note that you can't use macros (all those handy psuedo functions like GET_NAME and GET_MAX_HIT), so you'll have to look up the full structure path of variables you need.

Type ``list'' to see the source before and after the line you're currently looking at. There are other list options but I'm unfamiliar with them.

(From Sammy <Samedi@cris.com>)

For more information, you can try checking out the GDB Debugger

4.12 How can I hunt bugs more effectively?

There are only a couple of commands to use in gdb, though with some patience they can be very powerful. The only commands I've ever used are:

run                     well, duh.
print [variable]        also duh, though it does more than you might think
list                    shows you the source code in context
break [function]        set a breakpoint at a function
clear [function]        remove a breakpoint
step                    execute one line of code
cont                    continue running after a break or ctrl-c

I've run into nasty problems quite a few times. The cause is often a memory problem, usually with pointers, pointers to nonexistent memory. If you free a structure, or a string or something, the pointer isn't always set to NULL, so you may have code that checks for a NULL pointer that thinks the pointer is ok since it's not NULL. You should make sure you always set pointers to NULL after freeing them.

Ok, now for the hard part. If you know where the problem is, you should be able to duplicate it with a specific sequence of actions. That makes things much easier. What you'll have to do is pick a function to ``break'' at. The ideal place to break is immediately before the crash. For example, if the crash occurred when you tried to save a mob with medit, you might be able to ``break mobs_to_file''. Try that one first.

When you `medit save', the mud will hang. GDB will either give you segfault info, or it will be stopped at the beginning of mobs_to_file. If it segfaulted, pick an earlier function, like copy_mobile, or even do_medit.

When you hit a breakpoint, print the variables that are passed to the function to make sure they look ok. Note that printing the contents of pointers is possible with a little playing around. For example, if you print ch, you get a hex number that shows you the memory location where ch is at. It's a little helpful, but try print *ch and you'll notice that it prints the contents of the ch structure, which is usually more useful. print ch->player will give you the name of the person who entered the command you're looking at, and some other info. If you get a no ch in this context it is because the ch variable wasn't passed to the function you're currently looking at.

Ok, so now you're ready to start stepping. When GDB hit your breakpoint, it showed you the first line of executable code in your function, which will sometimes be in your variable declarations if you initialized any variables (ex: int i = 0). As you're stepping through lines of code, you'll see one line at a time. Note that the line you see hasn't been run yet. It's actually the _next_ line to be executed. So if the line is a = b + c;, printing a will show you what a was before this line, not the sum of b and c.

If you have an idea of where the crash is occurring, you can keep stepping till you get to that part of the code (tip: pressing return will repeat the last GDB command, so you can type step once, then keep pressing return to step quickly). If you have no idea where the problem is, the quick and dirty way to find your crash is to keep pressing return rapidly (don't hold the eturn key or you'll probably miss it). When you get the seg fault, you can't step any more, so it should be obvious when that happens.

Now that you've found the exact line where you get the crash, you should start the mud over and step more slowly this time. What I've found that works really well to save time is to create a dummy function. This one will work just fine:

void dummy(void){}
Put that somewhere in the file you're working on. Then, right before the crash, put a call to dummy in the code (ex: dummy();). Then set your breakpoint at dummy, andwhen you hit the breakpoint, step once to get back to the crashing code.

Now you're in total control. You should be looking at the exact line that gave you the crash last time. Print *every* variable on this line. Chances are one of them will be a pointer to an unaccessable memory location. For example, printing ch->player.name may give you an error. If it does, work your way back and print ch->player to make sure that one's valid, and if it isn't, try printing ch.

Somewhere in there you're going to have an invalid pointer. Once you know which one it is, it's up to you to figure out why it's invalid. You may have to move dummy() up higher in the code and step slowly, checking your pointer all the way to see where it changes from valid to invalid. You may just need to NULL a free'd pointer, or you may have to add a check for a NULL pointer, or you may have screwed up a loop. I've done all that and more :)

Well, that's it in a nutshell. There's a lot more to GDB that I haven't even begun to learn, but if you get comfortable with print and stepping you can fix just about any bug. I spent hours on the above procedure trying to get my ascii object and mail saving working right, but it could have taken weeks without gdb. The only other suggestion I have is to check out the online gdb help. It's not very helpful for learning, but you can see what commands are available and play around with them to see if you can find any new tools.

(From Sammy <samedi@cris.com>)

4.13 I just added n levels to my mud (from the stock 34). How do I set my imps up to level n without a pfile wipe?

You can write a quick and nasty function that will advance your imp (and imp only) to the max level (LVL_IMPL). This can be done with a quick idnum check so that only the original player (the first imp, he with id 1) can use the command to get to maximum level.

ACMD(do_upme)
{
  if (GET_IDNUM(ch) != 1) {
    send_to_char("You think IMP positions are that easy to come by?  Go Figure...\r\n", ch);
  } else {
    GET_LEVEL(ch) = LVL_IMPL;
    send_to_char("Advanced.\r\n", ch);
  }
}

4.14 I decided to wipe my pfile away anyway. What steps should I take to do this?

In order:

  1. Shutdown the mud with ``shutdown die'' so that it won't restart.
  2. Remove the player file, lib/etc/players
  3. Restart the mud and login to recreate your imp character.

You should probably also remove files in plrobjs, unless you want the recreated characters to come back with the same equipment they had when they were deleted.

4.15 I want to expand the ability to pk in my MUD, allowing ASSASSINS that'll be able to PK without getting flagged. How can I do this?

The simple way to do this is to find all the ``pk_allowed'' checks and replace them with a can_murder(ch, vict) function call. Prototype the function in utils.h. Then, in utils.c, create a can_murder() function something like this:

int can_murder(struct char_data *ch, struct char_data *victim) {
  if (pk_allowed == TRUE)
    return TRUE;
  if (IS_NPC(ch) || IS_NPC(victim))
    return TRUE;   /* you can always kill these */
  if (PLR_FLAGGED(ch, PLR_ASSASSIN))
    return TRUE;   /* they can kill anyone */
  /* Add further checks here */
}

4.16 Why does it say ``Connection closed by foreign host.'' and not display the ``Byebye!'' message I'm trying to send before cutting someone off?

This usually happens if you are doing something like this:

  send_to_char("Bye bye.  Come back soon, ya hear?", ch);
  close_socket(ch->desc);

The close_socket immediately dispatches/closes the connection, while send_to_char puts the message on the output queue to be dispatched next game_loop cycle. Therefore, the socket is gone. On some systems (ie old linux), this can even cause a infinite loop attempting to write to a closed socket. The proper way of doing this and other ``Byebye'' messages is to set the CON state of the player to CLOSE, like this:

  send_to_char("Bye bye.  Come back soon, ya hear?", ch);
  STATE(ch->desc) = CON_CLOSED;

This will then cycle to the next game_loop, dispatch the output queues (therefore sending the byebye message) and then close the socket. Further note, in some bizarre cases, this only seems to send about 40 characters and no escape codes. Sending more than 40 characters or escape codes (like the clear screen sequence) will crash the process reporting a problem similar to writing to a closed socket.

4.17 I run my mud on a unix system and the pfile/rent file works great, but on my home system it's all screwed up. What gives?

Some operating systems write binary data least-signifigant-digit-first, while others write it most-significant-first (big endian vs. little endian). Moving player files, rent files, mail files, and board files from one of these systems to the other will result in corrupted files. The solutions to this problem include:

4.18 How do I get the CircleMUD to autoload when the Linux server is restarted?

In /etc/rc.d/rc.local find where things like sendmail and (maybe) gpm are started. Add something like:

cd /home/mudlogin/circlebpl12/
su mudlogin -c ./autorun&
cd

Of course, change the "mudlogin" to whatever the name of the account is that normally has control of the mud, and change the path in the first cd to whereever the mud is run from.

For more info: man su

4.19 My server shuts down my MUD everytime I logoff. How do I keep the MUD running when I logoff?

Instead of typing "autorun &" to start the autorun script (which starts and keeps the mud running), type "nohup autorun &". Running the autorun via nohup will keep the script and the MUD running when you logoff of the server. For more information type "man nohup" at the prompt on your server.


Next Previous Contents