538
by Kay Roepke
merge copyright changes |
1 |
/* $%BEGINLICENSE%$
|
1037
by Kay Roepke
update copyright notices to oracle, update modification years |
2 |
Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
|
538
by Kay Roepke
merge copyright changes |
3 |
|
1037
by Kay Roepke
update copyright notices to oracle, update modification years |
4 |
This program is free software; you can redistribute it and/or
|
5 |
modify it under the terms of the GNU General Public License as
|
|
6 |
published by the Free Software Foundation; version 2 of the
|
|
7 |
License.
|
|
538
by Kay Roepke
merge copyright changes |
8 |
|
9 |
This program is distributed in the hope that it will be useful,
|
|
10 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
1037
by Kay Roepke
update copyright notices to oracle, update modification years |
11 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
538
by Kay Roepke
merge copyright changes |
12 |
GNU General Public License for more details.
|
13 |
||
14 |
You should have received a copy of the GNU General Public License
|
|
15 |
along with this program; if not, write to the Free Software
|
|
1037
by Kay Roepke
update copyright notices to oracle, update modification years |
16 |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
|
17 |
02110-1301 USA
|
|
538
by Kay Roepke
merge copyright changes |
18 |
|
19 |
$%ENDLICENSE%$ */
|
|
20 |
||
69
by jkneschke
added connection pooling |
21 |
|
22 |
#ifdef HAVE_CONFIG_H
|
|
23 |
#include "config.h" |
|
24 |
#endif
|
|
25 |
||
26 |
#ifndef _WIN32
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
27 |
#include <sys/ioctl.h> |
28 |
#include <sys/socket.h> |
|
532
by Kay Roepke
merge a lot of changes... |
29 |
#include <sys/uio.h> /* writev */ |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
30 |
|
400
by Jan Kneschke
merged Kay's freebsd changes |
31 |
#ifdef HAVE_SYS_TYPES_H
|
32 |
#include <sys/types.h> |
|
33 |
#endif
|
|
34 |
||
636.1.9
by jan at mysql
fixed compile on solaris about missing FIONREAD |
35 |
#ifdef HAVE_SYS_FILIO_H
|
36 |
/**
|
|
37 |
* required for FIONREAD on solaris
|
|
38 |
*/
|
|
39 |
#include <sys/filio.h> |
|
40 |
#endif
|
|
41 |
||
42 |
||
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
43 |
#include <arpa/inet.h> /** inet_ntoa */ |
44 |
#include <netinet/in.h> |
|
45 |
#include <netinet/tcp.h> |
|
46 |
||
47 |
#include <netdb.h> |
|
69
by jkneschke
added connection pooling |
48 |
#include <unistd.h> |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
49 |
#else
|
50 |
#include <winsock2.h> |
|
51 |
#include <io.h> |
|
52 |
#define ioctl ioctlsocket
|
|
53 |
#endif
|
|
54 |
||
55 |
#include <stdlib.h> |
|
445
by jan at mysql
added #include <string.h> as we use strlen() and friends |
56 |
#include <string.h> |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
57 |
#include <errno.h> |
58 |
#include <fcntl.h> |
|
59 |
||
60 |
#ifdef HAVE_WRITEV
|
|
61 |
#define USE_BUFFERED_NETIO
|
|
62 |
#else
|
|
63 |
#undef USE_BUFFERED_NETIO
|
|
64 |
#endif
|
|
65 |
||
66 |
#ifdef _WIN32
|
|
67 |
#define E_NET_CONNRESET WSAECONNRESET
|
|
68 |
#define E_NET_CONNABORTED WSAECONNABORTED
|
|
69 |
#define E_NET_WOULDBLOCK WSAEWOULDBLOCK
|
|
70 |
#define E_NET_INPROGRESS WSAEINPROGRESS
|
|
71 |
#else
|
|
72 |
#define E_NET_CONNRESET ECONNRESET
|
|
73 |
#define E_NET_CONNABORTED ECONNABORTED
|
|
74 |
#define E_NET_INPROGRESS EINPROGRESS
|
|
75 |
#if EWOULDBLOCK == EAGAIN
|
|
76 |
/**
|
|
77 |
* some system make EAGAIN == EWOULDBLOCK which would lead to a
|
|
78 |
* error in the case handling
|
|
79 |
*
|
|
80 |
* set it to -1 as this error should never happen
|
|
81 |
*/
|
|
82 |
#define E_NET_WOULDBLOCK -1
|
|
83 |
#else
|
|
84 |
#define E_NET_WOULDBLOCK EWOULDBLOCK
|
|
85 |
#endif
|
|
86 |
#endif
|
|
87 |
||
69
by jkneschke
added connection pooling |
88 |
|
89 |
#include "network-socket.h" |
|
90 |
#include "network-mysqld-proto.h" |
|
468
by Kay Roepke
merge with jan's changes |
91 |
#include "network-mysqld-packet.h" |
69
by jkneschke
added connection pooling |
92 |
|
598
by jan at mysql
tagged network_socket_init() and network_queue_init() as deprecated |
93 |
#ifndef DISABLE_DEPRECATED_DECL
|
69
by jkneschke
added connection pooling |
94 |
network_socket *network_socket_init() { |
598
by jan at mysql
tagged network_socket_init() and network_queue_init() as deprecated |
95 |
return network_socket_new(); |
96 |
}
|
|
97 |
#endif
|
|
98 |
||
99 |
network_socket *network_socket_new() { |
|
69
by jkneschke
added connection pooling |
100 |
network_socket *s; |
101 |
||
102 |
s = g_new0(network_socket, 1); |
|
103 |
||
598
by jan at mysql
tagged network_socket_init() and network_queue_init() as deprecated |
104 |
s->send_queue = network_queue_new(); |
105 |
s->recv_queue = network_queue_new(); |
|
106 |
s->recv_queue_raw = network_queue_new(); |
|
69
by jkneschke
added connection pooling |
107 |
|
147
by jkneschke
larger cleanup for stmt-balancing: |
108 |
s->default_db = g_string_new(NULL); |
329
by Jan Kneschke
merged Kays changes |
109 |
s->fd = -1; |
848
by jan at mysql
added UDP support to the network-core |
110 |
s->socket_type = SOCK_STREAM; /* let's default to TCP */ |
794
by jan at mysql
moved the packet-id handling down into the core |
111 |
s->packet_id_is_reset = TRUE; |
329
by Jan Kneschke
merged Kays changes |
112 |
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
113 |
s->src = network_address_new(); |
114 |
s->dst = network_address_new(); |
|
115 |
||
69
by jkneschke
added connection pooling |
116 |
return s; |
117 |
}
|
|
118 |
||
119 |
void network_socket_free(network_socket *s) { |
|
120 |
if (!s) return; |
|
121 |
||
122 |
network_queue_free(s->send_queue); |
|
123 |
network_queue_free(s->recv_queue); |
|
302
by Jan Kneschke
merged the chassis |
124 |
network_queue_free(s->recv_queue_raw); |
184
by jkneschke
mixing two bugfixes (fixes #30668) |
125 |
|
431
by Kay Roepke
merge |
126 |
if (s->response) network_mysqld_auth_response_free(s->response); |
127 |
if (s->challenge) network_mysqld_auth_challenge_free(s->challenge); |
|
128 |
||
575
by jan at mysql
replaced .addr by ->dst and ->src |
129 |
network_address_free(s->dst); |
130 |
network_address_free(s->src); |
|
69
by jkneschke
added connection pooling |
131 |
|
304
by Jan Kneschke
merged the chassis changes from head |
132 |
event_del(&(s->event)); |
133 |
||
69
by jkneschke
added connection pooling |
134 |
if (s->fd != -1) { |
135 |
closesocket(s->fd); |
|
136 |
}
|
|
137 |
||
147
by jkneschke
larger cleanup for stmt-balancing: |
138 |
g_string_free(s->default_db, TRUE); |
69
by jkneschke
added connection pooling |
139 |
|
140 |
g_free(s); |
|
141 |
}
|
|
142 |
||
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
143 |
/**
|
144 |
* portable 'set non-blocking io'
|
|
145 |
*
|
|
636.1.33
by jan at mysql
fixed all warnings from doxygen about wrong doc-comments |
146 |
* @param sock a socket
|
147 |
* @return NETWORK_SOCKET_SUCCESS on success, NETWORK_SOCKET_ERROR on error
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
148 |
*/
|
149 |
network_socket_retval_t network_socket_set_non_blocking(network_socket *sock) { |
|
150 |
int ret; |
|
151 |
#ifdef _WIN32
|
|
152 |
int ioctlvar; |
|
153 |
||
154 |
ioctlvar = 1; |
|
155 |
ret = ioctlsocket(sock->fd, FIONBIO, &ioctlvar); |
|
156 |
#else
|
|
157 |
ret = fcntl(sock->fd, F_SETFL, O_NONBLOCK | O_RDWR); |
|
158 |
#endif
|
|
159 |
if (ret != 0) { |
|
160 |
#ifdef _WIN32
|
|
161 |
errno = WSAGetLastError(); |
|
162 |
#endif
|
|
163 |
g_critical("%s.%d: set_non_blocking() failed: %s (%d)", |
|
164 |
__FILE__, __LINE__, |
|
444
by jan at mysql
use g_strerror() instead of strerror() to satisfy win32 |
165 |
g_strerror(errno), errno); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
166 |
return NETWORK_SOCKET_ERROR; |
167 |
}
|
|
168 |
return NETWORK_SOCKET_SUCCESS; |
|
169 |
}
|
|
170 |
||
171 |
/**
|
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
172 |
* accept a connection
|
173 |
*
|
|
174 |
* event handler for listening connections
|
|
175 |
*
|
|
636.1.33
by jan at mysql
fixed all warnings from doxygen about wrong doc-comments |
176 |
* @param srv a listening socket
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
177 |
*
|
178 |
*/
|
|
179 |
network_socket *network_socket_accept(network_socket *srv) { |
|
180 |
network_socket *client; |
|
181 |
||
182 |
g_return_val_if_fail(srv, NULL); |
|
848
by jan at mysql
added UDP support to the network-core |
183 |
g_return_val_if_fail(srv->socket_type == SOCK_STREAM, NULL); /* accept() only works on stream sockets */ |
575
by jan at mysql
replaced .addr by ->dst and ->src |
184 |
|
598
by jan at mysql
tagged network_socket_init() and network_queue_init() as deprecated |
185 |
client = network_socket_new(); |
575
by jan at mysql
replaced .addr by ->dst and ->src |
186 |
|
187 |
if (-1 == (client->fd = accept(srv->fd, &client->src->addr.common, &(client->src->len)))) { |
|
188 |
network_socket_free(client); |
|
189 |
||
190 |
return NULL; |
|
191 |
}
|
|
192 |
||
193 |
network_socket_set_non_blocking(client); |
|
194 |
||
195 |
if (network_address_refresh_name(client->src)) { |
|
196 |
network_socket_free(client); |
|
197 |
return NULL; |
|
198 |
}
|
|
199 |
||
200 |
/* the listening side may be INADDR_ANY, let's get which address the client really connected to */
|
|
201 |
if (-1 == getsockname(client->fd, &client->dst->addr.common, &(client->dst->len))) { |
|
581
by jan at mysql
reset the network-address on eror instead of free()ing it |
202 |
network_address_reset(client->dst); |
575
by jan at mysql
replaced .addr by ->dst and ->src |
203 |
} else if (network_address_refresh_name(client->dst)) { |
581
by jan at mysql
reset the network-address on eror instead of free()ing it |
204 |
network_address_reset(client->dst); |
575
by jan at mysql
replaced .addr by ->dst and ->src |
205 |
}
|
206 |
||
207 |
return client; |
|
208 |
}
|
|
209 |
||
210 |
static network_socket_retval_t network_socket_connect_setopts(network_socket *sock) { |
|
807
by Kay Roepke
Fix linking errors on Win32: |
211 |
#ifdef WIN32
|
212 |
char val = 1; /* Win32 setsockopt wants a const char* instead of the UNIX void*...*/ |
|
213 |
#else
|
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
214 |
int val = 1; |
807
by Kay Roepke
Fix linking errors on Win32: |
215 |
#endif
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
216 |
/**
|
217 |
* set the same options as the mysql client
|
|
218 |
*/
|
|
219 |
#ifdef IP_TOS
|
|
220 |
val = 8; |
|
221 |
setsockopt(sock->fd, IPPROTO_IP, IP_TOS, &val, sizeof(val)); |
|
222 |
#endif
|
|
223 |
val = 1; |
|
224 |
setsockopt(sock->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val) ); |
|
225 |
val = 1; |
|
226 |
setsockopt(sock->fd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val) ); |
|
227 |
||
581
by jan at mysql
reset the network-address on eror instead of free()ing it |
228 |
/* the listening side may be INADDR_ANY, let's get which address the client really connected to */
|
229 |
if (-1 == getsockname(sock->fd, &sock->src->addr.common, &(sock->src->len))) { |
|
230 |
g_debug("%s: getsockname() failed: %s (%d)", |
|
231 |
G_STRLOC, |
|
232 |
g_strerror(errno), |
|
233 |
errno); |
|
234 |
network_address_reset(sock->src); |
|
235 |
} else if (network_address_refresh_name(sock->src)) { |
|
236 |
g_debug("%s: network_address_refresh_name() failed", |
|
237 |
G_STRLOC); |
|
238 |
network_address_reset(sock->src); |
|
239 |
}
|
|
240 |
||
575
by jan at mysql
replaced .addr by ->dst and ->src |
241 |
return NETWORK_SOCKET_SUCCESS; |
242 |
}
|
|
243 |
||
244 |
/**
|
|
245 |
* finish the non-blocking connect()
|
|
246 |
*
|
|
247 |
* sets 'errno' as if connect() would have failed
|
|
248 |
*
|
|
249 |
*/
|
|
250 |
network_socket_retval_t network_socket_connect_finish(network_socket *sock) { |
|
251 |
int so_error = 0; |
|
788
by jan at mysql
fixed accept() failures on HP/UX 64 |
252 |
network_socklen_t so_error_len = sizeof(so_error); |
575
by jan at mysql
replaced .addr by ->dst and ->src |
253 |
|
254 |
/**
|
|
255 |
* we might get called a 2nd time after a connect() == EINPROGRESS
|
|
256 |
*/
|
|
810
by Kay Roepke
fix socketpair handling on windows, use send/recv instead of write/read on the "ping-fd" |
257 |
#ifdef _WIN32
|
258 |
/* need to cast to get rid of the compiler warning. otherwise identical to the UNIX version below. */
|
|
259 |
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, (char*)&so_error, &so_error_len)) { |
|
260 |
errno = WSAGetLastError(); |
|
261 |
#else
|
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
262 |
if (getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &so_error, &so_error_len)) { |
263 |
#endif
|
|
264 |
/* getsockopt failed */
|
|
810
by Kay Roepke
fix socketpair handling on windows, use send/recv instead of write/read on the "ping-fd" |
265 |
g_critical("%s: getsockopt(%s) failed: %s (%d)", |
575
by jan at mysql
replaced .addr by ->dst and ->src |
266 |
G_STRLOC, |
810
by Kay Roepke
fix socketpair handling on windows, use send/recv instead of write/read on the "ping-fd" |
267 |
sock->dst->name->str, g_strerror(errno), errno); |
575
by jan at mysql
replaced .addr by ->dst and ->src |
268 |
return NETWORK_SOCKET_ERROR; |
269 |
}
|
|
270 |
||
271 |
switch (so_error) { |
|
272 |
case 0: |
|
273 |
network_socket_connect_setopts(sock); |
|
274 |
||
275 |
return NETWORK_SOCKET_SUCCESS; |
|
276 |
default: |
|
277 |
errno = so_error; |
|
278 |
||
279 |
return NETWORK_SOCKET_ERROR_RETRY; |
|
280 |
}
|
|
281 |
}
|
|
282 |
||
283 |
/**
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
284 |
* connect a socket
|
285 |
*
|
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
286 |
* the sock->addr has to be set before
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
287 |
*
|
636.1.33
by jan at mysql
fixed all warnings from doxygen about wrong doc-comments |
288 |
* @param sock a socket
|
289 |
* @return NETWORK_SOCKET_SUCCESS on connected, NETWORK_SOCKET_ERROR on error, NETWORK_SOCKET_ERROR_RETRY for try again
|
|
588
by jan at mysql
added extra checks for calling _connect() against a already setup socket |
290 |
* @see network_address_set_address()
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
291 |
*/
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
292 |
network_socket_retval_t network_socket_connect(network_socket *sock) { |
588
by jan at mysql
added extra checks for calling _connect() against a already setup socket |
293 |
g_return_val_if_fail(sock->dst, NETWORK_SOCKET_ERROR); /* our _new() allocated it already */ |
294 |
g_return_val_if_fail(sock->dst->name->len, NETWORK_SOCKET_ERROR); /* we want to use the ->name in the error-msgs */ |
|
295 |
g_return_val_if_fail(sock->fd < 0, NETWORK_SOCKET_ERROR); /* we already have a valid fd, we don't want to leak it */ |
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
296 |
g_return_val_if_fail(sock->socket_type == SOCK_STREAM, NETWORK_SOCKET_ERROR); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
297 |
|
298 |
/**
|
|
588
by jan at mysql
added extra checks for calling _connect() against a already setup socket |
299 |
* create a socket for the requested address
|
300 |
*
|
|
301 |
* if the dst->addr isn't set yet, socket() will fail with unsupported type
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
302 |
*/
|
848
by jan at mysql
added UDP support to the network-core |
303 |
if (-1 == (sock->fd = socket(sock->dst->addr.common.sa_family, sock->socket_type, 0))) { |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
304 |
#ifdef _WIN32
|
305 |
errno = WSAGetLastError(); |
|
306 |
#endif
|
|
307 |
g_critical("%s.%d: socket(%s) failed: %s (%d)", |
|
308 |
__FILE__, __LINE__, |
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
309 |
sock->dst->name->str, g_strerror(errno), errno); |
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
310 |
return NETWORK_SOCKET_ERROR; |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
311 |
}
|
312 |
||
313 |
/**
|
|
314 |
* make the connect() call non-blocking
|
|
315 |
*
|
|
316 |
*/
|
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
317 |
network_socket_set_non_blocking(sock); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
318 |
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
319 |
if (-1 == connect(sock->fd, &sock->dst->addr.common, sock->dst->len)) { |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
320 |
#ifdef _WIN32
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
321 |
errno = WSAGetLastError(); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
322 |
#endif
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
323 |
/**
|
324 |
* in most TCP cases we connect() will return with
|
|
325 |
* EINPROGRESS ... 3-way handshake
|
|
326 |
*/
|
|
327 |
switch (errno) { |
|
328 |
case E_NET_INPROGRESS: |
|
329 |
case E_NET_WOULDBLOCK: /* win32 uses WSAEWOULDBLOCK */ |
|
330 |
return NETWORK_SOCKET_ERROR_RETRY; |
|
331 |
default: |
|
332 |
g_critical("%s.%d: connect(%s) failed: %s (%d)", |
|
333 |
__FILE__, __LINE__, |
|
334 |
sock->dst->name->str, |
|
444
by jan at mysql
use g_strerror() instead of strerror() to satisfy win32 |
335 |
g_strerror(errno), errno); |
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
336 |
return NETWORK_SOCKET_ERROR; |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
337 |
}
|
338 |
}
|
|
339 |
||
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
340 |
network_socket_connect_setopts(sock); |
341 |
||
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
342 |
return NETWORK_SOCKET_SUCCESS; |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
343 |
}
|
344 |
||
345 |
/**
|
|
346 |
* connect a socket
|
|
347 |
*
|
|
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
348 |
* the con->dst->addr has to be set before
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
349 |
*
|
350 |
* @param con a socket
|
|
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
351 |
* @return NETWORK_SOCKET_SUCCESS on connected, NETWORK_SOCKET_ERROR on error
|
352 |
*
|
|
353 |
* @see network_address_set_address()
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
354 |
*/
|
355 |
network_socket_retval_t network_socket_bind(network_socket * con) { |
|
807
by Kay Roepke
Fix linking errors on Win32: |
356 |
#ifdef WIN32
|
357 |
char val = 1; /* Win32 setsockopt wants a const char* instead of the UNIX void*...*/ |
|
358 |
#else
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
359 |
int val = 1; |
807
by Kay Roepke
Fix linking errors on Win32: |
360 |
#endif
|
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
361 |
g_return_val_if_fail(con->fd < 0, NETWORK_SOCKET_ERROR); /* socket is already bound */ |
848
by jan at mysql
added UDP support to the network-core |
362 |
g_return_val_if_fail((con->socket_type == SOCK_DGRAM) || (con->socket_type == SOCK_STREAM), NETWORK_SOCKET_ERROR); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
363 |
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
364 |
if (con->socket_type == SOCK_STREAM) { |
365 |
g_return_val_if_fail(con->dst, NETWORK_SOCKET_ERROR); |
|
366 |
g_return_val_if_fail(con->dst->name->len > 0, NETWORK_SOCKET_ERROR); |
|
367 |
||
368 |
if (-1 == (con->fd = socket(con->dst->addr.common.sa_family, con->socket_type, 0))) { |
|
369 |
g_critical("%s: socket(%s) failed: %s (%d)", |
|
370 |
G_STRLOC, |
|
371 |
con->dst->name->str, |
|
372 |
g_strerror(errno), errno); |
|
373 |
return NETWORK_SOCKET_ERROR; |
|
374 |
}
|
|
375 |
||
376 |
if (con->dst->addr.common.sa_family == AF_INET || |
|
377 |
con->dst->addr.common.sa_family == AF_INET6) { |
|
848
by jan at mysql
added UDP support to the network-core |
378 |
if (0 != setsockopt(con->fd, IPPROTO_TCP, TCP_NODELAY, &val, sizeof(val))) { |
379 |
g_critical("%s: setsockopt(%s, IPPROTO_TCP, TCP_NODELAY) failed: %s (%d)", |
|
380 |
G_STRLOC, |
|
381 |
con->dst->name->str, |
|
382 |
g_strerror(errno), errno); |
|
383 |
return NETWORK_SOCKET_ERROR; |
|
384 |
}
|
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
385 |
|
386 |
if (0 != setsockopt(con->fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val))) { |
|
387 |
g_critical("%s: setsockopt(%s, SOL_SOCKET, SO_REUSEADDR) failed: %s (%d)", |
|
388 |
G_STRLOC, |
|
389 |
con->dst->name->str, |
|
390 |
g_strerror(errno), errno); |
|
391 |
return NETWORK_SOCKET_ERROR; |
|
392 |
}
|
|
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
393 |
}
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
394 |
|
395 |
if (-1 == bind(con->fd, &con->dst->addr.common, con->dst->len)) { |
|
396 |
g_critical("%s: bind(%s) failed: %s (%d)", |
|
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
397 |
G_STRLOC, |
398 |
con->dst->name->str, |
|
399 |
g_strerror(errno), errno); |
|
400 |
return NETWORK_SOCKET_ERROR; |
|
401 |
}
|
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
402 |
|
848
by jan at mysql
added UDP support to the network-core |
403 |
if (-1 == listen(con->fd, 128)) { |
404 |
g_critical("%s: listen(%s, 128) failed: %s (%d)", |
|
405 |
G_STRLOC, |
|
406 |
con->dst->name->str, |
|
407 |
g_strerror(errno), errno); |
|
408 |
return NETWORK_SOCKET_ERROR; |
|
409 |
}
|
|
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
410 |
} else { |
411 |
/* UDP sockets bind the ->src address */
|
|
412 |
g_return_val_if_fail(con->src, NETWORK_SOCKET_ERROR); |
|
413 |
g_return_val_if_fail(con->src->name->len > 0, NETWORK_SOCKET_ERROR); |
|
414 |
||
415 |
if (-1 == (con->fd = socket(con->src->addr.common.sa_family, con->socket_type, 0))) { |
|
416 |
g_critical("%s: socket(%s) failed: %s (%d)", |
|
417 |
G_STRLOC, |
|
418 |
con->src->name->str, |
|
419 |
g_strerror(errno), errno); |
|
420 |
return NETWORK_SOCKET_ERROR; |
|
421 |
}
|
|
422 |
||
423 |
if (-1 == bind(con->fd, &con->src->addr.common, con->src->len)) { |
|
424 |
g_critical("%s: bind(%s) failed: %s (%d)", |
|
425 |
G_STRLOC, |
|
426 |
con->src->name->str, |
|
427 |
g_strerror(errno), errno); |
|
428 |
return NETWORK_SOCKET_ERROR; |
|
429 |
}
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
430 |
}
|
431 |
||
1050
by michael.schuster at oracle
remove unix socket at shutdown: remove race window, make logic for "remove the once we created only" better |
432 |
con->dst->can_unlink_socket = TRUE; |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
433 |
return NETWORK_SOCKET_SUCCESS; |
434 |
}
|
|
435 |
||
436 |
/**
|
|
437 |
* read a data from the socket
|
|
438 |
*
|
|
439 |
* @param sock the socket
|
|
440 |
*/
|
|
397
by Jan Kneschke
merged the new peek(), pop() and test-cases around network_queue |
441 |
network_socket_retval_t network_socket_read(network_socket *sock) { |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
442 |
gssize len; |
443 |
||
444 |
if (sock->to_read > 0) { |
|
445 |
GString *packet = g_string_sized_new(sock->to_read); |
|
446 |
||
447 |
g_queue_push_tail(sock->recv_queue_raw->chunks, packet); |
|
448 |
||
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
449 |
if (sock->socket_type == SOCK_STREAM) { |
450 |
len = recv(sock->fd, packet->str, sock->to_read, 0); |
|
451 |
} else { |
|
452 |
/* UDP */
|
|
962
by jan at mysql
fixed recvfrom() support on HPUX (recvfrom() wants int instead of socklen_t) |
453 |
network_socklen_t dst_len = sizeof(sock->dst->addr.common); |
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
454 |
len = recvfrom(sock->fd, packet->str, sock->to_read, 0, &(sock->dst->addr.common), &(dst_len)); |
455 |
sock->dst->len = dst_len; |
|
456 |
}
|
|
457 |
if (-1 == len) { |
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
458 |
#ifdef _WIN32
|
459 |
errno = WSAGetLastError(); |
|
460 |
#endif
|
|
461 |
switch (errno) { |
|
462 |
case E_NET_CONNABORTED: |
|
463 |
case E_NET_CONNRESET: /** nothing to read, let's let ioctl() handle the close for us */ |
|
464 |
case E_NET_WOULDBLOCK: /** the buffers are empty, try again later */ |
|
465 |
case EAGAIN: |
|
466 |
return NETWORK_SOCKET_WAIT_FOR_EVENT; |
|
467 |
default: |
|
444
by jan at mysql
use g_strerror() instead of strerror() to satisfy win32 |
468 |
g_debug("%s: recv() failed: %s (errno=%d)", G_STRLOC, g_strerror(errno), errno); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
469 |
return NETWORK_SOCKET_ERROR; |
470 |
}
|
|
471 |
} else if (len == 0) { |
|
472 |
/**
|
|
473 |
* connection close
|
|
474 |
*
|
|
475 |
* let's call the ioctl() and let it handle it for use
|
|
476 |
*/
|
|
477 |
return NETWORK_SOCKET_WAIT_FOR_EVENT; |
|
478 |
}
|
|
479 |
||
480 |
sock->to_read -= len; |
|
481 |
sock->recv_queue_raw->len += len; |
|
482 |
#if 0
|
|
483 |
sock->recv_queue_raw->offset = 0; /* offset into the first packet */
|
|
484 |
#endif
|
|
485 |
packet->len = len; |
|
486 |
}
|
|
487 |
||
488 |
return NETWORK_SOCKET_SUCCESS; |
|
489 |
}
|
|
490 |
||
491 |
#ifdef HAVE_WRITEV
|
|
492 |
/**
|
|
493 |
* write data to the socket
|
|
494 |
*
|
|
495 |
*/
|
|
496 |
static network_socket_retval_t network_socket_write_writev(network_socket *con, int send_chunks) { |
|
497 |
/* send the whole queue */
|
|
498 |
GList *chunk; |
|
499 |
struct iovec *iov; |
|
500 |
gint chunk_id; |
|
501 |
gint chunk_count; |
|
502 |
gssize len; |
|
503 |
int os_errno; |
|
523
by Kay Roepke
merge |
504 |
gint max_chunk_count; |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
505 |
|
506 |
if (send_chunks == 0) return NETWORK_SOCKET_SUCCESS; |
|
507 |
||
508 |
chunk_count = send_chunks > 0 ? send_chunks : (gint)con->send_queue->chunks->length; |
|
509 |
||
510 |
if (chunk_count == 0) return NETWORK_SOCKET_SUCCESS; |
|
511 |
||
523
by Kay Roepke
merge |
512 |
max_chunk_count = sysconf(_SC_IOV_MAX); |
513 |
||
514 |
if (max_chunk_count < 0) { /* option is unknown */ |
|
524
by Kay Roepke
merge |
515 |
#if defined(UIO_MAXIOV)
|
516 |
max_chunk_count = UIO_MAXIOV; /* as defined in POSIX */ |
|
517 |
#elif defined(IOV_MAX)
|
|
523
by Kay Roepke
merge |
518 |
max_chunk_count = IOV_MAX; /* on older Linux'es */ |
519 |
#else
|
|
520 |
g_assert_not_reached(); /* make sure we provide a work-around in case sysconf() fails on us */ |
|
521 |
#endif
|
|
522 |
}
|
|
523 |
||
524 |
chunk_count = chunk_count > max_chunk_count ? max_chunk_count : chunk_count; |
|
525 |
||
526 |
g_assert_cmpint(chunk_count, >, 0); /* make sure it is never negative */ |
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
527 |
|
528 |
iov = g_new0(struct iovec, chunk_count); |
|
529 |
||
530 |
for (chunk = con->send_queue->chunks->head, chunk_id = 0; |
|
531 |
chunk && chunk_id < chunk_count; |
|
532 |
chunk_id++, chunk = chunk->next) { |
|
533 |
GString *s = chunk->data; |
|
534 |
||
535 |
if (chunk_id == 0) { |
|
536 |
g_assert(con->send_queue->offset < s->len); |
|
537 |
||
538 |
iov[chunk_id].iov_base = s->str + con->send_queue->offset; |
|
539 |
iov[chunk_id].iov_len = s->len - con->send_queue->offset; |
|
540 |
} else { |
|
541 |
iov[chunk_id].iov_base = s->str; |
|
542 |
iov[chunk_id].iov_len = s->len; |
|
543 |
}
|
|
544 |
}
|
|
545 |
||
546 |
len = writev(con->fd, iov, chunk_count); |
|
547 |
os_errno = errno; |
|
548 |
||
549 |
g_free(iov); |
|
550 |
||
551 |
if (-1 == len) { |
|
552 |
switch (os_errno) { |
|
553 |
case E_NET_WOULDBLOCK: |
|
554 |
case EAGAIN: |
|
555 |
return NETWORK_SOCKET_WAIT_FOR_EVENT; |
|
556 |
case EPIPE: |
|
557 |
case E_NET_CONNRESET: |
|
558 |
case E_NET_CONNABORTED: |
|
559 |
/** remote side closed the connection */
|
|
560 |
return NETWORK_SOCKET_ERROR; |
|
561 |
default: |
|
562 |
g_message("%s.%d: writev(%s, ...) failed: %s", |
|
563 |
__FILE__, __LINE__, |
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
564 |
con->dst->name->str, |
444
by jan at mysql
use g_strerror() instead of strerror() to satisfy win32 |
565 |
g_strerror(errno)); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
566 |
return NETWORK_SOCKET_ERROR; |
567 |
}
|
|
568 |
} else if (len == 0) { |
|
569 |
return NETWORK_SOCKET_ERROR; |
|
570 |
}
|
|
571 |
||
572 |
con->send_queue->offset += len; |
|
532
by Kay Roepke
merge a lot of changes... |
573 |
con->send_queue->len -= len; |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
574 |
|
575 |
/* check all the chunks which we have sent out */
|
|
576 |
for (chunk = con->send_queue->chunks->head; chunk; ) { |
|
577 |
GString *s = chunk->data; |
|
578 |
||
579 |
if (con->send_queue->offset >= s->len) { |
|
580 |
con->send_queue->offset -= s->len; |
|
581 |
||
582 |
g_string_free(s, TRUE); |
|
583 |
||
584 |
g_queue_delete_link(con->send_queue->chunks, chunk); |
|
585 |
||
586 |
chunk = con->send_queue->chunks->head; |
|
587 |
} else { |
|
588 |
return NETWORK_SOCKET_WAIT_FOR_EVENT; |
|
589 |
}
|
|
590 |
}
|
|
591 |
||
592 |
return NETWORK_SOCKET_SUCCESS; |
|
593 |
}
|
|
594 |
#endif
|
|
595 |
||
596 |
/**
|
|
597 |
* write data to the socket
|
|
598 |
*
|
|
599 |
* use a loop over send() to be compatible with win32
|
|
600 |
*/
|
|
848
by jan at mysql
added UDP support to the network-core |
601 |
static network_socket_retval_t network_socket_write_send(network_socket *con, int send_chunks) { |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
602 |
/* send the whole queue */
|
603 |
GList *chunk; |
|
604 |
||
605 |
if (send_chunks == 0) return NETWORK_SOCKET_SUCCESS; |
|
606 |
||
607 |
for (chunk = con->send_queue->chunks->head; chunk; ) { |
|
608 |
GString *s = chunk->data; |
|
609 |
gssize len; |
|
610 |
||
611 |
g_assert(con->send_queue->offset < s->len); |
|
612 |
||
848
by jan at mysql
added UDP support to the network-core |
613 |
if (con->socket_type == SOCK_STREAM) { |
614 |
len = send(con->fd, s->str + con->send_queue->offset, s->len - con->send_queue->offset, 0); |
|
615 |
} else { |
|
616 |
len = sendto(con->fd, s->str + con->send_queue->offset, s->len - con->send_queue->offset, 0, &(con->dst->addr.common), con->dst->len); |
|
617 |
}
|
|
618 |
if (-1 == len) { |
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
619 |
#ifdef _WIN32
|
620 |
errno = WSAGetLastError(); |
|
621 |
#endif
|
|
622 |
switch (errno) { |
|
623 |
case E_NET_WOULDBLOCK: |
|
624 |
case EAGAIN: |
|
625 |
return NETWORK_SOCKET_WAIT_FOR_EVENT; |
|
626 |
case EPIPE: |
|
627 |
case E_NET_CONNRESET: |
|
628 |
case E_NET_CONNABORTED: |
|
629 |
/** remote side closed the connection */
|
|
630 |
return NETWORK_SOCKET_ERROR; |
|
631 |
default: |
|
632 |
g_message("%s: send(%s, %"G_GSIZE_FORMAT") failed: %s", |
|
633 |
G_STRLOC, |
|
575
by jan at mysql
replaced .addr by ->dst and ->src |
634 |
con->dst->name->str, |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
635 |
s->len - con->send_queue->offset, |
444
by jan at mysql
use g_strerror() instead of strerror() to satisfy win32 |
636 |
g_strerror(errno)); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
637 |
return NETWORK_SOCKET_ERROR; |
638 |
}
|
|
639 |
} else if (len == 0) { |
|
640 |
return NETWORK_SOCKET_ERROR; |
|
641 |
}
|
|
642 |
||
643 |
con->send_queue->offset += len; |
|
644 |
||
645 |
if (con->send_queue->offset == s->len) { |
|
646 |
g_string_free(s, TRUE); |
|
647 |
||
648 |
g_queue_delete_link(con->send_queue->chunks, chunk); |
|
649 |
con->send_queue->offset = 0; |
|
650 |
||
651 |
if (send_chunks > 0 && --send_chunks == 0) break; |
|
652 |
||
653 |
chunk = con->send_queue->chunks->head; |
|
654 |
} else { |
|
655 |
return NETWORK_SOCKET_WAIT_FOR_EVENT; |
|
656 |
}
|
|
657 |
}
|
|
658 |
||
1053
by michael.schuster at oracle
fix diversion |
659 |
con->dst->can_unlink_socket = TRUE; |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
660 |
return NETWORK_SOCKET_SUCCESS; |
661 |
}
|
|
662 |
||
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
663 |
/**
|
664 |
* write a content of con->send_queue to the socket
|
|
665 |
*
|
|
636.1.33
by jan at mysql
fixed all warnings from doxygen about wrong doc-comments |
666 |
* @param con socket to read from
|
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
667 |
* @param send_chunks number of chunks to send, if < 0 send all
|
668 |
*
|
|
669 |
* @returns NETWORK_SOCKET_SUCCESS on success, NETWORK_SOCKET_ERROR on error and NETWORK_SOCKET_WAIT_FOR_EVENT if the call would have blocked
|
|
670 |
*/
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
671 |
network_socket_retval_t network_socket_write(network_socket *con, int send_chunks) { |
848
by jan at mysql
added UDP support to the network-core |
672 |
if (con->socket_type == SOCK_STREAM) { |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
673 |
#ifdef HAVE_WRITEV
|
848
by jan at mysql
added UDP support to the network-core |
674 |
return network_socket_write_writev(con, send_chunks); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
675 |
#else
|
848
by jan at mysql
added UDP support to the network-core |
676 |
return network_socket_write_send(con, send_chunks); |
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
677 |
#endif
|
848
by jan at mysql
added UDP support to the network-core |
678 |
} else { |
679 |
return network_socket_write_send(con, send_chunks); |
|
680 |
}
|
|
396
by Jan Kneschke
merged indenpendent changes from the rest tree |
681 |
}
|
682 |
||
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
683 |
network_socket_retval_t network_socket_to_read(network_socket *sock) { |
684 |
int b = -1; |
|
685 |
||
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
686 |
#ifdef SO_NREAD
|
687 |
/* on MacOS X ioctl(..., FIONREAD) returns _more_ than what we have in the queue */
|
|
688 |
if (sock->socket_type == SOCK_DGRAM) { |
|
962
by jan at mysql
fixed recvfrom() support on HPUX (recvfrom() wants int instead of socklen_t) |
689 |
network_socklen_t b_len = sizeof(b); |
850
by jan at mysql
for UDP we bind() to the src-address as _read() will set the dst-address to write to |
690 |
|
691 |
if (0 != getsockopt(sock->fd, SOL_SOCKET, SO_NREAD, &b, &b_len)) { |
|
692 |
g_critical("%s: getsockopt(%d, SO_NREAD, ...) failed: %s (%d)", |
|
693 |
G_STRLOC, |
|
694 |
sock->fd, |
|
695 |
g_strerror(errno), errno); |
|
696 |
return NETWORK_SOCKET_ERROR; |
|
697 |
} else if (b < 0) { |
|
698 |
g_critical("%s: getsockopt(%d, SO_NREAD, ...) succeeded, but is negative: %d", |
|
699 |
G_STRLOC, |
|
700 |
sock->fd, |
|
701 |
b); |
|
702 |
||
703 |
return NETWORK_SOCKET_ERROR; |
|
704 |
} else { |
|
705 |
sock->to_read = b; |
|
706 |
return NETWORK_SOCKET_SUCCESS; |
|
707 |
}
|
|
708 |
}
|
|
709 |
#endif
|
|
710 |
||
584
by jan at mysql
all network_socket_* calls should really return network_socket_retval_t instead of just integers |
711 |
if (0 != ioctl(sock->fd, FIONREAD, &b)) { |
712 |
g_critical("%s: ioctl(%d, FIONREAD, ...) failed: %s (%d)", |
|
713 |
G_STRLOC, |
|
714 |
sock->fd, |
|
715 |
g_strerror(errno), errno); |
|
716 |
return NETWORK_SOCKET_ERROR; |
|
717 |
} else if (b < 0) { |
|
718 |
g_critical("%s: ioctl(%d, FIONREAD, ...) succeeded, but is negative: %d", |
|
719 |
G_STRLOC, |
|
720 |
sock->fd, |
|
721 |
b); |
|
722 |
||
723 |
return NETWORK_SOCKET_ERROR; |
|
724 |
} else { |
|
725 |
sock->to_read = b; |
|
726 |
return NETWORK_SOCKET_SUCCESS; |
|
727 |
}
|
|
728 |
||
729 |
}
|