Library of Assembled Shared Sources
socket_libc.inl
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43#include "../io_common.h"
44#include "../socket.h"
46#include <sys/socket.h>
47#include <sys/types.h>
48#include <netinet/in.h>
49#include <netdb.h>
50#include <unistd.h>
51
52#pragma GCC diagnostic ignored "-Wconversion" // htons, can't avoid conversion within macro.
53
54namespace lass
55{
56namespace io
57{
58namespace impl
59{
60
61class SocketImpl: public util::NonCopyable
62{
63public:
64 typedef Socket::TPort TPort;
65
66 SocketImpl():
67 socket_(invalidSocket)
68 {
69 }
70
71 ~SocketImpl()
72 {
73 try
74 {
75 closeSocket();
76 }
77 catch (const std::exception& error)
78 {
79 std::cerr << "[LASS RUN MSG] WARNING: closeSocket() failed: " << error.what();
80 }
81 }
82
83 void bind(const std::string& address, TPort portNumber)
84 {
85 openSocket();
86
87 ::sockaddr_in addr;
88 if (address.empty())
89 {
90 addr.sin_addr.s_addr = htonl(INADDR_ANY);
91 }
92 else
93 {
94 ::hostent* other = gethostbyname(address.c_str());
95 if (!other)
96 {
97 LASS_THROW_EX(SocketError, "could not bind " << address << ":" << portNumber << " : failed to lookup hostname.");
98 }
99 addr.sin_addr = *(in_addr*) other->h_addr;
100 }
101 addr.sin_family = AF_INET;
102 addr.sin_port = htons(portNumber);
103
104 if (::bind(socket_, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)) != 0)
105 {
106 const int err = util::impl::lass_errno();
107 LASS_THROW_EX(SocketError, "Failed to bind socket to port " << portNumber
108 << ": " << util::impl::lass_strerror(err));
109 }
110 }
111
112 std::string address() const
113 {
114 /*sockaddr_in addr;
115 addr.sin_family = AF_INET;
116 socklen_t size = sizeof(addr);
117 if (::getsockname(socket_, (sockaddr*)&addr, &size) != 0)
118 {
119 const int err = util::impl::lass_errno();
120 LASS_THROW_EX(SocketError, "Failed to retrieve address: " << util::impl::lass_strerror(err));
121 }
122 return ::inet_ntoa(addr.sin_addr);*/
123 return "";
124 }
125
126 TPort port() const
127 {
128 /*sockaddr_in addr;
129 addr.sin_family = AF_INET;
130 socklen_t size = sizeof(addr);
131 if (::getsockname(socket_, (sockaddr*)&addr, &size) != 0)
132 {
133 const int err = util::impl::lass_errno();
134 LASS_THROW_EX(SocketError, "Failed to retrieve address: " << util::impl::lass_strerror(err));
135 }
136 return ::ntohs(addr.sin_port);*/
137 return 0;
138 }
139
140 void listen()
141 {
142 LASS_ASSERT(socket_ != invalidSocket);
143 if (::listen(socket_, SOMAXCONN) != 0)
144 {
145 const int err = util::impl::lass_errno();
146 LASS_THROW_EX(SocketError, "Failed to listen: " << util::impl::lass_strerror(err));
147 }
148 }
149
150 void accept(SocketImpl* connection) const
151 {
152 LASS_ASSERT(socket_ != invalidSocket);
153 int socket = ::accept(socket_, 0, 0);
154 if (socket == invalidSocket)
155 {
156 const int err = util::impl::lass_errno();
157 LASS_THROW_EX(SocketError, "Failed to accept connection: " << util::impl::lass_strerror(err));
158 }
159 LASS_ASSERT(connection);
160 connection->socket_ = socket;
161 }
162
163 void connect(const std::string& ipAddress, unsigned short portNumber)
164 {
165 openSocket();
166
167 ::hostent* other = gethostbyname(ipAddress.c_str());
168 if (!other)
169 {
170 LASS_THROW_EX(SocketError, "could not connect " << ipAddress << ":" << portNumber << " : failed to lookup hostname.");
171 }
172
173 sockaddr_in dest;
174 dest.sin_addr = *(in_addr*) other->h_addr;
175 dest.sin_family = PF_INET;
176 dest.sin_port = htons(portNumber);
177 const int ret = ::connect(socket_, reinterpret_cast<sockaddr*>(&dest), sizeof(dest));
178 if (ret != 0)
179 {
180 const int err = util::impl::lass_errno();
181 LASS_THROW_EX(SocketError, "Could not connect " << ipAddress << ":" << portNumber
182 << " : " << util::impl::lass_strerror(err));
183 }
184 }
185
186 int send(const void* begin, int length) const
187 {
188 LASS_ASSERT(socket_ != invalidSocket);
189 const int ret = ::send(socket_, static_cast<const char*>(begin), length, 0);
190 if (ret == -1)
191 {
192 const int err = util::impl::lass_errno();
193 LASS_THROW_EX(SocketError, "Failed to send data: " << util::impl::lass_strerror(err));
194 }
195 LASS_ASSERT(ret >= 0);
196 return ret;
197 }
198
199 int receive(void* begin, int length) const
200 {
201 const int ret = ::recv(socket_, static_cast<char*>(begin), length, 0);
202 if (ret == -1)
203 {
204 const int err = util::impl::lass_errno();
205 LASS_THROW_EX(SocketError, "Failed to receive data: " << util::impl::lass_strerror(err));
206 }
207 LASS_ASSERT(ret >= 0);
208 return ret;
209 }
210
211 int sizeSendBuffer() const
212 {
213 return 4096; // stub impl
214 }
215
216 void openSocket()
217 {
218 if (socket_ != invalidSocket)
219 {
220 return;
221 }
222 socket_ = socket(AF_INET, SOCK_STREAM, 0);
223 if (socket_ == invalidSocket)
224 {
225 const int err = util::impl::lass_errno();
226 LASS_THROW_EX(SocketError, "Failed to create socket: " << util::impl::lass_strerror(err));
227 }
228 }
229
230 void closeSocket()
231 {
232 if (socket_ == invalidSocket)
233 {
234 return;
235 }
236 const int ret = close(socket_);
237 if (ret != 0)
238 {
239 const int err = util::impl::lass_errno();
240 LASS_THROW_EX(SocketError, "Failed to close socket: " << util::impl::lass_strerror(err));
241 }
242 socket_ = invalidSocket;
243 }
244
245private:
246
247 enum { invalidSocket = -1 };
248
249 int socket_;
250};
251
252}
253}
254}
255
256// EOF
const std::string lass_strerror(int errnum)
returns message associated to an CLIB error code
int lass_errno()
returns CLIB errno
streams, binary streams, vrmlstreams, ...
Library for Assembled Shared Sources.
Definition config.h:53