e576bb | 2002-10-11 | Martin Nilsson | |
|
aedfb1 | 2002-10-09 | Martin Nilsson | |
|
6afca9 | 2000-07-29 | Fredrik Hübinette (Hubbe) | | #define NO_PIKE_SHORTHAND
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | #include "global.h"
|
574088 | 1998-01-01 | Fredrik Hübinette (Hubbe) | | #include "fdlib.h"
|
5f1c62 | 2003-04-30 | Henrik Grubbström (Grubba) | | #include "pike_netlib.h"
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | #include "interpret.h"
#include "svalue.h"
#include "stralloc.h"
#include "array.h"
#include "object.h"
|
bb55f8 | 1997-03-16 | Fredrik Hübinette (Hubbe) | | #include "pike_macros.h"
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | #include "backend.h"
#include "fd_control.h"
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | | #include "threads.h"
|
852415 | 1999-12-14 | Fredrik Hübinette (Hubbe) | | #include "program_id.h"
|
c4d100 | 2004-05-14 | Martin Nilsson | | #include "module_support.h"
|
f01020 | 2011-11-16 | Tobias S. Josefowitz | | #include "time_stuff.h"
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
#include "file_machine.h"
#include "file.h"
|
bdfb86 | 1997-12-22 | Fredrik Hübinette (Hubbe) | | #ifdef HAVE_SYS_PARAM_H
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | #include <sys/param.h>
|
bdfb86 | 1997-12-22 | Fredrik Hübinette (Hubbe) | | #endif
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | #include <errno.h>
#include <fcntl.h>
#include <signal.h>
|
bdfb86 | 1997-12-22 | Fredrik Hübinette (Hubbe) | | #ifdef HAVE_SYS_WAIT_H
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | #include <sys/wait.h>
|
bdfb86 | 1997-12-22 | Fredrik Hübinette (Hubbe) | | #endif
#ifdef HAVE_SYS_SOCKET_H
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | #include <sys/socket.h>
|
bdfb86 | 1997-12-22 | Fredrik Hübinette (Hubbe) | | #endif
|
5ad6ac | 1995-09-25 | Per Hedbor | | #ifdef HAVE_SYS_STREAM_H
#include <sys/stream.h>
|
2a15e5 | 1996-11-25 | Fredrik Hübinette (Hubbe) | |
#ifdef u
#undef u
#endif
|
5ad6ac | 1995-09-25 | Per Hedbor | | #endif
#ifdef HAVE_SYS_PROTOSW_H
#include <sys/protosw.h>
#endif
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | #ifdef HAVE_SYS_SOCKETVAR_H
#include <sys/socketvar.h>
#endif
|
905884 | 2004-05-13 | Martin Nilsson | | #ifdef HAVE_SYS_UN_H
#include <sys/un.h>
#endif
|
61e9a0 | 1998-01-25 | Fredrik Hübinette (Hubbe) | |
|
f4b4de | 2014-10-17 | Henrik Grubbström (Grubba) | | #if !defined(SOL_TCP) && defined(IPPROTO_TCP)
|
adde17 | 2014-10-17 | Henrik Grubbström (Grubba) | |
#define SOL_TCP IPPROTO_TCP
#endif
|
66f19d | 2002-02-14 | Martin Nilsson | |
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | struct port
{
|
10dac8 | 2004-04-05 | Martin Stjernholm | | struct fd_callback_box box;
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | | int my_errno;
|
f01020 | 2011-11-16 | Tobias S. Josefowitz | | unsigned int immediate_cnt;
|
10dac8 | 2004-04-05 | Martin Stjernholm | | struct svalue accept_callback;
struct svalue id;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | };
|
bdfb86 | 1997-12-22 | Fredrik Hübinette (Hubbe) | | #undef THIS
|
206c15 | 2000-07-07 | Henrik Grubbström (Grubba) | | #define THIS ((struct port *)(Pike_fp->current_storage))
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
74dfe8 | 2012-12-30 | Jonas Walldén | | static int got_port_event (struct fd_callback_box *box, int DEBUGUSED(event))
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
10dac8 | 2004-04-05 | Martin Stjernholm | | struct port *p = (struct port *) box;
#ifdef PIKE_DEBUG
#ifndef __NT__
if(!query_nonblocking(p->box.fd))
Pike_fatal("Port is in blocking mode in port accept callback!!!\n");
#endif
if (event != PIKE_FD_READ)
Pike_fatal ("Got unexpected event %d.\n", event);
#endif
p->my_errno = errno;
|
f01020 | 2011-11-16 | Tobias S. Josefowitz | | p->immediate_cnt++;
|
10dac8 | 2004-04-05 | Martin Stjernholm | | push_svalue (&p->id);
apply_svalue(& p->accept_callback, 1);
pop_stack();
return 0;
}
|
0941cf | 2003-10-15 | Henrik Grubbström (Grubba) | |
|
10dac8 | 2004-04-05 | Martin Stjernholm | | static void assign_accept_cb (struct port *p, struct svalue *cb)
{
assign_svalue(& p->accept_callback, cb);
if (UNSAFE_IS_ZERO (cb)) {
if (p->box.backend)
|
ca6bd0 | 2012-05-01 | Bill Welliver | | set_fd_callback_events (&p->box, 0, 0);
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | set_nonblocking(p->box.fd,0);
|
10dac8 | 2004-04-05 | Martin Stjernholm | | }
else {
if (!p->box.backend)
INIT_FD_CALLBACK_BOX (&p->box, default_backend, p->box.ref_obj,
|
ca6bd0 | 2012-05-01 | Bill Welliver | | p->box.fd, PIKE_BIT_FD_READ, got_port_event, 0);
|
10dac8 | 2004-04-05 | Martin Stjernholm | | else
|
ca6bd0 | 2012-05-01 | Bill Welliver | | set_fd_callback_events (&p->box, PIKE_BIT_FD_READ, 0);
|
10dac8 | 2004-04-05 | Martin Stjernholm | | set_nonblocking(p->box.fd,1);
}
}
static void do_close(struct port *p)
{
retry:
if(p->box.fd >= 0)
{
if(fd_close(p->box.fd) < 0)
|
700dac | 2002-02-05 | Martin Stjernholm | | if(errno == EINTR) {
check_threads_etc();
|
d3ef71 | 1995-11-02 | Fredrik Hübinette (Hubbe) | | goto retry;
|
700dac | 2002-02-05 | Martin Stjernholm | | }
|
10dac8 | 2004-04-05 | Martin Stjernholm | | change_fd_for_box (&p->box, -1);
|
f3c715 | 2001-04-14 | Fredrik Hübinette (Hubbe) | | }
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }
|
de411a | 2002-04-01 | Martin Nilsson | | |
66f19d | 2002-02-14 | Martin Nilsson | | *!
|
de411a | 2002-04-01 | Martin Nilsson | | *! This function sets the id used for accept_callback by this port.
*! The default id is @[this_object()].
*!
*! @seealso
*! @[query_id]
|
66f19d | 2002-02-14 | Martin Nilsson | | */
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | static void port_set_id(INT32 args)
{
|
c4d100 | 2004-05-14 | Martin Nilsson | | check_all_args("Port->set_id", args, BIT_MIXED, 0);
|
6afca9 | 2000-07-29 | Fredrik Hübinette (Hubbe) | | assign_svalue(& THIS->id, Pike_sp-args);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args-1);
}
|
66f19d | 2002-02-14 | Martin Nilsson | | |
de411a | 2002-04-01 | Martin Nilsson | | *! This function returns the id for this port. The id is normally the
*! first argument to accept_callback.
*!
*! @seealso
*! @[set_id]
|
66f19d | 2002-02-14 | Martin Nilsson | | */
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | static void port_query_id(INT32 args)
{
pop_n_elems(args);
|
6afca9 | 2000-07-29 | Fredrik Hübinette (Hubbe) | | assign_svalue_no_free(Pike_sp++,& THIS->id);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }
|
66f19d | 2002-02-14 | Martin Nilsson | | |
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! If the last call done on this port failed, this function will
*! return an integer describing what went wrong. Refer to your unix
*! manual for further information.
|
66f19d | 2002-02-14 | Martin Nilsson | | */
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | static void port_errno(INT32 args)
{
pop_n_elems(args);
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | | push_int(THIS->my_errno);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }
|
de411a | 2002-04-01 | Martin Nilsson | | |
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! This function does the same as @[bind], except that instead of
*! creating a new socket and bind it to a port, it expects the file
*! descriptor @[fd] to be an already open port.
|
66f19d | 2002-02-14 | Martin Nilsson | | *!
|
de411a | 2002-04-01 | Martin Nilsson | | *! @note
*! This function is only for the advanced user, and is generally used
*! when sockets are passed to Pike at exec time.
*!
*! @seealso
*! @[bind], @[accept]
|
66f19d | 2002-02-14 | Martin Nilsson | | */
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | static void port_listen_fd(INT32 args)
{
|
10dac8 | 2004-04-05 | Martin Stjernholm | | struct port *p = THIS;
|
ddc1a3 | 2010-07-27 | Martin Stjernholm | | struct svalue *cb = NULL;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | int fd;
|
10dac8 | 2004-04-05 | Martin Stjernholm | | do_close(p);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
69c0aa | 2014-08-25 | Martin Nilsson | | get_all_args("listen_fd", args, "%d.%*", &fd, &cb);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
b80e8b | 2000-05-20 | Per Hedbor | | if(fd<0)
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
10dac8 | 2004-04-05 | Martin Stjernholm | | errno = p->my_errno=EBADF;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args);
push_int(0);
return;
}
|
574088 | 1998-01-01 | Fredrik Hübinette (Hubbe) | | if(fd_listen(fd, 16384) < 0)
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
10dac8 | 2004-04-05 | Martin Stjernholm | | p->my_errno=errno;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args);
push_int(0);
return;
}
|
10dac8 | 2004-04-05 | Martin Stjernholm | | change_fd_for_box (&p->box, fd);
|
ddc1a3 | 2010-07-27 | Martin Stjernholm | | if(cb) assign_accept_cb (p, cb);
|
10dac8 | 2004-04-05 | Martin Stjernholm | | p->my_errno=0;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args);
push_int(1);
}
|
c4d100 | 2004-05-14 | Martin Nilsson | | |
572711 | 2014-09-02 | Per Hedbor | | *! void|string ip, void|string reuse_port)
|
de411a | 2002-04-01 | Martin Nilsson | | *!
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! Opens a socket and binds it to port number on the local machine.
*! If the second argument is present, the socket is set to
*! nonblocking and the callback funcition is called whenever
*! something connects to it. The callback will receive the id for
*! this port as argument and should typically call @[accept] to
*! establish a connection.
*!
*! If the optional argument @[ip] is given, @[bind] will try to bind
|
64ce98 | 2012-05-30 | Chris Angelico | | *! to an interface with that host name or IP number. Omitting this
*! will bind to all available IPv4 addresses; specifying "::" will
*! bind to all IPv4 and IPv6 addresses.
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | *!
|
86eae4 | 2014-08-26 | Per Hedbor | | *! If the OS supports TCP_FASTOPEN it is enabled automatically.
*!
|
572711 | 2014-09-02 | Per Hedbor | | *! If the OS supports SO_REUSEPORT it is enabled if the fourth argument is true.
*!
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! @returns
*! 1 is returned on success, zero on failure. @[errno] provides
*! further details about the error in the latter case.
|
66f19d | 2002-02-14 | Martin Nilsson | | *!
|
de411a | 2002-04-01 | Martin Nilsson | | *! @seealso
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! @[accept], @[set_id]
|
66f19d | 2002-02-14 | Martin Nilsson | | */
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | static void port_bind(INT32 args)
{
|
10dac8 | 2004-04-05 | Martin Stjernholm | | struct port *p = THIS;
|
cf7709 | 2003-04-24 | Marcus Comstedt | | PIKE_SOCKADDR addr;
|
486dbe | 2003-04-23 | Marcus Comstedt | | int addr_len,fd,tmp;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
10dac8 | 2004-04-05 | Martin Stjernholm | | do_close(p);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
if(args < 1)
|
de22f7 | 2014-08-25 | Martin Nilsson | | SIMPLE_TOO_FEW_ARGS_ERROR("bind", 1);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
017b57 | 2011-10-28 | Henrik Grubbström (Grubba) | | if(TYPEOF(Pike_sp[-args]) != PIKE_T_INT &&
(TYPEOF(Pike_sp[-args]) != PIKE_T_STRING ||
|
3c0d58 | 2003-04-22 | Marcus Comstedt | | Pike_sp[-args].u.string->size_shift))
|
f98274 | 2016-01-26 | Martin Nilsson | | SIMPLE_ARG_TYPE_ERROR("bind", 1, "int|string(8bit)");
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
572711 | 2014-09-02 | Per Hedbor | | addr_len = get_inet_addr(&addr,
(args > 2 && TYPEOF(Pike_sp[2-args])==PIKE_T_STRING?
Pike_sp[2-args].u.string->str : NULL),
(TYPEOF(Pike_sp[-args]) == PIKE_T_STRING?
Pike_sp[-args].u.string->str : NULL),
|
017b57 | 2011-10-28 | Henrik Grubbström (Grubba) | | (TYPEOF(Pike_sp[-args]) == PIKE_T_INT?
|
20c99e | 2003-04-24 | Marcus Comstedt | | Pike_sp[-args].u.integer : -1), 0);
|
f01020 | 2011-11-16 | Tobias S. Josefowitz | | INVALIDATE_CURRENT_TIME();
|
20c99e | 2003-04-24 | Marcus Comstedt | |
fd=fd_socket(SOCKADDR_FAMILY(addr), SOCK_STREAM, 0);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
if(fd < 0)
{
|
10dac8 | 2004-04-05 | Martin Stjernholm | | p->my_errno=errno;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args);
push_int(0);
return;
}
|
572711 | 2014-09-02 | Per Hedbor | | #ifdef SO_REUSEPORT
if( args > 3 && Pike_sp[3-args].u.integer )
{
int o=1;
if(fd_setsockopt(fd, SOL_SOCKET, SO_REUSEPORT, (char *)&o, sizeof(int)) < 0)
{
p->my_errno=errno;
while (fd_close(fd) && errno == EINTR) {}
errno = p->my_errno;
pop_n_elems(args);
push_int(0);
return;
}
}
#endif
|
1b21b8 | 1998-01-21 | Fredrik Hübinette (Hubbe) | | #ifndef __NT__
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
e8527f | 2001-09-24 | Henrik Grubbström (Grubba) | | int o=1;
if(fd_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&o, sizeof(int)) < 0)
{
|
10dac8 | 2004-04-05 | Martin Stjernholm | | p->my_errno=errno;
|
d6964c | 2003-09-30 | Martin Stjernholm | | while (fd_close(fd) && errno == EINTR) {}
|
10dac8 | 2004-04-05 | Martin Stjernholm | | errno = p->my_errno;
|
8e8ff8 | 2003-01-05 | Martin Nilsson | | pop_n_elems(args);
|
e8527f | 2001-09-24 | Henrik Grubbström (Grubba) | | push_int(0);
return;
}
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }
|
1b21b8 | 1998-01-21 | Fredrik Hübinette (Hubbe) | | #endif
|
cb2256 | 1995-10-11 | Fredrik Hübinette (Hubbe) | |
|
226632 | 2012-01-31 | Henrik Grubbström (Grubba) | | #if defined(IPV6_V6ONLY) && defined(IPPROTO_IPV6)
|
302073 | 2012-01-30 | Henrik Grubbström (Grubba) | | if (SOCKADDR_FAMILY(addr) == AF_INET6) {
int o = 0;
fd_setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&o, sizeof(int));
}
#endif
|
fd36c6 | 1997-01-29 | Fredrik Hübinette (Hubbe) | | my_set_close_on_exec(fd,1);
|
cb2256 | 1995-10-11 | Fredrik Hübinette (Hubbe) | |
|
ef1e93 | 1998-03-26 | Henrik Grubbström (Grubba) | | THREADS_ALLOW_UID();
|
86eae4 | 2014-08-26 | Per Hedbor | | if( !(tmp=fd_bind(fd, (struct sockaddr *)&addr, addr_len) < 0) )
#ifdef TCP_FASTOPEN
tmp = 256,
setsockopt(fd,SOL_TCP, TCP_FASTOPEN, &tmp, sizeof(tmp)),
#endif
(tmp = fd_listen(fd, 16384) < 0);
|
ef1e93 | 1998-03-26 | Henrik Grubbström (Grubba) | | THREADS_DISALLOW_UID();
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | |
|
cedaa4 | 2007-11-03 | Henrik Grubbström (Grubba) | | if(!Pike_fp->current_object->prog)
{
if (fd >= 0)
while (fd_close(fd) && errno == EINTR) {}
Pike_error("Object destructed in Stdio.Port->bind()\n");
}
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | | if(tmp)
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
10dac8 | 2004-04-05 | Martin Stjernholm | | p->my_errno=errno;
|
d6964c | 2003-09-30 | Martin Stjernholm | | while (fd_close(fd) && errno == EINTR) {}
|
10dac8 | 2004-04-05 | Martin Stjernholm | | errno = p->my_errno;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args);
push_int(0);
return;
}
|
10dac8 | 2004-04-05 | Martin Stjernholm | | change_fd_for_box (&p->box, fd);
if(args > 1) assign_accept_cb (p, Pike_sp+1-args);
p->my_errno=0;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args);
push_int(1);
}
|
6eb336 | 2004-05-13 | H. William Welliver III | |
#ifdef HAVE_SYS_UN_H
|
07324b | 2004-05-13 | H. William Welliver III | | |
6eb336 | 2004-05-13 | H. William Welliver III | | *!
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! Opens a Unix domain socket at the given path in the file system.
*! If the second argument is present, the socket is set to
*! nonblocking and the callback funcition is called whenever
*! something connects to it. The callback will receive the id for
*! this port as argument and should typically call @[accept] to
*! establish a connection.
|
6eb336 | 2004-05-13 | H. William Welliver III | | *!
*! @returns
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! 1 is returned on success, zero on failure. @[errno] provides
*! further details about the error in the latter case.
|
6eb336 | 2004-05-13 | H. William Welliver III | | *!
*! @note
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! This function is only available on systems that support Unix domain
|
6eb336 | 2004-05-13 | H. William Welliver III | | *! sockets.
*!
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | *! @note
*! @[path] had a quite restrictive length limit (~100 characters)
*! prior to Pike 7.8.334.
*!
|
6eb336 | 2004-05-13 | H. William Welliver III | | *! @seealso
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | *! @[accept], @[set_id]
|
6eb336 | 2004-05-13 | H. William Welliver III | | */
|
b81782 | 2009-12-07 | Henrik Grubbström (Grubba) | | static void bind_unix(INT32 args)
|
6eb336 | 2004-05-13 | H. William Welliver III | | {
struct port *p = THIS;
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | struct sockaddr_un *addr;
|
c4d100 | 2004-05-14 | Martin Nilsson | | struct pike_string *path;
|
b81782 | 2009-12-07 | Henrik Grubbström (Grubba) | | struct svalue *cb = NULL;
|
6eb336 | 2004-05-13 | H. William Welliver III | | int addr_len,fd,tmp;
do_close(p);
|
69c0aa | 2014-08-25 | Martin Nilsson | | get_all_args("bind_unix", args, "%n.%*", &path, &cb);
|
6eb336 | 2004-05-13 | H. William Welliver III | |
|
1f0b46 | 2010-02-24 | Henrik Grubbström (Grubba) | |
addr_len = sizeof(struct sockaddr_un) + path->len + 1 -
sizeof(addr->sun_path);
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | addr = xalloc(addr_len);
|
6eb336 | 2004-05-13 | H. William Welliver III | |
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | strcpy(addr->sun_path, path->str);
addr->sun_family = AF_UNIX;
|
967067 | 2009-07-23 | Henrik Grubbström (Grubba) | | #ifdef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
|
caa2e4 | 2009-07-23 | Henrik Grubbström (Grubba) | | addr->sun_len = path->len + 1;
|
967067 | 2009-07-23 | Henrik Grubbström (Grubba) | | #endif
|
6eb336 | 2004-05-13 | H. William Welliver III | |
fd=fd_socket(AF_UNIX, SOCK_STREAM, 0);
if(fd < 0)
{
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | free(addr);
|
6eb336 | 2004-05-13 | H. William Welliver III | | p->my_errno=errno;
pop_n_elems(args);
push_int(0);
return;
}
#ifndef __NT__
{
int o=1;
|
b81782 | 2009-12-07 | Henrik Grubbström (Grubba) | | do {
tmp = fd_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *)&o, sizeof(int));
|
5344ae | 2012-12-02 | Peter Bortas | | } while ((tmp < 0) && (errno == EINTR));
|
6eb336 | 2004-05-13 | H. William Welliver III | | }
#endif
my_set_close_on_exec(fd,1);
THREADS_ALLOW_UID();
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | do {
|
b81782 | 2009-12-07 | Henrik Grubbström (Grubba) | | tmp = fd_bind(fd, (struct sockaddr *)addr, addr_len);
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | } while ((tmp < 0) && (errno == EINTR));
if (tmp >= 0) {
do {
tmp = fd_listen(fd, 16384);
} while ((tmp < 0) && (errno == EINTR));
}
|
6eb336 | 2004-05-13 | H. William Welliver III | | THREADS_DISALLOW_UID();
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | free(addr);
|
cedaa4 | 2007-11-03 | Henrik Grubbström (Grubba) | | if(!Pike_fp->current_object->prog)
{
if (fd >= 0)
while (fd_close(fd) && errno == EINTR) {}
|
b81782 | 2009-12-07 | Henrik Grubbström (Grubba) | | Pike_error("Object destructed in Stdio.Port->bind_unix()\n");
|
cedaa4 | 2007-11-03 | Henrik Grubbström (Grubba) | | }
|
200c10 | 2009-07-23 | Henrik Grubbström (Grubba) | | if(tmp < 0)
|
6eb336 | 2004-05-13 | H. William Welliver III | | {
p->my_errno=errno;
while (fd_close(fd) && errno == EINTR) {}
errno = p->my_errno;
pop_n_elems(args);
push_int(0);
return;
}
change_fd_for_box (&p->box, fd);
|
ddc1a3 | 2010-07-27 | Martin Stjernholm | | if (cb) assign_accept_cb (p, cb);
|
6eb336 | 2004-05-13 | H. William Welliver III | | p->my_errno=0;
pop_n_elems(args);
push_int(1);
}
#endif /* HAVE_SYS_UN_H */
|
2ea6c0 | 2004-04-04 | Martin Stjernholm | |
|
96f63c | 2015-11-25 | Henrik Grubbström (Grubba) | | static void port_close (INT32 UNUSED(args))
|
2ea6c0 | 2004-04-04 | Martin Stjernholm | | {
|
10dac8 | 2004-04-05 | Martin Stjernholm | | do_close (THIS);
|
2ea6c0 | 2004-04-04 | Martin Stjernholm | | }
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | |
de411a | 2002-04-01 | Martin Nilsson | | */
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | static void port_create(INT32 args)
{
if(args)
{
|
017b57 | 2011-10-28 | Henrik Grubbström (Grubba) | | if(TYPEOF(Pike_sp[-args]) == PIKE_T_INT ||
(TYPEOF(Pike_sp[-args]) == PIKE_T_STRING &&
|
8f7e13 | 2005-02-01 | Martin Stjernholm | | (Pike_sp[-args].u.string->len != 5 ||
strcmp("stdin",Pike_sp[-args].u.string->str))))
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
ed7b19 | 2015-11-16 | Martin Nilsson | | port_bind(args);
|
e4556f | 1997-04-10 | Marcus Comstedt | | return;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }else{
|
10dac8 | 2004-04-05 | Martin Stjernholm | | struct port *p = THIS;
|
017b57 | 2011-10-28 | Henrik Grubbström (Grubba) | | if(TYPEOF(Pike_sp[-args]) != PIKE_T_STRING)
|
de22f7 | 2014-08-25 | Martin Nilsson | | SIMPLE_TOO_FEW_ARGS_ERROR("create", 1);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
cedaa4 | 2007-11-03 | Henrik Grubbström (Grubba) | |
|
10dac8 | 2004-04-05 | Martin Stjernholm | | do_close(p);
change_fd_for_box (&p->box, 0);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
10dac8 | 2004-04-05 | Martin Stjernholm | | if(fd_listen(p->box.fd, 16384) < 0)
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
10dac8 | 2004-04-05 | Martin Stjernholm | | p->my_errno=errno;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }else{
|
10dac8 | 2004-04-05 | Martin Stjernholm | | if(args > 1) assign_accept_cb (p, Pike_sp+1-args);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }
}
}
}
extern struct program *file_program;
|
fe061b | 2009-02-23 | Henrik Grubbström (Grubba) | | static int port_fd_factory_fun_num = -1;
static void port_fd_factory(INT32 args)
{
pop_n_elems(args);
push_object(clone_object(file_program, 0));
}
|
d849ab | 2003-10-30 | Martin Stjernholm | | |
8f7e13 | 2005-02-01 | Martin Stjernholm | | *!
*! Get the first connection request waiting for this port and return
*! it as a connected socket.
*!
*! If no connection request is waiting and the port is in nonblocking
*! mode (i.e. an accept callback is installed) then zero is returned.
*! Otherwise this function waits until a connection has arrived.
|
ee7ba0 | 2008-06-13 | Henrik Grubbström (Grubba) | | *!
|
fe061b | 2009-02-23 | Henrik Grubbström (Grubba) | | *! In Pike 7.8 and later the returned object is created via @[fd_factory()].
*!
|
ee7ba0 | 2008-06-13 | Henrik Grubbström (Grubba) | | *! @note
*! In Pike 7.7 and later the resulting file object will be assigned
*! to the same backend as the port object.
|
8e8ff8 | 2003-01-05 | Martin Nilsson | | */
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | static void port_accept(INT32 args)
{
|
cf7709 | 2003-04-24 | Marcus Comstedt | | PIKE_SOCKADDR addr;
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | | struct port *this=THIS;
|
d6964c | 2003-09-30 | Martin Stjernholm | | int fd, err;
|
7c6a53 | 1998-08-07 | Henrik Grubbström (Grubba) | | ACCEPT_SIZE_T len=0;
|
cedaa4 | 2007-11-03 | Henrik Grubbström (Grubba) | | int one = 1;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
10dac8 | 2004-04-05 | Martin Stjernholm | | if(this->box.fd < 0)
|
b2d3e4 | 2000-12-01 | Fredrik Hübinette (Hubbe) | | Pike_error("port->accept(): Port not open.\n");
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
bac0ab | 2005-01-19 | Henrik Grubbström (Grubba) | |
THIS->box.revents = 0;
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | | THREADS_ALLOW();
|
a1ad68 | 1998-01-16 | Fredrik Hübinette (Hubbe) | | len=sizeof(addr);
|
d6964c | 2003-09-30 | Martin Stjernholm | | do {
|
10dac8 | 2004-04-05 | Martin Stjernholm | | fd=fd_accept(this->box.fd, (struct sockaddr *)&addr, &len);
|
d6964c | 2003-09-30 | Martin Stjernholm | | err = errno;
} while (fd < 0 && err == EINTR);
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | | THREADS_DISALLOW();
|
f01020 | 2011-11-16 | Tobias S. Josefowitz | | INVALIDATE_CURRENT_TIME();
|
cb2256 | 1995-10-11 | Fredrik Hübinette (Hubbe) | |
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | if(fd < 0)
{
|
10dac8 | 2004-04-05 | Martin Stjernholm | | this->my_errno=errno = err;
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args);
push_int(0);
return;
}
|
628379 | 1995-09-01 | Fredrik Hübinette (Hubbe) | |
|
cedaa4 | 2007-11-03 | Henrik Grubbström (Grubba) | |
while ((fd_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof(int)) < 0) &&
(errno == EINTR))
one = 1;
|
fd36c6 | 1997-01-29 | Fredrik Hübinette (Hubbe) | | my_set_close_on_exec(fd,1);
|
1227c4 | 2009-02-23 | Henrik Grubbström (Grubba) | | push_new_fd_object(port_fd_factory_fun_num,
fd, FILE_READ | FILE_WRITE, SOCKET_CAPABILITIES);
|
ee7170 | 2000-01-30 | Per Hedbor | |
|
ee7ba0 | 2008-06-13 | Henrik Grubbström (Grubba) | | if (this->box.backend) {
|
1227c4 | 2009-02-23 | Henrik Grubbström (Grubba) | | struct object *o = Pike_sp[-1].u.object;
struct my_file *f = (struct my_file *)
|
017b57 | 2011-10-28 | Henrik Grubbström (Grubba) | | (o->storage + o->prog->inherits[SUBTYPEOF(Pike_sp[-1])].storage_offset);
|
ee7ba0 | 2008-06-13 | Henrik Grubbström (Grubba) | | change_backend_for_box(&f->box, this->box.backend);
}
|
1227c4 | 2009-02-23 | Henrik Grubbström (Grubba) | | stack_pop_n_elems_keep_top(args);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }
|
5abc86 | 2008-05-12 | Martin Stjernholm | | |
66f19d | 2002-02-14 | Martin Nilsson | | *!
|
5abc86 | 2008-05-12 | Martin Stjernholm | | *! Get the address and port of the local socket end-point.
*!
*! @returns
*! This function returns the address and port of a socket end-point
*! on the form @expr{"x.x.x.x port"@} (IPv4) or
*! @expr{"x:x:x:x:x:x:x:x port"@} (IPv6).
*!
*! If there is some error querying or formatting the address,
*! @expr{0@} (zero) is returned and @[errno()] will return the
*! error code.
*!
*! @throws
*! An error is thrown if the socket isn't bound.
|
66f19d | 2002-02-14 | Martin Nilsson | | */
|
dfa0b6 | 1997-01-21 | Fredrik Hübinette (Hubbe) | | static void socket_query_address(INT32 args)
{
|
cf7709 | 2003-04-24 | Marcus Comstedt | | PIKE_SOCKADDR addr;
|
eaf8b9 | 1998-07-15 | Fredrik Hübinette (Hubbe) | | int i;
|
dfafa9 | 2003-09-01 | Martin Nilsson | | char buffer[496];
|
7c6a53 | 1998-08-07 | Henrik Grubbström (Grubba) | | ACCEPT_SIZE_T len;
|
dfa0b6 | 1997-01-21 | Fredrik Hübinette (Hubbe) | |
|
10dac8 | 2004-04-05 | Martin Stjernholm | | if(THIS->box.fd <0)
|
5abc86 | 2008-05-12 | Martin Stjernholm | | Pike_error("Stdio.Port->query_address(): Socket not bound yet.\n");
|
dfa0b6 | 1997-01-21 | Fredrik Hübinette (Hubbe) | |
len=sizeof(addr);
|
10dac8 | 2004-04-05 | Martin Stjernholm | | i=fd_getsockname(THIS->box.fd,(struct sockaddr *)&addr,&len);
|
dfa0b6 | 1997-01-21 | Fredrik Hübinette (Hubbe) | | pop_n_elems(args);
|
486dbe | 2003-04-23 | Marcus Comstedt | | if(i < 0 || len < (int)sizeof(addr.ipv4))
|
dfa0b6 | 1997-01-21 | Fredrik Hübinette (Hubbe) | | {
THIS->my_errno=errno;
push_int(0);
return;
}
|
6a539c | 2009-05-28 | Henrik Grubbström (Grubba) | | #ifdef fd_inet_ntop
if(!fd_inet_ntop(SOCKADDR_FAMILY(addr), SOCKADDR_IN_ADDR(addr),
buffer, sizeof(buffer)-20))
|
5abc86 | 2008-05-12 | Martin Stjernholm | | {
THIS->my_errno = errno;
push_int(0);
return;
}
#else
if(SOCKADDR_FAMILY(addr) == AF_INET)
{
char *q = inet_ntoa(*SOCKADDR_IN_ADDR(addr));
strncpy(buffer,q,sizeof(buffer)-20);
buffer[sizeof(buffer)-20]=0;
}else{
#ifdef EAFNOSUPPORT
|
a76ca1 | 2008-05-12 | Henrik Grubbström (Grubba) | | THIS->my_errno = EAFNOSUPPORT;
|
cae06e | 2003-04-22 | Marcus Comstedt | | #else
|
a76ca1 | 2008-05-12 | Henrik Grubbström (Grubba) | | THIS->my_errno = EINVAL;
|
5abc86 | 2008-05-12 | Martin Stjernholm | | #endif
push_int(0);
return;
}
|
cae06e | 2003-04-22 | Marcus Comstedt | | #endif
|
486dbe | 2003-04-23 | Marcus Comstedt | | sprintf(buffer+strlen(buffer)," %d",(int)(ntohs(addr.ipv4.sin_port)));
|
dfa0b6 | 1997-01-21 | Fredrik Hübinette (Hubbe) | |
|
90e0f7 | 2003-12-12 | Martin Nilsson | | push_text(buffer);
|
dfa0b6 | 1997-01-21 | Fredrik Hübinette (Hubbe) | | }
|
10dac8 | 2004-04-05 | Martin Stjernholm | |
static void port_set_backend (INT32 args)
{
struct port *p = THIS;
struct Backend_struct *backend;
if (!args)
|
de22f7 | 2014-08-25 | Martin Nilsson | | SIMPLE_TOO_FEW_ARGS_ERROR ("set_backend", 1);
|
017b57 | 2011-10-28 | Henrik Grubbström (Grubba) | | if (TYPEOF(Pike_sp[-args]) != PIKE_T_OBJECT)
|
f98274 | 2016-01-26 | Martin Nilsson | | SIMPLE_ARG_TYPE_ERROR ("set_backend", 1, "object(Pike.Backend)");
|
13b5ed | 2014-05-26 | Per Hedbor | | backend = get_storage (Pike_sp[-args].u.object, Backend_program);
|
10dac8 | 2004-04-05 | Martin Stjernholm | | if (!backend)
|
f98274 | 2016-01-26 | Martin Nilsson | | SIMPLE_ARG_TYPE_ERROR ("set_backend", 1, "object(Pike.Backend)");
|
10dac8 | 2004-04-05 | Martin Stjernholm | |
if (p->box.backend)
change_backend_for_box (&p->box, backend);
else
INIT_FD_CALLBACK_BOX (&p->box, backend, p->box.ref_obj,
|
ca6bd0 | 2012-05-01 | Bill Welliver | | p->box.fd, 0, got_port_event, 0);
|
10dac8 | 2004-04-05 | Martin Stjernholm | | }
static void port_query_backend (INT32 args)
{
pop_n_elems (args);
ref_push_object (get_backend_obj (THIS->box.backend ? THIS->box.backend :
default_backend));
}
|
3a5659 | 2015-05-18 | Henrik Grubbström (Grubba) | | int fd_from_portobject( struct object *p )
{
struct port *po = get_storage( p, port_program );
if(!po) return -1;
return po->box.fd;
}
static void port_query_fd(INT32 UNUSED(args))
{
push_int(fd_from_portobject(Pike_fp->current_object));
}
|
dfa0b6 | 1997-01-21 | Fredrik Hübinette (Hubbe) | |
|
06983f | 1996-09-22 | Fredrik Hübinette (Hubbe) | | static void init_port_struct(struct object *o)
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
ca6bd0 | 2012-05-01 | Bill Welliver | | INIT_FD_CALLBACK_BOX(&THIS->box, NULL, o, -1, 0, got_port_event, 0);
|
07513e | 1996-10-04 | Fredrik Hübinette (Hubbe) | | THIS->my_errno=0;
|
10dac8 | 2004-04-05 | Martin Stjernholm | |
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }
|
74dfe8 | 2012-12-30 | Jonas Walldén | | static void exit_port_struct(struct object *UNUSED(o))
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
10dac8 | 2004-04-05 | Martin Stjernholm | | do_close(THIS);
unhook_fd_callback_box (&THIS->box);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | }
|
66f19d | 2002-02-14 | Martin Nilsson | |
|
db1e8d | 2006-07-05 | Martin Stjernholm | | PMOD_EXPORT struct program *port_program = NULL;
|
ee7170 | 2000-01-30 | Per Hedbor | |
|
29f9a9 | 2013-06-11 | Martin Nilsson | | void exit_stdio_port(void)
|
ee7170 | 2000-01-30 | Per Hedbor | | {
free_program( port_program );
}
|
29f9a9 | 2013-06-11 | Martin Nilsson | | void init_stdio_port(void)
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | {
|
d7ae23 | 2000-08-10 | Henrik Grubbström (Grubba) | | ptrdiff_t offset;
|
48b97a | 2003-10-28 | Martin Stjernholm | | START_NEW_PROGRAM_ID (STDIO_PORT);
|
40f302 | 2004-04-11 | Henrik Grubbström (Grubba) | | offset = ADD_STORAGE(struct port);
|
0032aa | 2005-01-23 | Martin Nilsson | | MAP_VARIABLE("_accept_callback", tMix, 0,
|
40f302 | 2004-04-11 | Henrik Grubbström (Grubba) | | offset + OFFSETOF(port, accept_callback), PIKE_T_MIXED);
|
0032aa | 2005-01-23 | Martin Nilsson | | MAP_VARIABLE("_id", tMix, 0,
|
40f302 | 2004-04-11 | Henrik Grubbström (Grubba) | | offset + OFFSETOF(port, id), PIKE_T_MIXED);
|
3c0d58 | 2003-04-22 | Marcus Comstedt | |
|
40f302 | 2004-04-11 | Henrik Grubbström (Grubba) | | ADD_FUNCTION("bind", port_bind,
|
fcde91 | 2014-09-03 | Per Hedbor | | tFunc(tOr(tInt,tStr) tOr(tVoid,tMix) tOr(tVoid,tStr) tOr(tVoid,tInt),tInt), 0);
|
6eb336 | 2004-05-13 | H. William Welliver III | | #ifdef HAVE_SYS_UN_H
|
b81782 | 2009-12-07 | Henrik Grubbström (Grubba) | | ADD_FUNCTION("bind_unix", bind_unix,
|
904999 | 2015-04-28 | Henrik Grubbström (Grubba) | | tFunc(tStr tOr(tVoid,tMix),tInt), ID_OPTIONAL);
|
6eb336 | 2004-05-13 | H. William Welliver III | | #endif /* HAVE_SYS_UN_H */
|
2ea6c0 | 2004-04-04 | Martin Stjernholm | | ADD_FUNCTION("close",port_close,tFunc(tNone,tVoid),0);
|
45ee5d | 1999-02-10 | Fredrik Hübinette (Hubbe) | |
ADD_FUNCTION("listen_fd",port_listen_fd,tFunc(tInt tOr(tVoid,tMix),tInt),0);
ADD_FUNCTION("set_id",port_set_id,tFunc(tMix,tMix),0);
|
07228a | 1999-06-19 | Fredrik Hübinette (Hubbe) | | ADD_FUNCTION("query_id",port_query_id,tFunc(tNone,tMix),0);
|
45ee5d | 1999-02-10 | Fredrik Hübinette (Hubbe) | |
|
07228a | 1999-06-19 | Fredrik Hübinette (Hubbe) | | ADD_FUNCTION("query_address",socket_query_address,tFunc(tNone,tStr),0);
|
45ee5d | 1999-02-10 | Fredrik Hübinette (Hubbe) | |
|
07228a | 1999-06-19 | Fredrik Hübinette (Hubbe) | | ADD_FUNCTION("errno",port_errno,tFunc(tNone,tInt),0);
|
45ee5d | 1999-02-10 | Fredrik Hübinette (Hubbe) | |
|
fe061b | 2009-02-23 | Henrik Grubbström (Grubba) | | port_fd_factory_fun_num =
ADD_FUNCTION("fd_factory", port_fd_factory, tFunc(tNone,tObjIs_STDIO_FD),
ID_STATIC);
|
7352a8 | 1999-12-14 | Martin Stjernholm | | ADD_FUNCTION("accept",port_accept,tFunc(tNone,tObjIs_STDIO_FD),0);
|
45ee5d | 1999-02-10 | Fredrik Hübinette (Hubbe) | |
|
40f302 | 2004-04-11 | Henrik Grubbström (Grubba) | | ADD_FUNCTION("create", port_create,
tFunc(tOr3(tVoid,tStr,tInt) tOr(tVoid,tMix) tOr(tVoid,tStr),
tVoid), 0);
|
10dac8 | 2004-04-05 | Martin Stjernholm | | ADD_FUNCTION ("set_backend", port_set_backend, tFunc(tObj,tVoid), 0);
ADD_FUNCTION ("query_backend", port_query_backend, tFunc(tVoid,tObj), 0);
|
4d416e | 2014-09-04 | Per Hedbor | | ADD_FUNCTION ("query_fd", port_query_fd, tFunc(tVoid,tInt), 0);
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
4d416e | 2014-09-04 | Per Hedbor | | #ifdef SO_REUSEPORT
|
904999 | 2015-04-28 | Henrik Grubbström (Grubba) | | ADD_INT_CONSTANT( "SO_REUSEPORT_SUPPORT", SO_REUSEPORT, ID_OPTIONAL );
|
4d416e | 2014-09-04 | Per Hedbor | | #endif
#ifdef TCP_FASTOPEN
|
904999 | 2015-04-28 | Henrik Grubbström (Grubba) | | ADD_INT_CONSTANT( "TCP_FASTOPEN_SUPPORT", TCP_FASTOPEN, ID_OPTIONAL );
|
4d416e | 2014-09-04 | Per Hedbor | | #endif
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | | set_init_callback(init_port_struct);
set_exit_callback(exit_port_struct);
|
ee7170 | 2000-01-30 | Per Hedbor | | port_program = end_program();
add_program_constant( "_port", port_program, 0 );
|
5267b7 | 1995-08-09 | Fredrik Hübinette (Hubbe) | |
|
ee7170 | 2000-01-30 | Per Hedbor | | }
|