fixed sendto() error reporting - hopefully
[senf.git] / senf / Socket / ReadWritePolicy.cc
1 // $Id$
2 //
3 // Copyright (C) 2006
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief ReadPolicy and WritePolicy non-inline non-template implementation
30  */
31
32 #include "ReadWritePolicy.hh"
33 #include "senf/Utils/hexdump.hh"
34 #include "senf/Utils/String.hh"
35 //#include "ReadWritePolicy.ih"
36
37 // Custom includes
38 #include <sys/types.h>
39 #include <sys/socket.h>
40 #include <unistd.h>
41 #include <errno.h>
42
43 //#include "ReadWritePolicy.mpp"
44 #define prefix_
45 //-/////////////////////////////////////////////////////////////////////////////////////////////////
46
47 prefix_ unsigned senf::ReadablePolicy::read(FileHandle & handle, char * buffer,
48                                                    unsigned size)
49 {
50     int rv = -1;
51     do {
52         rv = ::read(handle.fd(), buffer, size);
53         if (rv < 0)
54             switch(errno) {
55             case EINTR:
56                 break;
57             case EAGAIN:
58                 // This means, the socket is non-blocking an no data was available
59                 rv = 0;
60                 break;
61             default:
62                 SENF_THROW_SYSTEM_EXCEPTION(":::read");
63             }
64     } while (rv<0);
65     return rv;
66 }
67
68 prefix_ unsigned senf::ReadablePolicy::do_readfrom(FileHandle & handle, char * buffer,
69                                                           unsigned size,
70                                                           struct ::sockaddr * addr, socklen_t * len)
71 {
72     int rv = -1;
73     do {
74         rv = ::recvfrom(handle.fd(),buffer, size, 0, addr, len);
75         if (rv < 0)
76             switch (errno) {
77             case EINTR:
78                 break;
79             case EAGAIN:
80                 rv = 0;
81                 break;
82             default:
83                 SENF_THROW_SYSTEM_EXCEPTION("::recvfrom");
84             }
85     } while (rv<0);
86     return rv;
87 }
88
89 prefix_ unsigned senf::WriteablePolicy::do_write(FileHandle & handle, char const * buffer,
90                                                         unsigned size)
91 {
92     int rv = -1;
93     do {
94         rv = ::write(handle.fd(), buffer, size);
95         if (rv < 0)
96             switch (errno) {
97             case EINTR:
98                 break;
99             case EAGAIN:
100             case ENOBUFS:
101                 // According to the man page this should not happen, since packets are just silently being dropped.
102                 // It does happen in NetEmu using small TxQueues on WLAN interfaces 
103             case ECONNREFUSED:
104                 // Writing to a UDP socket seems return this error code if a corresponding ICMP
105                 // error code has been received before (at least on linux). This is inconsistent
106                 // since I cannot rely on getting ECONNREFUSED. I therefore ignore this error. TCP
107                 // sockets will return this error on connect() and not on write(). Therefore we can
108                 // unconditionally ignore this error here.
109                 rv = 0;
110                 break;
111             default:
112                 SENF_THROW_SYSTEM_EXCEPTION("::write");
113             }
114     } while (rv<0);
115     return rv;
116 }
117
118 prefix_ unsigned senf::WriteablePolicy::do_writeto(FileHandle & handle,
119                                                           char const * buffer, unsigned size,
120                                                           struct sockaddr const * addr, socklen_t len)
121 {
122     int rv = -1;
123     do {
124         rv = ::sendto(handle.fd(), buffer, size, 0, addr, len);
125         if (rv < 0)
126             switch (errno) {
127             case EINTR:
128                 break;
129             case EAGAIN:
130             case ENOBUFS:
131                 // According to the man page this should not happen, since packets are just silently being dropped.
132                 // It does happen in NetEmu using small TxQueues on WLAN interfaces 
133                 rv = 0;
134                 break;
135             default:
136                 std::stringstream a, b;
137                 senf::hexdump( (char*) addr , ((char*) addr) + len , a);
138                 senf::hexdump( (char*) buffer , ((char*) buffer) + size , b);
139                 SENF_THROW_SYSTEM_EXCEPTION("::sendto(" + b.str() + ") to " + a.str());
140             }
141     } while (rv<0);
142     return rv;
143 }
144
145 //-/////////////////////////////////////////////////////////////////////////////////////////////////
146 #undef prefix_
147 //#include "ReadWritePolicy.mpp"
148
149 \f
150 // Local Variables:
151 // mode: c++
152 // fill-column: 100
153 // c-file-style: "senf"
154 // indent-tabs-mode: nil
155 // ispell-local-dictionary: "american"
156 // compile-command: "scons -u test"
157 // comment-column: 40
158 // End: