fd7ce87d6126bbce9b77cc4dc903f8407969e829
[irssi-notify.git] / listen.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <errno.h>
5 #include <string.h>
6 #include <sys/types.h>
7 #include <sys/socket.h>
8 #include <netinet/in.h>
9 #include <netdb.h>
10 #include <arpa/inet.h>
11 #include <sys/wait.h>
12 #include <signal.h>
13 #include <libnotify/notify.h>
14
15 #define PORT "3490"
16 #define QUEUE_LENGTH 10
17
18 // a function to reap future child processes
19 void sigchld_handler(int s)
20 {
21 while(waitpid(-1, NULL, WNOHANG) > 0);
22 }
23
24 // look for an IPv4 host:port in an address structure
25 void *get_in_addr(struct sockaddr *sa)
26 {
27 if (sa->sa_family == AF_INET) {
28 return &(((struct sockaddr_in*)sa)->sin_addr);
29 }
30 }
31
32 int main(void)
33 {
34 // new connections on activefd, always listening on sockfd
35 int sockfd, activefd;
36 struct addrinfo hints, *servinfo, *port;
37 struct sockaddr_storage their_addr;
38 socklen_t sin_size;
39 struct sigaction sa;
40 char source[INET6_ADDRSTRLEN];
41 int yes=1;
42 int rv;
43
44 memset(&hints, 0, sizeof hints);
45 hints.ai_family = AF_INET;
46 hints.ai_socktype = SOCK_STREAM;
47 hints.ai_flags = AI_PASSIVE;
48
49 // look up local address information
50 if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
51 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
52 return 1;
53 }
54
55 // loop over available interfaces and try to bind to port
56 for (port = servinfo; port != NULL; port = port->ai_next) {
57 if ((sockfd = socket(port->ai_family, port->ai_socktype,
58 port->ai_protocol)) == -1) {
59 perror("irssi-notify: socket");
60 continue;
61 }
62 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
63 sizeof(int)) == -1) {
64 perror("setsockopt");
65 exit(1);
66 }
67 if (bind(sockfd, port->ai_addr, port->ai_addrlen) == -1) {
68 close(sockfd);
69 perror("irssi-notify: bind");
70 continue;
71 }
72 break;
73 }
74
75 if (port == NULL) {
76 fprintf(stderr, "irssi-notify: failed to bind\n");
77 return 2;
78 }
79
80 freeaddrinfo(servinfo);
81
82 if (listen(sockfd, QUEUE_LENGTH) == -1) {
83 perror("listen");
84 exit(1);
85 }
86
87 // bind sigchld_handler to reap future child processes
88 sa.sa_handler = sigchld_handler;
89 sigemptyset(&sa.sa_mask);
90 sa.sa_flags = SA_RESTART;
91 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
92 perror("sigaction");
93 exit(1);
94 }
95
96 printf("irssi-notify: waiting for connections...\n");
97
98 while (1) {
99 sin_size = sizeof their_addr;
100 activefd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
101 if (activefd == -1) {
102 perror("accept");
103 continue;
104 }
105
106 inet_ntop(their_addr.ss_family,
107 get_in_addr((struct sockaddr *)&their_addr),
108 source, sizeof source);
109
110 // whitelist allowed
111 if (strcmp(source, "50.16.219.8") != 0 &&
112 strcmp(source, "127.0.0.1") != 0){
113 close(activefd);
114 continue;
115 }
116
117 // start a child process to handle notifications
118 if (!fork()) {
119 // the child process doesn't need the listener
120 close(sockfd);
121 char buf[4096];
122 if (recv(activefd, buf, 99, 0) == -1) {
123 perror("recv");
124 exit(1);
125 }
126 buf[4096] = '\0';
127 printf("irssi-notify: recieved '%s'\n", buf);
128 notify_init("irssi-notify");
129 NotifyNotification * notification =
130 notify_notification_new("", buf, "irssi-notify");
131 notify_notification_show(notification, NULL);
132 close(activefd);
133 exit(0);
134 }
135 close(activefd);
136 }
137
138 return 0;
139 }