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