1// vi:set ft=cpp: -*- Mode: C++ -*-
2/**
3 * \file
4 * IPC stream
5 */
6/*
7 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8 *               Alexander Warg <warg@os.inf.tu-dresden.de>,
9 *               Torsten Frenzel <frenzel@os.inf.tu-dresden.de>
10 *     economic rights: Technische Universität Dresden (Germany)
11 *
12 * This file is part of TUD:OS and distributed under the terms of the
13 * GNU General Public License 2.
14 * Please see the COPYING-GPL-2 file for details.
15 *
16 * As a special exception, you may use this file as part of a free software
17 * library without restriction.  Specifically, if other files instantiate
18 * templates or use macros or inline functions from this file, or you compile
19 * this file and link it with other files to produce an executable, this
20 * file does not by itself cause the resulting executable to be covered by
21 * the GNU General Public License.  This exception does not however
22 * invalidate any other reasons why the executable file might be covered by
23 * the GNU General Public License.
24 */
25#pragma once
26
27#include <l4/sys/ipc.h>
28#include <l4/sys/capability>
29#include <l4/sys/cxx/ipc_types>
30#include <l4/sys/cxx/ipc_varg>
31#include <l4/cxx/type_traits>
32#include <l4/cxx/minmax>
33
34namespace L4 {
35namespace Ipc {
36
37class Ostream;
38class Istream;
39
40namespace Internal {
41/**
42 * Abstraction for inserting an array into an Ipc::Ostream.
43 * \internal
44 *
45 * An object of Buf_cp_out can be used to insert an array of arbitrary values,
46 * that can be inserted into an Ipc::Ostream individually.
47 * The array is therefore copied to the message buffer, in contrast to
48 * data handled with Msg_out_buffer or Msg_io_buffer.
49 *
50 * On insertion into the Ipc::Ostream exactly the given number of elements
51 * of type T are copied to the message buffer, this means the source buffer
52 * is no longer referenced after insertion into the stream.
53 *
54 * The method buf_cp_out() should be used to create instances of Buf_cp_out.
55 *
56 * The counterpart is either Buf_cp_in (buf_cp_in()) or Buf_in (buf_in()).
57 */
58template< typename T >
59class Buf_cp_out
60{
61public:
62  /**
63   * Create a buffer object for the given array.
64   *
65   * \param v     The pointer to the array with size elements of type T.
66   * \param size  The number of elements in the array.
67   */
68  Buf_cp_out(T const *v, unsigned long size) : _v(v), _s(size) {}
69
70  /**
71   * Get the number of elements in the array.
72   *
73   * \return  The number of elements in the array.
74   *
75   * \note This function is usually used by the Ipc::Ostream itself.
76   */
77  unsigned long size() const { return _s; }
78
79  /**
80   * Get the pointer to the array.
81   *
82   * \return  Pointer to the array.
83   *
84   * \note This function is usually used by the Ipc::Ostream itself.
85   */
86  T const *buf() const { return _v; }
87
88private:
89  friend class Ostream;
90  T const *_v;
91  unsigned long _s;
92};
93}
94
95/**
96 * Insert an array into an Ipc::Ostream.
97 *
98 * \param v     Pointer to the array that shall be inserted into an
99 *              Ipc::Ostream.
100 * \param size  Number of elements in the array.
101 *
102 * This function inserts an array (e.g. a string) into an Ipc::Ostream.
103 * The data is copied to the stream. On insertion into the Ipc::Ostream
104 * exactly the given number of elements of type T are copied to the message
105 * buffer, this means the source buffer is no longer referenced after
106 * insertion into the stream.
107 *
108 * \see The counterpart is either buf_cp_in() or buf_in().
109 */
110template< typename T >
111Internal::Buf_cp_out<T> buf_cp_out(T const *v, unsigned long size)
112{ return Internal::Buf_cp_out<T>(v, size); }
113
114
115namespace Internal {
116/**
117 * Abstraction for extracting array from an Ipc::Istream.
118 * \internal
119 *
120 * An instance of Buf_cp_in can be used to extract an array from
121 * an Ipc::Istream. This is the counterpart to the Buf_cp_out abstraction.
122 * The data from the received message is thereby copied to the given buffer
123 * and size is set to the number of elements found in the stream.
124 * To avoid the copy operation Buf_in may be used instead.
125 *
126 * \see buf_cp_in(), Buf_in, buf_in(), Buf_cp_out, and buf_cp_out().
127 */
128template< typename T >
129class Buf_cp_in
130{
131public:
132  /**
133   * Create a buffer for extracting an array from an Ipc::Istream.
134   *
135   * \param         v     The buffer for array (copy in).
136   * \param[in,out] size  Input: the number of elements the array can take at
137   *                      most <br>
138   *                      Output: the number of elements found in the stream.
139   */
140  Buf_cp_in(T *v, unsigned long &size) : _v(v), _s(&size) {}
141
142  unsigned long &size() const { return *_s; }
143  T *buf() const { return _v; }
144
145private:
146  friend class Istream;
147  T *_v;
148  unsigned long *_s;
149};
150}
151
152/**
153 * Extract an array from an Ipc::Istream.
154 *
155 * \param         v     Pointer to the array that shall receive the values from
156 *                      the Ipc::Istream.
157 * \param[in,out] size  Input: the number of elements the array can take at
158 *                      most <br>
159 *                      Output: the number of elements found in the stream.
160 *
161 * buf_cp_in() can be used to extract an array from an Ipc::Istream. This is
162 * the counterpart buf_cp_out(). The data from the received message is
163 * thereby copied to the given buffer and size is set to the number of
164 * elements found in the stream. To avoid the copy operation buf_in() may be
165 * used instead.
166 *
167 * \see buf_in() and buf_cp_out().
168 */
169template< typename T >
170Internal::Buf_cp_in<T> buf_cp_in(T *v, unsigned long &size)
171{ return Internal::Buf_cp_in<T>(v, size); }
172
173/**
174 * Abstraction for extracting a zero-terminated string from an Ipc::Istream.
175 *
176 * An instance of Str_cp_in can be used to extract a zero-terminated string
177 * an Ipc::Istream. The data from the received message is thereby copied to the
178 * given buffer and size is set to the number of characters found in the
179 * stream.  The string is zero terminated in any circumstances. When the given
180 * buffer is smaller than the received string the last byte in the buffer will
181 * be the zero terminator. In the case the received string is shorter than the
182 * given buffer the zero termination will be placed behind the received data.
183 * This provides a zero-terminated result even in cases where the sender did
184 * not provide proper termination or in cases of too small receiver buffers.
185 *
186 * \see str_cp_in().
187 */
188template< typename T >
189class Str_cp_in
190{
191public:
192  /**
193   * Create a buffer for extracting an array from an Ipc::Istream.
194   *
195   * \param         v     The buffer for string.
196   * \param[in,out] size  Input: The number of bytes available in `v` <br>
197   *                      Output: The number of bytes received (including the
198   *                      terminator).
199   */
200  Str_cp_in(T *v, unsigned long &size) : _v(v), _s(&size) {}
201
202  unsigned long &size() const { return *_s; }
203  T *buf() const { return _v; }
204
205private:
206  friend class Istream;
207  T *_v;
208  unsigned long *_s;
209};
210
211/**
212 * Create a Str_cp_in for the given values.
213 *
214 * \param         v     Pointer to the array that shall receive the values from
215 *                      the Ipc::Istream.
216 * \param[in,out] size  Input: the number of elements the array can take at
217 *                      most <br>
218 *                      Output: the number of elements found in the stream.
219 *
220 * This function makes it more convenient to extract arrays from an
221 * Ipc::Istream (\see Str_cp_in.)
222 */
223template< typename T >
224Str_cp_in<T> str_cp_in(T *v, unsigned long &size)
225{ return Str_cp_in<T>(v, size); }
226
227/**
228 * Pointer to an element of type T in an Ipc::Istream.
229 *
230 * This wrapper can be used to extract an element of type T from an
231 * Ipc::Istream, whereas the data is not copied out, but a pointer into
232 * the message buffer itself is returned. With is mechanism it is possible
233 * to avoid an extra copy of large data structures from a received IPC
234 * message, instead the returned pointer gives direct access to the data
235 * in the message.
236 *
237 * See msg_ptr().
238 */
239template< typename T >
240class Msg_ptr
241{
242private:
243  T **_p;
244public:
245  /**
246   * Create a Msg_ptr object that set pointer p to point into the message
247   * buffer.
248   *
249   * \param p  The pointer that is adjusted to point into the message buffer.
250   */
251  explicit Msg_ptr(T *&p) : _p(&p) {}
252  void set(T *p) const { *_p = p; }
253};
254
255/**
256 * Create an Msg_ptr to adjust the given pointer.
257 *
258 * This function makes it more convenient to extract pointers to data in the
259 * message buffer itself from an Ipc::Istream.  This may be used to avoid copy
260 * out of large data structures.  (See Msg_ptr.)
261 */
262template< typename T >
263Msg_ptr<T> msg_ptr(T *&p)
264{ return Msg_ptr<T>(p); }
265
266
267namespace Internal {
268/**
269 * Abstraction to extract an array from an Ipc::Istream.
270 * \internal
271 *
272 * This wrapper provides a possibility to extract an array from an
273 * Ipc::Istream, without extra copy overhead. In contrast to Buf_cp_in
274 * the data is not copied to a buffer, but a pointer to the array is returned.
275 *
276 * The mechanism is comparable to that of Msg_ptr, however it handles arrays
277 * inserted with Buf_cp_out.
278 *
279 * See buf_in(), Buf_cp_out, buf_cp_out(), Buf_cp_in, and buf_cp_in().
280 */
281template< typename T >
282class Buf_in
283{
284public:
285  /**
286   * Create a Buf_in to adjust a pointer to the array and the size of the array.
287   *
288   * \param      v     The pointer to adjust to the first element of the array.
289   * \param[out] size  The number of elements found in the stream.
290   */
291  Buf_in(T *&v, unsigned long &size) : _v(&v), _s(&size) {}
292
293  void set_size(unsigned long s) const { *_s = s; }
294  T *&buf() const { return *_v; }
295
296private:
297  friend class Istream;
298  T **_v;
299  unsigned long *_s;
300};
301}
302
303/**
304 * Return a pointer to stream array data.
305 *
306 * \param[out] v     Pointer to the array within the Ipc::Istream.
307 * \param[out] size  The number of elements found in the stream.
308 *
309 * This routine provdes a possibility to extract an array from an
310 * Ipc::Istream, without extra copy overhead. In contrast to buf_cp_in()
311 * the data is not copied to a buffer, but a pointer to the array is returned.
312 * The user must make sure the UTCB is not used for other purposes while the
313 * returned pointer is still in use.
314 *
315 * The mechanism is comparable to that of Msg_ptr, however it handles arrays
316 * inserted with buf_cp_out().
317 *
318 * \see buf_cp_in() and buf_cp_out().
319 */
320template< typename T >
321Internal::Buf_in<T> buf_in(T *&v, unsigned long &size)
322{ return Internal::Buf_in<T>(v, size); }
323
324namespace Utcb_stream_check
325{
326  static bool check_utcb_data_offset(unsigned sz)
327  { return sz > sizeof(l4_umword_t) * L4_UTCB_GENERIC_DATA_SIZE; }
328}
329
330
331/**
332 * Input stream for IPC unmarshalling.
333 *
334 * Ipc::Istream is part of the dynamic IPC marshalling infrastructure, as well
335 * as Ipc::Ostream and Ipc::Iostream.
336 *
337 * Ipc::Istream is an input stream supporting extraction of values from an
338 * IPC message buffer. A received IPC message can be unmarshalled using the
339 * usual extraction operator (>>).
340 *
341 * There exist some special wrapper classes to extract arrays (see
342 * Ipc_buf_cp_in and Ipc_buf_in) and indirect strings (see Msg_in_buffer and
343 * Msg_io_buffer).
344 */
345class Istream
346{
347public:
348  /**
349   * Create an input stream for the given message buffer.
350   *
351   * The given message buffer is used for IPC operations wait()/receive()
352   * and received data can be extracted using the >> operator afterwards.
353   * In the case of indirect message parts a buffer of type Msg_in_buffer
354   * must be inserted into the stream before the IPC operation and contains
355   * received data afterwards.
356   *
357   * \param utcb  The message buffer to receive IPC messages.
358   */
359  Istream(l4_utcb_t *utcb)
360  : _tag(), _utcb(utcb),
361    _current_msg(reinterpret_cast<char*>(l4_utcb_mr_u(utcb)->mr)),
362    _pos(0), _current_buf(0)
363  {}
364
365  /**
366   * Reset the stream to empty, and ready for receive()/wait().
367   * The stream is reset to the same state as on its creation.
368   */
369  void reset()
370  {
371    _pos = 0;
372    _current_buf = 0;
373    _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
374  }
375
376  /**
377   * Check whether a value of type T can be obtained from the stream.
378   */
379  template< typename T >
380  bool has_more(unsigned long count = 1)
381  {
382    auto const max_bytes = L4_UTCB_GENERIC_DATA_SIZE * sizeof(l4_umword_t);
383    unsigned apos = cxx::Type_traits<T>::align(_pos);
384    return (count <= max_bytes / sizeof(T))
385           && (apos + (sizeof(T) * count)
386               <= _tag.words() * sizeof(l4_umword_t));
387  }
388
389  /**
390   * \name Get/Put Functions.
391   */
392  //@{
393
394  /**
395   * Copy out an array of type `T` with `size` elements.
396   *
397   * \param buf    Pointer to a buffer for size elements of type T.
398   * \param elems  Number of elements of type T to copy out.
399   *
400   * \return  The number of elements copied out.
401   *
402   * See \ref Istream::operator>>()
403   */
404  template< typename T >
405  unsigned long get(T *buf, unsigned long elems)
406  {
407    if (L4_UNLIKELY(!has_more<T>(elems)))
408      return 0;
409
410    unsigned long size = elems * sizeof(T);
411    _pos = cxx::Type_traits<T>::align(_pos);
412
413    __builtin_memcpy(buf, _current_msg + _pos, size);
414    _pos += size;
415    return elems;
416  }
417
418
419  /**
420   * Skip size elements of type T in the stream.
421   *
422   * \param elems  Number of elements to skip.
423   */
424  template< typename T >
425  void skip(unsigned long elems)
426  {
427    if (L4_UNLIKELY(!has_more<T>(elems)))
428      return;
429
430    unsigned long size = elems * sizeof(T);
431    _pos = cxx::Type_traits<T>::align(_pos);
432    _pos += size;
433  }
434
435  /**
436   * Read one size elements of type T from the stream and return a pointer.
437   *
438   * \param buf    A Msg_ptr that is actually set to point to the element in the
439   *               stream.
440   * \param elems  Number of elements to extract (default is 1).
441   *
442   * \return  The number of elements extracted.
443   *
444   * In contrast to a normal get, this version does actually not copy the data
445   * but returns a pointer to the data.
446   *
447   * See \ref Istream::operator>>()
448   */
449  template< typename T >
450  unsigned long get(Msg_ptr<T> const &buf, unsigned long elems = 1)
451  {
452    if (L4_UNLIKELY(!has_more<T>(elems)))
453      return 0;
454
455    unsigned long size = elems * sizeof(T);
456    _pos = cxx::Type_traits<T>::align(_pos);
457
458    buf.set(reinterpret_cast<T*>(_current_msg + _pos));
459    _pos += size;
460    return elems;
461  }
462
463
464  /**
465   * Extract a single element of type T from the stream.
466   *
467   * \param[out] v  The element.
468   *
469   * \retval true   An element was successfully extracted.
470   * \retval false  An element could not be extracted.
471   *
472   * See \ref Istream::operator>>()
473   */
474  template< typename T >
475  bool get(T &v)
476  {
477    if (L4_UNLIKELY(!has_more<T>()))
478      {
479        v = T();
480        return false;
481      }
482
483    _pos = cxx::Type_traits<T>::align(_pos);
484    v = *(reinterpret_cast<T*>(_current_msg + _pos));
485    _pos += sizeof(T);
486    return true;
487  }
488
489
490  bool get(Ipc::Varg *va)
491  {
492    Ipc::Varg::Tag t;
493    if (!has_more<Ipc::Varg::Tag>())
494      {
495        va->tag(0);
496	return 0;
497      }
498    get(t);
499    va->tag(t);
500    char const *d;
501    get(msg_ptr(d), va->length());
502    va->data(d);
503
504    return 1;
505  }
506
507  /**
508   * Get the message tag of a received IPC.
509   *
510   * \return  The L4 message tag for the received IPC.
511   *
512   * This is in particular useful for handling page faults or exceptions.
513   *
514   * See \ref Istream::operator>>()
515   */
516  l4_msgtag_t tag() const { return _tag; }
517
518
519  /**
520   * Get the message tag of a received IPC.
521   *
522   * \return  A reference to the L4 message tag for the received IPC.
523   *
524   * This is in particular useful for handling page faults or exceptions.
525   *
526   * See \ref Istream::operator>>()
527   */
528  l4_msgtag_t &tag() { return _tag; }
529
530  //@}
531
532  /**
533   * \internal
534   * Put a receive item into the stream's buffer registers.
535   */
536  inline bool put(Buf_item const &);
537
538  /**
539   * \internal
540   * Put a small receive item into the stream's buffer registers.
541   */
542  inline bool put(Small_buf const &);
543
544
545  /**
546   * \name IPC operations.
547   */
548  //@{
549
550  /**
551   * Wait for an incoming message from any sender.
552   *
553   * \param[out] src  Contains the sender after a successful IPC operation.
554   *
555   * \return  Syscall return tag.
556   *
557   * This wait is actually known as 'open wait'.
558   */
559  inline l4_msgtag_t wait(l4_umword_t *src)
560  { return wait(src, L4_IPC_NEVER); }
561
562  /**
563   * Wait for an incoming message from any sender.
564   *
565   * \param[out] src      Contains the sender after a successful IPC operation.
566   * \param      timeout  Timeout used for IPC.
567   *
568   * \return  The IPC result tag (l4_msgtag_t).
569   *
570   * This wait is actually known as 'open wait'.
571   */
572  inline l4_msgtag_t wait(l4_umword_t *src, l4_timeout_t timeout);
573
574  /**
575   * Wait for a message from the specified sender.
576   *
577   * \param src  The sender id to receive from.
578   *
579   * \return  The IPC result tag (l4_msgtag_t).
580   *
581   * This is commonly known as 'closed wait'.
582   */
583  inline l4_msgtag_t receive(l4_cap_idx_t src)
584  { return receive(src, L4_IPC_NEVER); }
585  inline l4_msgtag_t receive(l4_cap_idx_t src, l4_timeout_t timeout);
586
587  //@}
588
589  /**
590   * Return utcb pointer.
591   */
592  inline l4_utcb_t *utcb() const { return _utcb; }
593
594protected:
595  l4_msgtag_t _tag;
596  l4_utcb_t *_utcb;
597  char *_current_msg;
598  unsigned _pos;
599  unsigned char _current_buf;
600};
601
602class Istream_copy : public Istream
603{
604private:
605  l4_msg_regs_t _mrs;
606
607public:
608  Istream_copy(Istream const &o) : Istream(o), _mrs(*l4_utcb_mr_u(o.utcb()))
609  {
610    // do some reverse mr to utcb trickery
611    _utcb = (l4_utcb_t *)((l4_addr_t)&_mrs - (l4_addr_t)l4_utcb_mr_u((l4_utcb_t *)0));
612    _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
613  }
614
615};
616
617/**
618 * Output stream for IPC marshalling.
619 *
620 * Ipc::Ostream is part of the dynamic IPC marshalling infrastructure, as well
621 * as Ipc::Istream and Ipc::Iostream.
622 *
623 * Ipc::Ostream is an output stream supporting insertion of values into an
624 * IPC message buffer. A IPC message can be marshalled using the
625 * usual insertion operator <<, see \link ipc_stream IPC stream operators
626 * \endlink.
627 *
628 * There exist some special wrapper classes to insert arrays (see
629 * Ipc::Buf_cp_out) and indirect strings (see Msg_out_buffer and
630 * Msg_io_buffer).
631 */
632class Ostream
633{
634public:
635  /**
636   * Create an IPC output stream using the given message buffer `utcb`.
637   */
638  Ostream(l4_utcb_t *utcb)
639  : _tag(), _utcb(utcb),
640    _current_msg(reinterpret_cast<char *>(l4_utcb_mr_u(_utcb)->mr)),
641    _pos(0), _current_item(0)
642  {}
643
644  /**
645   * Reset the stream to empty, same state as a newly created stream.
646   */
647  void reset()
648  {
649    _pos = 0;
650    _current_item = 0;
651    _current_msg = reinterpret_cast<char*>(l4_utcb_mr_u(_utcb)->mr);
652  }
653
654  /**
655   * \name Get/Put functions.
656   *
657   * These functions are basically used to implement the insertion operators
658   * (<<) and should not be called directly.
659   */
660  //@{
661
662  /**
663   * Put an array with `size` elements of type `T` into the stream.
664   *
665   * \param buf   A pointer to the array to insert into the buffer.
666   * \param size  The number of elements in the array.
667   */
668  template< typename T >
669  bool put(T *buf, unsigned long size)
670  {
671    size *= sizeof(T);
672    _pos = cxx::Type_traits<T>::align(_pos);
673    if (Utcb_stream_check::check_utcb_data_offset(_pos + size))
674      return false;
675
676    __builtin_memcpy(_current_msg + _pos, buf, size);
677    _pos += size;
678    return true;
679  }
680
681  /**
682   * Insert an element of type `T` into the stream.
683   *
684   * \param v  The element to insert.
685   */
686  template< typename T >
687  bool put(T const &v)
688  {
689    _pos = cxx::Type_traits<T>::align(_pos);
690    if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T)))
691      return false;
692
693    *(reinterpret_cast<T*>(_current_msg + _pos)) = v;
694    _pos += sizeof(T);
695    return true;
696  }
697
698  int put(Varg const &va)
699  {
700    put(va.tag());
701    put(va.data(), va.length());
702
703    return 0;
704  }
705
706  template< typename T >
707  int put(Varg_t<T> const &va)
708  { return put(static_cast<Varg const &>(va)); }
709
710  /**
711   * Extract the L4 message tag from the stream.
712   *
713   * \return  The extracted L4 message tag.
714   */
715  l4_msgtag_t tag() const { return _tag; }
716
717  /**
718   * Extract a reference to the L4 message tag from the stream.
719   *
720   * \return  A reference to the L4 message tag.
721   */
722  l4_msgtag_t &tag() { return _tag; }
723
724  //@}
725
726  /**
727   * \internal
728   * Put a send item into the stream's message buffer.
729   */
730  inline bool put_snd_item(Snd_item const &);
731
732
733  /**
734   * \name IPC operations.
735   */
736  //@{
737
738  /**
739   * Send the message via IPC to the given receiver.
740   *
741   * \param dst    The destination for the message.
742   * \param proto  Protocol to use.
743   * \param flags  Flags to use.
744   *
745   * \return  The syscall return tag.
746   */
747  inline l4_msgtag_t send(l4_cap_idx_t dst, long proto = 0, unsigned flags = 0);
748
749  //@}
750
751  /**
752   * Return utcb pointer.
753   */
754  inline l4_utcb_t *utcb() const { return _utcb; }
755#if 0
756  /**
757   * Get the currently used bytes in the stream.
758   */
759  unsigned long tell() const
760  {
761    unsigned w = (_pos + sizeof(l4_umword_t)-1) / sizeof(l4_umword_t);
762    w -= _current_item * 2;
763    _tag = l4_msgtag(0, w, _current_item, 0);
764  }
765#endif
766public:
767  l4_msgtag_t prepare_ipc(long proto = 0, unsigned flags = 0)
768  {
769    unsigned w = (_pos + sizeof(l4_umword_t) - 1) / sizeof(l4_umword_t);
770    w -= _current_item * 2;
771    return l4_msgtag(proto, w, _current_item, flags);
772  }
773
774  // XXX: this is a hack for <l4/sys/cxx/ipc_server> adaption
775  void set_ipc_params(l4_msgtag_t tag)
776  {
777    _pos = (tag.words() + tag.items() * 2) * sizeof(l4_umword_t);
778    _current_item = tag.items();
779  }
780protected:
781  l4_msgtag_t _tag;
782  l4_utcb_t *_utcb;
783  char *_current_msg;
784  unsigned _pos;
785  unsigned char _current_item;
786};
787
788
789/**
790 * Input/Output stream for IPC [un]marshalling.
791 *
792 * The Ipc::Iostream is part of the AW Env IPC framework as well as
793 * Ipc::Istream and Ipc::Ostream.
794 * In particular an Ipc::Iostream is a combination of an Ipc::Istream and an
795 * Ipc::Ostream. It can use either a single message buffer for receiving and
796 * sending messages or a pair of a receive and a send buffer. The stream also
797 * supports combined IPC operations such as call() and reply_and_wait(), which
798 * can be used to implement RPC functionality.
799 */
800class Iostream : public Istream, public Ostream
801{
802public:
803
804  /**
805   * Create an IPC IO stream with a single message buffer.
806   *
807   * \param utcb  The message buffer used as backing store.
808   *
809   * The created IO stream uses the same message buffer for sending and
810   * receiving IPC messages.
811   */
812  explicit Iostream(l4_utcb_t *utcb)
813  : Istream(utcb), Ostream(utcb)
814  {}
815
816  // disambiguate those functions
817  l4_msgtag_t tag() const { return Istream::tag(); }
818  l4_msgtag_t &tag() { return Istream::tag(); }
819  l4_utcb_t *utcb() const { return Istream::utcb(); }
820
821  /**
822   * Reset the stream to its initial state.
823   *
824   * Input as well as the output stream are reset.
825   */
826  void reset()
827  {
828    Istream::reset();
829    Ostream::reset();
830  }
831
832
833  /**
834   * \name Get/Put functions.
835   *
836   * These functions are basically used to implement the insertion operators
837   * (<<) and should not be called directly.
838   */
839  //@{
840
841  using Istream::get;
842  using Istream::put;
843  using Ostream::put;
844
845  //@}
846
847  /**
848   * \name IPC operations.
849   */
850  //@{
851
852  /**
853   * Do an IPC call using the message in the output stream and receive the
854   * reply in the input stream.
855   *
856   * \param dst      The destination to call.
857   * \param timeout  The IPC timeout for the call.
858   * \param proto    The protocol value to use in the message tag.
859   *
860   * \return  The result tag of the IPC operation.
861   *
862   * This is a combined IPC operation consisting of a send and a receive
863   * to/from the given destination `dst`.
864   *
865   * A call is usually used by clients for RPCs to a server.
866   */
867  inline l4_msgtag_t call(l4_cap_idx_t dst, l4_timeout_t timeout, long proto = 0);
868  inline l4_msgtag_t call(l4_cap_idx_t dst, long proto = 0);
869
870  /**
871   * Do an IPC reply and wait.
872   *
873   * \param[in,out] src_dst  Input: the destination for the send operation. <br>
874   *                         Output: the source of the received message.
875   * \param         proto    Protocol to use.
876   *
877   * \return  The result tag of the IPC operation.
878   *
879   * This is a combined IPC operation consisting of a send operation and
880   * an open wait for any message.
881   *
882   * A reply and wait is usually used by servers that reply to a client
883   * and wait for the next request by any other client.
884   */
885  inline l4_msgtag_t reply_and_wait(l4_umword_t *src_dst, long proto = 0)
886  { return reply_and_wait(src_dst, L4_IPC_SEND_TIMEOUT_0, proto); }
887
888  inline l4_msgtag_t send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
889                                   long proto = 0)
890  { return send_and_wait(dest, src, L4_IPC_SEND_TIMEOUT_0, proto); }
891
892  /**
893   * Do an IPC reply and wait.
894   *
895   * \param[in,out] src_dst  Input: the destination for the send operation. <br>
896   *                         Output: the source of the received message.
897   * \param         timeout  Timeout used for IPC.
898   * \param         proto    Protocol to use.
899   *
900   * \return  The result tag of the IPC operation.
901   *
902   * This is a combined IPC operation consisting of a send operation and
903   * an open wait for any message.
904   *
905   * A reply and wait is usually used by servers that reply to a client
906   * and wait for the next request by any other client.
907   */
908  inline l4_msgtag_t reply_and_wait(l4_umword_t *src_dst,
909                                    l4_timeout_t timeout, long proto = 0);
910  inline l4_msgtag_t send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
911                                   l4_timeout_t timeout, long proto = 0);
912  inline l4_msgtag_t reply(l4_timeout_t timeout, long proto = 0);
913  inline l4_msgtag_t reply(long proto = 0)
914  { return reply(L4_IPC_SEND_TIMEOUT_0, proto); }
915
916  //@}
917};
918
919
920inline bool
921Ostream::put_snd_item(Snd_item const &v)
922{
923  typedef Snd_item T;
924  _pos = cxx::Type_traits<Snd_item>::align(_pos);
925  if (Utcb_stream_check::check_utcb_data_offset(_pos + sizeof(T)))
926    return false;
927
928  *(reinterpret_cast<T*>(_current_msg + _pos)) = v;
929  _pos += sizeof(T);
930  ++_current_item;
931  return true;
932}
933
934
935inline bool
936Istream::put(Buf_item const &item)
937{
938  if (_current_buf >= L4_UTCB_GENERIC_BUFFERS_SIZE - 3)
939    return false;
940
941  l4_utcb_br_u(_utcb)->bdr &= ~L4_BDR_OFFSET_MASK;
942
943  reinterpret_cast<Buf_item&>(l4_utcb_br_u(_utcb)->br[_current_buf]) = item;
944  _current_buf += 2;
945  return true;
946}
947
948
949inline bool
950Istream::put(Small_buf const &item)
951{
952  if (_current_buf >= L4_UTCB_GENERIC_BUFFERS_SIZE - 2)
953    return false;
954
955  l4_utcb_br_u(_utcb)->bdr &= ~L4_BDR_OFFSET_MASK;
956
957  reinterpret_cast<Small_buf&>(l4_utcb_br_u(_utcb)->br[_current_buf]) = item;
958  _current_buf += 1;
959  return true;
960}
961
962
963inline l4_msgtag_t
964Ostream::send(l4_cap_idx_t dst, long proto, unsigned flags)
965{
966  l4_msgtag_t tag = prepare_ipc(proto, L4_MSGTAG_FLAGS & flags);
967  return l4_ipc_send(dst, _utcb, tag, L4_IPC_NEVER);
968}
969
970inline l4_msgtag_t
971Iostream::call(l4_cap_idx_t dst, l4_timeout_t timeout, long label)
972{
973  l4_msgtag_t tag = prepare_ipc(label);
974  tag = l4_ipc_call(dst, Ostream::_utcb, tag, timeout);
975  Istream::tag() = tag;
976  Istream::_pos = 0;
977  return tag;
978}
979
980inline l4_msgtag_t
981Iostream::call(l4_cap_idx_t dst, long label)
982{ return call(dst, L4_IPC_NEVER, label); }
983
984
985inline l4_msgtag_t
986Iostream::reply_and_wait(l4_umword_t *src_dst, l4_timeout_t timeout, long proto)
987{
988  l4_msgtag_t tag = prepare_ipc(proto);
989  tag = l4_ipc_reply_and_wait(Ostream::_utcb, tag, src_dst, timeout);
990  Istream::tag() = tag;
991  Istream::_pos = 0;
992  return tag;
993}
994
995
996inline l4_msgtag_t
997Iostream::send_and_wait(l4_cap_idx_t dest, l4_umword_t *src,
998                        l4_timeout_t timeout, long proto)
999{
1000  l4_msgtag_t tag = prepare_ipc(proto);
1001  tag = l4_ipc_send_and_wait(dest, Ostream::_utcb, tag, src, timeout);
1002  Istream::tag() = tag;
1003  Istream::_pos = 0;
1004  return tag;
1005}
1006
1007inline l4_msgtag_t
1008Iostream::reply(l4_timeout_t timeout, long proto)
1009{
1010  l4_msgtag_t tag = prepare_ipc(proto);
1011  tag = l4_ipc_send(L4_INVALID_CAP | L4_SYSF_REPLY, Ostream::_utcb, tag, timeout);
1012  Istream::tag() = tag;
1013  Istream::_pos = 0;
1014  return tag;
1015}
1016
1017inline l4_msgtag_t
1018Istream::wait(l4_umword_t *src, l4_timeout_t timeout)
1019{
1020  l4_msgtag_t res;
1021  res = l4_ipc_wait(_utcb, src, timeout);
1022  tag() = res;
1023  _pos = 0;
1024  return res;
1025}
1026
1027
1028inline l4_msgtag_t
1029Istream::receive(l4_cap_idx_t src, l4_timeout_t timeout)
1030{
1031  l4_msgtag_t res;
1032  res = l4_ipc_receive(src, _utcb, timeout);
1033  tag() = res;
1034  _pos = 0;
1035  return res;
1036}
1037
1038} // namespace Ipc
1039} // namespace L4
1040
1041/**
1042 * Extract one element of type `T` from the stream `s`.
1043 *
1044 * \param      s  The stream to extract from.
1045 * \param[out] v  Extracted value.
1046 *
1047 * \return  The stream `s`.
1048 */
1049inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, bool &v) { s.get(v); return s; }
1050inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, int &v) { s.get(v); return s; }
1051inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, long int &v) { s.get(v); return s; }
1052inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, long long int &v) { s.get(v); return s; }
1053inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned int &v) { s.get(v); return s; }
1054inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned long int &v) { s.get(v); return s; }
1055inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned long long int &v) { s.get(v); return s; }
1056inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, short int &v) { s.get(v); return s; }
1057inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned short int &v) { s.get(v); return s; }
1058inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, char &v) { s.get(v); return s; }
1059inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, unsigned char &v) { s.get(v); return s; }
1060inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, signed char &v) { s.get(v); return s; }
1061inline L4::Ipc::Istream &operator << (L4::Ipc::Istream &s, L4::Ipc::Buf_item const &v) { s.put(v); return s; }
1062inline L4::Ipc::Istream &operator << (L4::Ipc::Istream &s, L4::Ipc::Small_buf const &v) { s.put(v); return s; }
1063inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Snd_item &v)
1064{
1065  l4_umword_t b, d;
1066  s >> b >> d;
1067  v = L4::Ipc::Snd_item(b, d);
1068  return s;
1069}
1070inline L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, L4::Ipc::Varg &v)
1071{ s.get(&v); return s; }
1072
1073
1074/**
1075 * Extract the L4 message tag from the stream `s`.
1076 *
1077 * \param      s  The stream to extract from.
1078 * \param[out] v  The extracted tag.
1079 *
1080 * \return  The stream `s`.
1081 */
1082inline
1083L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s, l4_msgtag_t &v)
1084{
1085  v = s.tag();
1086  return s;
1087}
1088
1089/**
1090 * Extract an array of `T` elements from the stream `s`.
1091 *
1092 * \param      s  The stream to extract from.
1093 * \param[out] v  Pointer to the extracted array (ipc_buf_in()).
1094 *
1095 * \return  The stream `s`.
1096 *
1097 * This operator actually does not copy out the data in the array, but
1098 * returns a pointer into the message buffer itself. This means that the
1099 * data is only valid as long as there is no new data inserted into the stream.
1100 *
1101 * \note If array does not fit into transmitted words size will be set to zero.
1102 * Client has to implement check against zero.
1103 *
1104 * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out.
1105 */
1106template< typename T >
1107inline
1108L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1109                               L4::Ipc::Internal::Buf_in<T> const &v)
1110{
1111  unsigned long si;
1112  if (s.get(si) && s.has_more<T>(si))
1113    v.set_size(s.get(L4::Ipc::Msg_ptr<T>(v.buf()), si));
1114  else
1115    v.set_size(0);
1116  return s;
1117}
1118
1119/**
1120 * Extract an element of type `T` from the stream `s`.
1121 *
1122 * \param      s  The stream to extract from.
1123 * \param[out] v  Pointer to the extracted element.
1124 *
1125 * \return  The stream `s`.
1126 *
1127 * This operator actually does not copy out the data, but
1128 * returns a pointer into the message buffer itself. This means that the
1129 * data is only valid as long as there is no new data inserted into the stream.
1130 *
1131 * See Msg_ptr.
1132 */
1133template< typename T >
1134inline
1135L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1136                               L4::Ipc::Msg_ptr<T> const &v)
1137{
1138  s.get(v);
1139  return s;
1140}
1141
1142/**
1143 * Extract an array of `T` elements from the stream `s`.
1144 *
1145 * \param      s  The stream to extract from.
1146 * \param[out] v  Buffer description to copy the array to (Ipc::Buf_cp_out()).
1147 *
1148 * \return  The stream `s`.
1149 *
1150 * This operator does a copy out of the data into the given buffer.
1151 *
1152 * See Ipc::Buf_in, Ipc::Buf_cp_in, and Ipc::Buf_cp_out.
1153 */
1154template< typename T >
1155inline
1156L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1157                               L4::Ipc::Internal::Buf_cp_in<T> const &v)
1158{
1159  unsigned long sz;
1160  s.get(sz);
1161  v.size() = s.get(v.buf(), cxx::min(v.size(), sz));
1162  return s;
1163}
1164
1165/**
1166 * Extract a zero-terminated string from the stream.
1167 *
1168 * \param      s  The stream to extract from.
1169 * \param[out] v  Buffer description to copy the array to (Ipc::Str_cp_out()).
1170 *
1171 * \return  The stream `s`.
1172 *
1173 * This operator does a copy out of the data into the given buffer.
1174 */
1175template< typename T >
1176inline
1177L4::Ipc::Istream &operator >> (L4::Ipc::Istream &s,
1178                               L4::Ipc::Str_cp_in<T> const &v)
1179{
1180  unsigned long sz;
1181  s.get(sz);
1182  unsigned long rsz = s.get(v.buf(), cxx::min(v.size(), sz));
1183  if (rsz < v.size() && v.buf()[rsz - 1])
1184    ++rsz; // add the zero termination behind the received data
1185
1186  if (rsz != 0)
1187    v.buf()[rsz - 1] = 0;
1188
1189  v.size() = rsz;
1190  return s;
1191}
1192
1193
1194/**
1195 * Insert an element to type `T` into the stream `s`.
1196 *
1197 * \param s  The stream to insert the element `v`.
1198 * \param v  The element to insert.
1199 *
1200 * \return  The stream `s`.
1201 */
1202inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, bool v) { s.put(v); return s; }
1203inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, int v) { s.put(v); return s; }
1204inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, long int v) { s.put(v); return s; }
1205inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, long long int v) { s.put(v); return s; }
1206inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned int v) { s.put(v); return s; }
1207inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned long int v) { s.put(v); return s; }
1208inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned long long int v) { s.put(v); return s; }
1209inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, short int v) { s.put(v); return s; }
1210inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned short int v) { s.put(v); return s; }
1211inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char v) { s.put(v); return s; }
1212inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, unsigned char v) { s.put(v); return s; }
1213inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, signed char v) { s.put(v); return s; }
1214inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Snd_item const &v) { s.put_snd_item(v); return s; }
1215template< typename T >
1216inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Cap<T> const &v)
1217{ s << L4::Ipc::Snd_fpage(v.fpage()); return s; }
1218
1219inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Varg const &v)
1220{ s.put(v); return s; }
1221template< typename T >
1222inline L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, L4::Ipc::Varg_t<T> const &v)
1223{ s.put(v); return s; }
1224
1225/**
1226 * Insert the L4 message tag into the stream `s`.
1227 *
1228 * \param s  The stream to insert the tag `v`.
1229 * \param v  The L4 message tag to insert.
1230 *
1231 * \return  The stream `s`.
1232 *
1233 * \note Only one message tag can be inserted into a stream. Multiple
1234 *       insertions simply overwrite previous insertions.
1235 */
1236inline
1237L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, l4_msgtag_t const &v)
1238{
1239  s.tag() = v;
1240  return s;
1241}
1242
1243/**
1244 * Insert an array with elements of type `T` into the stream `s`.
1245 *
1246 * \param s  The stream to insert the array `v`.
1247 * \param v  The array to insert (see Ipc::Buf_cp_out()).
1248 *
1249 * \return  The stream `s`.
1250 */
1251template< typename T >
1252inline
1253L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s,
1254                               L4::Ipc::Internal::Buf_cp_out<T> const &v)
1255{
1256  s.put(v.size());
1257  s.put(v.buf(), v.size());
1258  return s;
1259}
1260
1261/**
1262 * Insert a zero terminated character string into the stream `s`.
1263 *
1264 * \param s  The stream to insert the string `v`.
1265 * \param v  The string to insert.
1266 *
1267 * \return  The stream `s`.
1268 *
1269 * This operator produces basically the same content as the array insertion,
1270 * however the length of the array is calculated using `strlen(v) + 1`
1271 * The string is copied into the message including the trailing zero.
1272 */
1273inline
1274L4::Ipc::Ostream &operator << (L4::Ipc::Ostream &s, char const *v)
1275{
1276  unsigned long l = __builtin_strlen(v) + 1;
1277  s.put(l);
1278  s.put(v, l);
1279  return s;
1280}
1281
1282namespace L4 { namespace Ipc {
1283/**
1284 * Read a value out of a stream.
1285 *
1286 * \param s  An Istream.
1287 *
1288 * \return  The value of type `T`.
1289 *
1290 * The stream position is progressed accordingly.
1291 */
1292template< typename T >
1293inline
1294T read(Istream &s) { T t; s >> t; return t; }
1295
1296} // namespace Ipc
1297} // namespace L4
1298