/* The big picture: * For every outgoing request, we have to have the network-ready data * somewhere in memory. * * Using writev, any pieces that do not need endian conversion can * be written in-place. * * The pieces that do need endian conversion can be put into one or more * buffers. * * WHOA WHOA newsflash * Because IIOP lets the message sender specify the endianness, * we do not need to do endian conversion _ever_! The receiver can do all * conversions if need be, or if they are the same endianness as sender they * can just pull it in right off the wire :) * */ #include "config.h" #include "iiop-endianP.h" #include #include #include #include #ifdef HAVE_POLL # include #else # include # include #endif #include "IIOP.h" #include "IIOP-private.h" #ifdef HAVE_LIMITED_WRITEV #define writev g_writev #endif /* type defs */ #ifdef __GNUC__ #define PACKED __attribute__((packed)) #else #define PACKED #endif /* * Overlaps with struct _GIOPMessageHeader on purpose * - we save time because this stuff never changes */ struct _GIOPMessageHeaderConstants { GIOP_char magic[4]; GIOP_char GIOP_version[2]; GIOP_octet flags; } PACKED; /* functions */ static gint giop_recv_decode_message(GIOPRecvBuffer *buf); static gboolean num_on_list(GIOP_unsigned_long num, const GIOP_unsigned_long *request_ids, GIOP_unsigned_long req_count); static gint giop_recv_reply_decode_message(GIOPRecvBuffer *buf); static gint giop_recv_request_decode_message(GIOPRecvBuffer *buf); static gint giop_recv_locate_reply_decode_message(GIOPRecvBuffer *buf); static gint giop_recv_locate_request_decode_message(GIOPRecvBuffer *buf); static GIOPRecvBuffer *giop_received_list_check_reply(GIOP_unsigned_long request_id); #ifdef NOT_REENTRANT extern DEFINE_LOCK(iiop_connection_list); #endif GList *iiop_connection_list = NULL; /* global variables */ char giop_scratch_space[2048]; static const struct _GIOPMessageHeaderConstants giop_message_header_constants = { "GIOP", {1,0}, FLAG_ENDIANNESS, }; struct iovec giop_first_message_vec = {NULL, sizeof(struct _GIOPMessageHeaderConstants)}; DEFINE_LOCK(sendbufferlist); GSList *sendbufferlist = NULL; DEFINE_LOCK(recvbufferlist); GSList *recvbufferlist = NULL; DEFINE_LOCK(incoming_bufs); GList *incoming_bufs = NULL; /* List of incoming messages that had to be shunted aside */ DEFINE_LOCK(sendbuffers); DEFINE_LOCK(recvbuffers); GMemChunk *sendbuffers = NULL, *recvbuffers = NULL; DEFINE_LOCK(request_id_counter); GIOP_unsigned_long request_id_counter; inline void giop_message_buffer_append_iovec(GIOPMessageBuffer *msgbuf, const struct iovec *iovec) { /* g_print("Appending iovec %d bytes @ %p\n", iovec->iov_len, iovec->iov_base); */ g_array_append_val(msgbuf->iovecs, *iovec); } void giop_message_buffer_init(void) { giop_first_message_vec.iov_base = (gpointer)&giop_message_header_constants; INIT_LOCK(sendbufferlist); INIT_LOCK(recvbufferlist); request_id_counter = 1; INIT_LOCK(request_id_counter); INIT_LOCK(sendbuffers); sendbuffers = g_mem_chunk_create(GIOPSendBuffer, 2, G_ALLOC_ONLY); INIT_LOCK(recvbuffers); recvbuffers = g_mem_chunk_create(GIOPRecvBuffer, 2, G_ALLOC_ONLY); } static void giop_message_buffer_new(GIOPMessageBuffer *buf) { buf->iovecs = g_array_new(FALSE, FALSE, sizeof(struct iovec)); } #define STRUCT_OFFSET(t, f) ((int) ((char*) &((t*) 0)->f)) /* Send buffers only */ static GIOPSendBuffer * giop_send_buffer_new(void) { GIOPSendBuffer *msgbuf; struct iovec firstvec; GET_LOCK(sendbuffers); msgbuf = g_chunk_new(GIOPSendBuffer, sendbuffers); RELEASE_LOCK(sendbuffers); giop_message_buffer_new(GIOP_MESSAGE_BUFFER(msgbuf)); giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(msgbuf), &giop_first_message_vec); firstvec.iov_base = &(GIOP_MESSAGE_BUFFER(msgbuf)->message_header.message_type); firstvec.iov_len = sizeof(GIOPMessageHeader) - STRUCT_OFFSET(GIOPMessageHeader, message_type); GIOP_MESSAGE_BUFFER(msgbuf)->message_header.message_size = 0; msgbuf->indirects = g_mem_chunk_create(char[GIOP_INDIRECT_CHUNK_SIZE], 2, G_ALLOC_ONLY); giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(msgbuf), &firstvec); return msgbuf; } void giop_send_buffer_write(GIOPSendBuffer *send_buffer) { gulong nvecs; glong res, i, sum, t; struct iovec *curvec; int fd; GIOPConnection *cnx; cnx = GIOP_MESSAGE_BUFFER(send_buffer)->connection; g_return_if_fail(cnx->is_valid); fd = GIOP_CONNECTION_GET_FD(cnx); nvecs = GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->len; curvec = (struct iovec *)GIOP_MESSAGE_BUFFER(send_buffer)->iovecs->data; res = writev(fd, curvec, nvecs); for(sum = res; sum < (GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size + sizeof(GIOPMessageHeader)); ) { if(res < 0) { giop_main_handle_connection_exception(cnx); return; } for(i = t = 0; t < sum; i++) t += curvec[i].iov_len; curvec = &curvec[i-1]; ((char *)curvec->iov_base) += t - sum; curvec->iov_len -= t - sum; nvecs -= i - 1; res = writev(fd, curvec, nvecs); } } static GIOPSendBuffer * giop_send_buffer_use(GIOPConnection *connection) { GIOPSendBuffer *retval; g_return_val_if_fail(connection->is_valid, NULL); GET_LOCK(sendbufferlist); if(sendbufferlist) { GSList *head; retval = sendbufferlist->data; head = sendbufferlist; sendbufferlist = g_slist_remove_link(sendbufferlist, sendbufferlist); g_slist_free_1 (head); g_array_set_size(GIOP_MESSAGE_BUFFER(retval)->iovecs, 2); GIOP_MESSAGE_BUFFER(retval)->message_header.message_size = 0; } else retval = giop_send_buffer_new(); RELEASE_LOCK(sendbufferlist); giop_connection_ref(connection); GIOP_MESSAGE_BUFFER(retval)->connection = connection; g_mem_chunk_reset(retval->indirects); retval->indirect = g_chunk_new(gpointer, retval->indirects); #ifdef DEBUG memset(retval->indirect, '\xFE', GIOP_INDIRECT_CHUNK_SIZE); #endif retval->indirect_used = 0; return retval; } GIOPSendBuffer * giop_send_reply_buffer_use(GIOPConnection *connection, const IOP_ServiceContextList *service_context, GIOP_unsigned_long request_id, GIOPReplyStatusType reply_status) { GIOPSendBuffer *send_buffer; send_buffer = giop_send_buffer_use(connection); GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_REPLY; ENCODER_CALL(IOP_ServiceContextList, service_context); APIA(&request_id, sizeof(request_id)); APIA(&reply_status, sizeof(reply_status)); return send_buffer; } GIOPSendBuffer * giop_send_locate_reply_buffer_use(GIOPConnection *connection, GIOP_unsigned_long request_id, GIOPLocateStatusType locate_reply_status) { GIOPSendBuffer *send_buffer; send_buffer = giop_send_buffer_use(connection); GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_LOCATEREPLY; APIA(&request_id, sizeof(request_id)); APIA(&locate_reply_status, sizeof(locate_reply_status)); return send_buffer; } GIOPSendBuffer * giop_send_request_buffer_use(GIOPConnection *connection, const IOP_ServiceContextList *service_context, GIOP_unsigned_long request_id, GIOP_boolean response_expected, const struct iovec *object_key_vec, const struct iovec *operation_vec, const struct iovec *principal_vec) { GIOPSendBuffer *send_buffer; #if 0 static const struct { CORBA_unsigned_long _length; char _buffer[7]; } default_principal = { sizeof("nobody"), "nobody" }; static const struct iovec default_principal_vec = {(void *)&default_principal, sizeof(CORBA_unsigned_long) + sizeof("nobody")}; #endif if (!connection) return NULL; g_return_val_if_fail(object_key_vec, NULL); g_return_val_if_fail(operation_vec, NULL); ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "Sending request %s id %d to %s\n", operation_vec->iov_base + 4, request_id, object_key_vec->iov_base + 4); send_buffer = giop_send_buffer_use(connection); GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_REQUEST; ENCODER_CALL(IOP_ServiceContextList, service_context); APIA(&request_id, sizeof(request_id)); response_expected = response_expected?1:0; API(&response_expected, 1); AP((gpointer)giop_scratch_space, 3); giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), sizeof(CORBA_unsigned_long)); giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer), object_key_vec); GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size += object_key_vec->iov_len; /* * We can know the length at compile time - don't calculate it at runtime * if we can help it :) */ /* ENCODER_CALL(CORBA_string, (CORBA_string *)operation); */ giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), sizeof(CORBA_unsigned_long)); giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer), operation_vec); GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size += operation_vec->iov_len; giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), sizeof(CORBA_unsigned_long)); giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer), principal_vec); GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size += principal_vec->iov_len; return send_buffer; } GIOPSendBuffer * giop_send_locate_request_buffer_use(GIOPConnection *connection, GIOP_unsigned_long request_id, const struct iovec *object_key_vec) { GIOPSendBuffer *send_buffer; if (!connection) return NULL; g_return_val_if_fail(object_key_vec, NULL); ORBit_Trace(TraceMod_IIOP, TraceLevel_Debug, "Sending locate request id %d to %s\n", request_id, object_key_vec->iov_base + 4); send_buffer = giop_send_buffer_use(connection); GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_type = GIOP_LOCATEREQUEST; APIA(&request_id, sizeof(request_id)); giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), sizeof(CORBA_unsigned_long)); giop_message_buffer_append_iovec(GIOP_MESSAGE_BUFFER(send_buffer), object_key_vec); GIOP_MESSAGE_BUFFER(send_buffer)->message_header.message_size += object_key_vec->iov_len; return send_buffer; } void giop_send_buffer_unuse(GIOPSendBuffer *send_buffer) { g_return_if_fail(send_buffer != NULL); giop_connection_unref(GIOP_MESSAGE_BUFFER(send_buffer)->connection); GET_LOCK(sendbufferlist); sendbufferlist = g_slist_prepend(sendbufferlist, send_buffer); RELEASE_LOCK(sendbufferlist); } gulong giop_message_buffer_do_alignment(GIOPMessageBuffer *buffer, gulong align_for) { struct iovec newvec; struct iovec *lastvec; guint alignme; if(align_for < 2) return 0; if(align_for > MAX(sizeof(GIOP_long_long),sizeof(GIOP_long_double))) align_for = MAX(sizeof(GIOP_long_long), sizeof(GIOP_long_double)); alignme = (gulong)ALIGN_ADDRESS(buffer->message_header.message_size, align_for); if((alignme - buffer->message_header.message_size) > 0) { lastvec = (struct iovec *)(buffer->iovecs->data) + buffer->iovecs->len - 1; if(lastvec->iov_base == giop_scratch_space) { newvec.iov_len = alignme - buffer->message_header.message_size; lastvec->iov_len += newvec.iov_len; buffer->message_header.message_size = alignme; } else { newvec.iov_base = (gpointer)giop_scratch_space; newvec.iov_len = alignme - buffer->message_header.message_size; giop_message_buffer_append_iovec(buffer, &newvec); buffer->message_header.message_size += newvec.iov_len; } return newvec.iov_len; } else return 0; } void giop_message_buffer_append_mem_a(GIOPMessageBuffer *buffer, gconstpointer mem_region, gulong mem_region_length) { struct iovec newvec; struct iovec *lastvec; gint alignfor; alignfor = giop_message_buffer_do_alignment(buffer, mem_region_length); lastvec = (struct iovec *)(buffer->iovecs->data) + + buffer->iovecs->len - 1; if((mem_region == giop_scratch_space && lastvec->iov_base == giop_scratch_space) || (alignfor == 0 && (lastvec->iov_base + lastvec->iov_len) == mem_region)) { lastvec->iov_len += mem_region_length; } else { newvec.iov_base = (gpointer)mem_region; newvec.iov_len = mem_region_length; giop_message_buffer_append_iovec(buffer, &newvec); } buffer->message_header.message_size += mem_region_length; } void giop_message_buffer_append_mem(GIOPMessageBuffer *buffer, gconstpointer mem_region, gulong mem_region_length) { struct iovec newvec; struct iovec *lastvec; lastvec = (struct iovec *)(buffer->iovecs->data) + buffer->iovecs->len - 1; if((mem_region == giop_scratch_space && lastvec->iov_base == giop_scratch_space) || ((lastvec->iov_base + lastvec->iov_len) == mem_region)) { lastvec->iov_len += mem_region_length; } else { newvec.iov_base = (gpointer)mem_region; newvec.iov_len = mem_region_length; giop_message_buffer_append_iovec(buffer, &newvec); } buffer->message_header.message_size += mem_region_length; } /* I think we need a WE_WANT_NEW_CRAPPY_BUGGY_CODE ifdef here - this tiny routine seems to be horribly hard to get right. Basically we have to paste the whole of 'mem_region' into our memory chunks, possibly subdividing it up to fit it into multiple 1K chunks. Because we have to return the first paste point in case the client wants to manipulate it afterwards, if mem_region_length >= sizeof(CORBA_unsigned_long), we also have to guarantee that the pasted stuff doesn't get divided on a finer boundary than sizeof(CORBA_unsigned_long). */ gpointer giop_send_buffer_append_mem_indirect(GIOPSendBuffer *send_buffer, gconstpointer mem_region, gulong mem_region_length) { gulong offset = 0, thisblock_size; gpointer blockstart = NULL; while(offset < mem_region_length) { thisblock_size = MIN(mem_region_length - offset, GIOP_INDIRECT_CHUNK_SIZE - send_buffer->indirect_used); if((thisblock_size >= sizeof(CORBA_unsigned_long)) || (mem_region_length - offset) < sizeof(CORBA_unsigned_long)) { if (!blockstart) (guchar*)blockstart = ((guchar*) send_buffer->indirect) + send_buffer->indirect_used; memcpy((guchar*)send_buffer->indirect + send_buffer->indirect_used, (guchar*)mem_region + offset, thisblock_size); giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), (guchar*)send_buffer->indirect + send_buffer->indirect_used, thisblock_size); offset += thisblock_size; send_buffer->indirect_used += thisblock_size; } if(send_buffer->indirect_used >= (GIOP_INDIRECT_CHUNK_SIZE - sizeof(CORBA_unsigned_long))) { #ifdef I_CANT_FIGURE_OUT_WHAT_THIS_LOGIC_WAS_MEANT_TO_DO || (thisblock_size >= sizeof(CORBA_unsigned_long) && (mem_region_length - offset) > 0)) { #endif send_buffer->indirect_used = 0; send_buffer->indirect = g_chunk_new(gpointer, send_buffer->indirects); } } return blockstart; } #ifdef WE_WANT_OLD_DEAD_CRAPPY_BUGGY_CODE gpointer _giop_send_buffer_append_mem_indirect(GIOPSendBuffer *send_buffer, gconstpointer mem_region, gulong mem_region_length) { gpointer blockstart = NULL; gulong offset, new_offset; for(offset = new_offset = 0; new_offset < mem_region_length;) { new_offset = MIN(mem_region_length - offset, GIOP_INDIRECT_CHUNK_SIZE - send_buffer->indirect_used); if((new_offset - offset) > sizeof(CORBA_unsigned_long) || mem_region_length >= sizeof(CORBA_unsigned_long)) { if(!blockstart) blockstart = send_buffer->indirect + send_buffer->indirect_used; } memcpy(send_buffer->indirect + send_buffer->indirect_used, mem_region + offset, new_offset - offset); giop_message_buffer_append_mem(GIOP_MESSAGE_BUFFER(send_buffer), send_buffer->indirect + send_buffer->indirect_used, new_offset - offset); send_buffer->indirect_used += new_offset - offset; offset = new_offset; if(new_offset >= GIOP_INDIRECT_CHUNK_SIZE) { send_buffer->indirect_used = 0; send_buffer->indirect = g_chunk_new(gpointer, send_buffer->indirects); #ifdef DEBUG memset(send_buffer->indirect, '\xFE', GIOP_INDIRECT_CHUNK_SIZE); #endif } } return blockstart; } #endif gpointer giop_send_buffer_append_mem_indirect_a(GIOPSendBuffer *send_buffer, gconstpointer mem_region, gulong mem_region_length) { giop_message_buffer_do_alignment(GIOP_MESSAGE_BUFFER(send_buffer), mem_region_length); return giop_send_buffer_append_mem_indirect(send_buffer, mem_region, mem_region_length); } GIOP_unsigned_long giop_get_request_id(void) { GIOP_unsigned_long retval; GET_LOCK(request_id_counter); retval = request_id_counter++; RELEASE_LOCK(request_id_counter); return retval; } /**************************************************** * GIOPRecvBuffer routines ****************************************************/ static GIOPRecvBuffer * giop_recv_buffer_new(void) { GIOPRecvBuffer *msgbuf; GET_LOCK(recvbuffers); msgbuf = g_chunk_new(GIOPRecvBuffer, recvbuffers); RELEASE_LOCK(recvbuffers); giop_message_buffer_new(GIOP_MESSAGE_BUFFER(msgbuf)); msgbuf->message_body = NULL; return msgbuf; } void giop_recv_buffer_unuse(GIOPRecvBuffer *buffer) { g_return_if_fail(buffer != NULL); g_free(buffer->message_body); if(GIOP_MESSAGE_BUFFER(buffer)->connection->incoming_msg == buffer) GIOP_MESSAGE_BUFFER(buffer)->connection->incoming_msg = NULL; giop_connection_unref(GIOP_MESSAGE_BUFFER(buffer)->connection); GET_LOCK(recvbufferlist); recvbufferlist = g_slist_prepend(recvbufferlist, buffer); RELEASE_LOCK(recvbufferlist); } static GIOPRecvBuffer * giop_recv_buffer_use(GIOPConnection *connection) { GIOPRecvBuffer *retval; g_return_val_if_fail(connection->is_valid, NULL); GET_LOCK(recvbufferlist); if(recvbufferlist) { GSList *head; retval = recvbufferlist->data; head = recvbufferlist; recvbufferlist = g_slist_remove_link(recvbufferlist, recvbufferlist); g_slist_free_1 (head); GIOP_MESSAGE_BUFFER(retval)->message_header.message_size = 0; retval->message_body = NULL; } else retval = giop_recv_buffer_new(); retval->state = GIOP_MSG_READING_HEADER; retval->left_to_read = sizeof(GIOPMessageHeader); RELEASE_LOCK(recvbufferlist); giop_connection_ref(connection); GIOP_MESSAGE_BUFFER(retval)->connection = connection; return retval; } GIOPRecvBuffer * giop_recv_message_buffer_use(GIOPConnection *connection) { GIOPRecvBuffer *retval; char *bptr; int sysret; guint message_size; if (!connection) return NULL; g_return_val_if_fail(connection->is_valid, NULL); if(connection->incoming_msg) retval = connection->incoming_msg; else { retval = giop_recv_buffer_use(connection); connection->incoming_msg = retval; } if(!retval) return NULL; do { switch(retval->state) { case GIOP_MSG_READING_HEADER: bptr = ((char *)&(GIOP_MESSAGE_BUFFER(retval)->message_header)); bptr += sizeof(GIOP_MESSAGE_BUFFER(retval)->message_header) - retval->left_to_read; break; case GIOP_MSG_READING_BODY: bptr = retval->message_body; bptr += GIOP_MESSAGE_BUFFER(retval)->message_header.message_size; bptr -= retval->left_to_read; break; default: bptr = NULL; } sysret = read(GIOP_CONNECTION_GET_FD(connection), bptr, retval->left_to_read); if((sysret == 0) || ((sysret < 0) && (errno != EAGAIN))) goto errout; if(sysret > 0) retval->left_to_read -= sysret; if(retval->left_to_read == 0) { /* we change states here */ switch(retval->state) { case GIOP_MSG_READING_HEADER: /* Check the magic stuff */ if(strncmp(GIOP_MESSAGE_BUFFER(retval)->message_header.magic, "GIOP", 4) || GIOP_MESSAGE_BUFFER(retval)->message_header.GIOP_version[0] != 1) goto errout; if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_size == 0 && GIOP_MESSAGE_BUFFER(retval)->message_header.message_type != GIOP_CLOSECONNECTION) { g_warning("Unexpected 0-length IIOP message"); goto errout; } if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(retval))) { CORBA_unsigned_long t = GIOP_MESSAGE_BUFFER(retval)->message_header.message_size; retval->decoder = (gpointer)iiop_byteswap; iiop_byteswap((gpointer)&GIOP_MESSAGE_BUFFER(retval)->message_header.message_size, (gpointer)&t, sizeof(t)); } else { retval->decoder = (gpointer)memcpy; } message_size = GIOP_MESSAGE_BUFFER(retval)->message_header.message_size; if(!connection->is_auth && message_size > 131072) { g_warning("message size is bigger than 128k (%d)", message_size); goto errout; } retval->message_body = g_malloc(message_size); retval->state = GIOP_MSG_READING_BODY; retval->left_to_read = message_size; break; case GIOP_MSG_READING_BODY: retval->cur = retval->message_body; if(giop_recv_decode_message(retval)) goto errout; connection->incoming_msg = NULL; retval->state = GIOP_MSG_READY; break; default: break; } } else if(retval->left_to_read < 0) { g_warning("Whoa, we overstepped the number of bytes we were supposed to read by %d", -retval->left_to_read); goto errout; } else /* retval->left_to_read > 0 */ { /* couldn't read the whole piece, save it */ retval = NULL; } } while(retval && retval->state != GIOP_MSG_READY); return retval; errout: giop_recv_buffer_unuse(retval); giop_main_handle_connection_exception(connection); return NULL; } void giop_received_list_push(GIOPRecvBuffer *recv_buffer) { GET_LOCK(incoming_bufs); incoming_bufs = g_list_prepend(incoming_bufs, recv_buffer); RELEASE_LOCK(incoming_bufs); } GIOPRecvBuffer *giop_received_list_pop(void) { GList *head; GIOPRecvBuffer *retval; GET_LOCK(incoming_bufs); head = incoming_bufs; if(!head) return NULL; retval = head->data; incoming_bufs = g_list_remove_link(incoming_bufs, head); g_list_free_1 (head); RELEASE_LOCK(incoming_bufs); return retval; } static GIOPRecvBuffer * giop_received_list_check_reply(GIOP_unsigned_long request_id) { GIOPRecvBuffer *retval = NULL; GList *item = NULL; GET_LOCK(incoming_bufs); for(item = incoming_bufs; item; item = g_list_next(item)) { if(GIOP_MESSAGE_BUFFER(item->data)->message_header.message_type == GIOP_REPLY && GIOP_RECV_BUFFER(item->data)->message.u.reply.request_id == request_id) { retval = item->data; break; } } if(retval) incoming_bufs = g_list_remove(incoming_bufs, retval); RELEASE_LOCK(incoming_bufs); return retval; } /** giop_recv_reply_buffer_use_multiple */ GIOPRecvBuffer * giop_recv_reply_buffer_use_multiple(GArray *request_ids, gboolean block_for_reply) { return giop_recv_reply_buffer_use_multiple_2(NULL, request_ids, block_for_reply); } /* here is how it will be: one routine for getting next message with a specified reply ID. */ GIOPRecvBuffer * giop_recv_reply_buffer_use_multiple_2(GIOPConnection *request_cnx, GArray *request_ids, gboolean block_for_reply) { int i; GIOPRecvBuffer *retval = NULL; GSList *pushme = NULL; do { /* * We _do_ want to put this inside the loop, * because we may call ourselves recursively for different request_id's */ for(i = 0; i < request_ids->len && !retval; i++) retval = giop_received_list_check_reply(g_array_index(request_ids, GIOP_unsigned_long, i)); if(retval) break; retval = giop_main_next_message_2(TRUE, request_cnx); if(retval) { if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_type == GIOP_REPLY) { if(num_on_list(retval->message.u.reply.request_id, (GIOP_unsigned_long *)request_ids->data, request_ids->len)) break; else { pushme = g_slist_prepend(pushme, retval); retval = NULL; } } else { if(IIOPIncomingMessageHandler) IIOPIncomingMessageHandler(retval); else { pushme = g_slist_prepend(pushme, retval); retval = NULL; } retval = NULL; } } else return NULL; } while(!retval && block_for_reply); g_slist_foreach(pushme, (GFunc)giop_received_list_push, NULL); g_slist_free(pushme); return retval; } GIOPRecvBuffer * giop_recv_reply_buffer_use(GIOP_unsigned_long request_id, gboolean block_for_reply) { return giop_recv_reply_buffer_use_2(NULL, request_id, block_for_reply); } GIOPRecvBuffer * giop_recv_reply_buffer_use_2(GIOPConnection *request_cnx, GIOP_unsigned_long request_id, gboolean block_for_reply) { GArray fakeme; fakeme.len = 1; fakeme.data = (gpointer)&request_id; return giop_recv_reply_buffer_use_multiple_2(request_cnx, &fakeme, block_for_reply); } GIOPRecvBuffer * giop_recv_locate_reply_buffer_use(GIOP_unsigned_long request_id, gboolean block_for_reply) { GIOPRecvBuffer *retval = NULL; do { /* * We _do_ want to put this inside the loop, * because we may call ourselves recursively for different request_id's */ retval = giop_received_list_check_reply(request_id); if(retval) break; retval = giop_main_next_message_2(TRUE, NULL); if(retval) { if(GIOP_MESSAGE_BUFFER(retval)->message_header.message_type == GIOP_LOCATEREPLY && retval->message.u.locate_reply.request_id == request_id) break; else { if(IIOPIncomingMessageHandler) IIOPIncomingMessageHandler(retval); else giop_received_list_push(retval); retval = NULL; } } else return NULL; } while(!retval && block_for_reply); return retval; } static gint giop_recv_decode_message(GIOPRecvBuffer *buf) { switch(GIOP_MESSAGE_BUFFER(buf)->message_header.message_type) { case GIOP_REPLY: return giop_recv_reply_decode_message(buf); break; case GIOP_REQUEST: return giop_recv_request_decode_message(buf); break; case GIOP_LOCATEREQUEST: return(giop_recv_locate_request_decode_message(buf)); break; case GIOP_LOCATEREPLY: return(giop_recv_locate_reply_decode_message(buf)); break; case GIOP_CLOSECONNECTION: return 0; break; default: g_warning("Don't know how to decode message type %d", GIOP_MESSAGE_BUFFER(buf)->message_header.message_type); return -1; } } /* if(currptr+len > end || currptr + len < currptr) */ /* This whole mess needs redoing. */ #define CHECK_NEW_POS(buf, requested_increment) \ g_return_val_if_fail( (( ((guchar*)GIOP_RECV_BUFFER(buf)->cur) \ + (requested_increment) ) \ <= ( ((guchar *)GIOP_RECV_BUFFER(buf)->message_body) \ + GIOP_MESSAGE_BUFFER(buf)->message_header.message_size)) \ && ( ( ((guchar*)GIOP_RECV_BUFFER(buf)->cur) \ + (requested_increment) ) \ >= ((guchar*)GIOP_RECV_BUFFER(buf)->cur) ), -1) #define SAFE_ALIGN_ADDRESS(buf, amt) G_STMT_START { \ guchar *newval; \ newval = ALIGN_ADDRESS(GIOP_RECV_BUFFER(buf)->cur, amt); \ CHECK_NEW_POS(buf, newval-((guchar *)GIOP_RECV_BUFFER(buf)->cur)); \ GIOP_RECV_BUFFER(buf)->cur = newval; \ } G_STMT_END #define GET_ULONG(x) G_STMT_START{ \ (x) = GUINT32_SWAP_LE_BE((*(CORBA_unsigned_long *)buf->cur)); \ CHECK_NEW_POS(buf, sizeof(CORBA_unsigned_long)); \ (guchar*)buf->cur += sizeof(CORBA_unsigned_long); \ }G_STMT_END #define GET_ULONG_NC(x) G_STMT_START{ \ *(x) = (*((CORBA_unsigned_long *)(buf->cur))); \ CHECK_NEW_POS(buf, sizeof(CORBA_unsigned_long)); \ (guchar *)buf->cur += sizeof(CORBA_unsigned_long); \ }G_STMT_END /* There be dragons in here. */ static gint giop_recv_reply_decode_message(GIOPRecvBuffer *buf) { /* enum ReplyStatusType { NO_EXCEPTION, USER_EXCEPTION, SYSTEM_EXCEPTION, LOCATION_FORWARD }; struct ReplyHeader { IOP::ServiceContextList service_context; unsigned long request_id; ReplyStatusType reply_status; }; */ int i; buf->message.u.reply.service_context._maximum = 0; if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf))) { GET_ULONG(buf->message.u.reply.service_context._length); /* XXX bad hardcoded hack until someone gives a "right answer" to how to solve this problem */ if(buf->message.u.reply.service_context._length > 128) return -1; buf->message.u.reply.service_context._buffer = g_new(IOP_ServiceContext, buf->message.u.reply.service_context._length); for(i = 0; i < buf->message.u.reply.service_context._length; i++) { SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG(buf->message.u.reply.service_context._buffer[i].context_id); GET_ULONG(buf->message.u.reply.service_context._buffer[i].context_data._length); buf->message.u.reply.service_context._buffer[i].context_data._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.reply.service_context._buffer[i].context_data._length); (guchar *) buf->cur += buf->message.u.reply.service_context._buffer[i].context_data._length; } GET_ULONG(buf->message.u.reply.request_id); GET_ULONG(buf->message.u.reply.reply_status); } else { GET_ULONG_NC(&buf->message.u.reply.service_context._length); /* XXX bad hardcoded hack until someone gives a "right answer" to how to solve this problem */ if(buf->message.u.reply.service_context._length > 128) return -1; buf->message.u.reply.service_context._buffer = g_new(IOP_ServiceContext, buf->message.u.reply.service_context._length); for(i = 0; i < buf->message.u.reply.service_context._length; i++) { SAFE_ALIGN_ADDRESS(buf, sizeof(CORBA_unsigned_long)); GET_ULONG_NC(&buf->message.u.reply.service_context._buffer[i].context_id); GET_ULONG_NC(&buf->message.u.reply.service_context._buffer[i].context_data._length); buf->message.u.reply.service_context._buffer[i].context_data._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.reply.service_context._buffer[i].context_data._length); (guchar *) buf->cur += buf->message.u.reply.service_context._buffer[i].context_data._length; } GET_ULONG_NC(&buf->message.u.reply.request_id); GET_ULONG_NC(&buf->message.u.reply.reply_status); } #if 0 g_message("[%d] Received reply %d size %d to request %d", getpid(), buf->message.u.reply.reply_status, GIOP_MESSAGE_BUFFER(buf)->message_header.message_size, buf->message.u.reply.request_id); #endif return 0; } static gint giop_recv_locate_reply_decode_message(GIOPRecvBuffer *buf) { if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf))) { GET_ULONG(buf->message.u.locate_reply.request_id); GET_ULONG(buf->message.u.locate_reply.locate_status); } else { GET_ULONG_NC(&buf->message.u.locate_reply.request_id); GET_ULONG_NC(&buf->message.u.locate_reply.locate_status); } return 0; } static gint giop_recv_request_decode_message(GIOPRecvBuffer *buf) { GIOP_unsigned_long len; int i; buf->message.u.request.service_context._maximum = 0; if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf))) { GET_ULONG(buf->message.u.request.service_context._length); /* XXX bad hardcoded hack until someone gives a "right answer" to how to solve this problem */ if(buf->message.u.request.service_context._length > 128) return -1; buf->message.u.request.service_context._buffer = g_new(IOP_ServiceContext, buf->message.u.request.service_context._length); for(i = 0; i < buf->message.u.request.service_context._length; i++) { SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG(buf->message.u.request.service_context._buffer[i].context_id); GET_ULONG(buf->message.u.request.service_context._buffer[i].context_data._length); buf->message.u.request.service_context._buffer[i].context_data._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.request.service_context._buffer[i].context_data._length); (guchar*)buf->cur += buf->message.u.request.service_context._buffer[i].context_data._length; } SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG(buf->message.u.request.request_id); buf->message.u.request.response_expected = *((GIOP_boolean *)buf->cur); CHECK_NEW_POS(buf, sizeof(GIOP_boolean)); (guchar*)buf->cur += sizeof(GIOP_boolean); SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG(buf->message.u.request.object_key._length); buf->message.u.request.object_key._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.request.object_key._length); (guchar*)buf->cur += buf->message.u.request.object_key._length; SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG(len); buf->message.u.request.operation = buf->cur; CHECK_NEW_POS(buf, len); (guchar*)buf->cur += len; SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG(buf->message.u.request.requesting_principal._length); buf->message.u.request.requesting_principal._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.request.requesting_principal._length); (guchar*)buf->cur += buf->message.u.request.requesting_principal._length; } else { GET_ULONG_NC(&buf->message.u.request.service_context._length); /* XXX bad hardcoded hack until someone gives a "right answer" to how to solve this problem */ if(buf->message.u.request.service_context._length > 128) return -1; buf->message.u.request.service_context._buffer = g_new(IOP_ServiceContext, buf->message.u.request.service_context._length); for(i = 0; i < buf->message.u.request.service_context._length; i++) { SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG_NC(&buf->message.u.request.service_context._buffer[i].context_id); GET_ULONG_NC(&buf->message.u.request.service_context._buffer[i].context_data._length); buf->message.u.request.service_context._buffer[i].context_data._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.request.service_context._buffer[i].context_data._length); (guchar*)buf->cur += buf->message.u.request.service_context._buffer[i].context_data._length; } SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG_NC(&buf->message.u.request.request_id); buf->message.u.request.response_expected = *((GIOP_boolean *)buf->cur); CHECK_NEW_POS(buf, sizeof(GIOP_boolean)); (guchar*)buf->cur += sizeof(GIOP_boolean); SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG_NC(&buf->message.u.request.object_key._length); buf->message.u.request.object_key._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.request.object_key._length); (guchar*)buf->cur += buf->message.u.request.object_key._length; SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG_NC(&len); buf->message.u.request.operation = buf->cur; CHECK_NEW_POS(buf, len); (guchar*)buf->cur += len; SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG_NC(&buf->message.u.request.requesting_principal._length); buf->message.u.request.requesting_principal._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.request.requesting_principal._length); (guchar*)buf->cur += buf->message.u.request.requesting_principal._length; } #if 0 g_message("[%d] Received request %s size %d ID %d", getpid(), buf->message.u.request.operation, GIOP_MESSAGE_BUFFER(buf)->message_header.message_size, buf->message.u.request.request_id); #endif return 0; } static gint giop_recv_locate_request_decode_message(GIOPRecvBuffer *buf) { if(giop_msg_conversion_needed(GIOP_MESSAGE_BUFFER(buf))) { SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG(buf->message.u.locate_request.request_id); SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG(buf->message.u.locate_request.object_key._length); buf->message.u.locate_request.object_key._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.locate_request.object_key._length); (guchar*)buf->cur += buf->message.u.locate_request.object_key._length; } else { SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG_NC(&buf->message.u.locate_request.request_id); SAFE_ALIGN_ADDRESS(buf, sizeof(GIOP_unsigned_long)); GET_ULONG_NC(&buf->message.u.locate_request.object_key._length); buf->message.u.locate_request.object_key._buffer = buf->cur; CHECK_NEW_POS(buf, buf->message.u.locate_request.object_key._length); (guchar*)buf->cur += buf->message.u.locate_request.object_key._length; } return 0; } gboolean num_on_list(GIOP_unsigned_long num, const GIOP_unsigned_long *request_ids, GIOP_unsigned_long req_count) { int i; for(i = 0; i < req_count; i++) { if(num == request_ids[i]) return TRUE; } return FALSE; }