tags:

views:

100

answers:

2

Warning: Please treat me like the rookie I am. This is my first "real" C program. So if I don't understand some things, that's why.

I'm trying to make a chat server following the example from Beej's Guide to Network Programming. It came recommended, so there you go.

I want to have a function accept a pointer to a structure, modify properties in that pointer, and set up a listener on the passed port. In the below code, I am getting a Segmentation Fault, and I honestly can't figure out why. Blame me being green. (Developing in Netbeans 6.8 on Ubuntu, if needed):

#define PORT "4400"

typedef struct {
    int port;
    fd_set *connections;
    int connections_count;
    int listener;
    struct addrinfo address;
    struct addrinfo socket_hints;
} Server;

typedef struct {
    struct sockaddr_storage address;    // User's address
    int fs_id;                  // ID to the socket they belong to
    char *name;                 // Pointer to the user's name
    struct User *nextUser;      // Next user in the list
} User;

void initialize_server(Server *passed_server, char *port) {
    struct addrinfo *temp;
    int result;

    // Set up the server hints
    memset(&passed_server->socket_hints, 0, sizeof(struct addrinfo));
    passed_server->socket_hints.ai_family = AF_UNSPEC;
    passed_server->socket_hints.ai_socktype = SOCK_STREAM;
    passed_server->socket_hints.ai_flags = AI_PASSIVE;

    result = getaddrinfo(NULL, port, &passed_server->socket_hints, &temp);
    printf("Result: %d\n", result);
}

int main(int argc, char** argv) {
    // Set up socket stuff
    Server *server; // Set up the server
    memset(server, 0, sizeof(Server));

    fd_set read_sockets; // Master socket holder and sockets to read
    int new_connection; // Holds the socket ID of the new connection
    socklen_t address_length; // Used to hold the length of the address from the user
    struct addrinfo;

    // Useful sets
    char buffer[1024];
    int bytes_recieved;
    int yes = 1; // For SETOPT

    // Set up server info on defined port
    initialize_server(server, PORT);
    FD_ZERO(&read_sockets);

    return (EXIT_SUCCESS);
}

If you need the full code (I think I posted everything essential), you can find a link below. Thanks in advance for any help or attempt at it!

http://pastebin.org/529545

+4  A: 

The line:

Server *server;

does not actually allocate any space for a server structure, just for a pointer to one, that's set to a random value.

It looks like the change you need is:

Server *server = malloc (sizeof (Server));

which actually allocates some memory for you to use.

Think of the difference as follows:

Server *server;              |  Server *server = malloc (sizeof (Server));
       +----------+          |         +---------+     +-----------+
server | ???????? | --> ???  |  server | pointer | --> | structure |
       +----------+          |         +---------+     +-----------+
paxdiablo
But isn't the call following that doing so?memset(server, 0, sizeof(Server));
Codeacula
No, that's almost certainly the one causing the error. All `memset` does is to fill memory with a given value, you still have to have a valid addressable memory block - you're effectively passing it a random address to start filling from. When I use the malloc, I get back `Result: 0` from the program.
paxdiablo
Thanks, that absolutely did it! Helped me understand the pointer thing just a bit more, too.
Codeacula
+1, excellent post, especially after the edits. Nice ASCII art.
Thanatos
+2  A: 
int main(int argc, char** argv) {
// Set up socket stuff
Server *server; // Set up the server
memset(server, 0, sizeof(Server));

This is incorrect. Here, you're asking memset to zero out the memory pointed to by server. The call to memset is correct, it's the pointer server that isn't. This line:

Server *server;

Allocates memory for and gives you a pointer, but it does not allocate any memory for the pointed-to object, and it does not give the pointer an initial value. Thus, after this line, the pointer is just pointing to some random spot in memory. (It's using whatever was left over in RAM, probably) We haven't assigned it a valid value yet, so it's not valid to pass it to memset.

Now, we need to give it a valid value. You could either:

1) Allocate a Server on the stack, by just saying:

Server server;
memset(&server, 0, sizeof(server));

2) Allocate a Server dynamically, using malloc:

Server *server = malloc(sizeof(*server));
// Check for NULL, which means malloc failed.

(Also, note the use of sizeof - using the variable name instead of the type will allow the sizeof to adjust if you ever change the type of the variable.)

You might want to find and review a basic tutorial on pointers. This is a pretty classic mistake of someone who's just encounted pointers for the first time, so, don't feel too bad.

Thanatos
Much appreciated, Thanatos. I actually just got done learning this in school, but the example there was ready made. I learn best by making my own mistakes. I totally forgot about malloc. I had memset on the mind from looking through other posts for an answer first. I'd upvote this if I could. Thank you kindly for the warm welcome, too.
Codeacula