]> rtime.felk.cvut.cz Git - coffee/mt-apps.git/blob - mt_server.c
key
[coffee/mt-apps.git] / mt_server.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4
5 #include "mt_server.h"
6 #include "signal_exit.h"
7
8 static const struct lws_http_mount mount = {
9     /* .mount_next */            NULL,         /* linked-list "next" */
10     /* .mountpoint */            HTTP_MOUNTPOINT,
11     /* .origin */                HTTP_ORIGIN,  /* serve from dir */
12     /* .def */                   HTTP_DEFAULT, /* default filename */
13     /* .protocol */              NULL,
14     /* .cgienv */                NULL,
15     /* .extra_mimetypes */       NULL,
16     /* .interpret */             NULL,
17     /* .cgi_timeout */           0,
18     /* .cache_max_age */         0,
19     /* .auth_mask */             0,
20     /* .cache_reusable */        0,
21     /* .cache_revalidate */      0,
22     /* .cache_intermediaries */  0,
23     /* .origin_protocol */       LWSMPRO_FILE, /* files in a dir */
24     /* .mountpoint_len */        1,            /* char count */
25     /* .basic_auth_login_file */ NULL,
26 };
27
28 typedef struct per_vhost_data__merica_terminal {
29     struct lws_context *context;
30     struct lws_vhost *vhost;
31     const struct lws_protocols *protocol;
32 } per_vhost_data__merica_terminal;
33
34 /*
35 typedef struct per_session_data__merica_terminal {
36     int number;
37 } per_session_data__merica_terminal;
38 */
39
40 enum protocols {
41     PROTOCOL_HTTP = 0, // always first
42     PROTOCOL_MERICA_TERMINAL
43 };
44
45 static int callback_merica_terminal(struct lws *wsi,
46                                     enum lws_callback_reasons reason,
47                                     void *user, void *in, size_t len);
48
49 // list of supported protocols and callbacks
50 static struct lws_protocols protocols[] = {
51     // first protocol must always be HTTP handler
52     {"http", lws_callback_http_dummy, 0, 0},
53     {
54         "merica-terminal-protocol",
55         callback_merica_terminal,
56         0, //sizeof(struct per_session_data__merica_terminal),
57         MT_PROTOCOL_RX_BUFFER_SIZE
58     },
59     {NULL, NULL, 0, 0} // terminator
60 };
61
62 static int callback_merica_terminal(struct lws *wsi,
63                                     enum lws_callback_reasons reason,
64                                     void *user, void *in, size_t len)
65 {
66     struct lws_vhost *vhost = lws_get_vhost(wsi);
67     const struct lws_protocols *prot = lws_get_protocol(wsi);
68     /*
69     per_session_data__merica_terminal *pss =
70         (per_session_data__merica_terminal *)user;
71     */
72     per_vhost_data__merica_terminal *vhd =
73         (per_vhost_data__merica_terminal *)
74         lws_protocol_vh_priv_get(vhost, prot);
75
76     int n, m;
77
78     char *line = (char *)prot->user;
79
80     switch (reason) {
81         case LWS_CALLBACK_PROTOCOL_INIT:
82             vhd = lws_protocol_vh_priv_zalloc(
83                       vhost, prot,
84                       sizeof(struct per_vhost_data__merica_terminal)
85                   );
86             vhd->context = lws_get_context(wsi);
87             vhd->protocol = prot;
88             vhd->vhost = vhost;
89             break;
90
91         case LWS_CALLBACK_PROTOCOL_DESTROY:
92             if (!vhd) {
93                 break;
94             }
95             break;
96
97         case LWS_CALLBACK_ESTABLISHED:
98             break;
99
100         case LWS_CALLBACK_SERVER_WRITEABLE:
101             n = strlen(line);
102             m = lws_write(wsi, (unsigned char *)line, n, LWS_WRITE_TEXT);
103             if (m < n) {
104                 fprintf(stderr, "ERROR %d writing to di socket\n", n);
105                 return -1;
106             }
107             break;
108
109         case LWS_CALLBACK_RECEIVE:
110             if (strcmp((const char *)in, "reset") == 0) {
111                 strcpy(line, JSON_EMPTY);
112                 lws_callback_on_writable_all_protocol(lws_get_context(wsi),
113                                                       &protocols[PROTOCOL_MERICA_TERMINAL]);
114             } else if (strcmp((const char *)in, "close") == 0) {
115                 fprintf(stderr, "closing websocket\n");
116                 lws_close_reason(wsi, LWS_CLOSE_STATUS_GOINGAWAY,
117                                  (unsigned char *)"seeya", 5);
118                 return -1;
119             }
120             break;
121
122         default:
123             break;
124     }
125
126     return 0;
127 }
128
129 static void fd_cb(EV_P_ ev_io *w_, int revents)
130 {
131     ev_io_ws *w = (ev_io_ws *)w_;
132
133     char *pos = w->pos++;
134
135     read(w->w.fd, pos, 1);
136
137     if (*pos == '\n' || (w->pos - w->text) == INPUT_LINE_LENGTH) {
138         *pos = 0;
139         w->pos = w->text;
140         lws_callback_on_writable_all_protocol(w->context,
141                                               &protocols[PROTOCOL_MERICA_TERMINAL]);
142     }
143 }
144
145 int mt_server_init(mt_server_t *self, struct ev_loop *loop, int fd)
146 {
147     struct lws_context_creation_info info;
148
149     memset(&info, 0, sizeof(info));
150     info.port = HTTP_PORT;
151     info.mounts = &mount;
152     info.protocols = protocols;
153     info.max_http_header_pool = 1;
154     info.options |= LWS_SERVER_OPTION_LIBEV;
155
156     struct lws_context *context = lws_create_context(&info);
157     if (!context) {
158         fprintf(stderr, "lws_create_context failed\n");
159         return -1;
160     }
161
162     self->context = context;
163
164     ev_io_ws *w = &(self->fd_watcher);
165     w->context = context;
166     w->text = (char *)malloc(INPUT_LINE_LENGTH*sizeof(char));
167     if (!w->text) {
168         perror("malloc");
169         return -1;
170     }
171     strcpy(w->text, JSON_EMPTY);
172     w->pos = w->text;
173     protocols[PROTOCOL_MERICA_TERMINAL].user = (void *)w->text;
174     ev_io_init(&(w->w), fd_cb, fd, EV_READ);
175     ev_io_start(loop, (ev_io *)w);
176
177     return lws_ev_initloop(context, loop, 0);
178 }
179
180 void mt_server_deinit(mt_server_t *self) //TODO wtf
181 {
182     //free(self->fd_watcher.text);
183     //protocols[PROTOCOL_MERICA_TERMINAL].user = NULL;
184     lws_context_destroy(self->context);
185 }
186
187 #ifndef NO_MAIN
188 int main(int argc, const char **argv)
189 {
190     struct ev_loop *loop = EV_DEFAULT;
191     mt_server_t server;
192
193     set_signal_exit(loop);
194
195     if (mt_server_init(&server, loop, STDIN_FILENO) != 0) {
196         return -1;
197     }
198
199     ev_run(loop, 0);
200
201     mt_server_deinit(&server);
202
203     return 0;
204 }
205 #endif