1 #include <config.h>
2 #include <string.h>
3 #include <sys/types.h>
4 #include "giop-private.h"
5 #ifdef HAVE_SYS_UIO_H
6 #  include <sys/uio.h>
7 #endif
8 #include <orbit/GIOP/giop.h>
9 #include "../util/orbit-purify.h"
10 
11 #define GIOP_CHUNK_ALIGN 8
12 #define GIOP_CHUNK_SIZE (GIOP_CHUNK_ALIGN * 256)
13 
14 static gboolean giop_blank_wire_data = FALSE;
15 static GSList *send_buffer_list = NULL;
16 static GMutex *send_buffer_list_lock = NULL;
17 
18 static const char giop_zero_buf [GIOP_CHUNK_ALIGN * 10] = {0};
19 
20 void
giop_send_buffer_init(gboolean wipe)21 giop_send_buffer_init (gboolean wipe)
22 {
23 #ifdef ORBIT_PURIFY
24 	giop_blank_wire_data = TRUE;
25 #else
26 	giop_blank_wire_data = wipe;
27 #endif
28 	send_buffer_list_lock = link_mutex_new ();
29 }
30 
31 /* Marshal it at compile time so we don't have to do it over and over. This just stores codeset info to say that
32      we only speak UTF-8/UTF-16 */
33 static const CORBA_unsigned_long iop_service_context_data [] = {
34 	1 /* num_contexts */,
35 	1 /* ServiceId for CodeSets */,
36 	12 /* length of encapsulation: 4 endianness+align, 4 charset_id, 4 wcharset_id */,
37 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
38 	0x01010101 /* start of encapsulation */,
39 #else
40 	0,
41 #endif
42 	0x05010001, /* UTF-8 */
43 	0x00010109 /* UTF-16 */
44 };
45 
46 static const GIOP_AddressingDisposition giop_1_2_target_type = GIOP_KeyAddr;
47 
48 static gboolean
giop_send_buffer_is_oneway(const GIOPSendBuffer * buf)49 giop_send_buffer_is_oneway(const GIOPSendBuffer *buf)
50 {
51 	g_assert (buf);
52 
53 	switch (buf->giop_version) {
54 	case GIOP_1_0:
55 	case GIOP_1_1:
56 		return (buf->msg.u.request_1_0.response_expected ? FALSE : TRUE);
57 	case GIOP_1_2:
58 		return (buf->msg.u.request_1_2.response_flags ? FALSE : TRUE);
59 	default:
60 		break;
61 	}
62 	g_assert_not_reached();
63 
64 	return TRUE;
65 }
66 
67 GIOPSendBuffer *
giop_send_buffer_use_request(GIOPVersion giop_version,CORBA_unsigned_long request_id,CORBA_boolean response_expected,const CORBA_sequence_CORBA_octet * objkey,const struct iovec * operation_vec,const struct iovec * principal_vec)68 giop_send_buffer_use_request (GIOPVersion giop_version,
69 			      CORBA_unsigned_long request_id,
70 			      CORBA_boolean response_expected,
71 			      const CORBA_sequence_CORBA_octet *objkey,
72 			      const struct iovec *operation_vec,
73 			      const struct iovec *principal_vec)
74 {
75 	GIOPSendBuffer *buf = giop_send_buffer_use (giop_version);
76 	struct iovec zerovec;
77 
78 	if(!principal_vec) {
79 		zerovec.iov_base = (gpointer) giop_zero_buf;
80 		zerovec.iov_len = sizeof (CORBA_unsigned_long);
81 		principal_vec = &zerovec;
82 	}
83 
84 	buf->msg.header.message_type = GIOP_REQUEST;
85 	giop_send_buffer_align (buf, sizeof(CORBA_unsigned_long));
86 
87 	switch (giop_version) {
88 	case GIOP_1_0:
89 	case GIOP_1_1:
90 		buf->msg.u.request_1_0.request_id = request_id;
91 		buf->msg.u.request_1_0.response_expected = response_expected;
92 
93 		giop_send_buffer_append (buf, (const guchar *)iop_service_context_data, sizeof(iop_service_context_data));
94 		giop_send_buffer_append (buf, &buf->msg.u.request_1_0.request_id, sizeof(CORBA_unsigned_long));
95 		giop_send_buffer_append (buf, &buf->msg.u.request_1_0.response_expected, sizeof(CORBA_boolean));
96 		giop_send_buffer_append_aligned (buf, &objkey->_length, sizeof(CORBA_unsigned_long));
97 		giop_send_buffer_append (buf, objkey->_buffer, objkey->_length);
98 		giop_send_buffer_align (buf, sizeof(CORBA_unsigned_long));
99 		giop_send_buffer_append (buf, operation_vec->iov_base, operation_vec->iov_len);
100 		giop_send_buffer_append (buf, principal_vec->iov_base, principal_vec->iov_len);
101 		break;
102 
103 	case GIOP_1_2:
104 		buf->msg.u.request_1_2.request_id = request_id;
105 		buf->msg.u.request_1_2.response_flags = response_expected ? 0x3 /* SYNC_WITH_TARGET */ : 0x0 /* SYNC_NONE */;
106 
107 		giop_send_buffer_align (buf, sizeof(CORBA_unsigned_long));
108 		giop_send_buffer_append (buf, &buf->msg.u.request_1_2.request_id, sizeof(CORBA_unsigned_long));
109 		giop_send_buffer_append (buf, &buf->msg.u.request_1_2.response_flags, sizeof(CORBA_octet));
110 		giop_send_buffer_append (buf, giop_zero_buf, 3);
111 		giop_send_buffer_append (buf, &giop_1_2_target_type, 2); /* We always use GIOP::KeyAddr addressing - the only sane way */
112 		giop_send_buffer_append_aligned (buf, &objkey->_length, sizeof(CORBA_unsigned_long));
113 		giop_send_buffer_append (buf, objkey->_buffer, objkey->_length);
114 		giop_send_buffer_align (buf, sizeof(CORBA_unsigned_long));
115 		giop_send_buffer_append (buf, operation_vec->iov_base, operation_vec->iov_len);
116 		giop_send_buffer_append (buf, (const guchar *)iop_service_context_data, sizeof(iop_service_context_data));
117 		giop_send_buffer_align (buf, 8); /* alignment for the body */
118 	default:
119 		break;
120 	}
121 
122 	return buf;
123 }
124 
125 GIOPSendBuffer *
giop_send_buffer_use_reply(GIOPVersion giop_version,CORBA_unsigned_long request_id,CORBA_unsigned_long reply_status)126 giop_send_buffer_use_reply(GIOPVersion giop_version,
127 			   CORBA_unsigned_long request_id,
128 			   CORBA_unsigned_long reply_status)
129 {
130   GIOPSendBuffer *buf = giop_send_buffer_use(giop_version);
131 
132   buf->msg.header.message_type = GIOP_REPLY;
133 
134   switch(giop_version)
135     {
136     case GIOP_1_0:
137     case GIOP_1_1:
138       buf->msg.u.reply_1_0.reply_status = reply_status;
139       buf->msg.u.reply_1_0.request_id = request_id;
140       giop_send_buffer_append(buf, (const guchar *)iop_service_context_data, sizeof(iop_service_context_data));
141       giop_send_buffer_append(buf, &buf->msg.u.reply_1_0.request_id, sizeof(CORBA_unsigned_long));
142       giop_send_buffer_append(buf, &buf->msg.u.reply_1_0.reply_status, sizeof(CORBA_unsigned_long));
143       break;
144     case GIOP_1_2:
145       buf->msg.u.reply_1_2.reply_status = reply_status;
146       buf->msg.u.reply_1_2.request_id = request_id;
147       giop_send_buffer_append(buf, &buf->msg.u.reply_1_2.request_id, sizeof(CORBA_unsigned_long));
148       giop_send_buffer_append(buf, &buf->msg.u.reply_1_2.reply_status, sizeof(CORBA_unsigned_long));
149       giop_send_buffer_append(buf, (const guchar *)iop_service_context_data, sizeof(iop_service_context_data));
150       giop_send_buffer_align(buf, 8); /* alignment for the body */
151     default:
152       break;
153     }
154 
155   return buf;
156 }
157 
158 GIOPSendBuffer *
giop_send_buffer_use_locate_request(GIOPVersion giop_version,CORBA_unsigned_long request_id,const CORBA_sequence_CORBA_octet * objkey)159 giop_send_buffer_use_locate_request (GIOPVersion giop_version,
160 				     CORBA_unsigned_long request_id,
161 				     const CORBA_sequence_CORBA_octet *objkey)
162 {
163   GIOPSendBuffer *buf = giop_send_buffer_use(giop_version);
164 
165   buf->msg.header.message_type = GIOP_LOCATEREQUEST;
166 
167   buf->msg.u.locate_request_1_0.request_id = request_id;
168   giop_send_buffer_append(buf, &buf->msg.u.locate_request_1_0.request_id, sizeof(CORBA_unsigned_long));
169 
170   switch(giop_version)
171     {
172     case GIOP_1_0:
173     case GIOP_1_1:
174       giop_send_buffer_append_aligned(buf, &objkey->_length, sizeof(CORBA_unsigned_long));
175       giop_send_buffer_append(buf, objkey->_buffer, objkey->_length);
176       break;
177     case GIOP_1_2:
178       giop_send_buffer_append(buf, &giop_1_2_target_type, sizeof(giop_1_2_target_type));
179       giop_send_buffer_append_aligned(buf, &objkey->_length, sizeof(CORBA_unsigned_long));
180       giop_send_buffer_append(buf, objkey->_buffer, objkey->_length);
181     default:
182       break;
183     }
184 
185   return buf;
186 }
187 
188 GIOPSendBuffer *
giop_send_buffer_use_locate_reply(GIOPVersion giop_version,CORBA_unsigned_long request_id,CORBA_unsigned_long locate_status)189 giop_send_buffer_use_locate_reply(GIOPVersion giop_version,
190 				  CORBA_unsigned_long request_id,
191 				  CORBA_unsigned_long locate_status)
192 {
193   GIOPSendBuffer *buf = giop_send_buffer_use(giop_version);
194 
195   buf->msg.header.message_type = GIOP_LOCATEREPLY;
196 
197   buf->msg.u.locate_reply_1_0.request_id = request_id;
198   giop_send_buffer_append(buf, &buf->msg.u.locate_reply_1_0.request_id, sizeof(CORBA_unsigned_long));
199   buf->msg.u.locate_reply_1_0.locate_status = locate_status;
200   giop_send_buffer_append(buf, &buf->msg.u.locate_reply_1_0.locate_status, sizeof(CORBA_unsigned_long));
201 
202   return buf;
203 }
204 
205 GIOPSendBuffer *
giop_send_buffer_use_close_connection(GIOPVersion giop_version)206 giop_send_buffer_use_close_connection (GIOPVersion giop_version)
207 {
208 	GIOPSendBuffer *buf = giop_send_buffer_use (giop_version);
209 
210 	buf->msg.header.message_type = GIOP_CLOSECONNECTION;
211 
212 	return buf;
213 }
214 
215 GIOPSendBuffer *
giop_send_buffer_use_message_error(GIOPVersion giop_version)216 giop_send_buffer_use_message_error (GIOPVersion giop_version)
217 {
218 	GIOPSendBuffer *buf = giop_send_buffer_use (giop_version);
219 
220 	buf->msg.header.message_type = GIOP_MESSAGEERROR;
221 
222 	return buf;
223 }
224 
225 void
giop_send_buffer_unuse(GIOPSendBuffer * buf)226 giop_send_buffer_unuse (GIOPSendBuffer *buf)
227 {
228 	int i;
229 
230 	for (i = 0; i < buf->num_indirects_used; i++) {
231 		if (buf->indirects[i].size > GIOP_CHUNK_SIZE) {
232 			buf->indirects [i].size = GIOP_CHUNK_SIZE;
233 			buf->indirects [i].ptr = g_realloc (buf->indirects [i].ptr,
234 							    buf->indirects [i].size);
235 		}
236 	}
237 
238 	LINK_MUTEX_LOCK (send_buffer_list_lock);
239 	send_buffer_list = g_slist_prepend (send_buffer_list, buf);
240 
241 	LINK_MUTEX_UNLOCK (send_buffer_list_lock);
242 }
243 
244 static void
giop_send_buffer_append_real(GIOPSendBuffer * buf,gconstpointer mem,gulong len)245 giop_send_buffer_append_real (GIOPSendBuffer *buf,
246 			      gconstpointer   mem,
247 			      gulong          len)
248 {
249 	register gulong num_used;
250 	register const guchar *lastptr;
251 
252 	g_assert (mem);
253 
254 	lastptr = buf->lastptr;
255 	num_used = buf->num_used;
256 	if(num_used && mem == lastptr)
257 		buf->iovecs[num_used-1].iov_len += len;
258 
259 	else {
260 		if(num_used >= buf->num_alloced) {
261 			buf->num_alloced = MAX (buf->num_alloced, 4) * 2;
262 			buf->iovecs = g_realloc (buf->iovecs,
263 						 buf->num_alloced *
264 						 sizeof (struct iovec));
265 		}
266 
267 		buf->iovecs [num_used].iov_base = (gpointer) mem;
268 		buf->iovecs [num_used].iov_len = len;
269 		buf->num_used = num_used + 1;
270 	}
271 
272 	buf->msg.header.message_size += len;
273 
274 	buf->lastptr = ((const guchar *) mem) + len;
275 }
276 
277 /*
278  * get_next_indirect:
279  * @buf: the send buffer with an exhausted indirect.
280  * @for_size_hint: for very large buffers specify this
281  * so we don't allocate too much. If this is non 0 then
282  * buf->indirect will contain at least this much space.
283  *
284  * Pulls in the next indirect block into buf, and
285  * sets up @buf->indirect_left, and @buf->indirect
286  * to be correct.
287  */
288 static void
get_next_indirect(GIOPSendBuffer * buf,gulong for_size_hint)289 get_next_indirect (GIOPSendBuffer *buf, gulong for_size_hint)
290 {
291 	gulong max = buf->num_indirects_used;
292 
293 	if (max >= buf->num_indirects_alloced) {
294 		gulong new_size;
295 
296 		buf->num_indirects_alloced++;
297 		buf->indirects = g_realloc (
298 			buf->indirects, buf->num_indirects_alloced * sizeof (GIOPIndirectChunk));
299 
300 		if (for_size_hint) {
301 			new_size = (for_size_hint + 7) & ~7;
302 			if (new_size < GIOP_CHUNK_SIZE)
303 				new_size = GIOP_CHUNK_SIZE;
304 		} else
305 			new_size = GIOP_CHUNK_SIZE;
306 
307 		buf->indirects [max].size = new_size;
308 
309 		if (giop_blank_wire_data)
310 			buf->indirects [max].ptr = g_malloc0 (new_size);
311 		else
312 			buf->indirects [max].ptr = g_malloc (new_size);
313 
314 		/*
315 		 *   We assume that this is 8 byte aligned, for efficiency -
316 		 * so we can align to the memory address rather than the offset
317 		 * into the buffer.
318 		 */
319 		g_assert (((gulong)buf->indirects [max].ptr & 0x3) == 0);
320 	}
321 
322 	buf->indirect = buf->indirects [max].ptr;
323 	buf->indirect_left = buf->indirects [max].size;
324 	buf->num_indirects_used = max + 1;
325 }
326 
327 static void
giop_send_buffer_append_copy(GIOPSendBuffer * buf,gconstpointer mem,gulong len)328 giop_send_buffer_append_copy (GIOPSendBuffer *buf,
329 			      gconstpointer   mem,
330 			      gulong          len)
331 {
332 	/* FIXME: should we fill up the full indirects ? */
333 	if (buf->indirect_left < len)
334 		get_next_indirect (buf, len);
335 
336 	memcpy (buf->indirect, mem, len);
337 
338 	giop_send_buffer_append_real (buf, buf->indirect, len);
339 
340 	buf->indirect      += len;
341 	buf->indirect_left -= len;
342 }
343 
344 
345 void
giop_send_buffer_append(GIOPSendBuffer * buf,gconstpointer mem,gulong len)346 giop_send_buffer_append (GIOPSendBuffer *buf,
347 			 gconstpointer   mem,
348 			 gulong          len)
349 {
350 	if (len <= 32)
351 		giop_send_buffer_append_copy (buf, mem, len);
352 	else
353 		giop_send_buffer_append_real (buf, mem, len);
354 }
355 
356 /**
357  * giop_send_buffer_align:
358  * @buf: the buffer
359  * @boundary: the boundary.
360  *
361  * Appends memory to the SendBuffer to align it to a boundary
362  * of size @boundary bytes - if neccessary.
363  **/
364 void
giop_send_buffer_align(GIOPSendBuffer * buf,gulong boundary)365 giop_send_buffer_align (GIOPSendBuffer *buf, gulong boundary)
366 {
367 	gulong align_amt, ms;
368 
369 	/* 1. Figure out how much to align by */
370 	ms = buf->msg.header.message_size + buf->header_size;
371 	align_amt = ALIGN_VALUE(ms, boundary) - ms;
372 
373 	/* 2. Do the alignment */
374 	if (align_amt) {
375 
376 		if (buf->indirect_left < align_amt)
377 			get_next_indirect (buf, 0);
378 
379 		p_memzero (buf->indirect, align_amt);
380 		giop_send_buffer_append_real (buf, buf->indirect, align_amt);
381 
382 		buf->indirect      += align_amt;
383 		buf->indirect_left -= align_amt;
384 	}
385 }
386 
387 /**
388  * giop_send_buffer_append_aligned:
389  * @buf: the buffer
390  * @mem: the memory pointer
391  * @align_len: the alignment and length of @mem.
392  *
393  * This routine alignes the send buffer to a byte boundary
394  * of size @align_len, and writes align_len bytes of memory
395  * pointed to by @mem to the buffer, or simply expands the
396  * buffer if mem is NULL by that much.
397  *
398  * Return value: a pointer to the beggining of the
399  * contiguous space available for @mem
400  *
401  * Note: do not assume anything about the physical
402  *       alignment of the returned pointer.
403  **/
404 guchar *
giop_send_buffer_append_aligned(GIOPSendBuffer * buf,gconstpointer mem,gulong align_len)405 giop_send_buffer_append_aligned (GIOPSendBuffer *buf,
406 				 gconstpointer   mem,
407 				 gulong          align_len)
408 {
409 	guchar *indirect;
410 
411 	/* FIXME: could make this more efficient by in-lining the align
412 	   more aggressively here */
413 	giop_send_buffer_align (buf, align_len);
414 
415 	if (buf->indirect_left < align_len)
416 		get_next_indirect (buf, 0);
417 
418 	indirect = buf->indirect;
419 
420 	if (mem)
421 		memcpy (indirect, mem, align_len);
422 	else
423 		p_memzero (indirect, align_len);
424 
425 	giop_send_buffer_append_real (buf, indirect, align_len);
426 
427 	buf->indirect      += align_len;
428 	buf->indirect_left -= align_len;
429 
430 	return indirect;
431 }
432 
433 /**
434  * giop_send_buffer_write:
435  * @buf: the buffer to write
436  * @cnx: the connection to write it to.
437  *
438  * Writes @buf to @cnx as a block.
439  *
440  * Return value: 0 on sucess, non 0 on error.
441  **/
442 int
giop_send_buffer_write(GIOPSendBuffer * buf,GIOPConnection * cnx,gboolean blocking)443 giop_send_buffer_write (GIOPSendBuffer *buf,
444 			GIOPConnection *cnx,
445 			gboolean        blocking)
446 {
447 	int retval;
448 	LinkConnection *lcnx = LINK_CONNECTION (cnx);
449 	static LinkWriteOpts *non_block = NULL;
450 
451 	if (!non_block)
452 		non_block = link_write_options_new (FALSE);
453 
454 	/* FIXME: if a FRAGMENT, assert the 8 byte tail align,
455 	   &&|| giop_send_buffer_align (buf, 8); */
456 
457 	if (g_thread_supported ()
458 	    && lcnx->timeout_msec
459 	    && !lcnx->timeout_source_id
460 	    && !giop_send_buffer_is_oneway (buf)) {
461 		giop_timeout_add (cnx);
462 	}
463 
464 	retval = link_connection_writev (lcnx,
465 					 buf->iovecs,
466 					 buf->num_used,
467 					 blocking ? NULL : non_block);
468 
469 	if (!blocking && retval == LINK_IO_QUEUED_DATA)
470 		retval = 0;
471 
472 	/* FIXME: we need to flag the connection disconnected on fatal error */
473 
474 	return retval;
475 }
476 
477 
478 GIOPSendBuffer *
giop_send_buffer_use(GIOPVersion giop_version)479 giop_send_buffer_use (GIOPVersion giop_version)
480 {
481 	GIOPSendBuffer *buf;
482 
483 	g_return_val_if_fail (
484 		((int) giop_version) >= 0 &&
485 		giop_version < GIOP_NUM_VERSIONS, NULL);
486 
487 	LINK_MUTEX_LOCK (send_buffer_list_lock);
488 	if (send_buffer_list) {
489 		GSList *ltmp;
490 
491 		ltmp = send_buffer_list;
492 		send_buffer_list = g_slist_remove_link (
493 			send_buffer_list, ltmp);
494 
495 		LINK_MUTEX_UNLOCK (send_buffer_list_lock);
496 
497 		buf = ltmp->data;
498 		g_slist_free_1 (ltmp);
499 		buf->num_used = buf->indirect_left = 0;
500 
501 		if (giop_blank_wire_data) {
502 			int i;
503 
504 			for (i = 0; i < buf->num_indirects_used; i++)
505 				memset (buf->indirects [i].ptr, 0,
506 					buf->indirects [i].size);
507 		}
508 
509 		buf->num_indirects_used = 0;
510 	} else {
511 		LINK_MUTEX_UNLOCK (send_buffer_list_lock);
512 
513 		buf = g_new0 (GIOPSendBuffer, 1);
514 
515 		memcpy (buf->msg.header.magic, "GIOP", 4);
516 		buf->msg.header.flags = GIOP_FLAG_ENDIANNESS;
517 		buf->num_alloced = 8;
518 		buf->iovecs = g_new (struct iovec, 8);
519 	}
520 
521 
522 	memcpy (buf->msg.header.version,
523 		giop_version_ids [giop_version], 2);
524 	buf->giop_version = giop_version;
525 
526 	g_assert (sizeof (buf->msg.header) == 12);
527 	giop_send_buffer_append_real (
528 		buf, (guchar *)&buf->msg.header, 12);
529 
530 	buf->msg.header.message_size = 0;
531 	buf->header_size = 12;
532 
533 	return buf;
534 }
535 
536 void
giop_send_buffer_append_string(GIOPSendBuffer * buf,const char * str)537 giop_send_buffer_append_string (GIOPSendBuffer *buf,
538 				const char     *str)
539 {
540 	CORBA_unsigned_long len;
541 
542 	len = strlen (str) + 1;
543 
544 	/* FIXME: inline me ? */
545 	giop_send_buffer_align (buf, 4);
546 
547 	/* be cleverer for short strings */
548 	if (buf->indirect_left >= 4 + len) {
549 		guchar *indirect = buf->indirect;
550 
551 		memcpy (indirect, &len, 4);
552 		memcpy (indirect + 4, str, len);
553 
554 		giop_send_buffer_append_real (buf, indirect, 4 + len);
555 
556 		buf->indirect      += 4 + len;
557 		buf->indirect_left -= 4 + len;
558 	} else {
559 		giop_send_buffer_append_copy (buf, &len, 4);
560 		giop_send_buffer_append (buf, str, len);
561 	}
562 }
563 
564