diff options
| -rw-r--r-- | md/writeup.md | 2 | ||||
| -rw-r--r-- | md/writeup/mqueue_ipc_example.md | 740 | 
2 files changed, 741 insertions, 1 deletions
diff --git a/md/writeup.md b/md/writeup.md index 94ee3ff..e1d5655 100644 --- a/md/writeup.md +++ b/md/writeup.md @@ -28,7 +28,7 @@ title: Writeup page  [Compile static python](writeup/compile_python.md)    [Linux hello world in Swift](writeup/linux_hello_world_in_swift.md)    [Running disk images in QEMU](writeup/running_disk_images_in_qemu.md)   - +[Mqueue IPC example](writeup/mqueue_ipc_example.md)    ## Projects diff --git a/md/writeup/mqueue_ipc_example.md b/md/writeup/mqueue_ipc_example.md new file mode 100644 index 0000000..b98b40e --- /dev/null +++ b/md/writeup/mqueue_ipc_example.md @@ -0,0 +1,740 @@ +title:Mqueue IPC example in shell script +keywords:bash,linux,mqueue,ipc + +# Mqueue IPC example in shell script + +## Intro + +Idea of messages comes from beginning of computer history. Mainly used for inter-process +communication. Fascinating fact is no I havent seen someone using them on linux.  +Using mqueue is probably most easiest IPC interface possible. Cool feature of it it have +path where you can access it. And as its act as queue then you can just open/read message +with minimal amount of code. Disadvantage is you don't know who sent you message.  + +Advantages +    * simple API +    * no need to verify message size, comes as single packet +    * persistent, if one program crashed, message stays in queue + +Disadvantages: +    * cant be sure to who received message +    * bidirectional communication could be harder to implement + +One of bash hacks that can be archived is inter process communication between +two bash scripts. Example will be provided! + +## Linux mqueue API + +Most system have them compiled in kernel you can check if you system supports them +```bash +$ cat /proc/filesystems | grep mq +nodev   mqueue +``` + +and if its mounted with + +```bash +$ mount | grep mque +mqueue on /dev/mqueue type mqueue (rw,nosuid,nodev,noexec,relatime) +``` + +API for using mqueue is similar all UNIX interface. To check status of mqueue +use cat command + +```bash +$ cat /dev/mqueue/stack-0  +QSIZE:0          NOTIFY:0     SIGNO:0     NOTIFY_PID:0 +``` + +Further is mentioned API calls and API usage template. + + +### Library interfaces and system calls + + +    Library interface    System call +    mq_close(3)          close(2) +    mq_getattr(3)        mq_getsetattr(2) +    mq_notify(3)         mq_notify(2) +    mq_open(3)           mq_open(2) +    mq_receive(3)        mq_timedreceive(2) +    mq_send(3)           mq_timedsend(2) +    mq_setattr(3)        mq_getsetattr(2) +    mq_timedreceive(3)   mq_timedreceive(2) +    mq_timedsend(3)      mq_timedsend(2) +    mq_unlink(3)         mq_unlink(2) + +### Create mqueue + +Mqueue are located in mount point directory. Check with mount command where its located. +Majority system have it at /dev/mqueue . +Mqueue names passed to API should start with "/" no mount point path name needed in front.   + +Create mqueue by opening it + +```c +mq_open("/name",O_RDWR | O_CREAT, 0666, NULL); +``` + +### Send mqueue message + +If mqueue already created then it will be opened, otherwise created. + + +```c +mq_open("/name",O_RDWR | O_CREAT, 0666, NULL); +mq_send(fd, "packet", strlen("packet"), set_mesg_priority); + +``` + +### Receive mqueue message + +If mqueue already created then it will be opened, otherwise created + +```c +mq_open("/name",O_RDWR | O_CREAT, 0666, NULL); +mq_receive(mq_fd, ptr_to_str, ptr_size, &get_priority); +``` + +### Remove mqueue + +Unlink file, path will disappear after all process will release file descriptors, +after unlink. + +```c +mq_open("/name",O_RDWR | O_CREAT, 0666, NULL); +mq_unlink("/name"); +``` + +## Example bash IPC + +Further is source of utilities for using mqueues. Lets create example where +one message queue created from one script, and script loops over and check  +received messages from queue, and executes received commands. + +### Server script that check mqueue for commands + +loop reads queue with "./mqueue_pop -m QUEUE_NAME". If its successful +then it receives non-empty string, if not then string is empty. +Create queue if its not there with "./mqueue_create -m $QUEUE_NAME". +And after receiving stop command exits loops and unlink queue. + +3 commands supported to be sent stop/ls/aloha + + + +_daemon.sh_ +```bash +#!/bin/sh +QUEUE_NAME=/music-player-daemon +POP_CMD() +{ +    ./mqueue_pop -m $QUEUE_NAME +} +CREATE_QUEUE() +{ +    ./mqueue_create -m $QUEUE_NAME +} +REMOVE_QUEUE() +{ +    ./mqueue_remove -m $QUEUE_NAME +} +if [ ! -f "/dev/mqueue$QUEUE_NAME" ]; then +    CREATE_QUEUE +fi +state="1" +while [ $state -ne 0 ]; do +    get_cmd=$(POP_CMD) +    case "$get_cmd" in +        stop) +            state="0" +            ;; +        ls) +            ls /dev +            ;; +        aloha) +            echo "aloha" +            ;; +    esac +    sleep 1 +done +if [ -f "/dev/mqueue$QUEUE_NAME" ]; then +    REMOVE_QUEUE +fi +``` + +### Send commands to script + +Send commands to running server script. First lists /dev directory, +second output aloha and third one terminates script. + +``` +./send_command ls +./send_command aloha +./send_command stop +``` + +_send_command.sh_ +```bash +#!/bin/sh +QUEUE_NAME=/music-player-daemon +SEND_CMD() +{ +    ./mqueue_push -m $QUEUE_NAME -p "$1" +} +echo "Send command to daemon" +if [ -f "/dev/mqueue$QUEUE_NAME" ]; then +    SEND_CMD $1 +else +    echo "No queue to send" +fi +``` + +## Source of example utilities for using mqueue + +All source located at [http://git.main.lv/cgit.cgi/mqueue_examples.git/](http://git.main.lv/cgit.cgi/mqueue_examples.git/) + +When compiling **-lrt** flag required + +### mqueue_create.c - Create mqueue + +_mqueue_create.c_ +```c +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <mqueue.h> +#include <errno.h> + +typedef struct { +    char *f_mqname; +    int   f_verbose; +    int   f_helper; +} mqueue_params; + +mqueue_params g_params; + +void helper(char *progname) +{ +    printf("Usage: %s [OPTS]\n\n" +        "Version: 0.0.1 \n" +        "-m mqueue name\n" +        "-v verbose output\n" +        "-h help options\n" +        "\n" +        , progname); +} + +#define full_mqpath_len 1024 + + +int main(int argc, char **argv) +{ +    //stack params +    int c,err; +    int i; +    int mq_fd; +    char full_mqpath[full_mqpath_len]; +     + +    memset(&g_params,0,sizeof(g_params)); + +    //process arguments +    while ((c = getopt(argc, argv, "m:vh")) != -1) +    { +        switch (c) +        { +            case 'm': +                g_params.f_mqname = optarg; +                break; +            case 'v': +                g_params.f_verbose = 1; +                break; +            case 'h': +            default: +                helper(argv[0]); +                exit(1); +        } +    } + +    if (g_params.f_helper) +    { +        helper(argv[0]); +        return 0; +    } + +    //set mqueue name +    if (g_params.f_mqname == NULL) +    { +        g_params.f_mqname = "/stack-0"; +    } + +    //compose string +    memset(&full_mqpath[0], 0, full_mqpath_len); +    snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname); +    if (g_params.f_verbose) +    { +        printf("Full path: %s\n",&full_mqpath); +    } + +    mq_fd = mq_open(g_params.f_mqname,O_RDWR | O_CREAT, 0666, NULL); +    err = errno; +    if (mq_fd == -1) +    { +        if (g_params.f_verbose) +        { +            printf("ERROR:%d,%s\n",err,strerror(err)); +        } +        return -1; +    } +    printf("%s\n",g_params.f_mqname); + +    close(mq_fd); + +    return 0; +} +``` + +### mqueue_push.c - Push values to mqueue + +_mqueue_push.c_ +```c +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <mqueue.h> +#include <errno.h> + +typedef struct { +    char *f_mqname; +    char *f_push; +    int   f_verbose; +    int   f_helper; +} mqueue_params; + +mqueue_params g_params; + +void helper(char *progname) +{ +    printf("Usage: %s [OPTS] VALUE\n\n" +        "Version: 0.0.1 \n" +        "-m mqueue name\n" +        "-v verbose output\n" +        "-p push value\n" +        "-h help options\n" +        "\n" +        , progname); +} + +#define full_mqpath_len 1024 + +int main(int argc, char **argv) +{ +    //stack params +    int c,err; +    int i; +    int mq_fd; +    char full_mqpath[full_mqpath_len]; +    int prio=10; +    char *push_val="NONE"; +    int push_size=strlen(push_val); +     + +    memset(&g_params,0,sizeof(g_params)); + +    //process arguments +    while ((c = getopt(argc, argv, "m:vhp:")) != -1) +    { +        switch (c) +        { +            case 'm': +                g_params.f_mqname = optarg; +                break; +            case 'v': +                g_params.f_verbose = 1; +                break; +            case 'p': +                g_params.f_push = optarg; +                break; +            case 'h': +            default: +                helper(argv[0]); +                exit(1); +        } +    } + +    if (g_params.f_helper) +    { +        helper(argv[0]); +        return 0; +    } + +    //set mqueue name +    if (g_params.f_mqname == NULL) +    { +        g_params.f_mqname = "/stack-0"; +    } + +    //compose string +    memset(&full_mqpath[0], 0, full_mqpath_len); +    snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname); +    if (g_params.f_verbose) +    { +        printf("Full path: %s\n",&full_mqpath); +    } + +    mq_fd = mq_open(g_params.f_mqname,O_RDWR | O_CREAT, 0666, NULL); +    err = errno; +    if (mq_fd == -1) +    { +        if (g_params.f_verbose) +        { +            printf("ERROR:%d,%s\n",err,strerror(err)); +        } +        return -1; +    } +    printf("%s\n",g_params.f_mqname); + +    if (g_params.f_push != NULL) +    { +        push_val = g_params.f_push; +        push_size = strlen(push_val); +    } + +    mq_send(mq_fd, push_val, push_size, prio); + +    close(mq_fd); + +    return 0; +} +``` + +### mqueue_pop.c - Get value from mqueue + +_mqueue_pop.c_ +```c +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <mqueue.h> +#include <errno.h> + +typedef struct { +    char *f_mqname; +    int   f_verbose; +    int   f_helper; +} mqueue_params; + +mqueue_params g_params; + +void helper(char *progname) +{ +    printf("Usage: %s [OPTS] VALUE\n\n" +        "Version: 0.0.1 \n" +        "-m mqueue name\n" +        "-v verbose output\n" +        "-h help options\n" +        "\n" +        , progname); +} + +#define full_mqpath_len 1024 + +int main(int argc, char **argv) +{ +    //stack params +    int ret=0; +    int c,err; +    int i; +    int mq_fd; +    char full_mqpath[full_mqpath_len]; +    int prio; +    struct mq_attr attr; +    char *pop_val=NULL; +    int pop_size; +     + +    memset(&g_params,0,sizeof(g_params)); + +    //process arguments +    while ((c = getopt(argc, argv, "m:vh")) != -1) +    { +        switch (c) +        { +            case 'm': +                g_params.f_mqname = optarg; +                break; +            case 'v': +                g_params.f_verbose = 1; +                break; +            case 'h': +            default: +                helper(argv[0]); +                exit(1); +        } +    } + +    if (g_params.f_helper) +    { +        helper(argv[0]); +        return 0; +    } + +    //set mqueue name +    if (g_params.f_mqname == NULL) +    { +        g_params.f_mqname = "/stack-0"; +    } + +    //compose string +    memset(&full_mqpath[0], 0, full_mqpath_len); +    snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname); +    if (g_params.f_verbose) +    { +        printf("Full path: %s\n",&full_mqpath); +    } + +    mq_fd = mq_open(g_params.f_mqname,O_RDWR | O_CREAT, 0666, NULL); +    err = errno; +    if (mq_fd == -1) +    { +        if (g_params.f_verbose) +        { +            printf("ERROR:%d,%s\n",err,strerror(err)); +        } +        return -1; +    } +    //printf("%s\n",g_params.f_mqname); + +    mq_getattr(mq_fd, &attr); +     +    pop_val = malloc(attr.mq_msgsize+1); +    memset(pop_val, 0, attr.mq_msgsize+1); + +    if (attr.mq_curmsgs > 0) +    { +        pop_size = mq_receive(mq_fd, pop_val, attr.mq_msgsize, &prio); +        printf("%s\n",pop_val); +    } else { +        ret = -1; +    } + +    close(mq_fd); +    free(pop_val); + +    return ret; +} +``` + +### mqueue_remove.c - Remove mqueue + +_mqueue_remove.c_ +```c +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <mqueue.h> +#include <errno.h> + +typedef struct { +    char *f_mqname; +    int   f_verbose; +    int   f_helper; +} mqueue_params; + +mqueue_params g_params; + +void helper(char *progname) +{ +    printf("Usage: %s [OPTS] VALUE\n\n" +        "Version: 0.0.1 \n" +        "-m mqueue name\n" +        "-v verbose output\n" +        "-h help options\n" +        "\n" +        , progname); +} + +#define full_mqpath_len 1024 + +int main(int argc, char **argv) +{ +    //stack params +    int ret=0; +    int c,err; +    int i; +    int mq_fd; +    char full_mqpath[full_mqpath_len]; +     + +    memset(&g_params,0,sizeof(g_params)); + +    //process arguments +    while ((c = getopt(argc, argv, "m:vh")) != -1) +    { +        switch (c) +        { +            case 'm': +                g_params.f_mqname = optarg; +                break; +            case 'v': +                g_params.f_verbose = 1; +                break; +            case 'h': +            default: +                helper(argv[0]); +                exit(1); +        } +    } + +    if (g_params.f_helper) +    { +        helper(argv[0]); +        return 0; +    } + +    //set mqueue name +    if (g_params.f_mqname == NULL) +    { +        g_params.f_mqname = "/stack-0"; +    } + +    //compose string +    memset(&full_mqpath[0], 0, full_mqpath_len); +    snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname); +    if (g_params.f_verbose) +    { +        printf("Full path: %s\n",&full_mqpath); +    } +     +    mq_unlink(g_params.f_mqname); + +    close(mq_fd); + +    return ret; +} +``` + +### mqueue_info.c - Get stats from mqueue + +_mqueue_info.c_ +```c +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <getopt.h> +#include <unistd.h> +#include <mqueue.h> +#include <errno.h> + +typedef struct { +    char *f_mqname; +    int   f_verbose; +    int   f_helper; +} mqueue_params; + +mqueue_params g_params; + +void helper(char *progname) +{ +    printf("Usage: %s [OPTS] VALUE\n\n" +        "Version: 0.0.1 \n" +        "-m mqueue name\n" +        "-v verbose output\n" +        "-h help options\n" +        "\n" +        , progname); +} + +#define full_mqpath_len 1024 + +int main(int argc, char **argv) +{ +    //stack params +    int ret=0; +    int c,err; +    int i; +    int mq_fd; +    char full_mqpath[full_mqpath_len]; +    int prio; +    struct mq_attr attr; +    char *pop_val=NULL; +    int pop_size; +     + +    memset(&g_params,0,sizeof(g_params)); + +    //process arguments +    while ((c = getopt(argc, argv, "m:vh")) != -1) +    { +        switch (c) +        { +            case 'm': +                g_params.f_mqname = optarg; +                break; +            case 'v': +                g_params.f_verbose = 1; +                break; +            case 'h': +            default: +                helper(argv[0]); +                exit(1); +        } +    } + +    if (g_params.f_helper) +    { +        helper(argv[0]); +        return 0; +    } + +    //set mqueue name +    if (g_params.f_mqname == NULL) +    { +        g_params.f_mqname = "/stack-0"; +    } + +    //compose string +    memset(&full_mqpath[0], 0, full_mqpath_len); +    snprintf(&full_mqpath[0], full_mqpath_len-1, "%s", g_params.f_mqname); +    if (g_params.f_verbose) +    { +        printf("Full path: %s\n",&full_mqpath); +    } + +    mq_fd = mq_open(g_params.f_mqname,O_RDWR | O_CREAT, 0666, NULL); +    err = errno; +    if (mq_fd == -1) +    { +        if (g_params.f_verbose) +        { +            printf("ERROR:%d,%s\n",err,strerror(err)); +        } +        return -1; +    } + +    mq_getattr(mq_fd, &attr); + +    printf("%d\n",attr.mq_curmsgs); +     + +    close(mq_fd); + +    return ret; +} +``` + + + +## Links + +[1] [https://www.man7.org/linux/man-pages/man7/mq_overview.7.html](https://www.man7.org/linux/man-pages/man7/mq_overview.7.html)   +[2] [https://en.wikipedia.org/wiki/Message_queue](https://en.wikipedia.org/wiki/Message_queue)    | 
