summaryrefslogtreecommitdiff
path: root/ace/OS_NS_sys_uio.cpp
blob: 708ea5701a32b4ea29293d559aed952606ea6840 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// $Id$

#include "ace/OS_NS_sys_uio.h"

ACE_RCSID(ace, OS_NS_sys_uio, "$Id$")

#if !defined (ACE_HAS_INLINED_OSCALLS)
# include "ace/OS_NS_sys_uio.inl"
#endif /* ACE_HAS_INLINED_OS_CALLS */

#include "ace/OS_Memory.h"
#include "ace/OS_NS_string.h"
#include "ace/OS_NS_unistd.h"

ACE_BEGIN_VERSIONED_NAMESPACE_DECL

# if defined (ACE_LACKS_READV)

// "Fake" readv for operating systems without it.  Note that this is
// thread-safe.

ssize_t
ACE_OS::readv_emulation (ACE_HANDLE handle,
                         const iovec *iov,
                         int n)
{
  ACE_OS_TRACE ("ACE_OS::readv_emulation");

  // In case there's a single element, skip the memcpy.
  if (1 == n)
    return ACE_OS::read (handle, iov[0].iov_base, iov[0].iov_len);

  ssize_t length = 0;
  int i;

  for (i = 0; i < n; ++i)
    if (static_cast<int> (iov[i].iov_len) < 0)
      return -1;
    else
      length += iov[i].iov_len;

  char *buf;
#   if defined (ACE_HAS_ALLOCA)
  buf = (char *) alloca (length);
#   else
  ACE_NEW_RETURN (buf,
                  char[length],
                  -1);
#   endif /* !defined (ACE_HAS_ALLOCA) */

  length = ACE_OS::read (handle, buf, length);

  if (length != -1)
    {
      char *ptr = buf;
      ssize_t copyn = length;

      for (i = 0;
           i < n && copyn > 0;
           ++i)
        {
          ACE_OS::memcpy (iov[i].iov_base, ptr,
                          // iov_len is int on some platforms, size_t on others
                          copyn > (int) iov[i].iov_len
                            ? (size_t) iov[i].iov_len
                            : (size_t) copyn);
          ptr += iov[i].iov_len;
          copyn -= iov[i].iov_len;
        }
    }

#   if !defined (ACE_HAS_ALLOCA)
  delete [] buf;
#   endif /* !defined (ACE_HAS_ALLOCA) */
  return length;
}
# endif /* ACE_LACKS_READV */

# if defined (ACE_LACKS_WRITEV)

// "Fake" writev for operating systems without it.  Note that this is
// thread-safe.

ssize_t
ACE_OS::writev_emulation (ACE_HANDLE handle, const iovec *iov, int n)
{
  ACE_OS_TRACE ("ACE_OS::writev_emulation");

  // To avoid having to allocate a temporary buffer to which all of
  // the data will be copied and then written, this implementation
  // performs incremental writes.

  ssize_t bytes_sent = 0;

  for (int i = 0; i < n; ++i)
    {
      const ssize_t result =
        ACE_OS::write (handle, iov[i].iov_base, iov[i].iov_len);

      if (result == -1)
        {
          // There is a subtle difference in behaviour depending on
          // whether or not any data was sent.  If no data was sent,
          // then always return -1.  Otherwise return bytes_sent.
          // This gives the caller an opportunity to keep track of
          // bytes that have already been sent.
          if (bytes_sent > 0)
            break;
          else
            return -1;
        }
      else
        {
          bytes_sent += result;

          // Do not continue on to the next loop iteration if the
          // amount of data sent was less than the amount data given.
          // This avoids a subtle problem where "holes" in the data
          // stream would occur if partial sends of a given buffer in
          // the iovec array occured.
          if (static_cast<size_t> (result) < iov[i].iov_len)
            break;
        }
    }

  return bytes_sent;
}
# endif /* ACE_LACKS_WRITEV */

ACE_END_VERSIONED_NAMESPACE_DECL