thermferm/server.c

changeset 43
24e731bb2e08
parent 42
01b96a24ae7c
child 44
f37d73940699
--- a/thermferm/server.c	Sun May 18 21:27:07 2014 +0200
+++ b/thermferm/server.c	Sun May 18 22:56:43 2014 +0200
@@ -29,9 +29,19 @@
 extern bool		debug;
 extern int		lcdHandle;
 extern unsigned char	lcdbuf[MAX_LCDS][20][4];
+extern sys_config       Config;
+extern int		clients;
 
+int			s;		/* connected socket			*/
+int			ls;		/* listen socket			*/
 
-int			sock = -1;
+struct sockaddr_in	myaddr_in;	/* for local socket address             */
+struct sockaddr_in	peeraddr_in;	/* for peer socket address              */
+
+struct hostent		*hp;
+
+#define SS_BUFSIZE      1024
+#define SS_TIMEOUT      300
 
 
 char *exe_cmd(char *);
@@ -58,36 +68,244 @@
 
 
 
-void do_cmd(char *cmd)
+int server_init(void)
 {
-    char    buf[1024];
-    int     slen, tries = 0;
+    int		optval = 1;
+
+    memset((char *)&myaddr_in, 0, sizeof(struct sockaddr_in));
+    memset((char *)&peeraddr_in, 0, sizeof(struct sockaddr_in));
+    myaddr_in.sin_family = AF_INET;
+    myaddr_in.sin_addr.s_addr = INADDR_ANY;
+    myaddr_in.sin_port = htons(Config.my_port);
+
+    ls = socket(AF_INET, SOCK_STREAM, 0);
+    if (ls == -1) {
+	syslog(LOG_NOTICE, "Can't create listen socket: %s", strerror(errno));
+	fprintf(stderr, "Can't create listen socket: %s\n", strerror(errno));
+	return 1;
+    }
 
+    if (setsockopt(ls, SOL_SOCKET, SO_KEEPALIVE, &optval, sizeof(optval)) == -1) {
+	syslog(LOG_NOTICE, "Can't setsockopt SO_KEEPALIVE socket: %s", strerror(errno));
+	close(ls);
+	return 1;
+    }
+
+    if (setsockopt(ls, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) == -1) {
+	syslog(LOG_NOTICE, "Can't setsockopt SO_REUSEADDR socket: %s", strerror(errno));
+	close(ls);
+	return 1;
+    }
+
+    if (bind(ls, (struct sockaddr *)&myaddr_in, sizeof(struct sockaddr_in)) == -1) {
+	syslog(LOG_NOTICE, "Can't bind to listen socket: %s", strerror(errno));
+	close(ls);
+	return 1;
+    }
+
+    syslog(LOG_NOTICE, "listen socket created %d", ls);
     if (debug)
-	fprintf(stdout, "do_cmd(%s)\n", cmd);
+	fprintf(stdout, "listen socket created %d\n", ls);
+
+
+    return 0;
+}
+
+
+
+/*
+ * Send message to client
+ */
+int srv_send(const char *format, ...)
+{
+    char        out[SS_BUFSIZE];
+    va_list     va_ptr;
+
+    if (s == -1)
+	return -1;
 
-    snprintf(buf, 1024, "%s", exe_cmd(cmd));
+    va_start(va_ptr, format);
+    vsnprintf(out, SS_BUFSIZE-1, format, va_ptr);
+    va_end(va_ptr);
+
+    if (send(s, out, strlen(out), 0) != strlen(out)) {
+	syslog(LOG_NOTICE, "srv_send failed");
+	return -1;
+    }
+
+    if (send(s, (char *)"\r\n", 2, 0) != 2) {
+	syslog(LOG_NOTICE, "srv_send failed");
+	return -1;
+    }
+
+    syslog(LOG_NOTICE, "send: \"%s\"", out);
+    return 0;
+}
+
+
 
-    if (debug)
-	fprintf(stdout, "do_cmd() reply=\"%s\" len=%d\n", buf, strlen(buf));
+void cmd_die(int onsig)
+{
+    syslog(LOG_NOTICE, "Server process die on signal %d", onsig);
+    close(s);
+    exit(0);
+}
+
+
+
+void cmd_server(void)
+{
+    char                *hostname, buf[SS_BUFSIZE];
+    int                 i, rc, rlen, timer;
+    socklen_t           fromlen;
+    struct pollfd       pfd[1];
 
+    /*
+     * Close listen socket
+     */
+    close(ls);
+    /*
+     * Install private signal handler.
+     */
+    for (i = 0; i < NSIG; i++) {
+	if ((i == SIGHUP) || (i == SIGPIPE) || (i == SIGBUS) || (i == SIGILL) || (i == SIGSEGV))
+	    signal(i, (void (*))cmd_die);
+	else
+	    signal(i, SIG_IGN);
+    }
+
+    hp = gethostbyaddr ((char *) &peeraddr_in.sin_addr, sizeof(struct in_addr), peeraddr_in.sin_family);
+    if (hp == NULL) {
+	hostname = inet_ntoa(peeraddr_in.sin_addr);
+    } else {
+	hostname = hp->h_name;
+    }
+
+    clients++;
+    syslog(LOG_NOTICE, "Start new client connection (%d) from %s port %u", clients, hostname, ntohs(peeraddr_in.sin_port));
+    timer = SS_TIMEOUT * 4;
+
+    /*
+     * Receive loop
+     */
     for (;;) {
-//	slen = sendto(sock, buf, strlen(buf), 0, (struct sockaddr *)&from, fromlen);
+	/*
+	 * Poll socket until a define timeout of 0,25 second.
+	 */
+	pfd[0].fd = s;
+	pfd[0].events = POLLIN;
+	pfd[0].revents = 0;
+	rc = poll(pfd, 1, 250);
 
-	if (debug)
-	    fprintf(stdout, "do_cmd() slen=%d tries=%d %s\n", slen, tries, strerror(errno));
-//	if (slen == -1)
-//	    syslog(LOG_NOTICE, "do_cmd(): sendto error %d %s", tries, from.sun_path);
-	else if (slen != strlen(buf))
-	    syslog(LOG_NOTICE, "do_cmd(): send %d of %d bytes, try=%d", slen, strlen(buf), tries);
-	else
-	    return;
-	tries++;
-	if (tries == 3)
-	    return;
-	else
-	    sleep(1);
+	if (rc == -1) {
+	    /*
+	     * Poll can be interrupted by a finished child so that's not a real error.
+	     */
+	    if (errno != EINTR) {
+	    	syslog(LOG_NOTICE, "poll() rc=%d sock=%d events=%04x", rc, s, pfd[0].revents);
+	    }
+	} else if (rc) {
+	    if (pfd[0].revents & POLLIN) {
+                memset((char *)&buf, 0, SS_BUFSIZE);
+                fromlen = sizeof(peeraddr_in);
+                rlen = recvfrom(s, buf, sizeof(buf) -1, 0, (struct sockaddr *)&peeraddr_in, &fromlen);
+                if (rlen == -1) {
+	            syslog(LOG_NOTICE, "recvfrom(): %s", strerror(errno));
+	        } else {		    
+		    for (i = 0; i < strlen(buf); i++) {
+			if (buf[i] == '\n')
+			    buf[i] = '\0';
+			if (buf[i] == '\r')
+			    buf[i] = '\0';
+		    }
+		    timer = SS_TIMEOUT * 4;
+		    if (strlen(buf)) {
+			syslog(LOG_NOTICE, "recv: \"%s\"", buf);
+
+			/*
+			 * Process command from the client
+			 */
+			srv_send(exe_cmd(buf));
+		    }
+		}
+	    } else {
+		syslog(LOG_NOTICE, "poll other event");
+	    }
+
+	} else {
+	    /*
+	     * Poll timeout, do some housekeeping
+	     */
+	    if (timer) {
+	    	timer--;
+	    } else {
+		/* Inactivity timeout */
+		break;
+	    }
+	    if (my_shutdown) {
+		break;
+	    }
+	}
     }
 }
 
 
+
+PI_THREAD (my_server_loop)
+{
+    socklen_t   addrlen;
+
+    syslog(LOG_NOTICE, "Thread my_server_loop started");
+    if (debug)
+	fprintf(stdout, "Thread my_server_loop started\n");
+
+    /*
+     * Loop forever until the external shutdown variable is set.
+     */
+    for (;;) {
+	
+	addrlen = sizeof(struct sockaddr_in);
+        /*
+	 * This call will block until a new connection
+	 * arrives. Then it will return the address of
+	 * the connecting peer, and a new socket
+	 * descriptor, s, for that connection.
+	 */
+	s = accept(ls, (struct sockaddr *)&peeraddr_in, &addrlen);
+	if (s == -1) {
+	    syslog(LOG_NOTICE, "my_server_loop accept failed %s", strerror(errno));
+	    if (debug)
+		fprintf(stdout, "my_server_loop accept failed %s\n", strerror(errno));
+	    return 1;
+	}
+
+	switch (fork()) {
+	    case -1:        /*
+			     * Can't fork, just continue.
+			     */
+			    return 1;
+	    case 0:         /*
+			     * Child process, the commandline server.
+			     */
+			    cmd_server();
+			    return 0;
+	    default:        /*
+			     * Daemon process comes here. The daemon
+			     * needs to remember to close the new
+			     * accept socket after forking the child.
+			     */
+			    close(s);
+	}
+
+	if (my_shutdown) {
+	    syslog(LOG_NOTICE, "Thread my_server_loop stopped");
+	    if (debug)
+		fprintf(stdout, "Thread my_server_loop stopped\n");
+	    return 0;
+	}
+
+    }
+}
+
+
+

mercurial