40c7bd05d94b5286722263a37ba0689406194c9d
[irssi-notify.git] / server.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
14 #define PORT "3490" // the port users will be connecting to
15
16 #define BACKLOG 10 // how many pending connections queue will hold
17
18 void sigchld_handler(int s)
19 {
20 while(waitpid(-1, NULL, WNOHANG) > 0);
21 }
22
23 // get sockaddr, IPv4
24 void *get_in_addr(struct sockaddr *sa)
25 {
26 if (sa->sa_family == AF_INET) {
27 return &(((struct sockaddr_in*)sa)->sin_addr);
28 }
29 }
30
31 int main(void)
32 {
33 int sockfd, activefd; // listen on sockfd, new connection on activefd
34 struct addrinfo hints, *servinfo, *p;
35 struct sockaddr_storage their_addr; // connector's address information
36 socklen_t sin_size;
37 struct sigaction sa;
38 int yes=1;
39 char source[INET6_ADDRSTRLEN];
40 // char CLIENT_IP[15] = "107.21.205.69\0";
41 int rv;
42
43 memset(&hints, 0, sizeof hints); // make sure the struct is empty
44 hints.ai_family = AF_INET; // IPv4
45 hints.ai_socktype = SOCK_STREAM;
46 hints.ai_flags = AI_PASSIVE; // use my IP
47
48 if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
49 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
50 return 1;
51 }
52
53 // servinfo now points to a linked list of 1 or more struct addrinfos
54
55 // loop through all the results and bind to the first we can
56 for(p = servinfo; p != NULL; p = p->ai_next) {
57 if ((sockfd = socket(p->ai_family, p->ai_socktype,
58 p->ai_protocol)) == -1) {
59 perror("server: socket");
60 continue;
61 }
62
63 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
64 sizeof(int)) == -1) {
65 perror("setsockopt");
66 exit(1);
67 }
68
69 if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
70 close(sockfd);
71 perror("server: bind");
72 continue;
73 }
74
75 break;
76 }
77
78 if (p == NULL) {
79 fprintf(stderr, "server: failed to bind\n");
80 return 2;
81 }
82
83 freeaddrinfo(servinfo); // all done with this structure
84
85 if (listen(sockfd, BACKLOG) == -1) {
86 perror("listen");
87 exit(1);
88 }
89
90 sa.sa_handler = sigchld_handler; // reap all dead processes
91 sigemptyset(&sa.sa_mask);
92 sa.sa_flags = SA_RESTART;
93 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
94 perror("sigaction");
95 exit(1);
96 }
97
98 printf("server: waiting for connections...\n");
99
100 while(1) { // main accept() loop
101 sin_size = sizeof their_addr;
102 activefd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
103 if (activefd == -1) {
104 perror("accept");
105 continue;
106 }
107
108 inet_ntop(their_addr.ss_family,
109 get_in_addr((struct sockaddr *)&their_addr),
110 source, sizeof source);
111
112 if (strcmp(source, "107.21.205.69") != 0 &&
113 strcmp(source, "127.0.0.1") != 0){
114 close(activefd);
115 continue;
116 }
117
118 if (!fork()) { // this is the child process
119 close(sockfd); // child doesn't need the listener
120 char buf[4096];
121 if (recv(activefd, buf, 99, 0) == -1) {
122 perror("recv");
123 exit(1);
124 }
125 buf[4096] = '\0';
126 printf("server: recieved '%s'\n", buf);
127 if (!fork()){
128 setenv("DISPLAY", ":0", 1); // doesn't seem to be doing the trick
129 execl("notify-display",
130 "notify-display", buf, NULL);
131 // the first argument to execl is the command, the second is the first argument
132 // passed to the program ($0), customarily the evocation of the command
133 }
134 close(activefd);
135 exit(0);
136 }
137 close(activefd);
138 }
139
140 return 0;
141 }