1/*
2 * Copyright 2020, Data61, CSIRO (ABN 41 687 119 230)
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <arpa/inet.h>
8#include <string.h>
9
10#include "client.h"
11
12/* Benchmark utilization TCP handler */
13int utiliz_socket;
14int peer_socket = -1;
15
16#define WHOAMI "100 IPBENCH V1.0\n"
17#define HELLO "HELLO\n"
18#define OK_READY "200 OK (Ready to go)\n"
19#define LOAD "LOAD cpu_target_lukem\n"
20#define OK "200 OK\n"
21#define SETUP "SETUP args::\"\"\n"
22#define START "START\n"
23#define STOP "STOP\n"
24#define QUIT "QUIT\n"
25#define RESPONSE "220 VALID DATA (Data to follow)\n" \
26                 "Content-length: %d\n" \
27                 "%s\n"
28#define IDLE_FORMAT ",%ld,%ld"
29#define msg_match(msg, match) (strncmp(msg, match, strlen(match))==0)
30
31void handle_tcp_utiliz_notification(uint16_t events, int socket)
32{
33    int ret = 0;
34    char ip_string[16] = {0};
35
36    if (events & PICOSERVER_CONN) {
37        picoserver_peer_t peer = echo_control_accept(socket);
38        if (peer.result == -1) {
39            ZF_LOGF("Failed to accept a peer");
40        }
41        peer_socket = peer.socket;
42        inet_ntop(AF_INET, &peer.peer_addr, ip_string, 16);
43        printf("%s: Connection established with %s on socket %d\n", get_instance_name(), ip_string, socket);
44
45        memcpy(echo_send_buf, WHOAMI, strlen(WHOAMI));
46        echo_send_send(peer_socket, strlen(WHOAMI), 0);
47    }
48
49    if (events & PICOSERVER_READ) {
50        ret = echo_recv_recv(socket, 0x1000, 0);
51        if (ret == -1) {
52            printf("received -1\n");
53        } else if (ret == 0) {
54            printf("Error\n");
55        }
56        if (msg_match(echo_recv_buf, HELLO)) {
57            memcpy(echo_send_buf, OK_READY, strlen(OK_READY));
58            echo_send_send(socket, strlen(OK_READY), 0);
59        } else if (msg_match(echo_recv_buf, LOAD)) {
60            memcpy(echo_send_buf, OK, strlen(OK));
61            echo_send_send(socket, strlen(OK), 0);
62        } else if (msg_match(echo_recv_buf, SETUP)) {
63            memcpy(echo_send_buf, OK, strlen(OK));
64            echo_send_send(socket, strlen(OK), 0);
65        } else if (msg_match(echo_recv_buf, START)) {
66            idle_start();
67        } else if (msg_match(echo_recv_buf, STOP)) {
68            uint64_t total, kernel, idle;
69            idle_stop(&total, &kernel, &idle);
70            char *util_msg;
71            int len = asprintf(&util_msg, IDLE_FORMAT, idle, total);
72            if (len == -1) {
73                ZF_LOGE("asprintf: Failed to print string");
74            } else {
75                len = snprintf(echo_send_buf, 0x1000, RESPONSE, len + 1, util_msg);
76                if (len == -1) {
77                    ZF_LOGE("asprintf: Failed to print string");
78                } else {
79                    echo_send_send(socket, len, 0);
80                }
81                free(util_msg);
82            }
83            echo_control_shutdown(socket, PICOSERVER_SHUT_RDWR);
84        } else if (msg_match(echo_recv_buf, QUIT)) {
85        } else {
86            printf("Couldn't match message: %s\n", (char *)echo_recv_buf);
87        }
88
89    }
90
91    if (events & PICOSERVER_CLOSE) {
92        ret = echo_control_shutdown(socket, PICOSERVER_SHUT_RDWR);
93        printf("%s: Connection closing on socket %d\n", get_instance_name(), socket);
94    }
95    if (events & PICOSERVER_FIN) {
96        printf("%s: Connection closed on socket %d\n", get_instance_name(), socket);
97        peer_socket = -1;
98    }
99    if (events & PICOSERVER_ERR) {
100        printf("%s: Error with socket %d, going to die\n", get_instance_name(), socket);
101    }
102}
103
104
105static int setup_utilization_socket(ps_io_ops_t *io_ops)
106{
107    utiliz_socket = echo_control_open(false);
108    if (utiliz_socket == -1) {
109        ZF_LOGE("Failed to open a socket for listening!");
110        return -1;
111    }
112
113    int ret = echo_control_bind(utiliz_socket, PICOSERVER_ANY_ADDR_IPV4, UTILIZATION_PORT);
114    if (ret) {
115        ZF_LOGE("Failed to bind a socket for listening!");
116        return ret;
117    }
118
119    ret = echo_control_listen(utiliz_socket, 1);
120    if (ret) {
121        ZF_LOGE("Failed to listen for incoming connections!");
122        return ret;
123    }
124
125    return 0;
126
127}
128
129CAMKES_POST_INIT_MODULE_DEFINE(setup_utiliz, setup_utilization_socket);
130