File: RELATIVE:/../../../mfix.git/model/socket.c

1     /*
2     Code taken from the example on Wikipedia:  http://en.wikipedia.org/wiki/Select_(Unix)
3      */
4     
5     #include <stdio.h>
6     #include <stdlib.h>
7     #include <string.h>
8     
9     #include <sys/types.h>
10     #include <sys/socket.h>
11     #include <netinet/in.h>
12     #include <netdb.h>
13     
14     #include <sys/select.h>
15     #include <fcntl.h>
16     #include <unistd.h>
17     #include <err.h>
18     #include <errno.h>
19     #include <signal.h>
20     
21     extern void handle_command(char*, char*, ssize_t*);
22     
23     extern void flush_err_msg_gui(char*);
24     
25     void die(const char *msg)
26     {
27       perror(msg);
28       exit(EXIT_FAILURE);
29     }
30     
31     //-----------------------------------------------
32     // Global variables
33     //-----------------------------------------------
34     
35     int cmd_sockfd, cmd_maxfd;
36     int log_sockfd, log_maxfd;
37     fd_set cmd_master, cmd_readfds;
38     fd_set log_master, log_readfds;
39     
40     struct timeval timeout;
41     
42     //-----------------------------------------------
43     // for testing
44     //-----------------------------------------------
45     /*
46     int main(int argc, char **argv) {
47       init_socket("8888");
48     
49       while(1) {
50           printf("DO SOMETHING USEFUL\n");
51           sleep(1);
52           check_socket();
53       }
54       return 0;
55     }*/
56     
57     //-----------------------------------------------
58     //     Initialize socket listening on port
59     //-----------------------------------------------
60     
61     void init_log_socket(char* port) {
62     
63       struct addrinfo *res0, *res, hints;
64       int error;
65       int on = 1;
66     
67       (void)memset(&hints, '\0', sizeof(struct addrinfo));
68     
69       hints.ai_family = AF_INET;
70       hints.ai_socktype = SOCK_STREAM;
71       hints.ai_protocol = IPPROTO_TCP;
72       hints.ai_flags = AI_PASSIVE;
73     
74       if(0 != (error = getaddrinfo(NULL, port, &hints, &res0)))
75         errx(EXIT_FAILURE, "%s", gai_strerror(error));
76     
77       for(res = res0; res; res = res->ai_next)
78         {
79           if(-1 == (log_sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)))
80            {
81              perror("socket()");
82              continue;
83            }
84     
85           if(-1 == (setsockopt(log_sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int))))
86            {
87              perror("setsockopt()");
88              continue;
89            }
90     
91           if(-1 == (bind(log_sockfd, res->ai_addr, res->ai_addrlen)))
92            {
93              perror("bind");
94              continue;
95            }
96     
97           break;
98     
99         }
100     
101       if(-1 == log_sockfd)
102         exit(EXIT_FAILURE);
103     
104       freeaddrinfo(res0);
105     
106       if(-1 == (listen(log_sockfd, 32)))
107         die("listen()");
108     
109       if(-1 == (fcntl(log_sockfd, F_SETFD, O_NONBLOCK)))
110         die("fcntl()");
111     
112       FD_ZERO(&log_master);
113       FD_ZERO(&log_readfds);
114     
115       FD_SET(log_sockfd, &log_master);
116     
117       log_maxfd = log_sockfd;
118     
119       timeout.tv_sec = 0;
120       timeout.tv_usec = 0;
121     
122       signal(SIGPIPE, SIG_IGN);
123     
124     }
125     
126     void init_cmd_socket(char* port) {
127     
128       struct addrinfo *res0, *res, hints;
129       int error;
130       int on = 1;
131     
132       (void)memset(&hints, '\0', sizeof(struct addrinfo));
133     
134       hints.ai_family = AF_INET;
135       hints.ai_socktype = SOCK_STREAM;
136       hints.ai_protocol = IPPROTO_TCP;
137       hints.ai_flags = AI_PASSIVE;
138     
139       if(0 != (error = getaddrinfo(NULL, port, &hints, &res0)))
140         errx(EXIT_FAILURE, "%s", gai_strerror(error));
141     
142       for(res = res0; res; res = res->ai_next)
143         {
144           if(-1 == (cmd_sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)))
145            {
146              perror("socket()");
147              continue;
148            }
149     
150           if(-1 == (setsockopt(cmd_sockfd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(int))))
151            {
152              perror("setsockopt()");
153              continue;
154            }
155     
156           if(-1 == (bind(cmd_sockfd, res->ai_addr, res->ai_addrlen)))
157            {
158              perror("bind");
159              continue;
160            }
161     
162           break;
163     
164         }
165     
166       if(-1 == cmd_sockfd)
167         exit(EXIT_FAILURE);
168     
169       freeaddrinfo(res0);
170     
171       if(-1 == (listen(cmd_sockfd, 32)))
172         die("listen()");
173     
174       if(-1 == (fcntl(cmd_sockfd, F_SETFD, O_NONBLOCK)))
175         die("fcntl()");
176     
177       FD_ZERO(&cmd_master);
178       FD_ZERO(&cmd_readfds);
179     
180       FD_SET(cmd_sockfd, &cmd_master);
181     
182       cmd_maxfd = cmd_sockfd;
183     
184       timeout.tv_sec = 0;
185       timeout.tv_usec = 0;
186     
187       signal(SIGPIPE, SIG_IGN);
188     
189     }
190     
191     //-----------------------------------------------
192     //     Check for for connections on socket
193     //-----------------------------------------------
194     
195     void check_sockets() {
196     
197       int nready;
198       int new;
199     
200       memcpy(&cmd_readfds, &cmd_master, sizeof(cmd_master));
201       memcpy(&log_readfds, &log_master, sizeof(log_master));
202     
203       if(-1 == (nready = select(log_maxfd+1, &log_readfds, NULL, NULL, &timeout)))
204         die("select()");
205     
206       for(int ii=0; ii<=log_maxfd && nready>0; ii++) {
207         if(FD_ISSET(ii, &log_readfds)) {
208           nready--;
209     
210           if(ii == log_sockfd) {
211     	if(-1 == (new = accept(log_sockfd, NULL, NULL))) {
212     	  if(EWOULDBLOCK != errno)
213     	    perror("accept()");
214     
215     	  break;
216     	} else {
217     	  if(-1 == (fcntl(new, F_SETFD, O_NONBLOCK)))
218     	    die("fcntl()");
219     
220     	  FD_SET(new, &log_master);
221     
222     	  if(log_maxfd < new)
223     	    log_maxfd = new;
224     	}
225           } else {
226     	char outbuffer[BUFSIZ];
227     	flush_err_msg_gui(outbuffer);
228     
229     	ssize_t nbytes;
230     	if ((nbytes = send(ii, outbuffer, strlen(outbuffer), 0)) == -1) {
231     	  // Client probably disconnected
232     	  perror("send");
233     	  close(ii);
234     	  FD_CLR(ii, &log_master);
235     	}
236           }
237         }
238       }
239     
240       if(-1 == (nready = select(cmd_maxfd+1, &cmd_readfds, NULL, NULL, &timeout)))
241         die("select()");
242     
243       for(int ii=0; ii<=cmd_maxfd && nready>0; ii++) {
244         if(FD_ISSET(ii, &cmd_readfds)) {
245           nready--;
246     
247           if(ii == cmd_sockfd) {
248     	if(-1 == (new = accept(cmd_sockfd, NULL, NULL))) {
249     	  if(EWOULDBLOCK != errno)
250     	    perror("accept()");
251     
252     	  break;
253     	} else {
254     	  if(-1 == (fcntl(new, F_SETFD, O_NONBLOCK)))
255     	    die("fcntl()");
256     
257     	  FD_SET(new, &cmd_master);
258     
259     	  if(cmd_maxfd < new)
260     	    cmd_maxfd = new;
261     	}
262           } else {
263     	char buffer[BUFSIZ];
264     	char outbuffer[BUFSIZ];
265     
266     	ssize_t nbytes;
267     	if ((nbytes = recv(ii, buffer, strlen(buffer), 0)) == -1) {
268     	  if(nbytes <= 0) {
269     	    if(EWOULDBLOCK != errno)
270     	      die("recv()");
271     	    
272     	    break;
273     	  }
274     	}
275     
276     	handle_command(outbuffer, buffer, &nbytes);
277     
278     	if ((nbytes = send(ii, outbuffer, strlen(outbuffer), 0)) == -1) {
279     	  // Client probably disconnected
280     	  perror("send");
281     	  close(ii);
282     	  FD_CLR(ii, &cmd_master);
283     	}
284           }
285         }
286       }
287     
288     }
289