BSDnexus
29Jan/11Off

Printing extended characters in C

In order to print the extended character set on the CLI in C it is necessary to use setlocale(). Example code below, with highlight of the use of setlocale():

#include <stdio.h>
#include <locale.h>
 
int main(void) {
	int c = 0xF9;
	int c2 = 0xEA;
 
	if (!setlocale(LC_CTYPE, "")) {
		fprintf(stderr, "Can't set the specified locale! Check LANG, LC_CTYPE, LC_ALL.\n");
		return 1;
	}
 
	printf("%lc %lc --\n", c, c2);
	return(0);
}

Running this code results in:

$ ./a.out
ù ê
Tagged as: , No Comments
16Dec/10Off

Tuning malloc

According to the (Linux) malloc man page calling free twice on the same memory location is a certain crash:

Crashes in malloc(), calloc(), realloc(), or free() are almost always related to heap corruption, such as overflowing an allocated chunk or freeing the same pointer twice.

...something along the lines of:

$ ./a.out
*** glibc detected *** ./a.out: double free or corruption (top): 0x0944c008 ***

however, according to the same man page, this is now a tunable feature

Recent  versions  of  Linux  libc  (later  than 5.4.23) and glibc (2.x) include a malloc() implementation  which  is  tunable  via  environment variables.   When  MALLOC_CHECK_  is  set,  a  special (less efficient) implementation is used which is designed to be tolerant against  simple errors, such as double calls of free() ... If MALLOC_CHECK_ is set to  0,  any  detected  heap  corruption  is  silently ignored ...

I decided to create a simple test to see this in action. Exactly as detailed, I ran the compiled code with the environment variable and the program exited successfully.

$ MALLOC_CHECK_=0 ./a.out
$ echo $?
0

Sample code follows

#include <stdlib.h>
 
int
main(void) {
 char * foo;
 
 foo = (char *) malloc(500);
 
 free(foo);
 free(foo);
 return(0);
}
13Nov/10Off

Inter-Process Communication

Following a discussion at work this week I realised I had never written anything that had process to process communication; specifically UNIX domain sockets. As such I decided to write a simple app.

To make things more interesting I wanted the app to be a single binary that could be used as either the server or the client. Essentially, on startup it checks to see if the UNIX domain socket exists and if not, creates one and waits for connections. If one already exists it runs in client mode and sends the CLI parameter given a message to the server. Sending "quit" tells the server to shutdown.

Part of the inspiration for this came from the way squid works. A single binary is used to either start the server or issue commands to the running server.

Note - the code is not complete and some error checking is not undertaken

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#include <sys/socket.h>
#include <sys/types.h> /* included for portability */
#include <sys/un.h>
 
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
#define IPC_SOCK_PATH "/tmp/ipc001"
 
void client_mode(int sock_fd, struct sockaddr_un my_addr, const char* message);
void server_mode(int sock_fd);
void write_text (int sock_fd, const char* text);
 
void write_text (int sock_fd, const char* text) {
    /* Write the number of bytes in the string, including
     *      NUL-termination.  */
    int length = strlen(text) + 1;
    write(sock_fd, &length, sizeof(length));
    /* Write the string.  */
    write(sock_fd, text, length);
}
 
void client_mode(int sock_fd, struct sockaddr_un my_addr, const char* message) {
    printf("Client mode!\n");
 
    /* Connect the socket.  */
    if (connect(sock_fd, (struct sockaddr *) &my_addr, sizeof(struct sockaddr_un) ) == -1) {
        perror("Client connect failed");
        exit(200);
    }
 
    /* Write the text on the command line to the socket.  */
    write_text(sock_fd, message);
    close(sock_fd);
}
 
int get_message(int client_socket) {
    while (1) {
        int length;
        char * text;
        /* First, read the length of the text message from the socket. If
         * read returns zero, the client closed the connection. */
        if (read(client_socket, &length, sizeof(length)) == 0)
            return 0;
        /* Allocate a buffer to hold the text. */
        text = (char*) malloc(length);
        /* Read the text itself, and print it. */
        read(client_socket, text, length);
        printf ("%s\n", text);
        /* If the client sent the message “quit,” we’re all done. */
        printf("comparing - '%s' with 'quit'\n", text);
        if (!strcmp(text, "quit")) {
            /* Free the buffer. */
            free(text);
            return 1;
        }
        free(text);
    }
}
 
void server_mode(int sock_fd) {
    struct sockaddr_un client_name;
    socklen_t client_name_len;
    int client_socket_fd;
    int client_sent_quit_message;
 
    printf("Server waiting for connections ...\n");
    printf("Socket location : %s\n", IPC_SOCK_PATH);
 
    do {
        /* Accept a connection. */
        client_socket_fd = accept(sock_fd, (struct sockaddr *) &client_name, &client_name_len);
        /* Handle the connection. */
        client_sent_quit_message = get_message(client_socket_fd);
        /* Close our end of the connection. */
        close (client_socket_fd);
    } while (!client_sent_quit_message);
}
 
int main(int argc, char* argv[]) {
    int sock_fd;
    struct sockaddr_un my_addr;
 
    if ((sock_fd = socket(PF_UNIX, SOCK_STREAM, 0)) == -1) {
        perror("Socket creation failed");
        exit(255);
    }
 
    /* use bind to determine if we use server mode or client */
    memset(&my_addr, 0, sizeof(struct sockaddr_un));
    my_addr.sun_family = AF_UNIX;
    strncpy(my_addr.sun_path, IPC_SOCK_PATH, sizeof(my_addr.sun_path) -1);
 
    if ( bind(sock_fd,(struct sockaddr *) &my_addr, sizeof(struct sockaddr_un)) == -1) {
        if (errno == EADDRINUSE) {
            if ( argc < 2 ) {
                printf("Insufficient arguments for client mode\n");
                exit(200);
            }
            client_mode(sock_fd, my_addr, argv[1]);
            close(sock_fd);
        } else {
            perror("Socket bind failed");
            exit(255);
        }
    } else {
        if (listen(sock_fd, 5) == -1) {
            perror("Listen failed");
            exit(255);
        }
        server_mode(sock_fd);
 
        /* Remove the socket file. */
        close(sock_fd);
        unlink(IPC_SOCK_PATH);
    }
 
    return(0);
}
Tagged as: , , No Comments