vkpc-linux/desktop/server.c
2013-12-29 17:58:09 +02:00

183 lines
4.6 KiB
C

/**
* TODO: logging level
*/
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <libwebsockets.h>
#include <stdbool.h>
#include "server.h"
#include "vector.h"
#define SERVER_PORT 52178
#define SERVER_HOST "localhost"
static struct libwebsocket_context *context;
static char *server_last_cmd_values[] = {
"none", "play", "pause", "next", "prev"
};
struct per_session_data {
bool established;
char *next_command;
};
struct session {
struct per_session_data *pss;
struct libwebsocket *wsi;
};
vector *sessions;
static void add_session(struct libwebsocket *wsi, struct per_session_data *pss) {
struct session *s = malloc(sizeof(struct session));
s->wsi = wsi;
s->pss = pss;
vector_add(sessions, s);
}
static void delete_session(struct libwebsocket *wsi) {
for (int i = 0; i < vector_count(sessions); i++) {
struct session *s = vector_get(sessions, i);
if (s != NULL && s->wsi == wsi) {
printf("(delete_session) found, i=%d\n", i);
free(s);
vector_delete(sessions, i);
break;
}
}
}
static void send_command_to_all(char *command) {
printf("Got command: %s\n", command);
for (int i = 0; i < vector_count(sessions); i++) {
struct session *s = (struct session *)vector_get(sessions, i);
s->pss->next_command = command;
libwebsocket_callback_on_writable(context, s->wsi);
}
}
static int callback_http(struct libwebsocket_context *this,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user,
void *in,
size_t len)
{
switch (reason) {
case LWS_CALLBACK_HTTP: ;
libwebsocket_callback_on_writable(context, wsi);
break;
case LWS_CALLBACK_HTTP_WRITEABLE: ;
char *response = "vkpc, world!";
libwebsocket_write(wsi, (unsigned char *)response, strlen(response), LWS_WRITE_HTTP);
return -1;
default:
break;
}
return 0;
}
static int callback_signaling(struct libwebsocket_context *this,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason,
void *user,
void *in,
size_t len)
{
struct per_session_data *pss = (struct per_session_data *)user;
switch (reason) {
case LWS_CALLBACK_ESTABLISHED:
lwsl_info("Connection established");
pss->established = true;
pss->next_command = NULL;
add_session(wsi, pss);
libwebsocket_callback_on_writable(context, wsi);
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
if (pss->next_command != NULL) {
int length = strlen(pss->next_command);
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + length + LWS_SEND_BUFFER_POST_PADDING];
unsigned char *p = &buf[LWS_SEND_BUFFER_PRE_PADDING];
strcpy((char *)p, pss->next_command);
int m = libwebsocket_write(wsi, p, length, LWS_WRITE_TEXT);
if (m < length) {
lwsl_err("ERROR while writing %d bytes to socket\n", length);
return -1;
}
pss->next_command = NULL;
}
break;
case LWS_CALLBACK_RECEIVE:
lwsl_info("Received: %s, length: %d\n",
(char *)in, (int)strlen((char *)in));
break;
case LWS_CALLBACK_CLOSED:
lwsl_info("Connection closed\n");
delete_session(wsi);
break;
default:
break;
}
return 0;
}
static struct libwebsocket_protocols protocols[] = {
{ "http-only", callback_http, 0, 0 },
{ "signaling-protocol", callback_signaling, sizeof(struct per_session_data), 0 },
{ NULL, NULL, 0 }
};
void server_init() {
sessions = vector_create();
struct lws_context_creation_info info;
memset(&info, 0, sizeof(info));
info.port = SERVER_PORT;
info.iface = SERVER_HOST;
info.protocols = protocols;
info.extensions = libwebsocket_get_internal_extensions();
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
info.gid = -1;
info.uid = -1;
info.options = 0;
context = libwebsocket_create_context(&info);
if (context == NULL) {
fprintf(stderr, "libwebsocket init failed\n");
return;
}
enum server_last_cmd_enum last_cmd = NONE;
while (1) {
pthread_mutex_lock(&server_last_cmd_mutex);
last_cmd = server_last_cmd;
server_last_cmd = NONE;
pthread_mutex_unlock(&server_last_cmd_mutex);
if (last_cmd != NONE) {
send_command_to_all(server_last_cmd_values[last_cmd]);
}
libwebsocket_service(context, 50);
}
libwebsocket_context_destroy(context);
return;
}