ldmud-3.2.9/doc/
ldmud-3.2.9/doc/efun/
ldmud-3.2.9/mud/
ldmud-3.2.9/mud/heaven7/
ldmud-3.2.9/mud/heaven7/lib/
ldmud-3.2.9/mud/lp-245/
ldmud-3.2.9/mud/lp-245/banish/
ldmud-3.2.9/mud/lp-245/doc/
ldmud-3.2.9/mud/lp-245/doc/examples/
ldmud-3.2.9/mud/lp-245/doc/sefun/
ldmud-3.2.9/mud/lp-245/log/
ldmud-3.2.9/mud/lp-245/obj/Go/
ldmud-3.2.9/mud/lp-245/players/lars/
ldmud-3.2.9/mud/lp-245/room/death/
ldmud-3.2.9/mud/lp-245/room/maze1/
ldmud-3.2.9/mud/lp-245/room/sub/
ldmud-3.2.9/mud/lp-245/secure/
ldmud-3.2.9/mud/morgengrauen/
ldmud-3.2.9/mud/morgengrauen/lib/
ldmud-3.2.9/mud/sticklib/
ldmud-3.2.9/mud/sticklib/src/
ldmud-3.2.9/mudlib/uni-crasher/
ldmud-3.2.9/pkg/
ldmud-3.2.9/pkg/debugger/
ldmud-3.2.9/pkg/diff/
ldmud-3.2.9/pkg/misc/
ldmud-3.2.9/src/autoconf/
ldmud-3.2.9/src/bugs/
ldmud-3.2.9/src/bugs/MudCompress/
ldmud-3.2.9/src/bugs/b-020916-files/
ldmud-3.2.9/src/bugs/doomdark/
ldmud-3.2.9/src/bugs/ferrycode/ferry/
ldmud-3.2.9/src/bugs/ferrycode/obj/
ldmud-3.2.9/src/bugs/psql/
ldmud-3.2.9/src/done/
ldmud-3.2.9/src/done/order_alist/
ldmud-3.2.9/src/done/order_alist/obj/
ldmud-3.2.9/src/done/order_alist/room/
ldmud-3.2.9/src/gcc/
ldmud-3.2.9/src/gcc/2.7.0/
ldmud-3.2.9/src/gcc/2.7.1/
ldmud-3.2.9/src/hosts/
ldmud-3.2.9/src/hosts/GnuWin32/
ldmud-3.2.9/src/hosts/amiga/NetIncl/
ldmud-3.2.9/src/hosts/amiga/NetIncl/netinet/
ldmud-3.2.9/src/hosts/amiga/NetIncl/sys/
ldmud-3.2.9/src/hosts/i386/
ldmud-3.2.9/src/hosts/msdos/byacc/
ldmud-3.2.9/src/hosts/msdos/doc/
ldmud-3.2.9/src/hosts/os2/
ldmud-3.2.9/src/hosts/win32/
ldmud-3.2.9/src/util/
ldmud-3.2.9/src/util/erq/
ldmud-3.2.9/src/util/indent/hosts/next/
ldmud-3.2.9/src/util/xerq/
ldmud-3.2.9/src/util/xerq/lpc/
ldmud-3.2.9/src/util/xerq/lpc/www/
Short: TCP sockets for LDMud
From: Tomi Valkeinen
Date: 2002-09-12
Type: Patch
State: New
Driver: 3.2.9-dev.248
See also: f-981226-1, f-991104-0, p-021021

UDP is not handled, hardly documented, modelled after MudOS, but stable.

diff -burN 3-3/doc/efun/socket_accept 3-3.sock/doc/efun/socket_accept
--- 3-3/doc/efun/socket_accept	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_accept	Thu Sep 12 14:16:34 2002
@@ -0,0 +1,9 @@
+SYNOPSIS
+        int socket_accept(int fd, closure read_callback,
+                          closure close_callback)
+
+DESCRIPTION
+        Returns SE_SUCCESS or the error code.
+
+SEE ALSO
+
diff -burN 3-3/doc/efun/socket_address 3-3.sock/doc/efun/socket_address
--- 3-3/doc/efun/socket_address	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_address	Thu Sep 12 14:17:47 2002
@@ -0,0 +1,8 @@
+SYNOPSIS
+        string socket_send(int fd)
+
+DESCRIPTION
+        Returns the remote address of the socket.
+
+SEE ALSO
+
diff -burN 3-3/doc/efun/socket_bind 3-3.sock/doc/efun/socket_bind
--- 3-3/doc/efun/socket_bind	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_bind	Thu Sep 12 14:13:20 2002
@@ -0,0 +1,8 @@
+SYNOPSIS
+        int socket_bind(int fd, int port)
+
+DESCRIPTION
+        Returns SE_SUCCESS or the error code.
+
+SEE ALSO
+
diff -burN 3-3/doc/efun/socket_close 3-3.sock/doc/efun/socket_close
--- 3-3/doc/efun/socket_close	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_close	Thu Sep 12 14:12:01 2002
@@ -0,0 +1,8 @@
+SYNOPSIS
+        int socket_close(int fd)
+
+DESCRIPTION
+        Returns SE_SUCCESS or the error code.
+
+SEE ALSO
+
diff -burN 3-3/doc/efun/socket_connect 3-3.sock/doc/efun/socket_connect
--- 3-3/doc/efun/socket_connect	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_connect	Thu Sep 12 14:14:16 2002
@@ -0,0 +1,10 @@
+SYNOPSIS
+        int socket_connect(int fd, string address, closure connect_callback,
+                           closure read_callback)
+
+DESCRIPTION
+        The address is in the form "ipnumber:port".
+        Returns SE_SUCCESS or the error code.
+
+SEE ALSO
+
diff -burN 3-3/doc/efun/socket_create 3-3.sock/doc/efun/socket_create
--- 3-3/doc/efun/socket_create	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_create	Thu Sep 12 14:11:18 2002
@@ -0,0 +1,9 @@
+SYNOPSIS
+        int socket_create(closure close_callback)
+
+DESCRIPTION
+        Returns fd (zero or positive) for the newly created socket or
+        error number (negative) if the creation failed.
+
+SEE ALSO
+
diff -burN 3-3/doc/efun/socket_listen 3-3.sock/doc/efun/socket_listen
--- 3-3/doc/efun/socket_listen	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_listen	Thu Sep 12 14:14:41 2002
@@ -0,0 +1,8 @@
+SYNOPSIS
+        int socket_listen(int fd, closure listen_callback)
+
+DESCRIPTION
+        Returns SE_SUCCESS or the error code.
+
+SEE ALSO
+
diff -burN 3-3/doc/efun/socket_send 3-3.sock/doc/efun/socket_send
--- 3-3/doc/efun/socket_send	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_send	Thu Sep 12 14:17:17 2002
@@ -0,0 +1,8 @@
+SYNOPSIS
+        int socket_send(int fd, string data)
+
+DESCRIPTION
+        Returns SE_SUCCESS or the error code.
+
+SEE ALSO
+
diff -burN 3-3/doc/efun/socket_strerror 3-3.sock/doc/efun/socket_strerror
--- 3-3/doc/efun/socket_strerror	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/doc/efun/socket_strerror	Thu Sep 12 14:18:16 2002
@@ -0,0 +1,8 @@
+SYNOPSIS
+        string socket_strerror(int errno)
+
+DESCRIPTION
+        Returns string representation of the given socket error.
+
+SEE ALSO
+
diff -burN 3-3/mudlib/socket1.c 3-3.sock/mudlib/socket1.c
--- 3-3/mudlib/socket1.c	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/mudlib/socket1.c	Thu Sep 12 14:20:56 2002
@@ -0,0 +1,28 @@
+#include "sys/sockets.h"
+
+close_callback(int fd)
+{
+    debug_message(sprintf("close cb %d\n", fd));
+}
+
+read_callback(int fd, string msg)
+{
+    debug_message(sprintf("read cb %d, size %d: '%s'\n", fd, sizeof(msg), msg));
+}
+
+connect_callback(int fd, int err)
+{
+    debug_message(sprintf("connect cb %d, %s\n", fd, socket_strerror(err)));
+
+	if(err == SE_SUCCESS)
+	{
+		socket_send(fd, "hello world\n");
+	}
+}
+
+test()
+{
+    int fd = socket_create( (: close_callback($1) :) );
+
+    socket_connect(fd, "127.0.0.1:9999", #'connect_callback, #'read_callback);
+}
diff -burN 3-3/mudlib/socket2.c 3-3.sock/mudlib/socket2.c
--- 3-3/mudlib/socket2.c	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/mudlib/socket2.c	Thu Sep 12 14:21:00 2002
@@ -0,0 +1,26 @@
+
+
+close_callback(int fd)
+{
+    debug_message(sprintf("close cb %d\n", fd));
+}
+
+read_callback(int fd, string msg)
+{
+    debug_message(sprintf("read cb %d, size %d: '%s'\n", fd, sizeof(msg), msg));
+}
+
+listen_callback(int fd)
+{
+    printf("listen cb %O %O\n", previous_object(), this_object());
+
+    socket_accept(fd, #'read_callback, #'close_callback);
+}
+
+test()
+{
+    int fd = socket_create( #'close_callback );
+
+	socket_bind(fd, 8888);
+	socket_listen(fd, #'listen_callback );
+}
diff -burN 3-3/mudlib/sys/sockets.h 3-3.sock/mudlib/sys/sockets.h
--- 3-3/mudlib/sys/sockets.h	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/mudlib/sys/sockets.h	Thu Sep 12 14:05:11 2002
@@ -0,0 +1,21 @@
+#ifndef LPC_SOCKETS_H_
+#define LPC_SOCKETS_H_ 1
+
+#define SE_SUCCESS 0
+#define SE_UNKNOWN -1
+#define SE_CONNREFUSED -2
+#define SE_HOSTDOWN -3
+#define SE_HOSTUNREACH -4
+#define SE_NOMORESOCKETS -5
+#define SE_CREATESOCKET -6
+#define SE_SETNONBLOCKING -7
+#define SE_SETSOCKOPT -8
+#define SE_BADFD -9
+#define SE_ILLEGALADDR -10
+#define SE_INVALIDPORT -11
+#define SE_PIPE -12
+#define SE_ADDRINUSE -13
+#define SE_INVAL -14
+#define SE_CONNRESET -15
+
+#endif /* LPC_SOCKETS_H_ */
diff -burN 3-3/mudlib/test_master.c 3-3.sock/mudlib/test_master.c
--- 3-3/mudlib/test_master.c	Fri Aug 16 06:03:45 2002
+++ 3-3.sock/mudlib/test_master.c	Thu Sep 12 14:19:20 2002
@@ -47,6 +47,18 @@
         return;
     }
 
+	if (arg == "socket1")
+	{
+		load_object("socket1")->test();
+		return;
+	}
+
+	if (arg == "socket2")
+	{
+		load_object("socket2")->test();
+		return;
+	}
+
     if (arg == "gc")
     {
         garbage_collection();
diff -burN 3-3/src/Makefile.in 3-3.sock/src/Makefile.in
--- 3-3/src/Makefile.in	Wed Aug 21 21:07:36 2002
+++ 3-3.sock/src/Makefile.in	Thu Sep 12 13:36:18 2002
@@ -77,7 +77,7 @@
       parser.c parse.c parse_old.c pkg-alists.c pkg-mysql.c pkg-pcre.c port.c \
       ptrtable.c \
       random.c regexp.c simulate.c simul_efun.c stdstrings.c \
-      strfuns.c sprintf.c swap.c wiz_list.c xalloc.c 
+      strfuns.c sprintf.c swap.c wiz_list.c xalloc.c sockets.c
 OBJ = access_check.o actions.o array.o backend.o bitstrings.o call_out.o \
       closure.o comm.o \
       dumpstat.o ed.o efuns.o files.o gcollect.o hash.o heartbeat.o \
@@ -87,7 +87,7 @@
       parser.o parse.o parse_old.o pkg-alists.o pkg-mysql.o pkg-pcre.o port.o \
       ptrtable.o \
       random.o regexp.o simulate.o simul_efun.o stdstrings.o \
-      strfuns.o sprintf.o swap.o wiz_list.o xalloc.o @ALLOCA@ 
+      strfuns.o sprintf.o swap.o wiz_list.o xalloc.o sockets.o @ALLOCA@ 
 
 driver@EXEEXT@: $(OBJ)
 	$(CC) @OPTIMIZE_LINKING@ $(LDFLAGS) $(OBJ) -o $@ $(LIBS)
diff -burN 3-3/src/backend.c 3-3.sock/src/backend.c
--- 3-3/src/backend.c	Wed Aug 21 21:07:36 2002
+++ 3-3.sock/src/backend.c	Thu Sep 12 13:54:29 2002
@@ -71,6 +71,7 @@
 #include "swap.h"
 #include "wiz_list.h"
 #include "xalloc.h"
+#include "sockets.h"
 
 #include "../mudlib/sys/driver_hook.h"
 #include "../mudlib/sys/debug_message.h"
@@ -646,6 +647,8 @@
             wiz_decay();
         }
 
+		socket_poll();
+		
     } /* end of main loop */
 
     /* NOTREACHED */
diff -burN 3-3/src/func_spec 3-3.sock/src/func_spec
--- 3-3/src/func_spec	Fri Sep  6 10:00:07 2002
+++ 3-3.sock/src/func_spec	Thu Sep 12 13:37:54 2002
@@ -643,4 +643,15 @@
 
 #endif /* USE_MYSQL */
 
+string  socket_strerror(int);
+void    socket_print_stats();
+int     socket_create(closure);
+int     socket_close(int);
+int     socket_connect(int, string, closure, closure);
+int     socket_bind(int, int);
+int     socket_listen(int, closure);
+int     socket_accept(int, closure, closure);
+int     socket_send(int, string);
+string  socket_address(int);
+
 /***************************************************************************/
diff -burN 3-3/src/main.c 3-3.sock/src/main.c
--- 3-3/src/main.c	Thu Sep  5 00:02:49 2002
+++ 3-3.sock/src/main.c	Thu Sep 12 13:55:23 2002
@@ -68,6 +68,7 @@
 #include "swap.h"
 #include "wiz_list.h"
 #include "xalloc.h"
+#include "sockets.h"
 
 /*-------------------------------------------------------------------------*/
 
@@ -441,6 +442,8 @@
 #endif /* ERQ_DEMON */
     initialize_host_ip_number();
 
+	socket_init();
+	
     (void)signal(SIGFPE, SIG_IGN);
     current_object = &dummy_current_object_for_loads;
     if (setjmp(toplevel_context.con.text)) {
diff -burN 3-3/src/simulate.c 3-3.sock/src/simulate.c
--- 3-3/src/simulate.c	Wed Sep  4 21:38:36 2002
+++ 3-3.sock/src/simulate.c	Thu Sep 12 13:56:40 2002
@@ -2223,6 +2223,8 @@
     if (ob->flags & O_DESTRUCTED)
         return;
 
+    socket_object_destructed(ob);
+
 #ifdef CHECK_OBJECT_REF
     xallocate(shadow, sizeof(*shadow), "destructed object shadow");
 #endif /* CHECK_OBJECT_REF */
diff -burN 3-3/src/sockets.c 3-3.sock/src/sockets.c
--- 3-3/src/sockets.c	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/src/sockets.c	Thu Sep 12 13:53:38 2002
@@ -0,0 +1,1027 @@
+/*
+ * Sockets for ldmud 3.3
+ *
+ * 5-July-2002 - Tomba @ Batmud
+ *   * First version
+ *
+ * 20-July-2002 - Tomba @ Batmud
+ *   * Added ECONNRESET
+ *   * Fixed socket_address to return empty string on error
+ *   * sock->send_buffer was not always cleared when freed
+ *   * removed a few debug printfs
+ *
+ * TODO: UDP support
+ * TODO: access right handling
+ * TODO: event handling with select (comm.c) instead of poll
+ *
+ */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdio.h>
+
+#include "main.h"
+#include "svalue.h"
+#include "interpret.h"
+#include "simulate.h"
+#include "object.h"
+#include "mstrings.h"
+#include "comm.h"
+#include "actions.h"
+
+#define SE_SUCCESS 0
+#define SE_UNKNOWN -1
+#define SE_CONNREFUSED -2
+#define SE_HOSTDOWN -3
+#define SE_HOSTUNREACH -4
+#define SE_NOMORESOCKETS -5
+#define SE_CREATESOCKET -6
+#define SE_SETNONBLOCKING -7
+#define SE_SETSOCKOPT -8
+#define SE_BADFD -9
+#define SE_ILLEGALADDR -10
+#define SE_INVALIDPORT -11
+#define SE_PIPE -12
+#define SE_ADDRINUSE -13
+#define SE_INVAL -14
+#define SE_CONNRESET -15
+
+static char *socket_errors[] = {
+	"Success",
+	"Unknown error",
+	"Connection refused",
+	"Host is down",
+	"No route to host",
+	"No more mud sockets available",
+	"Failed to create socket",
+	"Failed to set socket to non-blocking mode",
+	"Failed to set socket options",
+	"Bad socket descriptor",
+	"Illegal address",
+	"Invalid port",
+	"Broken pipe",
+	"Address already in use",
+	"Invalid argument",
+	"Connection reset by peer"
+};
+
+
+enum socket_state
+{
+	STATE_UNUSED = 0,
+	STATE_READY,
+	STATE_BOUND,
+	STATE_LISTEN,
+	STATE_CONNECTING,
+	STATE_CONNECTED,
+	STATE_CLOSING
+};
+
+struct socket_struct
+{
+	int fd;
+	int lpc_fd;				   /* "fd" shown to lpc */
+	enum socket_state state;
+	object_t* object;
+	struct sockaddr_in local_addr;
+	struct sockaddr_in remote_addr;
+	svalue_t read_callback;
+	svalue_t close_callback;
+	svalue_t connect_callback;
+	svalue_t listen_callback;
+	char* send_buffer;
+	int send_buffer_size;
+	int send_buffer_used;
+} typedef socket_t;
+
+
+#define MAX_LPC_FD 100
+
+static socket_t g_socket_table[MAX_LPC_FD];
+static struct pollfd g_poll_table[MAX_LPC_FD];
+
+#define READ_BUFFER_SIZE 10240
+static char g_read_buffer[READ_BUFFER_SIZE];
+
+void socket_process_events(socket_t* sock, short events);
+
+
+
+void socket_init()
+{
+	int i;
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		struct socket_struct* sock = &g_socket_table[i];
+	
+		sock->state = STATE_UNUSED;
+		sock->lpc_fd = i;
+
+		g_poll_table[i].fd = -1;
+		g_poll_table[i].events = POLLIN | POLLOUT;
+		g_poll_table[i].revents = 0;
+
+	}
+}
+
+int socket_conv_errno(int err)
+{
+	switch(err)
+	{
+		case ECONNREFUSED:
+			return SE_CONNREFUSED;
+
+		case EHOSTDOWN:
+			return SE_HOSTDOWN;
+
+		case EHOSTUNREACH:
+			return SE_HOSTUNREACH;
+
+		case EPIPE:
+			return SE_PIPE;
+
+		case EADDRINUSE:
+			return SE_ADDRINUSE;
+
+		case EINVAL:
+			return SE_INVAL;
+
+		case ECONNRESET:
+			return SE_CONNRESET;
+
+		default:
+			fprintf(stderr, "socket_conv_errno: unknown system error %d, %s\n", err, strerror(err));
+			return SE_UNKNOWN;
+	}
+}
+
+struct socket_struct* new_socket_entry()
+{
+	int i;
+	
+	for (i = 0; i < MAX_LPC_FD; i++)
+	{
+		struct socket_struct* sock = &g_socket_table[i];
+		
+		if (sock->state == STATE_UNUSED)
+		{
+			sock->fd = -1;
+			sock->send_buffer = 0;
+			sock->send_buffer_size = 0;
+			sock->send_buffer_used = 0;
+		
+			put_number(&sock->read_callback, 0);
+			put_number(&sock->close_callback, 0);
+			put_number(&sock->connect_callback, 0);
+			put_number(&sock->listen_callback, 0);
+		
+			return sock;
+		}
+	}
+	
+	return 0;
+}
+
+void free_socket_entry(socket_t* sock)
+{
+	if(sock != 0)
+	{
+		if(sock->fd != -1)
+		{
+			if(close(sock->fd) == -1)
+			{
+				perror("free_socket_entry: close");
+			}
+
+			sock->fd = -1;
+		}
+	
+		if(sock->send_buffer)
+		{
+			free(sock->send_buffer);
+			sock->send_buffer = 0;
+		}
+
+		sock->state = STATE_UNUSED;
+
+		free_svalue(&sock->read_callback);
+		free_svalue(&sock->close_callback);
+		free_svalue(&sock->connect_callback);
+		free_svalue(&sock->listen_callback);
+	
+		g_poll_table[sock->lpc_fd].fd = -1;
+	}
+}
+
+socket_t* get_socket_entry(int lpc_fd)
+{
+	if(lpc_fd < 0 || lpc_fd >= MAX_LPC_FD ||
+	   g_socket_table[lpc_fd].state == STATE_UNUSED)
+	{
+		return 0;
+	}
+
+	return &g_socket_table[lpc_fd];
+}
+
+void socket_object_destructed(object_t* ob)
+{
+	int i;
+	
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		struct socket_struct* sock = &g_socket_table[i];
+
+		if(sock->state != STATE_UNUSED)
+		{
+			if(sock->object == ob)
+			{
+				free_socket_entry(sock);
+			}
+		}
+	}
+}
+
+
+
+
+
+
+svalue_t* f_socket_strerror(svalue_t* sp)
+{
+	int err = 0 - sp->u.number;
+	sp--;
+
+	if(err < 0 || err > sizeof(socket_errors))
+	{
+		push_string(sp, new_mstring("Unspecified error"));
+	}
+	else
+	{	
+		push_string(sp, new_mstring(socket_errors[err]));
+	}
+	
+	return sp;
+}
+
+svalue_t* f_socket_print_stats(svalue_t* sp)
+{
+	int i;
+	
+	add_message("-- Socket stats --\n");
+		
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		socket_t* sock = &g_socket_table[i];
+	
+		if(sock->state != STATE_UNUSED)
+		{
+			add_message("lpc_fd %d, fd %d, state %d, ob %s\n",
+						i, sock->fd, sock->state, get_txt(sock->object->name));
+		}
+	}
+
+	return sp;
+}
+
+int socket_init_socket(socket_t* sock, int fd, svalue_t* close_callback)
+{
+	int tmp;
+	
+	if(fcntl(fd, F_SETFL, O_NDELAY) == -1)
+	{
+		perror("socket_init_socket: fcntl O_NDELAY");
+
+		return SE_SETNONBLOCKING;
+	}
+
+	tmp = 1;
+	if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+				  (char *)&tmp, sizeof(tmp)) == -1)
+	{
+		perror("socket_init_socket: setsockopt SO_REUSEADDR");
+
+		return SE_SETSOCKOPT;
+	}
+
+	sock->fd = fd;
+	sock->state = STATE_READY;
+	sock->object = current_object;
+
+	assign_svalue(&sock->close_callback, close_callback);
+	
+	g_poll_table[sock->lpc_fd].fd = sock->fd;
+
+	return 0;
+}
+
+int socket_string_to_sockaddr(char* name, struct sockaddr_in* saddr)
+{
+#define ADDR_BUF_SIZE 512
+	int port;
+	char *cp, addr[ADDR_BUF_SIZE];
+
+	strncpy(addr, name, ADDR_BUF_SIZE);
+
+	cp = strchr(addr, ':');
+	if (cp == NULL)
+	{
+		return 0;
+	}
+	
+	*cp = '\0';
+	port = atoi(cp + 1);
+
+	saddr->sin_family = AF_INET;
+	saddr->sin_port = htons((unsigned short)port);
+	if(inet_aton(addr, &saddr->sin_addr) == 0)
+	{
+		return 0;
+	}
+
+	return 1;
+#undef ADDR_BUF_SIZE
+}
+
+
+
+svalue_t* f_socket_create(svalue_t* sp)
+{
+	int err, fd;
+	socket_t* sock;
+	
+	if(current_object->flags & O_DESTRUCTED)
+	{
+		error("socket_create: this_object has been destructed");
+	}
+
+	sock = new_socket_entry();
+	
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		push_number(sp, SE_NOMORESOCKETS);
+		return sp;
+	}
+
+	fd = socket(AF_INET, SOCK_STREAM, 0);
+
+	if(fd == -1)
+	{
+		perror("socket_create: socket");
+	
+		free_socket_entry(sock);
+	
+		free_svalue(sp--);
+	
+		push_number(sp, SE_CREATESOCKET);
+		return sp;
+	}
+	
+	err = socket_init_socket(sock, fd, &sp[0]);
+	
+	free_svalue(sp--);
+	
+	if(err != 0)
+	{
+		close(fd);
+	
+		free_socket_entry(sock);
+
+		push_number(sp, err);
+
+		return sp;
+	}
+	
+	push_number(sp, sock->lpc_fd);
+
+	return sp;
+}
+
+svalue_t* f_socket_close(svalue_t* sp)
+{
+	int ret, myerrno;
+
+	int lpc_fd = (sp--)->u.number;
+	
+	socket_t* sock = get_socket_entry(lpc_fd);
+
+	if(sock == 0)
+	{
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	sock->state = STATE_CLOSING;
+	
+	ret = close(sock->fd);
+	myerrno = errno;
+	sock->fd = -1;
+
+	if(ret == -1)
+	{
+		perror("socket_close: close");
+
+		push_number(sp, socket_conv_errno(myerrno));
+	}
+	else
+	{
+		push_number(sp, SE_SUCCESS);
+	}
+	
+	return sp;
+}
+
+svalue_t* f_socket_connect(svalue_t* sp)
+{
+	int lpc_fd, myerrno;
+	int ret;
+	socket_t* sock;
+
+	lpc_fd = sp[-3].u.number;
+
+	sock = get_socket_entry(lpc_fd);
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	if(socket_string_to_sockaddr(get_txt(sp[-2].u.str), &sock->remote_addr) == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_ILLEGALADDR);
+		return sp;
+	}
+	
+	ret = connect(sock->fd, (struct sockaddr *)&sock->remote_addr,
+				  sizeof(sock->remote_addr));
+	myerrno = errno;
+	
+	if(ret == -1 && myerrno != EINPROGRESS)
+	{
+		fprintf(stderr, "socket_connect: connect failed: %s\n", strerror(myerrno));
+
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		
+		push_number(sp, socket_conv_errno(myerrno));
+	}
+	else
+	{
+		sock->state = STATE_CONNECTING;
+
+		transfer_svalue(&sock->connect_callback, &sp[-1]);
+		transfer_svalue(&sock->read_callback, &sp[0]);
+
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+
+		push_number(sp, SE_SUCCESS);
+	}
+	
+	return sp;
+}
+
+svalue_t* f_socket_bind(svalue_t* sp)
+{
+	socket_t* sock;
+	int myerrno;
+   
+	int port = (sp--)->u.number;
+	int lpc_fd = (sp--)->u.number;
+
+	sock = get_socket_entry(lpc_fd);
+	if(sock == 0)
+	{
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	if(port < 0)
+	{
+		push_number(sp, SE_INVALIDPORT);
+		return sp;
+	}
+
+	sock->local_addr.sin_port = htons((unsigned short)port);
+	sock->local_addr.sin_addr.s_addr = INADDR_ANY;
+	sock->local_addr.sin_family = AF_INET;
+
+	if(bind(sock->fd, (struct sockaddr*)&sock->local_addr,
+			sizeof(sock->local_addr)) == -1)
+	{
+		myerrno = errno;
+	
+		perror("socket_bind: bind");
+		push_number(sp, socket_conv_errno(myerrno));
+	}
+	else
+	{
+		sock->state = STATE_BOUND;
+		push_number(sp, SE_SUCCESS);
+	}
+	 
+	return sp;
+}
+
+svalue_t* f_socket_listen(svalue_t* sp)
+{
+	socket_t* sock;
+	int myerrno;
+   
+	int lpc_fd = sp[-1].u.number;
+
+	sock = get_socket_entry(lpc_fd);
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+	
+	transfer_svalue(&sock->listen_callback, &sp[0]);
+	
+	free_svalue(sp--);
+	free_svalue(sp--);
+
+	if(listen(sock->fd, 10) == -1)
+	{
+		myerrno = errno;
+		perror("socket_listen: listen");
+		push_number(sp, socket_conv_errno(myerrno));
+	}
+	else
+	{
+		sock->state = STATE_LISTEN;
+		push_number(sp, SE_SUCCESS);
+	}
+
+	return sp;
+}
+
+svalue_t* f_socket_accept(svalue_t* sp)
+{
+	socket_t* sock;
+	socket_t* new_sock;
+	int new_fd;
+	struct sockaddr_in addr;
+	int addr_size = sizeof(addr);
+	int err;
+	int myerrno;
+   
+	int lpc_fd = sp[-2].u.number;
+	
+	sock = get_socket_entry(lpc_fd);
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	new_fd = accept(sock->fd, (struct sockaddr*)&addr, &addr_size);
+	myerrno = errno;
+	if(new_fd < 0)
+	{
+		perror("socket_accept: accept");
+	
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+
+		push_number(sp, socket_conv_errno(myerrno));
+		return sp;
+	}
+
+	new_sock = new_socket_entry();
+	
+	if(new_sock == 0)
+	{
+		close(new_fd);
+	
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_NOMORESOCKETS);
+		return sp;
+	}
+
+	err = socket_init_socket(new_sock, new_fd, &sp[0]);
+
+	if(err != 0)
+	{
+		close(new_fd);
+
+		free_socket_entry(new_sock);
+	
+		free_svalue(sp--);
+		free_svalue(sp--);
+		free_svalue(sp--);
+
+		push_number(sp, err);
+	}
+
+	assign_svalue(&new_sock->read_callback, &sp[-1]);
+
+	memcpy(&new_sock->remote_addr, &addr, sizeof(addr));
+	
+	free_svalue(sp--);
+	free_svalue(sp--);
+	free_svalue(sp--);
+
+	new_sock->state = STATE_CONNECTED;
+	
+	push_number(sp, new_sock->lpc_fd);
+
+	return sp;
+}
+
+svalue_t* f_socket_address(svalue_t* sp)
+{
+#define ADDR_BUF_SIZE 512
+	char addrstr[ADDR_BUF_SIZE];
+	socket_t* sock;
+	
+	int lpc_fd = sp[0].u.number;
+	
+	sock = get_socket_entry(lpc_fd);
+	
+	free_svalue(sp--);
+	
+	if(sock == 0)
+	{
+		push_string(sp, new_mstring(""));
+		return sp;
+	}
+
+	snprintf(addrstr, 511, "%s:%d",
+			 inet_ntoa(sock->remote_addr.sin_addr),
+			 ntohs(sock->remote_addr.sin_port));
+	addrstr[ADDR_BUF_SIZE-1] = 0;
+
+	push_string(sp, new_mstring(addrstr));
+
+	return sp;
+#undef ADDR_BUF_SIZE
+}
+
+void socket_flush_send_buffer(socket_t* sock)
+{
+	if(sock->state == STATE_CONNECTED && sock->send_buffer_used > 0)
+	{
+		int len, myerrno;
+
+		len = send(sock->fd, sock->send_buffer, sock->send_buffer_used, 0);
+		myerrno = errno;
+	
+		if(myerrno == EAGAIN || myerrno == EWOULDBLOCK)
+		{
+			len = 0;
+		}
+	
+		if(len == -1)
+		{
+			fprintf(stderr, "socket_flush_send_buffer: send failed %s\n", strerror(myerrno));
+
+			/* error -> clear buffer */
+			free(sock->send_buffer);
+			sock->send_buffer = 0;
+			sock->send_buffer_size = 0;
+			sock->send_buffer_used = 0;
+		}
+		else if(len < sock->send_buffer_used)
+		{
+			memmove(sock->send_buffer, sock->send_buffer + len,
+					sock->send_buffer_used - len);
+		
+			sock->send_buffer_used = sock->send_buffer_used - len;
+/*
+  printf("socket: sent %d of %d. %d in buffer\n", len, sock->send_buffer_used+len,
+  sock->send_buffer_used);
+*/
+		}
+		else
+		{
+/*		
+	printf("socket: sent %d of %d. %d in buffer\n", len, sock->send_buffer_used,
+	0);
+*/
+			free(sock->send_buffer);
+			sock->send_buffer = 0;
+			sock->send_buffer_size = 0;
+			sock->send_buffer_used = 0;
+		}
+	}
+}
+
+svalue_t* f_socket_send(svalue_t* sp)
+{
+	int lpc_fd, len, myerrno;
+	socket_t* sock;
+	char* buf;
+	int buflen;
+	
+	lpc_fd = sp[-1].u.number;
+	
+	sock = get_socket_entry(lpc_fd);
+
+	if(sock == 0)
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+		push_number(sp, SE_BADFD);
+		return sp;
+	}
+
+	buf =  get_txt(sp[0].u.str);
+	buflen = mstrsize(sp[0].u.str);
+
+	socket_flush_send_buffer(sock);
+	
+	if(sock->send_buffer_used == 0)
+	{
+		len = send(sock->fd, buf, buflen, 0);
+		myerrno = errno;
+	}
+	else
+	{
+		myerrno = 0;
+		len = 0;
+	}
+
+	if(len == -1 && (myerrno == EAGAIN || myerrno == EWOULDBLOCK))
+	{
+		len = 0;
+	}
+	
+	if(len == -1)
+	{
+		fprintf(stderr, "socket_send: send failed %s\n", strerror(myerrno));
+
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, socket_conv_errno(myerrno));
+	}
+	else if(len < buflen)
+	{
+		if(buflen - len > sock->send_buffer_size - sock->send_buffer_used)
+		{
+			sock->send_buffer = realloc(sock->send_buffer,
+										sock->send_buffer_used + buflen - len);
+
+			if(!sock->send_buffer)
+			{
+				error("out of memory");
+			}
+			else
+			{
+				sock->send_buffer_size = sock->send_buffer_used + buflen - len;
+			}
+		}
+
+		memcpy(sock->send_buffer + sock->send_buffer_used,
+			   buf + len,
+			   buflen - len);
+
+		sock->send_buffer_used += buflen - len;
+/*
+  printf("socket: sent %d of %d. %d in buffer\n", len, buflen, sock->send_buffer_used);
+*/
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, len);
+	}
+	else
+	{
+		free_svalue(sp--);
+		free_svalue(sp--);
+	
+		push_number(sp, SE_SUCCESS);
+	}
+	
+	return sp;
+}
+
+void socket_poll()
+{
+	int ret, i, myerrno;
+
+	object_t* hide_current_object = current_object;
+	program_t* hide_current_prog = current_prog;
+	object_t* hide_interactive = current_interactive;
+	object_t* hide_command_giver = command_giver;
+
+	current_interactive = 0;
+	command_giver = 0;
+	
+	for(i = 0; i < MAX_LPC_FD; i++)
+	{
+		socket_t* sock = &g_socket_table[i];
+
+		if(sock->state == STATE_CLOSING)
+		{
+			free_socket_entry(sock);
+		}	
+	}
+	
+	ret = poll(g_poll_table, MAX_LPC_FD, 0);
+	myerrno = errno;
+	
+	if(ret == -1)
+	{
+		perror("socket_poll: poll");
+	}
+	else
+	{
+		for(i = 0; i < MAX_LPC_FD; i++)
+		{
+			if(g_poll_table[i].revents)
+			{
+				socket_t* sock = get_socket_entry(i);
+		
+				if(sock == 0)
+				{
+					error("Internal error in socket_poll()");
+				}
+		
+				socket_process_events(sock, g_poll_table[i].revents);
+			}
+		}
+	}
+	
+	current_interactive = hide_interactive;
+	command_giver = hide_command_giver;
+	current_object = hide_current_object;
+	current_prog = hide_current_prog;
+}
+
+
+void socket_process_events(socket_t* sock, short events)
+{
+	int err, errlen;
+	int myerrno;
+	
+	if(events & POLLERR)
+	{
+//	printf("ERR %d\n", sock->lpc_fd);
+	
+		errlen = sizeof(err);
+		if(getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1)
+		{
+			perror("socket_process_events: getsockopt");
+		}
+	
+		if(sock->state == STATE_CONNECTING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, socket_conv_errno(err));
+			secure_callback_lambda(&sock->connect_callback, 2);
+		}
+
+		/* callback may have closed the socket */
+		if(sock->state != STATE_CLOSING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, socket_conv_errno(err));
+	
+			secure_callback_lambda(&sock->close_callback, 2);
+		
+			/* callback may have closed the socket */
+			if(sock->state != STATE_CLOSING)
+				free_socket_entry(sock);
+		}
+	
+		return;
+	}
+		
+	if(events & POLLHUP)
+	{
+//	printf("HUP %d\n", sock->lpc_fd);
+	
+		errlen = sizeof(err);
+		if(getsockopt(sock->fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1)
+		{
+			perror("socket_process_events: getsockopt");
+		}
+
+		if(sock->state == STATE_CONNECTING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, err);
+			secure_callback_lambda(&sock->connect_callback, 2);
+		}
+
+		/* callback may have closed the socket */
+		if(sock->state != STATE_CLOSING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, err);
+		
+			secure_callback_lambda(&sock->close_callback, 2);
+		
+			/* callback may have closed the socket */
+			if(sock->state != STATE_CLOSING)
+				free_socket_entry(sock);
+		}
+	
+		return;
+	}
+
+	if(events & POLLOUT)
+	{
+//	printf("OUT %d\n", sock->lpc_fd);
+
+		if(sock->state == STATE_CONNECTING)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+			push_number(inter_sp, 0);
+			secure_callback_lambda(&sock->connect_callback, 2);
+
+			sock->state = STATE_CONNECTED;
+		}
+		else
+		{
+			socket_flush_send_buffer(sock);
+		}
+	}
+	
+	if(events & POLLIN)
+	{
+//	printf("IN %d\n", sock->lpc_fd);
+		
+		if(sock->state == STATE_CONNECTED)
+		{
+			int len;
+			
+			len = recv(sock->fd, &g_read_buffer, READ_BUFFER_SIZE, 0);
+			myerrno = errno;
+
+			if(len == -1)
+			{
+				perror("socket_process_events: recv");
+		
+				push_number(inter_sp, sock->lpc_fd);
+				push_number(inter_sp, 0);
+				push_number(inter_sp, socket_conv_errno(myerrno));
+		
+				secure_callback_lambda(&sock->read_callback, 3);
+			}
+			else if(len == 0)
+			{
+				push_number(inter_sp, sock->lpc_fd);
+				push_number(inter_sp, 0);
+		
+				secure_callback_lambda(&sock->close_callback, 2);
+		
+				free_socket_entry(sock);
+				return;
+			}
+			else
+			{
+				push_number(inter_sp, sock->lpc_fd);
+				push_string(inter_sp, mstring_new_n_string(g_read_buffer, len));
+				push_number(inter_sp, len);
+		
+				secure_callback_lambda(&sock->read_callback, 3);
+			}
+		}
+		else if(sock->state == STATE_LISTEN)
+		{
+			push_number(inter_sp, sock->lpc_fd);
+		
+			secure_callback_lambda(&sock->listen_callback, 1);
+		}
+		else
+		{
+			fprintf(stderr, "socket_poll: read event in unknown state %d\n", sock->state);
+		}
+	}
+}
diff -burN 3-3/src/sockets.h 3-3.sock/src/sockets.h
--- 3-3/src/sockets.h	Thu Jan  1 02:00:00 1970
+++ 3-3.sock/src/sockets.h	Thu Sep 12 13:35:17 2002
@@ -0,0 +1,6 @@
+
+void socket_init();
+
+void socket_object_destructed(object_t* ob);
+
+void socket_poll();