~schuster/mysql-proxy/remove_unix_socket

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
}