This forum is in archive mode. You will not be able to post new content.

Author Topic: [C] datagram sockets example  (Read 2442 times)

0 Members and 1 Guest are viewing this topic.

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
[C] datagram sockets example
« on: May 10, 2012, 08:53:57 AM »
Hello EZ.

This program uses datagram sockets to communicate. There is one server that gets all messages from the clients collects them in files and repeats the messages after the client has logged off. The files are named after the client's pid numbers.
 The client is stopped with Crtl+d, which will log it off from the server and terminate. The server can be set in END modus by Ctrl+c. This won't stop it immediately. The server waits until all clients have logged off and terminates after that. In END modus the server will refuse the connection to new clients.
 
 There is the code for the server:

Code: [Select]
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define RUNNING 0
#define MESSAGE 1
#define END 2
#define BEGIN 3

void write_file(char fname[], char msg[]);
void display_file(char fname[]);
void sigfkt(int snr);
void register_sigfkt();
void init_address(struct sockaddr_un *srvadr);
void bind_address(struct sockaddr_un *srvadr, int sockd);
int init_socket();
int handle_client_request(char *eab, int sendcounter);

int modus = RUNNING;

int main(int argc, char **argv) {
        int sockd;
        int flags = 0;
        int rc;
        int sendcounter = 0;
        socklen_t len;
        struct sockaddr_un srvadr;
        struct sockaddr_un cladr;
        char eab[100];

        register_sigfkt();
        init_address(&srvadr); 
        sockd = init_socket();
        bind_address(&srvadr, sockd);

        printf("server started\n");
         
        do {
                len = sizeof(cladr);
                memset(eab, '\0', sizeof(eab));
                rc = recvfrom(sockd, eab, sizeof(eab), flags,
                        (struct sockaddr *)&cladr, &len);
                if(rc < 0) {
                        perror("recvfrom");
                } else {
                        sendcounter = handle_client_request(eab, sendcounter);
                }
         
        } while(sendcounter > 0 || modus != END);

        printf("server stopped\n"); 
 
        close(sockd);
        unlink(srvadr.sun_path);
        exit(0);
}

void write_file(char fname[], char msg[]) {
        FILE *fp;
        size_t rc;
        size_t count = 1;
        fp = fopen(fname, "a");

        rc = fwrite(msg, strlen(msg), count, fp);
        if(rc != count) {
                perror("fwrite");
        }
 
        fclose(fp);
}

void display_file(char fname[]) {
        FILE *fp;
        char msg;
        size_t count = 1;
 
        fp = fopen(fname, "r");

        while(fread(&msg, sizeof(char),count,fp) > 0) {
                printf("%c", msg);
        }
        if(feof(fp)) {
                puts("EOF\n");
        } else {
                perror("display_file");
        }

        fclose(fp);
}

void sigfkt(int snr) {
        printf("sigfkt called\n");
        if(snr == SIGINT) {
                printf("terminating program ...\n\n");
                modus = END;
        }
}

void register_sigfkt() {
        int rc;
        struct sigaction disp;
        disp.sa_handler = sigfkt;
        disp.sa_flags = 0;
        sigemptyset(&disp.sa_mask);
        rc = sigaction(SIGINT, &disp, NULL);
        if(rc != 0) {
                perror("sigaction");
                exit(1);
        }
}

void init_address(struct sockaddr_un *srvadr) {
        srvadr->sun_family = AF_UNIX;
        strcpy(srvadr->sun_path, "sockdgram1");
        unlink(srvadr->sun_path);
}

void bind_address(struct sockaddr_un *srvadr, int sockd) {
        int rc = bind(sockd, (struct sockaddr *)srvadr, sizeof(*srvadr));
        if(rc < 0) {
                perror("bind");
                exit(3);
        }
}

int init_socket() {
        int sockd = socket(AF_UNIX, SOCK_DGRAM, 0);
        if(sockd < 0) {
                perror("socket");
                exit(2);
        }
        return sockd;
}

int handle_client_request(char *eab, int sendcounter) {
        char fname[100];
        pid_t pid;
        int rc;
        int control = eab[0];
         unsigned int col_pos = strchr(eab,':') - eab;

        strncpy(fname, &eab[1], col_pos-1);
        fname[col_pos-1] = '\0';
        pid = atoi(fname);
        printf("client %s ", fname);
         
        if(control == BEGIN && modus == END) {
                //refuse clients in END modus
                rc = kill(pid, SIGUSR1);
                printf("refused\n");
                if(rc < 0) {
                        perror("kill");
                }
        }
        if(control == BEGIN && modus != END) {
                printf("added\n");
                sendcounter++;
                printf("sendcounter = %d\n", sendcounter);
        }
        if(control == MESSAGE) {
                write_file(fname, &eab[col_pos+1]);
                printf("message: %s\n", &eab[col_pos+1]);
        }
        if(control == END) {
                sendcounter--;
                printf("checked out, show file\n");
                display_file(fname);
                printf("sendcounter = %d\n", sendcounter);
        }
        return sendcounter;
}

For the client:

Code: [Select]
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

#define MESSAGE 1
#define END 2
#define BEGIN 3

void sigfkt(int signr);
void init_adr_info(struct sockaddr_un *srvadr);
int init_socket();
void create_socket_fname(struct sockaddr_un *cladr);
void send_start(struct sockaddr_un *srvadr, int sockd);
void send_end(struct sockaddr_un *srvadr, int sockd);
int send_msg(struct sockaddr_un *srvadr, int sockd, char *msg);

int main(int argc, char **argv){
        int sockd;
        char msg[100];
        int rc;
        struct sockaddr_un srvadr;
        struct sockaddr_un cladr;

        signal(SIGUSR1, sigfkt);
        printf("started client %d\n", getpid());       
        init_adr_info(&srvadr);
        sockd = init_socket();
        create_socket_fname(&cladr);
               
        send_start(&srvadr, sockd);
       
        printf("message: \n");
        while(fgets(msg, sizeof(msg), stdin) != NULL) {
                rc = send_msg(&srvadr, sockd, msg);
                if(rc == -1) {
                        break;
                }
        }
       
        send_end(&srvadr, sockd);
       
        close(sockd);
        unlink(cladr.sun_path);
        exit(0);
}

void sigfkt(int signr) {
        printf("sender refused, terminating ...\n");
        exit(3);
}

void init_adr_info(struct sockaddr_un *srvadr) {
        srvadr->sun_family = AF_UNIX;
        strcpy(srvadr->sun_path, "sockdgram1");
}

int init_socket() {
        int sockd = socket(AF_UNIX, SOCK_DGRAM, 0);
        if(sockd < 0) {
                perror("socket");
                exit(1);
        }
        return sockd;
}

void create_socket_fname(struct sockaddr_un *cladr) {
        char clientname[50];
        int rc;
        strcpy(clientname, "sockXXXXXX");
        rc = mkstemp(clientname);
        if(rc == -1) {
                perror("mkstemp");     
                exit(2);
        }
        strcpy(cladr->sun_path, clientname);
}

void send_start(struct sockaddr_un *srvadr, int sockd) {
        char eab[100];
        int flags = 0;
        int rc;
        sprintf(eab, "%c%d:", BEGIN, getpid());
        rc = sendto(sockd, eab, strlen(eab), flags, (struct sockaddr*)srvadr,
                sizeof(*srvadr));
        if(rc < 0) {
                perror("sendto start");
        }
}

void send_end(struct sockaddr_un *srvadr, int sockd) {
        char eab[100];
        int flags = 0;
        int rc;
        sprintf(eab, "%c%d:", END, getpid());   
        rc = sendto(sockd, eab, strlen(eab), flags, (struct sockaddr*)srvadr,
                sizeof(*srvadr));
        if(rc < 0) {
                perror("sendto end");
        }
}

int send_msg(struct sockaddr_un *srvadr, int sockd, char *msg) {
        char eab[100];
        int flags = 0;
        int rc;
       
        sprintf(eab,"%c%d:%s", MESSAGE, getpid(), msg);

        rc = sendto(sockd, eab, strlen(eab), flags,
                (struct sockaddr*)srvadr, sizeof(*srvadr));
        if(rc < 0) {
                perror("sendto message");
        }
        if(rc == 0) {
                printf("EOF");
                return -1;
        }
        return 0;
}

The makefile:

Code: [Select]
all: server client
server: server.o
        gcc -Wall -o server server.o
client: client.o
        gcc -Wall -o client client.o
client.o: client.c
        gcc -Wall -c client.c
server.o: server.c
        gcc -Wall -c server.c

As usual I am open for suggestions for a better code. I have one question: Would you use #define or const for the modus constants (RUNNING, MESSAGE, END, BEGIN) and why?

Edit: Syntax highlighting removed.
« Last Edit: May 10, 2012, 05:59:00 PM by Deque »

Offline s3my0n

  • Knight
  • **
  • Posts: 276
  • Cookies: 58
    • View Profile
    • ::1
Re: [C] datagram sockets example
« Reply #1 on: May 10, 2012, 02:45:25 PM »
What's with the grey hard to read text in the code boxes?
Easter egg in all *nix systems: E(){ E|E& };E

Offline Kulverstukas

  • Administrator
  • Zeus
  • *
  • Posts: 6627
  • Cookies: 542
  • Fascist dictator
    • View Profile
    • My blog
Re: [C] datagram sockets example
« Reply #2 on: May 10, 2012, 02:54:37 PM »
What's with the grey hard to read text in the code boxes?
It's how code-highlighter makes the code "readable".

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Re: [C] datagram sockets example
« Reply #3 on: May 10, 2012, 05:59:35 PM »
I removed the syntax highlighting, I guess it is better that way.

Z3R0

  • Guest
Re: [C] datagram sockets example
« Reply #4 on: May 10, 2012, 06:15:21 PM »
I would say that using const would be better, however, that's dependent on the nature of the code (being if the code is C in nature, or C++). If the code is C++, I would say const is better because if there is an error that occurs because of the const variable, the error message will be a lot more helpful than if it were declared via #define. If the code is C it really doesn't matter because the idea of const as it relates to C was borrowed from C++, and doesn't have an equivalent compile-time functionality. Either way, there's really no difference in core functionality between the two, they both do relatively the same thing, it just depends on what kind of trouble-shooting information you would like to get back from the program if an error occurs.

Good job btw, I think this is the first time I've seen a udp example of this type of program. Generally these are made with tcp functionality.

EDIT: See ca0s's reply, I'm not very strong in C/++, he'll be able to give you much more technical insight as to the difference between the two than I will.
« Last Edit: May 10, 2012, 06:18:33 PM by m0rph »

Offline ca0s

  • VIP
  • Sir
  • *
  • Posts: 432
  • Cookies: 53
    • View Profile
    • ka0labs #
Re: [C] datagram sockets example
« Reply #5 on: May 10, 2012, 06:15:32 PM »
Quote
I have one question: Would you use #define or const for the modus constants (RUNNING, MESSAGE, END, BEGIN) and why?

Const is just a label for the compiler, which will warn you or throw an error if you try to modify it run-time. If you do something like *((int *) &const_int_var) = 123; it will probably let you do it.
If its value will never be modified run time, I prefer to use #defines. The difference in the compiled program is (simplified):

Using const:
Code: [Select]
const int value = 5;
int something = value + 5;
Assembly:
Code: [Select]
{wherever in memory}
value:
.bytes 00 00 00 05
something:
.bytes 00 00 00 00
{code}
lea ebx, [value]
mov eax, [rbx]
lea ebx. [something]
mov dword[ebx], eax
add eax, 5
mov dword[something], eax

Using defines:
Code: [Select]
#define VALUE = 5
int something = VALUE + 5
Assembly:
Code: [Select]
{somewhere in memory}
something:
.byte 00 00 00 00
{code}
mov eax, 5
add eax, 5
lea ebx, [something]
mov dword[ebx], eax

So you don't allocate memory for it and value is put in the executable at compile-time, whereas if you use const it will need to be loaded every time it is used.
(I wrote those ASM lines on the fly, they are intentionally redundant, but I have seen worse things. Sorry for any mistake, I just wanted to make differences clear).
{ Oh, m0rph was faster :P }
« Last Edit: May 10, 2012, 06:18:38 PM by ca0s »

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Re: [C] datagram sockets example
« Reply #6 on: May 10, 2012, 08:53:49 PM »
Thank you for your explanations, m0rph and ca0s.

 



Want to be here? Contact Ande, Factionwars or Kulverstukas on the forum or at IRC.