Fixed bug in client which didn't send the null byte. added fork for notify-send
[irssi-notify.git] / server.c
1 /*
2 ** server.c -- a stream socket server demo
3 */
4
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <unistd.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <sys/types.h>
11 #include <sys/socket.h>
12 #include <netinet/in.h>
13 #include <netdb.h>
14 #include <arpa/inet.h>
15 #include <sys/wait.h>
16 #include <signal.h>
17
18 #define PORT "3490" // the port users will be connecting to
19
20 #define BACKLOG 10 // how many pending connections queue will hold
21
22 void sigchld_handler(int s)
23 {
24 while(waitpid(-1, NULL, WNOHANG) > 0);
25 }
26
27 // get sockaddr, IPv4 or IPv6:
28 void *get_in_addr(struct sockaddr *sa)
29 {
30 if (sa->sa_family == AF_INET) {
31 return &(((struct sockaddr_in*)sa)->sin_addr);
32 }
33
34 return &(((struct sockaddr_in6*)sa)->sin6_addr);
35 }
36
37 int main(void)
38 {
39 int sockfd, new_fd; // listen on sock_fd, new connection on new_fd
40 struct addrinfo hints, *servinfo, *p;
41 struct sockaddr_storage their_addr; // connector's address information
42 socklen_t sin_size;
43 struct sigaction sa;
44 int yes=1;
45 char s[INET6_ADDRSTRLEN];
46 int rv;
47
48 memset(&hints, 0, sizeof hints);
49 hints.ai_family = AF_UNSPEC;
50 hints.ai_socktype = SOCK_STREAM;
51 hints.ai_flags = AI_PASSIVE; // use my IP
52
53 if ((rv = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
54 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
55 return 1;
56 }
57
58 // loop through all the results and bind to the first we can
59 for(p = servinfo; p != NULL; p = p->ai_next) {
60 if ((sockfd = socket(p->ai_family, p->ai_socktype,
61 p->ai_protocol)) == -1) {
62 perror("server: socket");
63 continue;
64 }
65
66 if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes,
67 sizeof(int)) == -1) {
68 perror("setsockopt");
69 exit(1);
70 }
71
72 if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
73 close(sockfd);
74 perror("server: bind");
75 continue;
76 }
77
78 break;
79 }
80
81 if (p == NULL) {
82 fprintf(stderr, "server: failed to bind\n");
83 return 2;
84 }
85
86 freeaddrinfo(servinfo); // all done with this structure
87
88 if (listen(sockfd, BACKLOG) == -1) {
89 perror("listen");
90 exit(1);
91 }
92
93 sa.sa_handler = sigchld_handler; // reap all dead processes
94 sigemptyset(&sa.sa_mask);
95 sa.sa_flags = SA_RESTART;
96 if (sigaction(SIGCHLD, &sa, NULL) == -1) {
97 perror("sigaction");
98 exit(1);
99 }
100
101 printf("server: waiting for connections...\n");
102
103 while(1) { // main accept() loop
104 sin_size = sizeof their_addr;
105 new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
106 if (new_fd == -1) {
107 perror("accept");
108 continue;
109 }
110
111 inet_ntop(their_addr.ss_family,
112 get_in_addr((struct sockaddr *)&their_addr),
113 s, sizeof s);
114 printf("server: got connection from %s\n", s);
115
116 if (!fork()) { // this is the child process
117 close(sockfd); // child doesn't need the listener
118 char buf[100];
119 if (recv(new_fd, buf, 99, 0) == -1) {
120 perror("recv");
121 exit(1);
122 }
123 buf[100] = '\0';
124 printf("server: recieved '%s'\n", buf);
125 if (!fork())
126 execl("/home/dylan/test", "irssi", buf, NULL);
127 close(new_fd);
128 exit(0);
129 }
130 close(new_fd); // parent doesn't need this
131 }
132
133 return 0;
134 }
135