|
@@ -0,0 +1,168 @@
|
|
|
+/*
|
|
|
+ * server.cpp
|
|
|
+ *
|
|
|
+ * Created on: Jan 4, 2018
|
|
|
+ * Author: Philipp Hinz
|
|
|
+ * based on: https://gist.github.com/suyash/2488ff6996c98a8ee3a84fe3198a6f85
|
|
|
+ */
|
|
|
+
|
|
|
+#include <arpa/inet.h>
|
|
|
+#include <netinet/in.h>
|
|
|
+#include <stdbool.h>
|
|
|
+#include <stdio.h>
|
|
|
+#include <stdlib.h>
|
|
|
+#include <string.h>
|
|
|
+#include <unistd.h>
|
|
|
+#include <pthread.h>
|
|
|
+
|
|
|
+#include "server.h"
|
|
|
+#include "logger.h"
|
|
|
+#include "hal.h"
|
|
|
+#include "coffee.h"
|
|
|
+#include "stripe.h"
|
|
|
+
|
|
|
+/**
|
|
|
+ * TCP Uses 2 types of sockets, the connection socket and the listen socket.
|
|
|
+ * The Goal is to separate the connection phase from the data exchange phase.
|
|
|
+ * */
|
|
|
+
|
|
|
+int listen_sock;
|
|
|
+int sock;
|
|
|
+char buffer_ok[] = "OK\n";
|
|
|
+
|
|
|
+/**
|
|
|
+ * Just sends an ACK message back
|
|
|
+ */
|
|
|
+
|
|
|
+void sendACK() {
|
|
|
+ send(sock, buffer_ok, strlen(buffer_ok), 0);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Main thread to handle networking stuff
|
|
|
+ * @param *threadid Thread ID
|
|
|
+ */
|
|
|
+
|
|
|
+void* serverThread(void* threadid) {
|
|
|
+ sleep(1); // Wait for other components to initialize
|
|
|
+
|
|
|
+ // socket address used for the server
|
|
|
+ struct sockaddr_in server_address;
|
|
|
+ memset(&server_address, 0, sizeof(server_address));
|
|
|
+ server_address.sin_family = AF_INET;
|
|
|
+
|
|
|
+ // htons: host to network short: transforms a value in host byte
|
|
|
+ // ordering format to a short value in network byte ordering format
|
|
|
+ server_address.sin_port = htons(SERVER_PORT);
|
|
|
+
|
|
|
+ // htonl: host to network long: same as htons but to long
|
|
|
+ server_address.sin_addr.s_addr = htonl(INADDR_ANY);
|
|
|
+
|
|
|
+ // create a TCP socket, creation returns -1 on failure
|
|
|
+ if ((listen_sock = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
|
|
|
+ logger_error("could not create listen socket\n");
|
|
|
+ pthread_exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ // bind it to listen to the incoming connections on the created server
|
|
|
+ // address, will return -1 on error
|
|
|
+ if ((bind(listen_sock, (struct sockaddr *) &server_address,
|
|
|
+ sizeof(server_address))) < 0) {
|
|
|
+ logger_error("could not bind socket\n");
|
|
|
+ pthread_exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ int wait_size = 16; // maximum number of waiting clients, after which
|
|
|
+ // dropping begins
|
|
|
+ if (listen(listen_sock, wait_size) < 0) {
|
|
|
+ logger_error("could not open socket for listening\n");
|
|
|
+ pthread_exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ logger(V_BASIC, "Now listening for commands on port %d\n", SERVER_PORT);
|
|
|
+
|
|
|
+ // socket address used to store client address
|
|
|
+ struct sockaddr_in client_address;
|
|
|
+ unsigned int client_address_len = 0;
|
|
|
+
|
|
|
+ // run indefinitely
|
|
|
+ while (true) {
|
|
|
+ // open a new socket to transmit data per connection
|
|
|
+ if ((sock = accept(listen_sock, (struct sockaddr *) &client_address,
|
|
|
+ &client_address_len)) < 0) {
|
|
|
+ logger_error("could not open a socket to accept data\n");
|
|
|
+ pthread_exit(0);
|
|
|
+ }
|
|
|
+
|
|
|
+ int n = 0;
|
|
|
+ int len = 0, maxlen = 100, lastlen = 0;
|
|
|
+ char buffer[maxlen];
|
|
|
+ char cmd[maxlen];
|
|
|
+ char *pcmd = cmd;
|
|
|
+ char *pbuffer = buffer;
|
|
|
+ strncpy(buffer, "", maxlen);
|
|
|
+ strncpy(cmd, "", maxlen);
|
|
|
+
|
|
|
+ logger(V_HAL, "client connected with ip address: %s\n",
|
|
|
+ inet_ntoa(client_address.sin_addr));
|
|
|
+
|
|
|
+ // keep running as long as the client keeps the connection open
|
|
|
+ while ((n = recv(sock, pbuffer, maxlen, 0)) > 0) {
|
|
|
+ pbuffer += n;
|
|
|
+ maxlen -= n;
|
|
|
+ len += n;
|
|
|
+
|
|
|
+ strncpy(cmd, buffer, len - 1);
|
|
|
+ cmd[len - 1] = '\0';
|
|
|
+ pcmd = &cmd[lastlen];
|
|
|
+ logger(V_SPI, "received %d bytes: '%s' (cmd: %s)\n", len, buffer,
|
|
|
+ pcmd);
|
|
|
+
|
|
|
+ if (!strcmp(SERVER_CMD_ON, pcmd)) {
|
|
|
+ if (getState() == STATE_OFF) {
|
|
|
+ halSendSignal(SigInt0Rls);
|
|
|
+ sendACK();
|
|
|
+ }
|
|
|
+ } else if (!strcmp(SERVER_CMD_OFF, pcmd)) {
|
|
|
+ if (getState() != STATE_OFF) {
|
|
|
+ halSendSignal(SigInt1RlsLong);
|
|
|
+ sendACK();
|
|
|
+ }
|
|
|
+ } else if (!strcmp(SERVER_CMD_BREW, pcmd)) {
|
|
|
+ if (getState() == STATE_IDLE || getState() == STATE_HEATING) {
|
|
|
+ halSendSignal(SigInt1Rls);
|
|
|
+ sendACK();
|
|
|
+ }
|
|
|
+ } else if (!strcmp(SERVER_CMD_STATUS, pcmd)) {
|
|
|
+ char tmp[] = "0\n";
|
|
|
+ tmp[0] += getState();
|
|
|
+ send(sock, tmp, sizeof(tmp), 0);
|
|
|
+ } else if (!strcmp(SERVER_CMD_STRIPEON, pcmd)) {
|
|
|
+ stripeOn();
|
|
|
+ sendACK();
|
|
|
+ } else if (!strcmp(SERVER_CMD_STRIPEOFF, pcmd)) {
|
|
|
+ stripeOff();
|
|
|
+ sendACK();
|
|
|
+ }
|
|
|
+
|
|
|
+ lastlen = len;
|
|
|
+ // echo received content back
|
|
|
+ //send(sock, buffer, len, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ close(sock);
|
|
|
+ }
|
|
|
+
|
|
|
+ close(listen_sock);
|
|
|
+ pthread_exit(EXIT_SUCCESS);
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Closes all active connections
|
|
|
+ */
|
|
|
+
|
|
|
+void serverTerminate() {
|
|
|
+ close(sock);
|
|
|
+ close(listen_sock);
|
|
|
+}
|
|
|
+
|