aboutsummaryrefslogtreecommitdiff
path: root/src/ipc.c
blob: 565777c3432e1cd5c0a7b31f0d1fab50e2519d5b (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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "ipc.h"

#include <ctype.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <unistd.h>

struct imv_ipc {
  int fd;
  imv_ipc_callback callback;
  void *data;
};

struct connection {
  struct imv_ipc *ipc;
  int fd;
};

static void *wait_for_commands(void* void_conn)
{
  struct connection *conn = void_conn;

  while (1) {
    char buf[1024];
    ssize_t len = recv(conn->fd, buf, sizeof buf - 1, 0);
    if (len <= 0) {
      break;
    }

    buf[len] = 0;
    while (len > 0 && isspace(buf[len-1])) {
      buf[len-1] = 0;
      --len;
    }

    if (conn->ipc->callback) {
      conn->ipc->callback(buf, conn->ipc->data);
    }
  }

  close(conn->fd);
  free(conn);
  return NULL;
}

static void *wait_for_connections(void* void_ipc)
{
  struct imv_ipc *ipc = void_ipc;
  (void)ipc;

  while (1) {
    int client = accept(ipc->fd, NULL, NULL);
    if (client == -1) {
      break;
    }
    struct connection *conn = calloc(1, sizeof *conn);
    conn->ipc = ipc;
    conn->fd = client;

    pthread_t thread;
    pthread_create(&thread, NULL, wait_for_commands, conn);
    pthread_detach(thread);
  }
  return NULL;
}

struct imv_ipc *imv_ipc_create(void)
{
  int sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
  if (sockfd < 0) {
    return NULL;
  }

  struct sockaddr_un desc = {
    .sun_family = AF_UNIX
  };
  imv_ipc_path(desc.sun_path, sizeof desc.sun_path, getpid());

  unlink(desc.sun_path);

  if (bind(sockfd, (struct sockaddr*)&desc, sizeof desc) == -1) {
    close(sockfd);
    return NULL;
  }

  if (listen(sockfd, 5) == -1) {
    close(sockfd);
    return NULL;
  }

  struct imv_ipc *ipc = calloc(1, sizeof *ipc);
  if (ipc == NULL) {
    return NULL;
  }
  ipc->fd = sockfd;

  pthread_t thread;
  pthread_create(&thread, NULL, wait_for_connections, ipc);
  pthread_detach(thread);
  return ipc;
}

void imv_ipc_free(struct imv_ipc *ipc)
{
  if (!ipc) {
    return;
  }

  char ipc_filename[1024];
  imv_ipc_path(ipc_filename, sizeof ipc_filename, getpid());
  unlink(ipc_filename);
  close(ipc->fd);

  free(ipc);
}

void imv_ipc_set_command_callback(struct imv_ipc *ipc,
    imv_ipc_callback callback, void *data)
{
  ipc->callback = callback;
  ipc->data = data;
}