0

I am working on my school assignment which requires me to pass a structure that contains a char pointer from the client program to the server and print the structure data in the Server.c program. I am being able to pass the structure properly and being able to retrieve the integer data from the structure in server.c, but I am getting an error "Segmentation fault" when I try to print the char* data in the server.c program that is coming from the Client.c program. How do I fix it?

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<sys/types.h>
#include<sys/socket.h>

#define PORT 8080

struct StudentInfo
{
    char* name;
    int roll;

}student;


int main()
{
    student.name=(char*)malloc( 50 * sizeof(char));
    student.name="Sara You";
    student.roll=124;


    int network_socket=socket(AF_INET, SOCK_DGRAM, 0);

    struct sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));

    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(PORT);
    serveraddr.sin_addr.s_addr=INADDR_ANY;

    sendto(network_socket, &student, sizeof(student),0, (struct sockaddr*) &serveraddr, sizeof(serveraddr));

    close(network_socket);

}

Server.c

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<sys/socket.h>
#include<string.h>

#define PORT 8080


struct StudentInfo
{
    char* name;
    int roll;

} student1;

int main()
{
    student1.name=(char*)malloc( 50 * sizeof(char));
    struct sockaddr_in serveraddr, cliaddr;
    int network_socket=socket(AF_INET, SOCK_DGRAM, 0);

    memset(&serveraddr,0,sizeof(serveraddr));
    memset(&cliaddr,0,sizeof(cliaddr));

    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(PORT);
    serveraddr.sin_addr.s_addr=INADDR_ANY;

    bind(network_socket, (struct sockaddr*) &serveraddr, sizeof(serveraddr));


    int len=sizeof(cliaddr);
    recvfrom(network_socket, &student1, sizeof(student1), 0, (struct sockaddr*) &cliaddr, &len);
    printf("Name %s: ", student1.name);     //Segmentation fault
    printf("Name %d: ", student1.roll);



}
Sara Khan
  • 3
  • 1
  • 2
    You can pass the pointer from the client to the server but the server won't be able to access the client's memory unless the two processes share memory. No doubt the client will have to send the characters pointed to by the structure's pointer. – Jeff Holt Dec 06 '21 at 14:21
  • @AlexF I am required to use char* How do I fix it in that case? – Sara Khan Dec 06 '21 at 14:24
  • You have to serialize the characters of the string as well, e.g. by sending it as a NUL-terminated string or by sending the number of characters in addition to the characters. – Bodo Dec 06 '21 at 14:26
  • @Bodo can you please provide me a piece of code? – Sara Khan Dec 06 '21 at 14:34
  • 1
    `student.name=(char*)malloc( 50 * sizeof(char)); student.name="Sara You";` is a memory leak. Pointers are not magical; they are just variables that hold an address. In those two lines of code, you allocate some memory and assign the address of the memory to `student.name`. Then you throw away that value and reassign `student.name` the address of the string constant "Sara You". Perhaps you intended to do a `strcpy` there and copy the string constant into the newly allocated memory. – William Pursell Dec 06 '21 at 15:10
  • @WilliamPursell can you please provide a piece of code to achieve that? – Sara Khan Dec 06 '21 at 15:29
  • `const char msg[] = "Sara You"; student.name = malloc(sizeof msg); if( student.name == NULL ){ perror("malloc"); exit(1); } strcpy(student.name, msg);` – William Pursell Dec 06 '21 at 15:41

1 Answers1

0

It might be possible to fix this easily if you don't mind constraining student names to be less than, say, 100 bytes. It looks like you're sending the structure as a whole without any consideration for byte order. Therefore, if the byte order on the client and server match, then simply changing the structure definition will fix the problem. Of course, by making the memory for the name part of the structure, you don't have to allocate memory and you'll have to use strcpy instead of the assignment of a pointer. Like so:

struct StudentInfo {
    char name[100];
    int  roll;
} student;

int main (int argc, char *argv[]) {
    //student.name=(char*)malloc( 50 * sizeof(char));
    //student.name="Sara You";
    strcpy(student.name, "Sara You"); // check length, truncate, or send multiple messages

UPDATE 1

If you must serialize what you send and deserialize what you receive, then you can use these two functions that return something that can be freed:

char * serializeStudent (struct StudentInfo *stu) {
    char *rval;
    if (!stu || !stu->name) {
        // errno = EINVAL;
        return 0;
    }
    rval = malloc(strlen(stu->name) + 21); // never cast malloc
    if (!rval) {
        return 0; // errno will be set by malloc
    }
    sprintf(rval, "%10d%10d%s", stu->roll, strlen(stu->name), stu->name);
    return rval;
}

Call serializeStudent before sending, send the string it returns (if it's not null), and then free that string after the send is successful.

struct StudentInfo * deserializeSerializedStudent (char *ser) {
    struct StudentInfo *rval;
    if (!ser) {
        // errno = EINVAL;
        return 0;
    }
    rval = malloc(sizeof(*rval));
    if (!rval) {
        return 0; // errno will be set by malloc
    }
    int len;
    int n = sscanf(ser, "%10d%10d", rval->roll, &len);
    if (n != 2) {
        // errno = EINVAL;
        free(rval);
        return 0;
    }
    rval->name = malloc(len+1);
    if (!rval->name) {
        free(rval);
        return 0; // errno will be set by malloc
    }
    n = sscanf(ser+20, "%*s", len, rval->name);
    if (n != 1) {
        // errno = EINVAL;
        free(rval);
        return 0;
    }
    return rval;
}

Call deserializeSerializedStudent after receiving a string that you know is complete. Then do what you need with the structure, then free it after freeing the string that it contains.

Jeff Holt
  • 2,940
  • 3
  • 22
  • 29