summaryrefslogtreecommitdiffstats
path: root/1instance.c
blob: 8feadb535b0267a7f7f331242f37784bf4ebc6a3 (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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>

typedef struct {
  char* filename; /* this file is the pipe (set by user) */
  char is_server; /* this is set by open_control_file */
  int fd; /* this is set by open_control_file */
} single_instance_struct;

/* returns fd, is_server is set to -1 if server, 0 if client */
int open_control_file(single_instance_struct* str)
{
  struct stat buf;

  if(stat(str->filename,&buf)) {
    mkfifo(str->filename,128|256);
    str->is_server=-1;
    str->fd=open(str->filename,O_NONBLOCK|O_RDONLY);
  } else {
    str->fd=open(str->filename,O_NONBLOCK|O_WRONLY);
    if(errno==ENXIO) {
      str->is_server=-1;
      str->fd=open(str->filename,O_NONBLOCK|O_RDONLY);
    } else
      str->is_server=0;
  }

  return(str->fd);
}

void delete_control_file(single_instance_struct* str)
{
  remove(str->filename);
}

void close_control_file(single_instance_struct* str)
{
  close(str->fd);
}

typedef void (*event_dispatcher)(char* message);

int get_next_message(char* buffer,int len,single_instance_struct* str,int usecs)
{
  struct timeval tv;
  fd_set fdset;
  int num_fds;

  FD_ZERO(&fdset);
  FD_SET(str->fd,&fdset);
  tv.tv_sec=0;
  tv.tv_usec=usecs;

  num_fds=select(str->fd+1,&fdset,NULL,NULL,&tv);
  if(num_fds) {
    int reallen;

    reallen=read(str->fd,buffer,len);
    if(reallen==0) {
      close(str->fd);
      str->fd=open(str->filename,O_NONBLOCK|O_RDONLY);
      num_fds--;
    }
    buffer[reallen]=0;
#ifdef DEBUG_1INSTANCE
    if(reallen!=0) fprintf(stderr,"message received: %s.\n",buffer);
#endif
  }

  return(num_fds);
}

int dispatch_event(single_instance_struct* str,event_dispatcher dispatcher,int usecs)
{
  char buffer[1024];
  int num_fds;

  if((num_fds=get_next_message(buffer,1024,str,usecs)) && buffer[0])
    dispatcher(buffer);

  return(num_fds);
}

int loop_if_server(single_instance_struct* str,event_dispatcher dispatcher)
{
  open_control_file(str);
  if(str->is_server) {
    while(1)
      dispatch_event(str,dispatcher,50);
  }

  return(str->fd);
}

void send_message(single_instance_struct* str,char* message)
{
#ifdef DEBUG_1INSTANCE
  int i=
#endif
  write(str->fd,message,strlen(message));
#ifdef DEBUG_1INSTANCE
  fprintf(stderr,"send: %s => %d(%d)\n",message,i,strlen(message));
#endif
}

#ifdef DEBUG_MAIN

#include <stdio.h>
#include <stdlib.h>

single_instance_struct str1 = { "/tmp/1instance" };

void my_dispatcher(char* message)
{
#ifdef DEBUG_1INSTANCE
  fprintf(stderr,"Message arrived: %s.\n",message);
#endif
  if(!strcmp(message,"quit")) {
    delete_control_file(str1);
    exit(0);
  }
}

int main(int argc,char** argv)
{
  int i;

  loop_if_server(str1,my_dispatcher);

  for(i=1;i<argc;i++)
    send_event(str1,argv[i]);

  return(0);
}

#endif