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
ù ê |
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); } |
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); } |