Files
cosmopolite/clients/c/test.c

202 lines
5.5 KiB
C
Raw Normal View History

2015-06-02 22:21:28 -07:00
#include <assert.h>
#include <pthread.h>
#include <stdbool.h>
2015-06-02 22:21:28 -07:00
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <jansson.h>
#include <curl/curl.h>
#include <uuid/uuid.h>
#define COSMO_UUID_SIZE 37
#define COSMO_CLIENT_ID_SIZE COSMO_UUID_SIZE
#define COSMO_CHECK_SECONDS 10
#define min(a, b) ((a) < (b) ? (a) : (b))
typedef struct {
char client_id[COSMO_CLIENT_ID_SIZE];
char instance_id[COSMO_UUID_SIZE];
pthread_mutex_t lock;
pthread_cond_t cond;
bool shutdown;
json_t *command_queue;
2015-06-02 22:21:28 -07:00
pthread_t thread;
2015-06-03 20:15:31 -07:00
} cosmo;
2015-06-02 22:21:28 -07:00
2015-06-03 20:15:31 -07:00
typedef struct {
2015-06-02 22:21:28 -07:00
char *send_buf;
size_t send_buf_len;
char *recv_buf;
size_t recv_buf_len;
2015-06-03 20:15:31 -07:00
} cosmo_transfer;
2015-06-02 22:21:28 -07:00
static void cosmo_generate_uuid(char *uuid) {
uuid_t uu;
uuid_generate(uu);
uuid_unparse_lower(uu, uuid);
}
static size_t cosmo_read_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
2015-06-03 20:15:31 -07:00
cosmo_transfer *transfer = userp;
size_t to_write = min(transfer->send_buf_len, size * nmemb);
memcpy(ptr, transfer->send_buf, to_write);
transfer->send_buf += to_write;
transfer->send_buf_len -= to_write;
2015-06-02 22:21:28 -07:00
return to_write;
}
static size_t cosmo_write_callback(void *ptr, size_t size, size_t nmemb, void *userp) {
2015-06-03 20:15:31 -07:00
cosmo_transfer *transfer = userp;
size_t to_read = size * nmemb;
2015-06-03 20:32:00 -07:00
transfer->recv_buf = realloc(transfer->recv_buf, transfer->recv_buf_len + to_read + 1);
2015-06-03 20:15:31 -07:00
assert(transfer->recv_buf);
memcpy(transfer->recv_buf + transfer->recv_buf_len, ptr, to_read);
transfer->recv_buf_len += to_read;
2015-06-03 20:32:00 -07:00
transfer->recv_buf[transfer->recv_buf_len] = '\0';
return to_read;
}
2015-06-03 20:32:00 -07:00
static char *cosmo_build_rpc(cosmo *instance) {
json_t *to_send = json_pack("{sssss[]}", "client_id", instance->client_id, "instance_id", instance->instance_id, "commands");
assert(to_send);
2015-06-03 20:32:00 -07:00
char *ret = json_dumps(to_send, 0);
assert(ret);
json_decref(to_send);
2015-06-03 20:32:00 -07:00
return ret;
2015-06-03 20:15:31 -07:00
}
static bool cosmo_send_http_int(cosmo *instance, cosmo_transfer *transfer, CURL *curl) {
2015-06-02 22:21:28 -07:00
CURLcode res;
curl_easy_setopt(curl, CURLOPT_URL, "https://playground.cosmopolite.org/cosmopolite/api");
curl_easy_setopt(curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTPS);
curl_easy_setopt(curl, CURLOPT_REDIR_PROTOCOLS, CURLPROTO_HTTPS);
curl_easy_setopt(curl, CURLOPT_SSL_CIPHER_LIST, "ECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH");
curl_easy_setopt(curl, CURLOPT_POST, 1L);
2015-06-03 20:15:31 -07:00
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, transfer->send_buf_len);
2015-06-02 22:21:28 -07:00
curl_easy_setopt(curl, CURLOPT_READFUNCTION, cosmo_read_callback);
2015-06-03 20:15:31 -07:00
curl_easy_setopt(curl, CURLOPT_READDATA, transfer);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, cosmo_write_callback);
2015-06-03 20:15:31 -07:00
curl_easy_setopt(curl, CURLOPT_WRITEDATA, transfer);
curl_easy_setopt(curl, CURLOPT_TIMEOUT, COSMO_CHECK_SECONDS);
2015-06-02 22:21:28 -07:00
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
2015-06-03 20:15:31 -07:00
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
return false;
}
2015-06-02 22:21:28 -07:00
long return_code;
assert(curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &return_code) == CURLE_OK);
if (return_code != 200) {
fprintf(stderr, "server returned error: %ld\n", return_code);
return false;
2015-06-03 20:15:31 -07:00
}
return true;
2015-06-03 20:15:31 -07:00
}
2015-06-03 20:32:00 -07:00
// Takes ownership of request
static char *cosmo_send_http(cosmo *instance, char *request) {
CURL *curl = curl_easy_init();
assert(curl);
cosmo_transfer transfer = {
.send_buf = request,
.send_buf_len = strlen(request),
.recv_buf = NULL,
.recv_buf_len = 0
};
2015-06-03 20:15:31 -07:00
2015-06-03 20:32:00 -07:00
int ret = cosmo_send_http_int(instance, &transfer, curl);
curl_easy_cleanup(curl);
free(request);
return ret ? transfer.recv_buf : NULL;
2015-06-03 20:32:00 -07:00
}
static void cosmo_send_rpc(cosmo *instance) {
char *request = cosmo_build_rpc(instance);
2015-06-03 20:15:31 -07:00
2015-06-03 20:32:00 -07:00
char *response = cosmo_send_http(instance, request);
if (!response) {
return;
}
2015-06-02 22:21:28 -07:00
json_error_t error;
2015-06-03 20:32:00 -07:00
json_t *received = json_loads(response, 0, &error);
if (!received) {
2015-06-03 20:32:00 -07:00
fprintf(stderr, "json_loads() failed: %s (json: \"%s\")\n", error.text, response);
free(response);
return;
}
2015-06-03 20:32:00 -07:00
free(response);
2015-06-02 22:21:28 -07:00
printf("profile: %s\n", json_string_value(json_object_get(received, "profile")));
json_decref(received);
2015-06-02 22:21:28 -07:00
}
static void *cosmo_thread_main(void *arg) {
cosmo *instance = arg;
assert(!pthread_mutex_lock(&instance->lock));
while (!instance->shutdown) {
cosmo_send_rpc(instance);
assert(!pthread_cond_wait(&instance->cond, &instance->lock));
2015-06-02 22:21:28 -07:00
}
assert(!pthread_mutex_unlock(&instance->lock));
2015-06-02 22:21:28 -07:00
return NULL;
}
void cosmo_generate_client_id(char *client_id) {
cosmo_generate_uuid(client_id);
}
cosmo *cosmo_create(char *client_id) {
curl_global_init(CURL_GLOBAL_DEFAULT);
cosmo *instance = malloc(sizeof(cosmo));
assert(instance);
strcpy(instance->client_id, client_id);
cosmo_generate_uuid(instance->instance_id);
assert(!pthread_mutex_init(&instance->lock, NULL));
assert(!pthread_cond_init(&instance->cond, NULL));
instance->shutdown = false;
instance->command_queue = json_array();
2015-06-02 22:21:28 -07:00
assert(!pthread_create(&instance->thread, NULL, cosmo_thread_main, instance));
return instance;
}
void cosmo_destroy(cosmo *instance) {
pthread_mutex_lock(&instance->lock);
instance->shutdown = 1;
pthread_cond_signal(&instance->cond);
2015-06-02 22:21:28 -07:00
pthread_mutex_unlock(&instance->lock);
assert(!pthread_join(instance->thread, NULL));
assert(!pthread_mutex_destroy(&instance->lock));
assert(!pthread_cond_destroy(&instance->cond));
json_decref(instance->command_queue);
2015-06-02 22:21:28 -07:00
free(instance);
curl_global_cleanup();
}
int main(int argc, char *argv[]) {
char client_id[COSMO_CLIENT_ID_SIZE];
cosmo_generate_client_id(client_id);
cosmo *instance = cosmo_create(client_id);
sleep(5);
2015-06-02 22:21:28 -07:00
cosmo_destroy(instance);
return 0;
}