Why do I receive Program received signal SIGABRT, Aborted?

Im using gdb and when a user disconnects from my server I receive a message
Program received signal SIGABRT, Aborted.
0x7ffe0304 in ?? ()
I was hoping someone here might have a explination for this message in gdb

We need lots more information. I am assuming by 'my server' you mean your code, the part that acts as a server.

What OS do you have? Please show the output of:

uname -a

Is this a socket app? Is it threaded?

Ouput:

CYGWIN_NT-5.1 a 1.7.9(0.237/5/3) 2011-03-29 10:10 i686 Cygwin

I wanna provide some information about this that might help. It seems to happen when a funtions recv function returns 0 to the while loop below. I might be wrong though but it just seems that way to me.

        while(keepsake != NULL)
        {
            if(FD_ISSET(keepsake->newfd, &read_fds))
            {
                if(keepsake->state == CHARACTER_LOGIN)      /* Character login    */
                    character_login(keepsake);
                else if(keepsake->state==CREATE_CHARACTER)  /* Character creation */
                    create_character(keepsake);
            }
            keepsake = keepsake->next;
        }

We'll need to see a whole lot more than that... We can't see any of the code which defines any of that, so any of it could be crashing for any reason.

Try printing out the pointers with fprintf(stderr, "%p", pointer); to see if you're getting bad values creeping into your list.

Also here is keepsake:

struct descr
{
    int newfd;             /* Player socket                             */
    char char_name[11];    /* Character's name                          */
    char char_pass[27];    /* Character's password                      */
    short int sex;         /* Character's sex                           */
    short int char_class;  /* Characters class                          */
    short int char_race;   /* Characters race                           */
    short int state;       /* Game state                                */
    short int create_state;/* Character creation state                  */
    struct descr *next;    /* Used to create a linked list              */
    struct descr *list;    /* Used to define the top of the linked list */
} keepsake;

---------- Post updated at 09:32 PM ---------- Previous update was at 09:25 PM ----------

Ok I tried printing the information. It prints alot because it loops alot before I can get to that part but also it seems to just be a problem with FD_ISSET when somone disconnects. have any ideas on that?

Are you handling EOF? How do you do zero/clr your fds in your loop and at EOF?

You know I don't ever FD_ZERO anything. But I do FD_CLR stuff. How should I FD_ZERO stuff?
FD_CLR is in the loop below:

        keepsake = descr_list;
        while(descr_list != NULL)
        {
            r = descr_list->next;
            if(descr_list->state == SAY_GOODBY)
            {
                close(descr_list->newfd);
                FD_CLR(descr_list->newfd, &master);
                free(descr_list);
            }
            descr_list = r;
        }
        descr_list = keepsake;

Also when there is only one user and it aborts, the command list displays:

486                                             create_character(keepsake);
487                             }
488                             keepsake = keepsake->next;
489                     }
490                     keepsake = descr_list;
491                     while(descr_list != NULL)
492                     {
493                             r = descr_list->next;
494                             if(descr_list->state == SAY_GOODBY)
495                             {

And when there are two users and it aborts, the command list displays:

475                             heart_pulse = 0;
476                     } /* END if (heart_pulse == 15000) */
477                     keepsake = descr_list;
478                     while(keepsake != NULL)
479                     {
480                             if(FD_ISSET(keepsake->newfd, &read_fds))
481                             {
482                                     if(keepsake->state == CHARACTER_LOGIN)      /* Character login    */
483                                             character_login(keepsake);
484                                     else if(keepsake->state==CREATE_CHARACTER)  /* Character creation */

Both of the bottom code are kind of the two loops I posted. You could pretty much copy the main and run it if you comment out a few lines that it is dependent on.

---------- Post updated at 10:43 PM ---------- Previous update was at 10:26 PM ----------

Alright I wanna add that I do FD_ZERO like this before my infinity loop:

    FD_ZERO(&master);    // clear the master and temp sets
    FD_ZERO(&read_fds);
    FD_ZERO(&write_fds);
    FD_ZERO(&except_fds);

Hard to tell with snippets. If your descr_list is all your clients, imagine this:

descr_list: client1, client2, client3

client2.state is SAY_GOODBYE, you free(client2), did you change client1.next to be client2.next?

you set state=SAY_GOODBYE when recv returns 0?

May I post the entire main.c, there are a few lines you can comment out and it should work. because I only use a couple outside functions and include two files that are not needed.

The descr_list is exactly what you think it is.
I believe I am freeing the list correctly and maybe I am handling the descr_list wrong.
And Yes I set state to SAY_GOODBYE when recv returns 0.
The code below is the updated code that clears the descr_list of unwanted descriptors. keepsake = the first descr structure on descr_list

        descr_list = keepsake;
        if(descr_list)
        {
            while(descr_list->state == SAY_GOODBY && descr_list->next != NULL)
            {
                descr_list = descr_list->next;
            }
            tmp = keepsake;
            keepsake = descr_list;
            descr_list = tmp;
        }
        while(descr_list != NULL)
        {
            tmp = descr_list->next;
            if(descr_list->state == SAY_GOODBY)
            {
                close(descr_list->newfd);
                FD_CLR(descr_list->newfd, &master);
                free(descr_list);
            } 
            descr_list = tmp;
        }
        descr_list = keepsake;

Lastly I want to add that I used the bg command with gdb and the output was this after an Abort. I'm not sure why it Aborts but it does when one user connects and then disconnects straight way. Again the code below is the output of ba in gdb.

#0  0x7ffe0304 in ?? ()
#1  0x77f7671a in ntdll!ZwWaitForSingleObject () from /cygdrive/c/WINDOWS/System32/ntdll.dll
#2  0x77e7a62d in WaitForSingleObjectEx () from /cygdrive/c/WINDOWS/system32/kernel32.dll
#3  0x000006f8 in ?? ()
#4  0x00000000 in ?? ()

Ok before I go to bed I want to post this and the entire main.c maybe one of you guys could try compiling and running it. First the ba full command after two users connect and one user disconnects, connects and then disconnects again causing:

Program received signal SIGSEGV, Segmentation fault.
0x004024cd in main () at main.c:478
478                             if(FD_ISSET(descr_list->newfd, &read_fds))
(gdb) ba full
#0  0x004024cd in main () at main.c:478
        keepsake = 0x4b96b8
        tmp = 0x0
        serv = {sin_family = 2, sin_port = 40975, sin_addr = {s_addr = 0}, __pad = "\000\000\000\000\000\000\000"}
        inco = {sin_family = 2, sin_port = 54546, sin_addr = {s_addr = 16777343}, __pad = "\000\000\000\000\000\000\000"}
        rtime = {second = -6360, minute = 24864, hour = 2, day = 0, month = -12288, year = 34}
        seconds = {tv_sec = 0, tv_usec = 1000}
        inclen = 16
        simpleSocket = 2
        yes = 1
        fdmax = 5
        newfd = 5
        heart_pulse = 12844
        master = {fds_bits = {28, 0}}
        read_fds = {fds_bits = {16, 0}}
        write_fds = {fds_bits = {24, 0}}
        except_fds = {fds_bits = {0, 0}}

Here is main.c, compile it, run it in gdb and then connect to port 4000. The error happens when one user connects then disconnects or another error happens when multiple users start to connect and disconnect.

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <fcntl.h>
//#include "server.h"

/* Game create_state's, maximum allowed 65536                                                 */
#define PERGITORY           0 /* Tells create_character to announce there pergitory position  */
#define CREATE_NAME         1 /* Tells create_character to check for the character's name     */
#define CREATE_PASSWORD     2 /* Tells create_character to check for the character's password */
#define VERIFY_PASSWORD     3 /* Tells create_character to verify the character's password    */
#define CHOOSE_SEX          4 /* Tells create_character to check for the character's sex      */
#define CHOOSE_RACE         5 /* Tells create_character to check for the character's race     */
#define CHOOSE_CLASS        6 /* Tells create_character to check for the character's class    */
#define NUM_CREATE_STATES   7 /* The number of creation states                                */

/* Game state's, maximum allowed 65536                                                        */
#define SAY_GOODBY          0 /* Character log off                                            */
#define CHARACTER_LOGIN     1 /* Character login                                              */
#define CREATE_CHARACTER    2 /* Character creation                                           */
#define CHARACTER_LOGGED_IN 3 /* Character is logged in                                       */
#define NUM_GAME_STATES     4 /* The number of game states                                    */

/* Gender types                                                                               */
#define GENDER_NEUTRAL      0 /* The gender type neutral                                      */
#define GENDER_MALE         1 /* The gender type male                                         */
#define GENDER_FEMALE       2 /* The gender type female                                       */
#define NUM_GENDERS         3 /* The number of genders                                        */
 

struct descr *descr_list = NULL;

/* Game time                                                                                  */
struct game_time
{
    short int second;         /* Game time seconds                                            */
    short int minute;         /* Game time minutes                                            */
    short int hour;           /* Game time hours                                              */
    short int day;            /* Game time days                                               */
    short int month;          /* Game time months                                             */
    short int year;           /* Game time years                                              */
};

/* Real time                                                                                  */
struct real_time
{
    short int second;         /* Real time seconds                                            */
    short int minute;         /* Real time minutes                                            */
    short int hour;           /* Real time hours                                              */
    short int day;            /* Real time days                                               */
    short int month;          /* Real time months                                             */
    short int year;           /* Real time years                                              */
};

struct descr
{
    int newfd;                /* Player socket                                                */
    char char_name[11];       /* Character's name                                             */
    char char_pass[27];       /* Character's password                                         */
    short int sex;            /* Character's sex                                              */
    short int char_class;     /* Characters class                                             */
    short int char_race;      /* Characters race                                              */
    short int state;          /* Game state                                                   */
    short int create_state;   /* Character creation state                                     */
    struct descr *next;       /* Used to create a linked list                                 */
    struct descr *list;       /* Used to define the top of the linked list                    */
};

int initialize_descr(int newfd, struct descr **p)
{
    struct descr *d;
    if(!(d = malloc(sizeof(struct descr))))
    {
        //nonfatal("malloc failure initializing descr");
        return 0;
    }
    d->newfd = newfd;
    d->state = CHARACTER_LOGIN;
    d->next = NULL;
    d->list = descr_list;
    *p = d;
    if(descr_list == NULL)
    {
        descr_list = d;
    }
    else
    {
        while(descr_list->next != NULL)
        {
            descr_list=descr_list->next;
        }
        descr_list->next = d;
        descr_list = descr_list->list;
    }
    return 1;
}

/*************************************************************************************
 * This is a character login function created for a passive style multi user dungeon *
 * game. It returns -1 if it receives less then or equal to zero bytes. It returns   *
 * 0 if it receives stuff over the control limits of the integers. It returns 1 if   *
 * everything is acceptable and the state has been changed. Lastly if the function   *
 * reaches the the last return then it will return -2 which should never be reached  *
 * by the program                                                                    *
 *************************************************************************************/
int character_login(struct descr *d)
{
    int rbytes = 0;
    char buffer[12];
    const char er[] = "Character name must be less then, twelve characters.\r\n";
    const char err[]= "Please enter either (n) or (N).\r\n";
    const char ln[] = "Character name or (n)ew: ";
    
    if ((rbytes = recv(d->newfd, buffer, 12, 0)) <= 0)
    {
        if (rbytes == 0)
        {
            printf("Socket %d hung up\n", d->newfd);
        }
        else
        {
            //nonfatal("Receiving a file descriptor");
        }
        d->state=SAY_GOODBY;
        return -1;
    }
    else if (rbytes > 13)
    {
        send(d->newfd, er, sizeof er, 0);
        send(d->newfd, ln, sizeof ln, 0);
        return 0;
    }
    else
    {
        if (rbytes == 3)
        {
            if((buffer[0] == 'n' || buffer[0] == 'N'))
            {
                d->state = CREATE_CHARACTER;   /* Now we know to Create a new character  */
                d->create_state = CREATE_NAME; /* Here we know to create the username    */
                send(d->newfd, "By what name do you wish to be known? ", 38, 0);
                return 1;
            }
            else
            {
                send(d->newfd, err, sizeof err, 0);
                send(d->newfd, ln, sizeof ln, 0);
                return 0;
            }
        }
        else
        {
            send(d->newfd, err, sizeof err, 0);
            send(d->newfd, ln, sizeof ln, 0);
            return 0;
        }
        /*
        int *fp;
        FILE *fp = fopen(buffer, "r");
        if( fp )
        {
            d->state = ENTER_PASSWORD;  Enter character password
            fclose(fp);
            return 1;
        } 
        else
        {
            send(d->newfd, "Character does not exist", 24, 0);
            return 0;
        }*/
    }
    return -2;
}

/************************************************************************************
 *This is a character creation script used for prompting players to select aspects  *
 *of a character sheet for there personal use as they play this multi user dungeon  *
 *game. It returns -1 if recv returns less then or equal to 0. It returns 0 if a    *
 *player enters an amount of data that is larger then the integer that is waiting   *
 *to recieve it. It returns 1 if the player has entered a validated option and this *
 *function will return -2 if it recheas it's end which should never happen.         *  
 ************************************************************************************/
int create_character(struct descr *d)
{
    int rbytes = 0;
    char buffer[27];
    const char ne[] = "Character name must be less then, twelve characters.\r\n";
    const char nl[] = "By what name do you wish to be known? ";
    const char pe[] = "Password must be less then twenty eight characters.\r\n";
    const char pl[] = "Please enter a password for you're character: ";
    const char vpe[]= "Passwords are not the same.\r\n";
    const char vp[] = "Please varify you're password or type (b)ack: ";
    const char se[] = "Please enter (m)ale , (f)emale or (n)eutral.\r\n";
    const char sl[] = "Please choose you're sex, \r\n(m)ale, (f)emale, or (n)eutral? ";
    const char race_menu[] = 
                                "(H)uman\r\n"
                                "(D)row\r\n"
                                "(B)arbarian\r\n"
                                "\r\n"
                                "Highlighted races are available: ";
    const char class_menu[] =
                                "(M)age\r\n"
                                "(W)arrior\r\n"
                                "(C)leric\r\n"
                                "(T)hief\r\n"
                                "\r\n"
                                "Highlighted classes are available: ";
    if ((rbytes = recv(d->newfd, buffer, 27, 0)) <= 0)
    {
        if (rbytes == 0)
        {
            printf("Socket %d hung up\n", d->newfd);
        }
        else
        {
            //nonfatal("Receiving a file descriptor, function create_character");
        }
        d->state=SAY_GOODBY;
        return -1;
    }
    if ( d->create_state == CREATE_NAME)
    {
        if (rbytes > 13)
        {
            send(d->newfd, ne, sizeof ne, 0);
            send(d->newfd, nl, sizeof nl, 0);
            return 0;
        }
        else
        {
            strncpy(d->char_name, buffer, rbytes - 2);
            d->create_state = CREATE_PASSWORD;
            send(d->newfd, pl, sizeof pl, 0);
            return 1;
        }
    }
    else if (d->create_state == CREATE_PASSWORD)
    {
        if (rbytes > 29)
        {
            send(d->newfd, pe, sizeof pe, 0);
            send(d->newfd, pl, sizeof pl, 0);
            return 0;
        }
        else
        {
            strncpy(d->char_pass, buffer, rbytes - 2);
            d->create_state = VERIFY_PASSWORD;
            send(d->newfd, vp, sizeof vp, 0);
            return 1;
        }
    }
    else if (d->create_state == VERIFY_PASSWORD)
    {
        char tmp[27];
        if (rbytes < 30)
            strncpy(tmp, buffer, rbytes - 2);
        if (rbytes == 3 && (buffer[0] == 'b' || buffer[0] == 'B'))
        {
            d->create_state = CREATE_PASSWORD;
            send(d->newfd, pe, sizeof pe, 0);
            send(d->newfd, pl, sizeof pl, 0);
            return 1;
        }
        else if (rbytes > 29 || (strncmp(tmp, d->char_pass, rbytes -2) != 0))
        {
            send(d->newfd, vpe, sizeof vpe, 0);
            send(d->newfd, vp, sizeof vp, 0);
            return 0;
        }
        else
        {
            d->create_state = CHOOSE_SEX;
            send(d->newfd, sl, sizeof sl, 0);
            return 1;
        }
    }
    else if (d->create_state == CHOOSE_SEX)
    {
        if (rbytes > 3) {
            send(d->newfd, se, sizeof se, 0);
            send(d->newfd, sl, sizeof sl, 0);
            return 0;
        }
        else
        {
            if(buffer[0] == 'n' || buffer[0] == 'N'){d->sex = GENDER_NEUTRAL;}
            else if(buffer[0] == 'M' || buffer[0] == 'M'){d->sex = GENDER_MALE;}
            else if(buffer[0] == 'F' || buffer[0] == 'F'){d->sex = GENDER_FEMALE;}
            d->create_state = CHOOSE_RACE;
            send(d->newfd, race_menu, sizeof race_menu, 0);
            return 1;
        }
    }
    else if (d->create_state == CHOOSE_RACE)
    {
        d->create_state = CHOOSE_CLASS;
        send(d->newfd, class_menu, sizeof class_menu, 0);
        return 1;
    }
    else if (d->create_state == CHOOSE_CLASS)
    {
        d->state = CHARACTER_LOGGED_IN;
        d->state = CREATE_CHARACTER;
        d->create_state = CREATE_NAME;
        return 1;
    }
    return -2;
}

int main()
{ 
    struct sockaddr_in serv;
    struct sockaddr_in inco;
    struct game_time rtime;
    struct timeval seconds;
    socklen_t inclen;
    int simpleSocket;
    int yes = 1;
    int fdmax;        /* maximum file descriptor number */
    int newfd;
    unsigned int heart_pulse = 0;
    fd_set master;    /* master file descriptor list */
    fd_set read_fds;  /* will be watched to see if characters become available for reading */
    fd_set write_fds; /* will be watched to see if a write will not block */
    fd_set except_fds; /* will be watched for exceptions. */
    seconds.tv_sec  = 0;      /* seconds for select to wait for connections     */
    seconds.tv_usec = 1000;   /* microseconds for select to wait for connections
                               * there are 1,000 microseconds in a millisecond
                               * there are 1,000 milliseconds in a second     
                               * thus there are 1,000,000 Microseconds in one 
                               * second, and there are 60 seconds in one minute */
    printf("Process id #%i\n", getpid());
 
    FD_ZERO(&master);    // clear the master and temp sets
    FD_ZERO(&read_fds);
    FD_ZERO(&write_fds);
    FD_ZERO(&except_fds);
    if ((simpleSocket=socket(AF_INET, SOCK_STREAM,0)) == -1)
    {
        //fatal("Creating simpleSocket, AF_INET SOCK_STREAM failed");
    }
    fcntl(simpleSocket, F_SETFL, O_NONBLOCK); 
    setsockopt(simpleSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
    serv.sin_family = AF_INET;
    serv.sin_addr.s_addr = INADDR_ANY;
    serv.sin_port = htons(4000);
    if (bind(simpleSocket,(struct sockaddr *)&serv,sizeof(serv)) == -1)
    {
        close(simpleSocket);
        //fatal("Binding simpleSocket, AF_INET SOCK_STREAM failed");
    }
    if (listen(simpleSocket, 1000) == -1) 
    {
        close(simpleSocket);
        //fatal("Listening to simpleSocket, AF_INET SOCK_STREAM failed");
    }
    // add the listener to the master set
    FD_SET(simpleSocket, &master);
    // keep track of the biggest file descriptor
    fdmax = simpleSocket; // so far, it's this one
    for(;;)
    {
        struct descr *keepsake, *tmp;

        read_fds = master;
        write_fds = master;
        except_fds = master;
        /* Wait for connections for seconds amount of time and set the 
           specific file descriptor for each connection */
        if (select(fdmax+1, &read_fds, &write_fds, &except_fds, &seconds) == -1)
        {
            //nonfatal("Select failed");
        }
        /* handle new connections */
        if (FD_ISSET(simpleSocket, &read_fds))
        {
            /* Accept the next pending connection from simpleSocket */
            newfd = accept(simpleSocket, (struct sockaddr *)&inco, &inclen);
            if(newfd == -1)
            {
                //nonfatal("Accepting a file descriptor");
            }
            else 
            {
                struct descr *init;
                FD_SET(newfd, &master);   /* add to master set */
                if (newfd > fdmax)        /* keep track of the max */
                    fdmax = newfd;
                const char name_prompt[] = "Character name or (n)ew: ";
                const char error_prompt[]= "Unable to proceed please report this problem.";
                if(initialize_descr(newfd, &init) == 0)
                {
                    send(newfd, error_prompt, sizeof error_prompt, 0);
                    FD_CLR(newfd, &master);
                    close(newfd);
                }
                else
                {
                    send(init->newfd, name_prompt, sizeof name_prompt, 0);
                    printf("New connection: on socket:  %d,\r\n", init->newfd);
                    printf("                 sin_addr:  %s\r\n", inet_ntoa(inco.sin_addr));
                }
            }
        }/* END FD_ISSET(simpleSocket, &read_fds) */
        heart_pulse++;
        if (heart_pulse == 15000) /* The longest int type is unsigned long long int 18446744073709551616 */
        {
            if(rtime.second > -1)
                rtime.second++;
            if(rtime.second > 0x29) /* 41 */
            {
                rtime.second = 0x0; /* 0 */
                rtime.minute++;
                if(rtime.minute > 0x25) /* 37 */
                {
                    rtime.minute = 0x0; /* 0 */
                    rtime.hour++;
                    if(rtime.hour > 0x15) /* 21 */
                    {
                        rtime.hour = 0x0; /* 0 */
                        rtime.day++;
                        if(rtime.day > 0x1b) /* 27 */
                        {
                            rtime.day = 0x1; /* 1 */
                            rtime.month++;
                            if(rtime.month > 0xA) /* 10 */
                            {
                                rtime.month = 0x1; /* 1 */
                                rtime.year++;
                                if(rtime.year > 0x17cf87f) /* 24967295 */
                                {
                                    rtime.second = -1;     /* Apocolypse */
                                    rtime.minute = -1;     /* Apocolypse */
                                    rtime.hour = -1;       /* Apocolypse */
                                    rtime.day = -1;        /* Apocolypse */
                                    rtime.month = -1;      /* Apocolypse */
                                    rtime.year = -1;       /* Apocolypse */
                                }/* END if(rtime.year > 0x17cf87f) */
                            }/* END if(rtime.month > 0xA) */
                        }/* END if(rtime.day > 0x1b) */
                    }/* END if(rtime.hour > 0x15) */
                }/* END if(rtime.minute > 0x25) */
            }/* END if(rtime.second > 0x29) */
            int j;
            const char tick[5] = "tick.";
            for(j = 0; j <= fdmax; j++) 
            {
                  /* send to everyone! */
                  if (FD_ISSET(j, &master)) 
                {
                    //send(j, tick, sizeof tick, 0);
                  }
            }
            heart_pulse = 0;
        } /* END if (heart_pulse == 15000) */
        keepsake = descr_list;
        while(descr_list != NULL)
        {
            if(FD_ISSET(descr_list->newfd, &read_fds))
            {
                if(descr_list->state == CHARACTER_LOGIN)      /* Character login    */
                {
                    character_login(descr_list);
                }
                else if(descr_list->state == CREATE_CHARACTER)  /* Character creation */
                {
                    create_character(descr_list);
                }
            }
            descr_list = descr_list->next;
        }
        descr_list = keepsake;
        if(descr_list)
        {
            while(descr_list->state == SAY_GOODBY && descr_list->next != NULL)
            {
                descr_list = descr_list->next;
            }
            tmp = keepsake;
            keepsake = descr_list;
            descr_list = tmp;
        }
        while(descr_list != NULL)
        {
            tmp = descr_list->next;
            if(descr_list->state == SAY_GOODBY)
            {
                close(descr_list->newfd);
                FD_CLR(descr_list->newfd, &master);
                free(descr_list);
            } 
            descr_list = tmp;
        }
        descr_list = keepsake;
    }/* END for(;;) */
    close(simpleSocket);
    exit(EXIT_SUCCESS);
}

During lunch I grabbed your code and it compiled cleanly. accept() didn't work (on Linux) because intlen wasn't initalized to sizeof(struct inaddr_in) .

The way you have keepsake temporarily hold onto the head of the list and iterate using descr_list is odd. So I changed descr_list to be descr_head. It always is the head of the list (Then no need wasting struct space on a list pointer in each and every descr). Then iterate with:

struct descr *d;
for (d = descr_head; d; d = d->next)

Removed some dead code and it worked.

I think somehow you're getting descr_list to be NULL and trying to reference descr_list->next. Not sure, might look later at the original code but it was easier this way for me.

---------- Post updated at 03:50 PM ---------- Previous update was at 01:35 PM ----------

I looked again at fixing your implimentation and couldn't. I can't wrap my head around where descr_list may be at any given moment since it's a global and changed in a function (initalize_descr) called from main().... here's snipplets of my changes

int initialize_descr(int newfd, struct descr **p)
{
    struct descr *d;
    if(!(d = malloc(sizeof(struct descr))))
    {
        nonfatal("malloc failure initializing descr");
        return 0;
    }
    d->newfd = newfd;
    d->state = CHARACTER_LOGIN;
    d->next = NULL;
    *p = d;
    if(descr_head == NULL)
    {
        descr_head = d;
    }
    else
    {
        for (d = descr_head; d->next; d = d->next)
                ;
        d->next = *p;
    }
    return 1;
}
int main()
{
    socklen_t inclen = sizeof(struct sockaddr_in);
    for(;;)
    {
        struct descr *d, *prev;
        /* END if (heart_pulse == 15000) */
        prev = NULL;
        d = descr_head;
        while (d != NULL)
        {
            if(FD_ISSET(d->newfd, &read_fds))
            {
                if(d->state == CHARACTER_LOGIN)      /* Character login    */
                {
                    character_login(d);
                }
                else if(d->state == CREATE_CHARACTER)  /* Character creation */
                {
                    create_character(d);
                }
                if(d->state == SAY_GOODBY)
                {
                struct descr *next = d->next;
                    close(d->newfd);
                    FD_CLR(d->newfd, &master);
                    if (d == descr_head)
                        descr_head = next;
                    else
                        prev->next = next;
                    free(d);
                    d = next;
                    continue;
                }
            }
            d = d->next;
            prev = d;
        }
    }/* END for(;;) */
    close(simpleSocket);
    exit(EXIT_SUCCESS);
}

Did you test it after and did the disconnecting bug go away?

ah, i changed the loop to continue rather than break as well just now...

yes. I've not been able to kill it yet with 2-3 connections, closing in different orders each time.

Hey I just tried it to and it seems to be working. Is there any way to make sure that when someone disconnects, the socket someone else connects on will fill an empty socket. For me every time I connect, the socket number increases and there is a limit to the size of the number that the integer can handle. So I was hoping there was a way when socket 3 hangs up for the next person that logs in to be socket 3 and not socket 7.

You are properly close-ing disconnected FD's, yes? If so, you don't need to worry -- FD numbers will be recycled eventually, long before the integer would wrap.

If you're not closing them, your process will soon hit the limit on how many file descriptors it can have open at once, which is going to be far less than the 4-billion limit 32-bit integers have.

getconf OPEN_MAX
256

will show you how many file one process can have open at one time (don't forget three for stdin, stdout, stderr).

In the example above you have 253 available file slots. In C you can call getdtablesize() (unistd.h) to see what the limit is, it may NOT be OPEN_MAX. It probably is more.

1 Like

Ok thankyou.

---------- Post updated at 05:31 PM ---------- Previous update was at 05:21 PM ----------

Thanks neutronscott. While you still have the program handy could you maybe help me with an overflow problem. When I receive with my two functions create_character, and character_login. Well when I receive data that is longer then recv is receiving It seems to recv again three or four times depending on the amount of characters over the limit there are. I was hoping you could shine some light on this subject so I can try to fix it myself maybe even post some more snippets. I had the idea that if you sent one thousand characters I would only receive 12 and that would be the end of it. Should I FD_CLR and then FD_SET after a receive and if so how to I send a fd_set to a function?

It's like a file. If you read 30 bytes from a 100 byte file, there's still 90 bytes to go. If you don't know how long it is, you have to keep reading until you find the end.

Except it's a file that arrives whenever it feels like it, in chunks of whatever variable size it feels like. If you don't know how long a field's supposed to be, the socket can't tell you. Not dependably, anyway. It might arrive in the size it was sent in -- or the socket might decide to wait and send it all in one big 64K chunk. You can't guess.

Your protocol should include some sort of terminator for variable-length things, since you can't guess from how much you read.

what do you mean terminator? how do you tell recv to only recv 12 bytes and only 12 bytes from a single send regardless of the amount of data they sent? Is it possible to recv in that manor?

I noticed that too. In my trials to learn such things each client had their own buffer and also an int or ptr into where it's at, since you're not guaranteed to get the entire line in 1 read (unless you wrote the client too). I appended into it until a newline. If the clients buffer was full, my read loop would just discard the extra data between buffer size and newline. Then attempt to process it all. Then reset the buffer.

I think all your FD_SET/FD_CLR stuff is OK. In mine, I FD_ZERO at the top of the loop and then FD_SET my listener, and iterated over my linked list and FD_SET those. Yours is more efficient.

Send the string with a \n on the end. So when you see the \n, you know you've received the entire thing. Once you have, just chop off the front of it and put it in your structure, ignoring the rest.

If they send 1000 bytes, you get 1000 bytes.