You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

244 lines
4.6 KiB

#include "wsfs/protocol.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <pthread.h>
#include "wsfs/util.h"
#include "wsfs/server.h"
struct wsfs_message
{
char * content;
size_t length;
};
struct wsfs_protocol
{
pthread_mutex_t lock;
struct lws * wsi;
struct wsfs_message pending_message;
struct wsfs_server * server;
};
static struct wsfs_protocol * wsfs_protocol_from_wsi(
struct lws * wsi)
{
struct lws_protocols const * protocol = lws_get_protocol(wsi);
return protocol->user;
}
static bool wsfs_protocol_connect(
struct wsfs_protocol * protocol,
struct lws * wsi)
{
pthread_mutex_lock(&protocol->lock);
bool const success = (NULL == protocol->wsi);
if (success)
{
protocol->wsi = wsi;
}
pthread_mutex_unlock(&protocol->lock);
return success;
}
static bool wsfs_protocol_is_wsi_connected(
struct wsfs_protocol * protocol,
struct lws * wsi)
{
pthread_mutex_lock(&protocol->lock);
bool const result = (wsi == protocol->wsi);
pthread_mutex_unlock(&protocol->lock);
return result;
}
static void wsfs_protocol_disconnect(
struct wsfs_protocol * protocol,
struct lws * wsi)
{
pthread_mutex_lock(&protocol->lock);
if (wsi == protocol->wsi)
{
protocol->wsi = NULL;
}
pthread_mutex_unlock(&protocol->lock);
}
static void wsfs_protocol_get_message(
struct wsfs_protocol * protocol,
struct wsfs_message * message)
{
pthread_mutex_lock(&protocol->lock);
message->content = protocol->pending_message.content;
message->length = protocol->pending_message.length;
protocol->pending_message.content = NULL;
protocol->pending_message.length = 0;
pthread_mutex_unlock(&protocol->lock);
}
static int wsfs_protocol_callback(
struct lws *wsi,
enum lws_callback_reasons reason,
void * WSFS_UNUSED_PARAM(user),
void *in,
size_t len)
{
int result = 0;
struct wsfs_protocol * const protocol = wsfs_protocol_from_wsi(wsi);
switch (reason)
{
case LWS_CALLBACK_ESTABLISHED:
{
if (!wsfs_protocol_connect(protocol, wsi))
{
puts("connect failed");
lws_callback_on_writable(wsi);
result = -1;
}
}
break;
case LWS_CALLBACK_CLOSED:
{
wsfs_protocol_disconnect(protocol, wsi);
}
break;
case LWS_CALLBACK_SERVER_WRITEABLE:
{
if (wsfs_protocol_is_wsi_connected(protocol, wsi))
{
struct wsfs_message message;
wsfs_protocol_get_message(protocol, &message);
if (NULL != message.content)
{
lws_write(wsi, (unsigned char*) message.content, message.length, LWS_WRITE_TEXT);
wsfs_protocol_message_dispose(message.content);
}
}
else
{
result = -1;
}
}
break;
case LWS_CALLBACK_RECEIVE:
{
wsfs_server_handle_message(protocol->server, in, len);
}
break;
default:
break;
}
return result;
}
struct wsfs_protocol * wsfs_protocol_create(
struct wsfs_server * server)
{
struct wsfs_protocol * protocol = malloc(sizeof(struct wsfs_protocol));
if (NULL != protocol)
{
pthread_mutex_init(&protocol->lock, NULL);
protocol->wsi = NULL;
protocol->pending_message.content = NULL;
protocol->pending_message.length = 0;
protocol->server = server;
}
return protocol;
}
void wsfs_protocol_dispose(
struct wsfs_protocol * protocol)
{
pthread_mutex_destroy(&protocol->lock);
if (NULL != protocol->pending_message.content)
{
wsfs_protocol_message_dispose(protocol->pending_message.content);
protocol->pending_message.content = NULL;
}
free(protocol);
}
void wsfs_protocol_check(
struct wsfs_protocol * protocol)
{
pthread_mutex_lock(&protocol->lock);
if ((NULL != protocol->wsi) && (NULL != protocol->pending_message.content))
{
lws_callback_on_writable(protocol->wsi);
}
pthread_mutex_unlock(&protocol->lock);
}
void wsfs_protocol_init_lws(
struct wsfs_protocol * protocol,
struct lws_protocols * lws_protocol)
{
lws_protocol->callback = &wsfs_protocol_callback;
lws_protocol->per_session_data_size = 1;
lws_protocol->user = protocol;
}
char * wsfs_protocol_message_create(
size_t size)
{
char * buffer = malloc(LWS_PRE + size);
return &buffer[LWS_PRE];
}
void wsfs_protocol_message_dispose(
char * message)
{
char * buffer = message - LWS_PRE;
free(buffer);
}
bool wsfs_protocol_send(
char * message,
size_t length,
void * user_data)
{
struct wsfs_protocol * protocol = user_data;
pthread_mutex_lock(&protocol->lock);
struct wsfs_server * server = protocol->server;
bool result = (NULL != protocol->wsi) && (NULL == protocol->pending_message.content);
if (result)
{
protocol->pending_message.content = message;
protocol->pending_message.length = length;
}
else
{
wsfs_protocol_message_dispose(message);
}
pthread_mutex_unlock(&protocol->lock);
if (result)
{
wsfs_server_wakeup(server);
}
return result;
}