/* * Copyright (c) Likewise Software. All rights Reserved. * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the license, or (at * your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser * General Public License for more details. You should have received a copy * of the GNU Lesser General Public License along with this program. If * not, see . * * LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING * TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT * WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE * TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU * LESSER GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU * HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING * TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT * license@likewisesoftware.com */ /* * Module Name: * * test-assoc.c * * Abstract: * * Association unit tests * * Authors: Brian Koropoff (bkoropoff@likewisesoftware.com) * */ #include #include #include #include #include #include #include #include #include #include #include "test-private.h" typedef enum EmptyTag { EMPTY_REQUEST, EMPTY_REPLY } EmptyTag; static LWMsgProtocolSpec EmptyProtocol_spec[] = { LWMSG_MESSAGE(EMPTY_REQUEST, NULL), LWMSG_MESSAGE(EMPTY_REPLY, NULL), LWMSG_PROTOCOL_END }; static void* empty_sender(void* _assoc) { LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); request_msg.tag = EMPTY_REQUEST; request_msg.data = NULL; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message_transact(assoc, &request_msg, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, EMPTY_REPLY); MU_ASSERT_EQUAL(MU_TYPE_POINTER, reply_msg.data, NULL); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } static void* empty_receiver(void* _assoc) { LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &request_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, request_msg.tag, EMPTY_REQUEST); MU_ASSERT_EQUAL(MU_TYPE_POINTER, request_msg.data, NULL); reply_msg.tag = EMPTY_REPLY; reply_msg.data = NULL; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &reply_msg)); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } MU_TEST(assoc, empty_send_recv) { int err = 0; int sockets[2]; LWMsgAssoc* send_assoc = NULL; LWMsgAssoc* recv_assoc = NULL; pthread_t sender; pthread_t receiver; LWMsgProtocol* empty_protocol = NULL; MU_TRY(lwmsg_protocol_new(NULL, &empty_protocol)); MU_TRY_PROTOCOL(empty_protocol, lwmsg_protocol_add_protocol_spec(empty_protocol, EmptyProtocol_spec)); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { MU_FAILURE("socketpair(): %s", strerror(errno)); } MU_TRY(lwmsg_connection_new(NULL, empty_protocol, &send_assoc)); MU_TRY(lwmsg_connection_set_fd( send_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[0])); MU_TRY(lwmsg_connection_new(NULL, empty_protocol, &recv_assoc)); MU_TRY(lwmsg_connection_set_fd( recv_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[1])); if ((err = pthread_create(&sender, NULL, empty_sender, send_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_create(&receiver, NULL, empty_receiver, recv_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_join(sender, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } if ((err = pthread_join(receiver, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } } typedef struct FooRequest { int size; } FooRequest; typedef struct FooReply { int size; int numbers[]; } FooReply; typedef enum FooType { FOO_REQUEST = 1, FOO_REPLY = 2 } FooType; static LWMsgTypeSpec FooRequest_spec[] = { LWMSG_STRUCT_BEGIN(FooRequest), LWMSG_MEMBER_INT16(FooRequest, size), LWMSG_STRUCT_END, LWMSG_TYPE_END }; static LWMsgTypeSpec FooReply_spec[] = { LWMSG_STRUCT_BEGIN(FooReply), LWMSG_MEMBER_INT16(FooReply, size), LWMSG_MEMBER_ARRAY_BEGIN(FooReply, numbers), LWMSG_INT16(int), LWMSG_ARRAY_END, LWMSG_ATTR_LENGTH_MEMBER(FooReply, size), LWMSG_STRUCT_END, LWMSG_TYPE_END }; static LWMsgProtocolSpec FooProtocol_spec[] = { LWMSG_MESSAGE(FOO_REQUEST, FooRequest_spec), LWMSG_MESSAGE(FOO_REPLY, FooReply_spec), LWMSG_PROTOCOL_END }; static void* foo_sender(void* _assoc) { LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; FooRequest request; FooReply* reply; size_t i; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); request.size = 1024; request_msg.tag = FOO_REQUEST; request_msg.data = &request; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message_transact(assoc, &request_msg, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, FOO_REPLY); reply = reply_msg.data; MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply->size, request.size); for (i = 0; i < reply->size; i++) { MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply->numbers[i], i); } free(reply); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } static void* foo_receiver(void* _assoc) { LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; FooRequest* request; FooReply* reply; size_t i; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &request_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, request_msg.tag, FOO_REQUEST); request = request_msg.data; reply = malloc(sizeof(*reply) + request->size * sizeof(*reply->numbers)); reply->size = request->size; for (i = 0; i < reply->size; i++) { reply->numbers[i] = i; } reply_msg.tag = FOO_REPLY; reply_msg.data = reply; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &reply_msg)); free(request); free(reply); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } MU_TEST(assoc, foo_send_recv) { int err = 0; int sockets[2]; LWMsgAssoc* send_assoc = NULL; LWMsgAssoc* recv_assoc = NULL; pthread_t sender; pthread_t receiver; LWMsgProtocol* foo_protocol = NULL; MU_TRY(lwmsg_protocol_new(NULL, &foo_protocol)); MU_TRY_PROTOCOL(foo_protocol, lwmsg_protocol_add_protocol_spec(foo_protocol, FooProtocol_spec)); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { MU_FAILURE("socketpair(): %s", strerror(errno)); } MU_TRY(lwmsg_connection_new(NULL, foo_protocol, &send_assoc)); MU_TRY(lwmsg_connection_set_fd( send_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[0])); MU_TRY(lwmsg_connection_new(NULL, foo_protocol, &recv_assoc)); MU_TRY(lwmsg_connection_set_fd( recv_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[1])); if ((err = pthread_create(&sender, NULL, foo_sender, send_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_create(&receiver, NULL, foo_receiver, recv_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_join(sender, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } if ((err = pthread_join(receiver, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } } /* Tests that fragmentation of messages works by transmitting a message far larger than the packet size of the connection */ MU_TEST(assoc, foo_send_recv_fragment) { int err = 0; int sockets[2]; LWMsgAssoc* send_assoc = NULL; LWMsgAssoc* recv_assoc = NULL; pthread_t sender; pthread_t receiver; LWMsgProtocol* foo_protocol = NULL; MU_TRY(lwmsg_protocol_new(NULL, &foo_protocol)); MU_TRY_PROTOCOL(foo_protocol, lwmsg_protocol_add_protocol_spec(foo_protocol, FooProtocol_spec)); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { MU_FAILURE("socketpair(): %s", strerror(errno)); } MU_TRY(lwmsg_connection_new(NULL, foo_protocol, &send_assoc)); MU_TRY(lwmsg_connection_set_packet_size( send_assoc, 512)); MU_TRY(lwmsg_connection_set_fd( send_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[0])); MU_TRY(lwmsg_connection_new(NULL, foo_protocol, &recv_assoc)); MU_TRY(lwmsg_connection_set_packet_size( recv_assoc, 512)); MU_TRY(lwmsg_connection_set_fd( recv_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[1])); if ((err = pthread_create(&sender, NULL, foo_sender, send_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_create(&receiver, NULL, foo_receiver, recv_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_join(sender, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } if ((err = pthread_join(receiver, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } } MU_TEST(assoc, foo_send_timeout_connect) { int sockets[2]; LWMsgAssoc* send_assoc = NULL; static LWMsgProtocol* foo_protocol = NULL; LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgTime time = {0, 200000}; MU_TRY(lwmsg_protocol_new(NULL, &foo_protocol)); MU_TRY_PROTOCOL(foo_protocol, lwmsg_protocol_add_protocol_spec(foo_protocol, FooProtocol_spec)); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { MU_FAILURE("socketpair(): %s", strerror(errno)); } MU_TRY(lwmsg_connection_new(NULL, foo_protocol, &send_assoc)); MU_TRY(lwmsg_connection_set_fd( send_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[0])); lwmsg_assoc_set_timeout(send_assoc, LWMSG_TIMEOUT_ESTABLISH, &time); status = lwmsg_assoc_establish(send_assoc); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, status, LWMSG_STATUS_TIMEOUT); MU_TRY_ASSOC(send_assoc, lwmsg_assoc_close(send_assoc)); lwmsg_assoc_delete(send_assoc); } typedef struct AuthRequest { int fortytwo; } AuthRequest; typedef struct AuthReply { uid_t uid; gid_t gid; } AuthReply; typedef enum AuthType { AUTH_REQUEST, AUTH_REPLY } AuthType; static LWMsgTypeSpec AuthRequest_spec[] = { LWMSG_STRUCT_BEGIN(AuthRequest), LWMSG_MEMBER_UINT8(AuthRequest, fortytwo), LWMSG_STRUCT_END, LWMSG_TYPE_END }; static LWMsgTypeSpec AuthReply_spec[] = { LWMSG_STRUCT_BEGIN(AuthReply), LWMSG_MEMBER_UINT32(AuthReply, uid), LWMSG_MEMBER_UINT32(AuthReply, gid), LWMSG_STRUCT_END, LWMSG_TYPE_END }; static LWMsgProtocolSpec AuthProtocol_spec[] = { LWMSG_MESSAGE(AUTH_REQUEST, AuthRequest_spec), LWMSG_MESSAGE(AUTH_REPLY, AuthReply_spec), LWMSG_PROTOCOL_END }; static void* auth_sender(void* _assoc) { LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; AuthRequest request = {0}; AuthReply* reply = NULL; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; request.fortytwo = 42; request_msg.tag = AUTH_REQUEST; request_msg.data = &request; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message_transact(assoc, &request_msg, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, AUTH_REPLY); reply = reply_msg.data; MU_VERBOSE("uid = %u", (unsigned int) reply->uid); MU_VERBOSE("gid = %u", (unsigned int) reply->gid); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply->uid, geteuid()); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply->gid, getegid()); free(reply); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } static void* auth_receiver(void* _assoc) { LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; AuthRequest* request; AuthReply reply; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgSecurityToken* token; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &request_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, request_msg.tag, AUTH_REQUEST); request = request_msg.data; MU_ASSERT_EQUAL(MU_TYPE_INTEGER, request->fortytwo, 42); MU_TRY_ASSOC(assoc, lwmsg_assoc_get_peer_security_token(assoc, &token)); MU_ASSERT(token != NULL); MU_ASSERT_EQUAL(MU_TYPE_STRING, lwmsg_security_token_get_type(token), "local"); MU_TRY(lwmsg_local_token_get_eid(token, &reply.uid, &reply.gid)); reply_msg.tag = AUTH_REPLY; reply_msg.data = &reply; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &reply_msg)); free(request); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } MU_TEST(assoc, auth_send_recv) { int err = 0; int sockets[2]; LWMsgAssoc* send_assoc = NULL; LWMsgAssoc* recv_assoc = NULL; pthread_t sender; pthread_t receiver; LWMsgProtocol* auth_protocol = NULL; MU_TRY(lwmsg_protocol_new(NULL, &auth_protocol)); MU_TRY_PROTOCOL(auth_protocol, lwmsg_protocol_add_protocol_spec(auth_protocol, AuthProtocol_spec)); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { MU_FAILURE("socketpair(): %s", strerror(errno)); } MU_TRY(lwmsg_connection_new(NULL, auth_protocol, &send_assoc)); MU_TRY(lwmsg_connection_set_fd( send_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[0])); MU_TRY(lwmsg_connection_new(NULL, auth_protocol, &recv_assoc)); MU_TRY(lwmsg_connection_set_fd( recv_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[1])); if ((err = pthread_create(&sender, NULL, auth_sender, send_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_create(&receiver, NULL, auth_receiver, recv_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_join(sender, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } if ((err = pthread_join(receiver, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } } typedef struct Handle { char* saved_string; int saved_integer; } Handle; static LWMsgTypeSpec Handle_local_spec[] = { LWMSG_HANDLE(Handle), LWMSG_ATTR_HANDLE_LOCAL_FOR_RECEIVER, LWMSG_TYPE_END, }; static LWMsgTypeSpec Handle_remote_spec[] = { LWMSG_HANDLE(Handle), LWMSG_ATTR_HANDLE_LOCAL_FOR_SENDER, LWMSG_TYPE_END, }; typedef struct HandleCreateRequest { char* save_string; int save_integer; } HandleCreateRequest; static LWMsgTypeSpec HandleCreateRequest_spec[] = { LWMSG_STRUCT_BEGIN(HandleCreateRequest), LWMSG_MEMBER_PSTR(HandleCreateRequest, save_string), LWMSG_MEMBER_INT32(HandleCreateRequest, save_integer), LWMSG_STRUCT_END, LWMSG_TYPE_END }; typedef enum HandleGetType { HANDLE_GET_STRING = 0, HANDLE_GET_INTEGER = 1 } HandleGetType; typedef struct HandleGetRequest { Handle* handle; HandleGetType type; } HandleGetRequest; static LWMsgTypeSpec HandleGetRequest_spec[] = { LWMSG_STRUCT_BEGIN(HandleGetRequest), LWMSG_MEMBER_TYPESPEC(HandleGetRequest, handle, Handle_local_spec), LWMSG_MEMBER_UINT8(HandleGetRequest, type), LWMSG_STRUCT_END, LWMSG_TYPE_END }; typedef struct HandleGetReply { HandleGetType type; union ReplyUnion { char* string; int integer; } value; } HandleGetReply; static LWMsgTypeSpec HandleGetReply_spec[] = { LWMSG_STRUCT_BEGIN(HandleGetReply), LWMSG_MEMBER_UINT8(HandleGetReply, type), LWMSG_MEMBER_UNION_BEGIN(HandleGetReply, value), LWMSG_MEMBER_PSTR(union ReplyUnion, string), LWMSG_ATTR_TAG(HANDLE_GET_STRING), LWMSG_MEMBER_INT32(union ReplyUnion, integer), LWMSG_ATTR_TAG(HANDLE_GET_INTEGER), LWMSG_UNION_END, LWMSG_ATTR_DISCRIM(HandleGetReply, type), LWMSG_STRUCT_END, LWMSG_TYPE_END }; typedef struct HandleDestroyReply { int status; } HandleDestroyReply; static LWMsgTypeSpec HandleDestroyReply_spec[] = { LWMSG_STRUCT_BEGIN(HandleDestroyReply), LWMSG_MEMBER_UINT8(HandleDestroyReply, status), LWMSG_STRUCT_END, LWMSG_TYPE_END }; typedef enum HandleMessageType { HANDLE_CREATE_REQUEST, HANDLE_CREATE_REPLY, HANDLE_DESTROY_REQUEST, HANDLE_DESTROY_REPLY, HANDLE_GET_REQUEST, HANDLE_GET_REPLY } HandleMessageType; static LWMsgProtocolSpec HandleProtocol_spec[] = { LWMSG_MESSAGE(HANDLE_CREATE_REQUEST, HandleCreateRequest_spec), LWMSG_MESSAGE(HANDLE_CREATE_REPLY, Handle_remote_spec), LWMSG_MESSAGE(HANDLE_GET_REQUEST, HandleGetRequest_spec), LWMSG_MESSAGE(HANDLE_GET_REPLY, HandleGetReply_spec), LWMSG_MESSAGE(HANDLE_DESTROY_REQUEST, Handle_local_spec), LWMSG_MESSAGE(HANDLE_DESTROY_REPLY, HandleDestroyReply_spec), LWMSG_PROTOCOL_END }; static void* handle_sender(void* _assoc) { LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; Handle* handle = NULL; HandleCreateRequest create_request = {0}; HandleGetRequest get_request = {0}; HandleGetReply* get_reply = NULL; HandleDestroyReply* destroy_reply = NULL; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; create_request.save_string = (char*) "Hello, world!"; create_request.save_integer = 42; request_msg.tag = HANDLE_CREATE_REQUEST; request_msg.data = &create_request; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message_transact(assoc, &request_msg, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, HANDLE_CREATE_REPLY); handle = reply_msg.data; get_request.type = HANDLE_GET_STRING; get_request.handle = handle; request_msg.tag = HANDLE_GET_REQUEST; request_msg.data = &get_request; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message_transact(assoc, &request_msg, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, HANDLE_GET_REPLY); get_reply = reply_msg.data; MU_ASSERT_EQUAL(MU_TYPE_INTEGER, get_reply->type, HANDLE_GET_STRING); MU_ASSERT_EQUAL(MU_TYPE_STRING, get_reply->value.string, "Hello, world!"); free(get_reply->value.string); free(get_reply); get_request.type = HANDLE_GET_INTEGER; get_request.handle = handle; request_msg.tag = HANDLE_GET_REQUEST; request_msg.data = &get_request; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message_transact(assoc, &request_msg, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, HANDLE_GET_REPLY); get_reply = reply_msg.data; MU_ASSERT_EQUAL(MU_TYPE_INTEGER, get_reply->type, HANDLE_GET_INTEGER); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, get_reply->value.integer, 42); free(get_reply); request_msg.tag = HANDLE_DESTROY_REQUEST; request_msg.data = handle; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message_transact(assoc, &request_msg, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, HANDLE_DESTROY_REPLY); destroy_reply = reply_msg.data; MU_ASSERT_EQUAL(MU_TYPE_INTEGER, destroy_reply->status, 0); free(destroy_reply); MU_TRY_ASSOC(assoc, lwmsg_assoc_unregister_handle(assoc, handle)); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } static LWMsgStatus handle_create_srv( LWMsgAssoc* assoc, const LWMsgMessage* in, LWMsgMessage* out, void* data ) { HandleCreateRequest* request = in->data; Handle* handle = NULL; handle = malloc(sizeof(*handle)); handle->saved_string = strdup(request->save_string); handle->saved_integer = request->save_integer; MU_TRY_ASSOC(assoc, lwmsg_assoc_register_handle(assoc, "Handle", handle, free)); out->tag = HANDLE_CREATE_REPLY; out->data = handle; MU_TRY_ASSOC(assoc, lwmsg_assoc_retain_handle(assoc, handle)); return LWMSG_STATUS_SUCCESS; } static LWMsgStatus handle_destroy_srv( LWMsgAssoc* assoc, const LWMsgMessage* in, LWMsgMessage* out, void* data ) { Handle* handle = in->data; HandleDestroyReply* reply = malloc(sizeof(*reply)); reply->status = 0; out->tag = HANDLE_DESTROY_REPLY; out->data = reply; MU_TRY_ASSOC(assoc, lwmsg_assoc_unregister_handle(assoc, handle)); return LWMSG_STATUS_EOF; } static LWMsgStatus handle_get_srv( LWMsgAssoc* assoc, const LWMsgMessage* in, LWMsgMessage* out, void* data ) { HandleGetRequest* request = in->data; HandleGetReply* reply = malloc(sizeof(*reply)); reply->type = request->type; switch (request->type) { case HANDLE_GET_STRING: reply->value.string = request->handle->saved_string; break; case HANDLE_GET_INTEGER: reply->value.integer = request->handle->saved_integer; break; } out->tag = HANDLE_GET_REPLY; out->data = reply; return LWMSG_STATUS_SUCCESS; } static LWMsgDispatchSpec handle_dispatch[] = { LWMSG_DISPATCH(HANDLE_CREATE_REQUEST, handle_create_srv), LWMSG_DISPATCH(HANDLE_DESTROY_REQUEST, handle_destroy_srv), LWMSG_DISPATCH(HANDLE_GET_REQUEST, handle_get_srv), LWMSG_DISPATCH_END }; static void* handle_receiver(void* _assoc) { LWMsgStatus status = LWMSG_STATUS_SUCCESS; LWMsgAssoc* assoc = _assoc; LWMsgMessage recv_message; LWMsgMessage send_message; size_t i; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); do { MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &recv_message)); for (i = 0; handle_dispatch[i].type != LWMSG_DISPATCH_TYPE_END; i++) { if (recv_message.tag == handle_dispatch[i].tag) { break; } } status = ((LWMsgAssocDispatchFunction) handle_dispatch[i].data)( assoc, &recv_message, &send_message, NULL); MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &send_message)); if (status == LWMSG_STATUS_EOF) { break; } } while (1); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } MU_TEST(assoc, handle_store_state) { int err = 0; int sockets[2]; LWMsgAssoc* send_assoc = NULL; LWMsgAssoc* recv_assoc = NULL; pthread_t sender; pthread_t receiver; LWMsgProtocol* handle_protocol = NULL; MU_TRY(lwmsg_protocol_new(NULL, &handle_protocol)); MU_TRY_PROTOCOL(handle_protocol, lwmsg_protocol_add_protocol_spec(handle_protocol, HandleProtocol_spec)); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { MU_FAILURE("socketpair(): %s", strerror(errno)); } MU_TRY(lwmsg_connection_new(NULL, handle_protocol, &send_assoc)); MU_TRY(lwmsg_connection_set_fd( send_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[0])); MU_TRY(lwmsg_connection_new(NULL, handle_protocol, &recv_assoc)); MU_TRY(lwmsg_connection_set_fd( recv_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[1])); if ((err = pthread_create(&sender, NULL, handle_sender, send_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_create(&receiver, NULL, handle_receiver, recv_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_join(sender, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } if ((err = pthread_join(receiver, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } } typedef struct FdRequest { int readfd; } FdRequest; typedef struct FdReply { char* message; } FdReply; typedef enum FdType { FD_REQUEST = 1, FD_REPLY = 2 } FdType; static LWMsgTypeSpec FdRequest_spec[] = { LWMSG_STRUCT_BEGIN(FdRequest), LWMSG_MEMBER_FD(FdRequest, readfd), LWMSG_STRUCT_END, LWMSG_TYPE_END }; static LWMsgTypeSpec FdReply_spec[] = { LWMSG_STRUCT_BEGIN(FdReply), LWMSG_MEMBER_PSTR(FdReply, message), LWMSG_STRUCT_END, LWMSG_TYPE_END }; static LWMsgProtocolSpec FdProtocol_spec[] = { LWMSG_MESSAGE(FD_REQUEST, FdRequest_spec), LWMSG_MESSAGE(FD_REPLY, FdReply_spec), LWMSG_PROTOCOL_END }; static void* fd_sender(void* _assoc) { const char message[] = "hello"; LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; FdRequest request = {0}; FdReply* reply = NULL; int fds[2]; if (pipe(fds)) { MU_FAILURE("pipe(): %s", strerror(errno)); } request.readfd = fds[0]; if (write(fds[1], message, sizeof(message)) != sizeof(message)) { MU_FAILURE("write(): %s", strerror(errno)); } MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); request_msg.tag = FD_REQUEST; request_msg.data = &request; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message_transact(assoc, &request_msg, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, FD_REPLY); reply = reply_msg.data; MU_ASSERT_EQUAL(MU_TYPE_STRING, reply->message, message); lwmsg_assoc_destroy_message(assoc, &reply_msg); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); close(fds[1]); close(fds[0]); return NULL; } static void* fd_receiver(void* _assoc) { LWMsgAssoc* assoc = (LWMsgAssoc*) _assoc; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; FdRequest* request = NULL; FdReply reply; char buffer[1024]; MU_TRY_ASSOC(assoc, lwmsg_assoc_establish(assoc)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &request_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, request_msg.tag, FD_REQUEST); request = request_msg.data; if (read(request->readfd, buffer, sizeof(buffer)) < 0) { MU_FAILURE("read(): %s", strerror(errno)); } reply.message = buffer; reply_msg.tag = FD_REPLY; reply_msg.data = &reply; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &reply_msg)); lwmsg_assoc_destroy_message(assoc, &request_msg); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); lwmsg_assoc_delete(assoc); return NULL; } MU_TEST(assoc, fd_send_recv) { int err = 0; int sockets[2]; LWMsgAssoc* send_assoc = NULL; LWMsgAssoc* recv_assoc = NULL; pthread_t sender; pthread_t receiver; LWMsgProtocol* fd_protocol = NULL; MU_TRY(lwmsg_protocol_new(NULL, &fd_protocol)); MU_TRY_PROTOCOL(fd_protocol, lwmsg_protocol_add_protocol_spec(fd_protocol, FdProtocol_spec)); if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)) { MU_FAILURE("socketpair(): %s", strerror(errno)); } MU_TRY(lwmsg_connection_new(NULL, fd_protocol, &send_assoc)); MU_TRY(lwmsg_connection_set_fd( send_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[0])); MU_TRY(lwmsg_connection_new(NULL, fd_protocol, &recv_assoc)); MU_TRY(lwmsg_connection_set_fd( recv_assoc, LWMSG_CONNECTION_MODE_PAIR, sockets[1])); if ((err = pthread_create(&sender, NULL, fd_sender, send_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_create(&receiver, NULL, fd_receiver, recv_assoc))) { MU_FAILURE("pthread_create(): %s", strerror(err)); } if ((err = pthread_join(sender, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } if ((err = pthread_join(receiver, NULL))) { MU_FAILURE("pthread_join(): %s", strerror(err)); } } static LWMsgTypeSpec local_handle_spec[] = { LWMSG_HANDLE(AHandle), LWMSG_ATTR_HANDLE_LOCAL_FOR_RECEIVER, LWMSG_TYPE_END }; static LWMsgTypeSpec remote_handle_spec[] = { LWMSG_HANDLE(AHandle), LWMSG_ATTR_HANDLE_LOCAL_FOR_SENDER, LWMSG_TYPE_END }; enum { TRIVIAL_LOCAL, TRIVIAL_REMOTE, }; static LWMsgProtocolSpec trivial_handle_spec[] = { LWMSG_MESSAGE(TRIVIAL_LOCAL, local_handle_spec), LWMSG_MESSAGE(TRIVIAL_REMOTE, remote_handle_spec), LWMSG_PROTOCOL_END }; static void send_local_recv_back_success(LWMsgAssoc* assoc) { int dummy; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; request_msg.tag = TRIVIAL_REMOTE; request_msg.data = &dummy; /* The handle is being created by us, so it is REMOTE for the receiver */ MU_TRY_ASSOC(assoc, lwmsg_assoc_register_handle(assoc, "AHandle", &dummy, NULL)); MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &request_msg)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &reply_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.tag, TRIVIAL_LOCAL); MU_ASSERT_EQUAL(MU_TYPE_POINTER, reply_msg.data, &dummy); } static void recv_remote_send_back_success(LWMsgAssoc* assoc) { LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &request_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, request_msg.tag, TRIVIAL_REMOTE); reply_msg.tag = TRIVIAL_LOCAL; reply_msg.data = request_msg.data; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &reply_msg)); } static void send_local_recv_back_failure(LWMsgAssoc* assoc) { int dummy = 0; int* dummy2 = NULL; LWMsgTag tag = 0; LWMsgStatus status = LWMSG_STATUS_SUCCESS; /* The handle is being created by us, so it is REMOTE for the recvr */ MU_TRY_ASSOC(assoc, lwmsg_assoc_register_handle(assoc, "AHandle", &dummy, NULL)); MU_TRY_ASSOC(assoc, lwmsg_assoc_send(assoc, TRIVIAL_REMOTE, &dummy)); /* The peer is going to bomb out on us, so expect a disconnect */ status = lwmsg_assoc_recv(assoc, &tag, (void**) (void*) &dummy2); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, status, LWMSG_STATUS_PEER_CLOSE); } static void recv_remote_send_back_failure(LWMsgAssoc* assoc) { int* dummy = NULL; int dummy2 = 0; LWMsgTag tag = 0; LWMsgStatus status = LWMSG_STATUS_SUCCESS; MU_TRY_ASSOC(assoc, lwmsg_assoc_recv(assoc, &tag, (void**) (void*) &dummy)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, tag, TRIVIAL_REMOTE); /* Send back a local handle instead of what it expects */ MU_TRY_ASSOC(assoc, lwmsg_assoc_register_handle(assoc, "AHandle", &dummy2, NULL)); status = lwmsg_assoc_send(assoc, TRIVIAL_LOCAL, &dummy2); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, status, LWMSG_STATUS_INVALID_HANDLE); MU_VERBOSE("%s", lwmsg_assoc_get_error_message(assoc, status)); MU_TRY_ASSOC(assoc, lwmsg_assoc_close(assoc)); } static void send_null_recv_null_success(LWMsgAssoc* assoc) { int* dummy2 = NULL; LWMsgTag tag = 0; MU_TRY_ASSOC(assoc, lwmsg_assoc_send(assoc, TRIVIAL_REMOTE, NULL)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv(assoc, &tag, (void**) (void*) &dummy2)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, tag, TRIVIAL_LOCAL); MU_ASSERT_EQUAL(MU_TYPE_POINTER, dummy2, NULL); } static void recv_null_send_null_success(LWMsgAssoc* assoc) { int* dummy = NULL; LWMsgTag tag = 0; MU_TRY_ASSOC(assoc, lwmsg_assoc_recv(assoc, &tag, (void**) (void*) &dummy)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, tag, TRIVIAL_REMOTE); MU_ASSERT_EQUAL(MU_TYPE_POINTER, dummy, NULL); MU_TRY_ASSOC(assoc, lwmsg_assoc_send(assoc, TRIVIAL_LOCAL, dummy)); } static void send_local_recv_back_send_back_success(LWMsgAssoc* assoc) { int dummy = 0; int* dummy2 = NULL; LWMsgTag tag = 0; /* The handle is being created by us, so it is REMOTE for the receiver */ MU_TRY_ASSOC(assoc, lwmsg_assoc_register_handle(assoc, "AHandle", &dummy, NULL)); MU_TRY_ASSOC(assoc, lwmsg_assoc_send(assoc, TRIVIAL_REMOTE, &dummy)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv(assoc, &tag, (void**) (void*) &dummy2)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, tag, TRIVIAL_LOCAL); MU_ASSERT_EQUAL(MU_TYPE_POINTER, dummy2, &dummy); MU_TRY_ASSOC(assoc, lwmsg_assoc_send(assoc, TRIVIAL_REMOTE, dummy2)); } static void recv_remote_send_back_recv_back_success(LWMsgAssoc* assoc) { int* dummy = 0; int* dummy2 = NULL; LWMsgTag tag = 0; MU_TRY_ASSOC(assoc, lwmsg_assoc_recv(assoc, &tag, (void**) (void*) &dummy)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, tag, TRIVIAL_REMOTE); MU_TRY_ASSOC(assoc, lwmsg_assoc_send(assoc, TRIVIAL_LOCAL, dummy)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv(assoc, &tag, (void**) (void*) &dummy2)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, tag, TRIVIAL_REMOTE); MU_ASSERT_EQUAL(MU_TYPE_POINTER, dummy, dummy2); } static void recv_remote_send_back_remote_recv_failure(LWMsgAssoc* assoc) { LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &request_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, request_msg.tag, TRIVIAL_REMOTE); reply_msg.tag = TRIVIAL_LOCAL; reply_msg.data = request_msg.data; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &reply_msg)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &reply_msg)); MU_ASSERT(reply_msg.flags & LWMSG_MESSAGE_FLAG_REPLY); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.status, LWMSG_STATUS_INVALID_HANDLE); } static void send_local_recv_back_local_send_failure(LWMsgAssoc* assoc) { int dummy; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; request_msg.tag = TRIVIAL_REMOTE; request_msg.data = &dummy; /* The handle is being created by us, so it is REMOTE for the receiver */ MU_TRY_ASSOC(assoc, lwmsg_assoc_register_handle(assoc, "AHandle", &dummy, NULL)); MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &request_msg)); /* Before receiving it back, we sabotage things by unregistering the handle */ MU_TRY_ASSOC(assoc, lwmsg_assoc_unregister_handle(assoc, &dummy)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &reply_msg)); MU_ASSERT(reply_msg.flags & LWMSG_MESSAGE_FLAG_SYNTHETIC); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.status, LWMSG_STATUS_INVALID_HANDLE); reply_msg.flags = LWMSG_MESSAGE_FLAG_REPLY; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &reply_msg)); } static void recv_remote_send_back_bogus(LWMsgAssoc* assoc) { LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &request_msg)); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, request_msg.tag, TRIVIAL_REMOTE); reply_msg.tag = -42; reply_msg.data = request_msg.data; MU_ASSERT_EQUAL(MU_TYPE_INTEGER, lwmsg_assoc_send_message(assoc, &reply_msg), LWMSG_STATUS_MALFORMED); reply_msg.flags = LWMSG_MESSAGE_FLAG_REPLY | LWMSG_MESSAGE_FLAG_SYNTHETIC; reply_msg.status = LWMSG_STATUS_MALFORMED; reply_msg.tag = LWMSG_TAG_INVALID; reply_msg.data = NULL; MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &reply_msg)); } static void send_local_recv_back_bogus(LWMsgAssoc* assoc) { int dummy; LWMsgMessage request_msg = LWMSG_MESSAGE_INITIALIZER; LWMsgMessage reply_msg = LWMSG_MESSAGE_INITIALIZER; request_msg.tag = TRIVIAL_REMOTE; request_msg.data = &dummy; /* The handle is being created by us, so it is REMOTE for the receiver */ MU_TRY_ASSOC(assoc, lwmsg_assoc_register_handle(assoc, "AHandle", &dummy, NULL)); MU_TRY_ASSOC(assoc, lwmsg_assoc_send_message(assoc, &request_msg)); MU_TRY_ASSOC(assoc, lwmsg_assoc_recv_message(assoc, &reply_msg)); MU_ASSERT(reply_msg.flags & LWMSG_MESSAGE_FLAG_SYNTHETIC); MU_ASSERT_EQUAL(MU_TYPE_INTEGER, reply_msg.status, LWMSG_STATUS_MALFORMED); } MU_TEST(assoc, handle_enforce_locality_success) { lwmsg_test_assoc_pair( trivial_handle_spec, send_local_recv_back_success, recv_remote_send_back_success ); } MU_TEST(assoc, handle_enforce_locality_failure) { lwmsg_test_assoc_pair( trivial_handle_spec, send_local_recv_back_failure, recv_remote_send_back_failure ); } MU_TEST(assoc, handle_ping_pong) { lwmsg_test_assoc_pair( trivial_handle_spec, send_local_recv_back_send_back_success, recv_remote_send_back_recv_back_success ); } MU_TEST(assoc, handle_null_success) { lwmsg_test_assoc_pair( trivial_handle_spec, send_null_recv_null_success, recv_null_send_null_success ); } MU_TEST(assoc, handle_error_synthetic_message) { lwmsg_test_assoc_pair( trivial_handle_spec, recv_remote_send_back_remote_recv_failure, send_local_recv_back_local_send_failure ); } MU_TEST(assoc, malformed_synthetic_message) { lwmsg_test_assoc_pair( trivial_handle_spec, recv_remote_send_back_bogus, send_local_recv_back_bogus ); }