|
|
|
@ -1,4 +1,5 @@
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#define __USE_GNU
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#include <stdarg.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
@ -12,6 +13,10 @@
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
#include <assert.h>
|
|
|
|
|
#include <time.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/wait.h>
|
|
|
|
|
#include <execinfo.h>
|
|
|
|
|
#include <sys/resource.h>
|
|
|
|
|
|
|
|
|
|
#include <tdata/usrtc.h>
|
|
|
|
|
#include <sexpr/sexp.h>
|
|
|
|
@ -19,8 +24,118 @@
|
|
|
|
|
|
|
|
|
|
/* define a little bit */
|
|
|
|
|
#define DEFAULT_PORT 13133
|
|
|
|
|
#define CHANNEL_COUNT 1
|
|
|
|
|
#define CLIENT_COUNT 2
|
|
|
|
|
#define CHANNEL_COUNT 4000
|
|
|
|
|
#define CLIENT_COUNT 2000
|
|
|
|
|
#define MESSAGES_PER_SESSION 10
|
|
|
|
|
#define ITERATION_COUNT 10
|
|
|
|
|
|
|
|
|
|
#define FAILS_ONLY
|
|
|
|
|
//#define SIMPLE_TESTING
|
|
|
|
|
|
|
|
|
|
static FILE *log_file = NULL;
|
|
|
|
|
|
|
|
|
|
inline int log_init(const char *file)
|
|
|
|
|
{
|
|
|
|
|
if(log_file) {
|
|
|
|
|
fclose(log_file);
|
|
|
|
|
}
|
|
|
|
|
log_file = fopen(file, "w");
|
|
|
|
|
if(!log_file) return EIO;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void log_msg(const char *prefix, const char *data)
|
|
|
|
|
{
|
|
|
|
|
if(log_file) fprintf(log_file, "[%s]: %s\n", prefix, data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void log_begin(const char *data)
|
|
|
|
|
{
|
|
|
|
|
#ifndef FAILS_ONLY
|
|
|
|
|
log_msg("BEGIN", data);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void log_end(const char *data)
|
|
|
|
|
{
|
|
|
|
|
#ifndef FAILS_ONLY
|
|
|
|
|
log_msg("END", data);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void log_info(const char *data)
|
|
|
|
|
{
|
|
|
|
|
#ifndef FAILS_ONLY
|
|
|
|
|
log_msg("INFO", data);
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void log_error(const char *data)
|
|
|
|
|
{
|
|
|
|
|
log_msg("FAILED", data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void log_assert(const char *info, int rc, int exp)
|
|
|
|
|
{
|
|
|
|
|
if(log_file && (rc) != (exp)) {
|
|
|
|
|
fprintf(log_file, "[FAILED]: %s result: %d, expected: %d\n", info, rc, exp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void log_close()
|
|
|
|
|
{
|
|
|
|
|
if(log_file) {
|
|
|
|
|
fflush(log_file);
|
|
|
|
|
fclose(log_file);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline void log_flush()
|
|
|
|
|
{
|
|
|
|
|
fflush(log_file);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void signal_error(int sig, siginfo_t *si, void *ptr)
|
|
|
|
|
{
|
|
|
|
|
void* error_addr;
|
|
|
|
|
void* trace[16];
|
|
|
|
|
int x;
|
|
|
|
|
int trace_size;
|
|
|
|
|
char** messages;
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "Something is wrong: backtrace: \n");
|
|
|
|
|
uintptr_t fptr = (uintptr_t)(si->si_addr);
|
|
|
|
|
fprintf(stderr, "Signal: %d, function pointer: 0x%.12lX \n", sig, fptr);
|
|
|
|
|
#if __WORDSIZE == 64
|
|
|
|
|
error_addr = (void*)((ucontext_t*)ptr)->uc_mcontext.gregs[REG_RIP];
|
|
|
|
|
#else
|
|
|
|
|
error_addr = (void*)((ucontext_t*)ptr)->uc_mcontext.gregs[REG_EIP];
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
trace_size = backtrace(trace, 16);
|
|
|
|
|
trace[1] = error_addr;
|
|
|
|
|
|
|
|
|
|
messages = backtrace_symbols(trace, trace_size);
|
|
|
|
|
if (messages)
|
|
|
|
|
{
|
|
|
|
|
for (x = 1; x < trace_size; x++)
|
|
|
|
|
{
|
|
|
|
|
fprintf(stderr, "%s\n", messages[x]);
|
|
|
|
|
}
|
|
|
|
|
free(messages);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fprintf(stderr, "end of backtrace\n");
|
|
|
|
|
|
|
|
|
|
exit(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
pthread_t **threads;
|
|
|
|
|
int thread_count;
|
|
|
|
|
conn_t *co;
|
|
|
|
|
} test_data_t;
|
|
|
|
|
|
|
|
|
|
/*static*/ sexp_t *make_request(const char *req)
|
|
|
|
|
{
|
|
|
|
@ -30,96 +145,160 @@
|
|
|
|
|
return sx;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *test_send_message(void *ch)
|
|
|
|
|
/*static */int allocate_threads(int count, test_data_t *data)
|
|
|
|
|
{
|
|
|
|
|
__DBGLINE;
|
|
|
|
|
chnl_t *chnl = (chnl_t *)ch;
|
|
|
|
|
char buf[1024];
|
|
|
|
|
int a = rand() % 100;
|
|
|
|
|
int b = rand() % 100;
|
|
|
|
|
sprintf(buf, "(ar-add (%d %d))", a, b);
|
|
|
|
|
sexp_t *add_request = make_request(buf);
|
|
|
|
|
sxmsg_t *msg = NULL;
|
|
|
|
|
int rc = 0;
|
|
|
|
|
clock_t start = clock();
|
|
|
|
|
rc = msg_send(chnl, add_request, &msg);
|
|
|
|
|
clock_t end = clock();
|
|
|
|
|
double time = (double)(end - start) / CLOCKS_PER_SEC;
|
|
|
|
|
printf("msg_send execution time: %lf. rc = %d\n", time, rc);
|
|
|
|
|
assert(rc == a + b);
|
|
|
|
|
destroy_sexp(add_request);
|
|
|
|
|
return 0x00;
|
|
|
|
|
int i = 0;
|
|
|
|
|
data->threads = (pthread_t **)malloc(count * sizeof(pthread_t *));
|
|
|
|
|
for(i = 0; i < count; ++i) {
|
|
|
|
|
data->threads[i] = (pthread_t *)malloc(sizeof(pthread_t));
|
|
|
|
|
if(!data->threads) return ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
data->thread_count = count;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/*static */int deallocate_threads(test_data_t *data)
|
|
|
|
|
{
|
|
|
|
|
int i = 0;
|
|
|
|
|
for(i = 0; i < data->thread_count; ++i) {
|
|
|
|
|
if(!data->threads[i]) return EINVAL;
|
|
|
|
|
pthread_join(*data->threads[i], NULL);
|
|
|
|
|
free(data->threads[i]);
|
|
|
|
|
data->threads[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
free(data->threads);
|
|
|
|
|
data->thread_count = 0;
|
|
|
|
|
|
|
|
|
|
void *test_channel(void *ctx)
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *test_invalid_channel(void *ctx)
|
|
|
|
|
{
|
|
|
|
|
log_begin("Invalid channel testing");
|
|
|
|
|
conn_t *co = (conn_t *)ctx;
|
|
|
|
|
printf("Testing channel (%ld)\n", pthread_self());
|
|
|
|
|
chnl_t *channel = NULL;
|
|
|
|
|
int rc = 0;
|
|
|
|
|
rc = channel_open(co, &channel, 12);
|
|
|
|
|
if(rc) {
|
|
|
|
|
printf("Failed to open channel. rc=%d\n", rc);
|
|
|
|
|
int rc = 0, i;
|
|
|
|
|
for(i = 0; i < ITERATION_COUNT || ITERATION_COUNT < 0; ++i) {
|
|
|
|
|
rc = channel_open(co, &channel, 1);
|
|
|
|
|
log_assert("channel_open with type 1", rc, EINVAL);
|
|
|
|
|
// TODO: segmentation fault below
|
|
|
|
|
//rc = channel_close(channel);
|
|
|
|
|
//log_assert("channel_close with type 1", rc, EINVAL);
|
|
|
|
|
}
|
|
|
|
|
assert(rc == 0);
|
|
|
|
|
|
|
|
|
|
// test message sending
|
|
|
|
|
int i;
|
|
|
|
|
pthread_t threads[CLIENT_COUNT];
|
|
|
|
|
for(i = 0; i < CLIENT_COUNT; ++i) {
|
|
|
|
|
if(pthread_create(&(threads[i]), NULL, test_send_message, channel)) {
|
|
|
|
|
fprintf(stderr, "Error creating thread\n");
|
|
|
|
|
log_end("Invalid channel testing");
|
|
|
|
|
return 0x00;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void *test_correct_channel(void *ctx)
|
|
|
|
|
{
|
|
|
|
|
log_begin("Channel testing");
|
|
|
|
|
|
|
|
|
|
conn_t *co = (conn_t *)ctx;
|
|
|
|
|
chnl_t *channel = NULL;
|
|
|
|
|
int rc = 0, i, j;
|
|
|
|
|
char buf[128];
|
|
|
|
|
time_t start, end;
|
|
|
|
|
int a, b;
|
|
|
|
|
sexp_t *add_request = NULL;
|
|
|
|
|
sxmsg_t *msg = NULL;
|
|
|
|
|
double exec_time;
|
|
|
|
|
|
|
|
|
|
for(j = 0; j < ITERATION_COUNT || ITERATION_COUNT < 0; ++j) {
|
|
|
|
|
rc = channel_open(co, &channel, 12);
|
|
|
|
|
log_assert("channel_open with type 12", rc, 0);
|
|
|
|
|
log_begin("Test messaging");
|
|
|
|
|
for(i = 0; i < MESSAGES_PER_SESSION; ++i) {
|
|
|
|
|
a = rand() % 100;
|
|
|
|
|
b = rand() % 100;
|
|
|
|
|
sprintf(buf, "(ar-add (%d %d))", a, b);
|
|
|
|
|
add_request = make_request(buf);
|
|
|
|
|
time(&start);
|
|
|
|
|
rc = msg_send(channel, add_request, &msg);
|
|
|
|
|
time(&end);
|
|
|
|
|
exec_time = difftime(end, start);
|
|
|
|
|
sprintf(buf, "rpc execution time: %lf", exec_time);
|
|
|
|
|
log_info(buf);
|
|
|
|
|
log_assert("rpc execution", rc, a + b);
|
|
|
|
|
//destroy_sexp(add_request);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for(i = 0; i < CLIENT_COUNT; ++i) {
|
|
|
|
|
pthread_join(threads[i], NULL);
|
|
|
|
|
}
|
|
|
|
|
log_end("Test messaging");
|
|
|
|
|
|
|
|
|
|
rc = channel_close(channel);
|
|
|
|
|
if(rc) {
|
|
|
|
|
printf("Failed to close channel. rc=%d\n", rc);
|
|
|
|
|
// rc = channel_close(channel);
|
|
|
|
|
// log_assert("channel_close with type 12", rc, 0);
|
|
|
|
|
}
|
|
|
|
|
assert(rc == 0);
|
|
|
|
|
|
|
|
|
|
log_end("Channel testing");
|
|
|
|
|
return 0x00;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/ int start_testing(conn_t *co)
|
|
|
|
|
int test_channels(test_data_t *data, int index)
|
|
|
|
|
{
|
|
|
|
|
printf("---------------=========== Testing... ===========------------------\n");
|
|
|
|
|
int i;
|
|
|
|
|
pthread_t threads[CHANNEL_COUNT];
|
|
|
|
|
for(i = 0; i < CHANNEL_COUNT; ++i) {
|
|
|
|
|
if(pthread_create(&(threads[i]), NULL, test_channel, co)) {
|
|
|
|
|
fprintf(stderr, "Error creating thread\n");
|
|
|
|
|
return EINVAL;
|
|
|
|
|
}
|
|
|
|
|
int rc = 0;
|
|
|
|
|
if(index < CLIENT_COUNT) {
|
|
|
|
|
rc = pthread_create(data->threads[index], NULL, test_correct_channel, data->co);
|
|
|
|
|
} else {
|
|
|
|
|
rc = pthread_create(data->threads[index], NULL, test_invalid_channel, data->co);
|
|
|
|
|
}
|
|
|
|
|
for(i = 0; i < CHANNEL_COUNT; ++i) {
|
|
|
|
|
pthread_join(threads[i], NULL);
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void test_channel_handling(conn_t *co)
|
|
|
|
|
{
|
|
|
|
|
chnl_t *channel = NULL;
|
|
|
|
|
int rc = 0, i = 0;
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < ITERATION_COUNT; ++i) {
|
|
|
|
|
rc = channel_open(co, &channel, 12);
|
|
|
|
|
log_assert("channel open function", rc, 0);
|
|
|
|
|
rc = channel_close(channel);
|
|
|
|
|
log_assert("channel close function", rc, 0);
|
|
|
|
|
}
|
|
|
|
|
printf("---------------=========== Testing end ===========------------------\n");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*static*/ int test_error_codes(conn_t *co)
|
|
|
|
|
void test_message_handling(conn_t* co)
|
|
|
|
|
{
|
|
|
|
|
printf("---------------=========== Error codes ===========------------------\n");
|
|
|
|
|
chnl_t *channel = NULL;
|
|
|
|
|
// there is no such channel on the server
|
|
|
|
|
assert(channel_open(co, &channel, 777) == EINVAL);
|
|
|
|
|
int rc = 0, i = 0, a = 0, b = 0;
|
|
|
|
|
sexp_t *sx = NULL;
|
|
|
|
|
char *buf = NULL;
|
|
|
|
|
sxmsg_t *msg = NULL;
|
|
|
|
|
|
|
|
|
|
printf("---------------=========== Error codes end ===========------------------\n");
|
|
|
|
|
return 0;
|
|
|
|
|
buf = malloc(4096);
|
|
|
|
|
rc = channel_open(co, &channel, 12);
|
|
|
|
|
log_assert("channel open function", rc, 0);
|
|
|
|
|
for(i = 0; i < ITERATION_COUNT; ++i) {
|
|
|
|
|
a = rand() % 100;
|
|
|
|
|
b = rand() % 100;
|
|
|
|
|
sprintf(buf, "(ar-add (%d %d))", a, b);
|
|
|
|
|
sx = parse_sexp(buf, strlen(buf));
|
|
|
|
|
rc = msg_send(channel, sx, &msg);
|
|
|
|
|
log_assert("message send function", rc, a + b);
|
|
|
|
|
// destroy_sexp(sx);
|
|
|
|
|
}
|
|
|
|
|
rc = channel_close(channel);
|
|
|
|
|
free(buf);
|
|
|
|
|
log_assert("channel close function", rc, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
|
|
|
{
|
|
|
|
|
// set detailed signal handler
|
|
|
|
|
struct sigaction sigact;
|
|
|
|
|
sigact.sa_flags = SA_SIGINFO;
|
|
|
|
|
sigact.sa_sigaction = signal_error;
|
|
|
|
|
sigemptyset(&sigact.sa_mask);
|
|
|
|
|
sigaction(SIGFPE, &sigact, 0);
|
|
|
|
|
sigaction(SIGILL, &sigact, 0);
|
|
|
|
|
sigaction(SIGSEGV, &sigact, 0);
|
|
|
|
|
sigaction(SIGBUS, &sigact, 0);
|
|
|
|
|
|
|
|
|
|
char *rootca = NULL, *cert = NULL;
|
|
|
|
|
int port = DEFAULT_PORT;
|
|
|
|
|
char *addr = NULL, *login = NULL, *password = NULL;
|
|
|
|
|
int opt;
|
|
|
|
|
#ifndef SIMPLE_TESTING
|
|
|
|
|
int rc, i;
|
|
|
|
|
#endif
|
|
|
|
|
while((opt = getopt(argc, argv, "p:r:a:u:l:w:")) != -1) {
|
|
|
|
|
switch(opt) {
|
|
|
|
|
case 'p':
|
|
|
|
@ -192,10 +371,36 @@ int main(int argc, char **argv)
|
|
|
|
|
ctx->login = login;
|
|
|
|
|
ctx->passwd = password;
|
|
|
|
|
|
|
|
|
|
assert(connection_initiate(co, addr, port, cert, ctx) == 0);
|
|
|
|
|
assert(start_testing(co) == 0);
|
|
|
|
|
assert(test_error_codes(co) == 0);
|
|
|
|
|
assert(connection_close(co) == 0);
|
|
|
|
|
log_init("test.log");
|
|
|
|
|
|
|
|
|
|
log_begin("Connection initiate");
|
|
|
|
|
log_assert("Connection initiate", connection_initiate(co, addr, port, cert, ctx), 0);
|
|
|
|
|
log_end("Connection initiate");
|
|
|
|
|
|
|
|
|
|
#ifndef SIMPLE_TESTING
|
|
|
|
|
test_data_t data;
|
|
|
|
|
data.co = co;
|
|
|
|
|
rc = allocate_threads(CHANNEL_COUNT, &data);
|
|
|
|
|
log_assert("Thread list allocation", rc, 0);
|
|
|
|
|
|
|
|
|
|
for(i = 0; i < CHANNEL_COUNT; ++i) {
|
|
|
|
|
log_assert("Channel testing", test_channels(&data, i), 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rc = deallocate_threads(&data);
|
|
|
|
|
log_assert("Thread list deallocation", rc, 0);
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef SIMPLE_TESTING
|
|
|
|
|
//test_channel_handling(co);
|
|
|
|
|
test_message_handling(co);
|
|
|
|
|
#endif
|
|
|
|
|
printf("HERE!!!!\n");
|
|
|
|
|
log_begin("Connection close");
|
|
|
|
|
log_assert("Connection close", connection_close(co), 0);
|
|
|
|
|
log_end("Connection close");
|
|
|
|
|
|
|
|
|
|
log_close();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(rootca);
|
|
|
|
|
free(cert);
|
|
|
|
|