Library of Assembled Shared Sources
socket_winsock.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-2024 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 <winsock.h>
47
48#if LASS_PLATFORM_TYPE == LASS_PLATFORM_TYPE_WIN32
49# pragma comment(lib, "ws2_32.lib")
50#endif
51
52namespace lass
53{
54namespace io
55{
56namespace impl
57{
58
59class SocketImpl: public util::NonCopyable
60{
61public:
62
63 typedef Socket::TPort TPort;
64
65 SocketImpl():
66 socket_(INVALID_SOCKET)
67 {
68 WSADATA wsaData;
69 if (::WSAStartup(0x0202, &wsaData) != 0)
70 {
71 LASS_THROW_EX(SocketError, "Failed to startup Windows Socket API.");
72 }
73 if (wsaData.wVersion != 0x0202)
74 {
75 ::WSACleanup();
76 LASS_THROW_EX(SocketError, "Windows Socket API is not version 2.2.");
77 }
78 }
79
80 ~SocketImpl()
81 {
82 try
83 {
84 closeSocket();
85 }
86 catch (const std::exception& error)
87 {
88 std::cerr << "[LASS RUN MSG] WARNING: closeSocket() failed: " << error.what();
89 }
90 [[maybe_unused]] const int err = ::WSACleanup();
91 LASS_ASSERT(err == 0);
92 }
93
94 void bind(const std::string& address, TPort port)
95 {
96 openSocket();
97
98 SOCKADDR_IN addr;
99 addr.sin_family = AF_INET;
100 addr.sin_addr.s_addr = address.empty() ? ::htonl(INADDR_ANY) : ::inet_addr(address.c_str());
101 addr.sin_port = ::htons(port);
102
103 if (::bind(socket_, (LPSOCKADDR)&addr, sizeof(addr)) != 0)
104 {
105 LASS_THROW_EX(SocketError, "Failed to bind socket to port " << port);
106 }
107 }
108
109 void listen() const
110 {
111 LASS_ASSERT(socket_ != INVALID_SOCKET);
112 ::listen(socket_, SOMAXCONN);
113 }
114
115 void accept(SocketImpl* connection) const
116 {
117 LASS_ASSERT(socket_ != INVALID_SOCKET);
118 SOCKET conn = ::accept(socket_, 0, 0);
119 if (conn == INVALID_SOCKET)
120 {
121 LASS_THROW_EX(SocketError, "Failed to accept connection");
122 }
123 LASS_ASSERT(connection);
124 connection->socket_ = conn;
125 }
126
127 void connect(const std::string& address, TPort port)
128 {
129 openSocket();
130
131 SOCKADDR_IN dest;
132 dest.sin_family = AF_INET;
133 dest.sin_addr.s_addr = ::inet_addr(address.c_str());
134 dest.sin_port = ::htons(port);
135 const int ret = ::connect(socket_, reinterpret_cast<SOCKADDR*>(&dest), sizeof(dest));
136 if (ret == SOCKET_ERROR)
137 {
138 LASS_THROW_EX(SocketError, "could not connect " << address << ":" << port);
139 }
140 }
141
142 std::string address() const
143 {
144 SOCKADDR_IN addr;
145 addr.sin_family = AF_INET;
146 int size = sizeof(addr);
147 if (::getsockname(socket_, (LPSOCKADDR)&addr, &size) != 0)
148 {
149 LASS_THROW_EX(SocketError, "Failed to retrieve address");
150 }
151 return ::inet_ntoa(addr.sin_addr);
152 }
153
154 TPort port() const
155 {
156 SOCKADDR_IN addr;
157 addr.sin_family = AF_INET;
158 int size = sizeof(addr);
159 if (::getsockname(socket_, (LPSOCKADDR)&addr, &size) != 0)
160 {
161 LASS_THROW_EX(SocketError, "Failed to retrieve port number");
162 }
163 return ::ntohs(addr.sin_port);
164 }
165
166 int send(const void* begin, int length) const
167 {
168 LASS_ASSERT(socket_ != INVALID_SOCKET);
169 const int ret = ::send(socket_, static_cast<const char*>(begin), length, 0);
170 if (ret == SOCKET_ERROR)
171 {
172 LASS_THROW_EX(SocketError, "Failure to send data: " << WSAGetLastError());
173 }
174 LASS_ASSERT(ret >= 0);
175 return ret;
176 }
177
178 int receive(void* begin, int length) const
179 {
180 const int ret = ::recv(socket_, static_cast<char*>(begin), length, 0);
181 if (ret == SOCKET_ERROR)
182 {
183 LASS_THROW_EX(SocketError, "Failure to receive data: " << WSAGetLastError());
184 }
185 LASS_ASSERT(ret >= 0);
186 return ret;
187 }
188
189 int sizeSendBuffer() const
190 {
191 LASS_ASSERT(socket_ != INVALID_SOCKET);
192 int size;
193 int optlen = sizeof(size);
194 const int ret = ::getsockopt(socket_, SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&size), &optlen);
195 if (ret == SOCKET_ERROR || optlen != sizeof(size))
196 {
197 LASS_THROW_EX(SocketError, "failed to query send buffer size");
198 }
199 return size;
200 }
201
202 void openSocket()
203 {
204 if (socket_ != INVALID_SOCKET)
205 {
206 return;
207 }
208 socket_ = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
209 if (socket_ == INVALID_SOCKET)
210 {
211 LASS_THROW_EX(SocketError, "Failed to create socket.");
212 }
213 }
214 void closeSocket()
215 {
216 if (socket_ == INVALID_SOCKET)
217 {
218 return;
219 }
220 const int err = ::closesocket(socket_);
221 if (err != 0)
222 {
223 LASS_THROW_EX(SocketError, "Failed to close socket");
224 }
225 socket_ = INVALID_SOCKET;
226 }
227
228private:
229
230 SOCKET socket_;
231};
232
233}
234}
235}
236
237// EOF
streams, binary streams, vrmlstreams, ...
Library for Assembled Shared Sources.
Definition config.h:53