aboutsummaryrefslogtreecommitdiff
path: root/src/plugins/utils/UniqueProcess.cpp
blob: d2025f55b310ba9f4e83fa8d4432f3bcd28a1b5e (plain)
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
#include "../../../plugins/utils/UniqueProcess.hpp"
#include "../../../include/Storage.hpp"
#include <stdio.h>
#include <limits.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>

namespace QuickMedia {
    bool is_quickmedia_instance_already_running(const char *sock_file_dir, const char *plugin_name) {
        char sock_file[PATH_MAX];
        snprintf(sock_file, sizeof(sock_file), "%s/quickmedia.%s.sock", sock_file_dir, plugin_name);

        std::string resolved_path;
        if(file_get_content(sock_file, resolved_path) != 0)
            return false;
        
        resolved_path.resize(108); // sizeof(addr.sun_path) is 108

        int fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if(fd == -1) {
            fprintf(stderr, "Error: failed to create unix domain socket, error: %s\n", strerror(errno));
            return true;
        }

        fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);

        struct sockaddr_un addr;
        memset(&addr, 0, sizeof(addr));
        addr.sun_family = AF_UNIX;
        strcpy(addr.sun_path, resolved_path.c_str());

        bool running = connect(fd, (struct sockaddr*)&addr, sizeof(addr)) == 0;
        int err = errno;
        if(err == EAGAIN)
            running = true;
        else if(err == ENOENT)
            running = false;
        close(fd);
        return running;
    }

    bool set_quickmedia_instance_unique(const char *sock_file_dir, const char *plugin_name) {
        char socket_file[] = "/tmp/quickmedia.XXXXXX";
        int tmp_file_fd = mkstemp(socket_file);
        if(tmp_file_fd == -1) {
            fprintf(stderr, "Error: failed to create temporary file for unix domain socket, error: %s\n", strerror(errno));
            return false;
        }
        unlink(socket_file);
        close(tmp_file_fd);

        int fd = socket(AF_UNIX, SOCK_STREAM, 0);
        if(fd == -1) {
            fprintf(stderr, "Error: failed to create unix domain socket, error: %s\n", strerror(errno));
            return false;
        }

        struct sockaddr_un addr;
        memset(&addr, 0, sizeof(addr));
        addr.sun_family = AF_UNIX;
        strcpy(addr.sun_path, socket_file);

        if(bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1) {
            fprintf(stderr, "Error: failed to bind unix domain socket, error: %s\n", strerror(errno));
            unlink(socket_file);
            close(fd);
            return false;
        }

        if(listen(fd, 0) == -1) {
            fprintf(stderr, "Error: failed to listen to unix domain socket, error: %s\n", strerror(errno));
            unlink(socket_file);
            close(fd);
            return false;
        }

        char sock_file[PATH_MAX];
        snprintf(sock_file, sizeof(sock_file), "%s/quickmedia.%s.sock", sock_file_dir, plugin_name);
        bool success = file_overwrite(sock_file, socket_file) == 0;
        if(!success) {
            fprintf(stderr, "Error: failed to create %s unix domain socket link file\n", sock_file);
            unlink(socket_file);
            close(fd);
        }
        return success;
    }

    void remove_quickmedia_instance_lock(const char *sock_file_dir, const char *plugin_name) {
        char sock_file[PATH_MAX];
        snprintf(sock_file, sizeof(sock_file), "%s/quickmedia.%s.sock", sock_file_dir, plugin_name);

        std::string resolved_path;
        if(file_get_content(sock_file, resolved_path) != 0) {
            unlink(sock_file);
            return;
        }
        
        resolved_path.resize(108); // sizeof(addr.sun_path) is 108

        if(resolved_path.size() < 4 || memcmp(resolved_path.data(), "/tmp", 4) != 0) {
            unlink(sock_file);
            return;
        }
        
        unlink(sock_file);
        unlink(resolved_path.c_str());
    }
}