[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Emacs-diffs] Changes to emacs/src/process.c
From: |
Kim F. Storm |
Subject: |
[Emacs-diffs] Changes to emacs/src/process.c |
Date: |
Sun, 17 Mar 2002 15:20:34 -0500 |
Index: emacs/src/process.c
diff -c emacs/src/process.c:1.355 emacs/src/process.c:1.356
*** emacs/src/process.c:1.355 Sat Mar 2 19:31:22 2002
--- emacs/src/process.c Sun Mar 17 15:20:33 2002
***************
*** 57,62 ****
--- 57,73 ----
#ifdef NEED_NET_ERRNO_H
#include <net/errno.h>
#endif /* NEED_NET_ERRNO_H */
+
+ /* Are local (unix) sockets supported? */
+ #ifndef NO_SOCKETS_IN_FILE_SYSTEM
+ #if !defined (AF_LOCAL) && defined (AF_UNIX)
+ #define AF_LOCAL AF_UNIX
+ #endif
+ #ifdef AF_LOCAL
+ #define HAVE_LOCAL_SOCKETS
+ #include <sys/un.h>
+ #endif
+ #endif
#endif /* HAVE_SOCKETS */
/* TERM is a poor-man's SLIP, used on GNU/Linux. */
***************
*** 113,119 ****
Lisp_Object Qprocessp;
Lisp_Object Qrun, Qstop, Qsignal;
! Lisp_Object Qopen, Qclosed, Qconnect, Qfailed;
Lisp_Object Qlast_nonmenu_event;
/* Qexit is declared and initialized in eval.c. */
--- 124,135 ----
Lisp_Object Qprocessp;
Lisp_Object Qrun, Qstop, Qsignal;
! Lisp_Object Qopen, Qclosed, Qconnect, Qfailed, Qlisten;
! Lisp_Object Qlocal;
! Lisp_Object QCname, QCbuffer, QChost, QCservice, QCfamily;
! Lisp_Object QClocal, QCremote, QCcoding;
! Lisp_Object QCserver, QCdatagram, QCnowait, QCnoquery, QCstop;
! Lisp_Object QCfilter, QCsentinel, QClog, QCoptions, QCfeature;
Lisp_Object Qlast_nonmenu_event;
/* Qexit is declared and initialized in eval.c. */
***************
*** 122,129 ****
--- 138,147 ----
#ifdef HAVE_SOCKETS
#define NETCONN_P(p) (GC_CONSP (XPROCESS (p)->childp))
+ #define NETCONN1_P(p) (GC_CONSP ((p)->childp))
#else
#define NETCONN_P(p) 0
+ #define NETCONN1_P(p) 0
#endif /* HAVE_SOCKETS */
/* Define first descriptor number available for subprocesses. */
***************
*** 194,203 ****
--- 212,250 ----
#endif /* NON_BLOCKING_CONNECT */
#endif /* BROKEN_NON_BLOCKING_CONNECT */
+ /* Define DATAGRAM_SOCKETS if datagrams can be used safely on
+ this system. We need to read full packets, so we need a
+ "non-destructive" select. So we require either native select,
+ or emulation of select using FIONREAD. */
+
+ #ifdef GNU_LINUX
+ /* These are not yet in configure.in (they will be eventually)
+ -- so add them here temporarily. ++kfs */
+ #define HAVE_RECVFROM
+ #define HAVE_SENDTO
+ #define HAVE_GETSOCKNAME
+ #endif
+
+ #ifdef BROKEN_DATAGRAM_SOCKETS
+ #undef DATAGRAM_SOCKETS
+ #else
+ #ifndef DATAGRAM_SOCKETS
+ #ifdef HAVE_SOCKETS
+ #if defined (HAVE_SELECT) || defined (FIONREAD)
+ #if defined (HAVE_SENDTO) && defined (HAVE_RECVFROM) && defined (EMSGSIZE)
+ #define DATAGRAM_SOCKETS
+ #endif /* HAVE_SENDTO && HAVE_RECVFROM && EMSGSIZE */
+ #endif /* HAVE_SELECT || FIONREAD */
+ #endif /* HAVE_SOCKETS */
+ #endif /* DATAGRAM_SOCKETS */
+ #endif /* BROKEN_DATAGRAM_SOCKETS */
+
#ifdef TERM
#undef NON_BLOCKING_CONNECT
+ #undef DATAGRAM_SOCKETS
#endif
+
#include "sysselect.h"
extern int keyboard_bit_set P_ ((SELECT_TYPE *));
***************
*** 257,262 ****
--- 304,322 ----
static struct coding_system *proc_decode_coding_system[MAXDESC];
static struct coding_system *proc_encode_coding_system[MAXDESC];
+ #ifdef DATAGRAM_SOCKETS
+ /* Table of `partner address' for datagram sockets. */
+ struct sockaddr_and_len {
+ struct sockaddr *sa;
+ int len;
+ } datagram_address[MAXDESC];
+ #define DATAGRAM_CHAN_P(chan) (datagram_address[chan].sa != 0)
+ #define DATAGRAM_CONN_P(proc) (datagram_address[XPROCESS (proc)->infd].sa !=
0)
+ #else
+ #define DATAGRAM_CHAN_P(chan) (0)
+ #define DATAGRAM_CONN_P(proc) (0)
+ #endif
+
static Lisp_Object get_process ();
static void exec_sentinel ();
***************
*** 367,381 ****
return build_string ("finished\n");
string = Fnumber_to_string (make_number (code));
string2 = build_string (coredump ? " (core dumped)\n" : "\n");
! return concat2 (build_string ("exited abnormally with code "),
! concat2 (string, string2));
}
else if (EQ (symbol, Qfailed))
{
string = Fnumber_to_string (make_number (code));
string2 = build_string ("\n");
! return concat2 (build_string ("failed with code "),
! concat2 (string, string2));
}
else
return Fcopy_sequence (Fsymbol_name (symbol));
--- 427,441 ----
return build_string ("finished\n");
string = Fnumber_to_string (make_number (code));
string2 = build_string (coredump ? " (core dumped)\n" : "\n");
! return concat3 (build_string ("exited abnormally with code "),
! string, string2);
}
else if (EQ (symbol, Qfailed))
{
string = Fnumber_to_string (make_number (code));
string2 = build_string ("\n");
! return concat3 (build_string ("failed with code "),
! string, string2);
}
else
return Fcopy_sequence (Fsymbol_name (symbol));
***************
*** 635,640 ****
--- 695,701 ----
exit -- for a process that has exited.
signal -- for a process that has got a fatal signal.
open -- for a network stream connection that is open.
+ listen -- for a network stream server that is listening.
closed -- for a network stream connection that is closed.
connect -- when waiting for a non-blocking connection to complete.
failed -- when a non-blocking connection has failed.
***************
*** 661,672 ****
status = p->status;
if (CONSP (status))
status = XCAR (status);
! if (NETCONN_P (process))
{
! if (EQ (status, Qrun))
! status = Qopen;
! else if (EQ (status, Qexit))
status = Qclosed;
}
return status;
}
--- 722,735 ----
status = p->status;
if (CONSP (status))
status = XCAR (status);
! if (NETCONN1_P (p))
{
! if (EQ (status, Qexit))
status = Qclosed;
+ else if (EQ (p->command, Qt))
+ status = Qstop;
+ else if (EQ (status, Qrun))
+ status = Qopen;
}
return status;
}
***************
*** 737,746 ****
(process, buffer)
register Lisp_Object process, buffer;
{
CHECK_PROCESS (process);
if (!NILP (buffer))
CHECK_BUFFER (buffer);
! XPROCESS (process)->buffer = buffer;
return buffer;
}
--- 800,814 ----
(process, buffer)
register Lisp_Object process, buffer;
{
+ struct Lisp_Process *p;
+
CHECK_PROCESS (process);
if (!NILP (buffer))
CHECK_BUFFER (buffer);
! p = XPROCESS (process);
! p->buffer = buffer;
! if (NETCONN1_P (p))
! p->childp = Fplist_put (p->childp, QCbuffer, buffer);
return buffer;
}
***************
*** 791,802 ****
if (XINT (p->infd) >= 0)
{
! if (EQ (filter, Qt))
{
FD_CLR (XINT (p->infd), &input_wait_mask);
FD_CLR (XINT (p->infd), &non_keyboard_wait_mask);
}
! else if (EQ (XPROCESS (process)->filter, Qt))
{
FD_SET (XINT (p->infd), &input_wait_mask);
FD_SET (XINT (p->infd), &non_keyboard_wait_mask);
--- 859,871 ----
if (XINT (p->infd) >= 0)
{
! if (EQ (filter, Qt) && !EQ (p->status, Qlisten))
{
FD_CLR (XINT (p->infd), &input_wait_mask);
FD_CLR (XINT (p->infd), &non_keyboard_wait_mask);
}
! else if (EQ (p->filter, Qt)
! && !EQ (p->command, Qt)) /* Network process not stopped. */
{
FD_SET (XINT (p->infd), &input_wait_mask);
FD_SET (XINT (p->infd), &non_keyboard_wait_mask);
***************
*** 804,809 ****
--- 873,880 ----
}
p->filter = filter;
+ if (NETCONN1_P (p))
+ p->childp = Fplist_put (p->childp, QCfilter, filter);
return filter;
}
***************
*** 899,930 ****
return XPROCESS (process)->inherit_coding_system_flag;
}
! DEFUN ("process-kill-without-query", Fprocess_kill_without_query,
! Sprocess_kill_without_query, 1, 2, 0,
! doc: /* Say no query needed if PROCESS is running when Emacs is exited.
! Optional second argument if non-nil says to require a query.
! Value is t if a query was formerly required. */)
! (process, value)
! register Lisp_Object process, value;
{
- Lisp_Object tem;
-
CHECK_PROCESS (process);
! tem = XPROCESS (process)->kill_without_query;
! XPROCESS (process)->kill_without_query = Fnull (value);
!
! return Fnull (tem);
}
! DEFUN ("process-contact", Fprocess_contact, Sprocess_contact,
1, 1, 0,
! doc: /* Return the contact info of PROCESS; t for a real child.
! For a net connection, the value is a cons cell of the form (HOST SERVICE).
*/)
(process)
register Lisp_Object process;
{
CHECK_PROCESS (process);
! return XPROCESS (process)->childp;
}
#if 0 /* Turned off because we don't currently record this info
--- 970,1033 ----
return XPROCESS (process)->inherit_coding_system_flag;
}
! DEFUN ("set-process-query-on-exit-flag",
! Fset_process_query_on_exit_flag, Sset_process_query_on_exit_flag,
! 2, 2, 0,
! doc: /* Specify if query is needed for PROCESS when Emacs is exited.
! If the second argument FLAG is non-nil, emacs will query the user before
! exiting if PROCESS is running. */)
! (process, flag)
! register Lisp_Object process, flag;
{
CHECK_PROCESS (process);
! XPROCESS (process)->kill_without_query = Fnull (flag);
! return flag;
}
! DEFUN ("process-query-on-exit-flag",
! Fprocess_query_on_exit_flag, Sprocess_query_on_exit_flag,
1, 1, 0,
! doc: /* Return the current value of query on exit flag for PROCESS.
*/)
(process)
register Lisp_Object process;
{
CHECK_PROCESS (process);
! return Fnull (XPROCESS (process)->kill_without_query);
! }
!
! #ifdef DATAGRAM_SOCKETS
! Lisp_Object Fprocess_datagram_address ();
! #endif
!
! DEFUN ("process-contact", Fprocess_contact, Sprocess_contact,
! 1, 2, 0,
! doc: /* Return the contact info of PROCESS; t for a real child.
! For a net connection, the value depends on the optional KEY arg.
! If KEY is nil, value is a cons cell of the form (HOST SERVICE),
! if KEY is t, the complete contact information for the connection is
! returned, else the specific value for the keyword KEY is returned.
! See `make-network-process' for a list of keywords. */)
! (process, key)
! register Lisp_Object process, key;
! {
! Lisp_Object contact;
!
! CHECK_PROCESS (process);
! contact = XPROCESS (process)->childp;
!
! #ifdef DATAGRAM_SOCKETS
! if (DATAGRAM_CONN_P (process)
! && (EQ (key, Qt) || EQ (key, QCremote)))
! contact = Fplist_put (contact, QCremote,
! Fprocess_datagram_address (process));
! #endif
!
! if (!NETCONN_P (process) || EQ (key, Qt))
! return contact;
! if (NILP (key))
! return Fcons (Fplist_get (contact, QChost),
! Fcons (Fplist_get (contact, QCservice), Qnil));
! return Fplist_get (contact, key);
}
#if 0 /* Turned off because we don't currently record this info
***************
*** 941,952 ****
#endif
Lisp_Object
! list_processes_1 ()
{
register Lisp_Object tail, tem;
Lisp_Object proc, minspace, tem1;
register struct Lisp_Process *p;
! char tembuf[80];
XSETFASTINT (minspace, 1);
--- 1044,1098 ----
#endif
Lisp_Object
! list_processes_1 (query_only)
! Lisp_Object query_only;
{
register Lisp_Object tail, tem;
Lisp_Object proc, minspace, tem1;
register struct Lisp_Process *p;
! char tembuf[300];
! int w_proc, w_buffer, w_tty;
! Lisp_Object i_status, i_buffer, i_tty, i_command;
!
! w_proc = 4; /* Proc */
! w_buffer = 6; /* Buffer */
! w_tty = 0; /* Omit if no ttys */
!
! for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
! {
! int i;
!
! proc = Fcdr (Fcar (tail));
! p = XPROCESS (proc);
! if (NILP (p->childp))
! continue;
! if (!NILP (query_only) && !NILP (p->kill_without_query))
! continue;
! if (STRINGP (p->name)
! && ( i = XSTRING (p->name)->size, (i > w_proc)))
! w_proc = i;
! if (!NILP (p->buffer))
! {
! if (NILP (XBUFFER (p->buffer)->name) && w_buffer < 8)
! w_buffer = 8; /* (Killed) */
! else if ((i = XSTRING (XBUFFER (p->buffer)->name)->size, (i >
w_buffer)))
! w_buffer = i;
! }
! if (STRINGP (p->tty_name)
! && (i = XSTRING (p->tty_name)->size, (i > w_tty)))
! w_tty = i;
! }
!
! XSETFASTINT (i_status, w_proc + 1);
! XSETFASTINT (i_buffer, XFASTINT (i_status) + 9);
! if (w_tty)
! {
! XSETFASTINT (i_tty, XFASTINT (i_buffer) + w_buffer + 1);
! XSETFASTINT (i_command, XFASTINT (i_buffer) + w_tty + 1);
! } else {
! i_tty = Qnil;
! XSETFASTINT (i_command, XFASTINT (i_buffer) + w_buffer + 1);
! }
XSETFASTINT (minspace, 1);
***************
*** 955,963 ****
current_buffer->truncate_lines = Qt;
! write_string ("\
! Proc Status Buffer Tty Command\n\
! ---- ------ ------ --- -------\n", -1);
for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
{
--- 1101,1125 ----
current_buffer->truncate_lines = Qt;
! write_string ("Proc", -1);
! Findent_to (i_status, minspace); write_string ("Status", -1);
! Findent_to (i_buffer, minspace); write_string ("Buffer", -1);
! if (!NILP (i_tty))
! {
! Findent_to (i_tty, minspace); write_string ("Tty", -1);
! }
! Findent_to (i_command, minspace); write_string ("Command", -1);
! write_string ("\n", -1);
!
! write_string ("----", -1);
! Findent_to (i_status, minspace); write_string ("------", -1);
! Findent_to (i_buffer, minspace); write_string ("------", -1);
! if (!NILP (i_tty))
! {
! Findent_to (i_tty, minspace); write_string ("---", -1);
! }
! Findent_to (i_command, minspace); write_string ("-------", -1);
! write_string ("\n", -1);
for (tail = Vprocess_alist; !NILP (tail); tail = Fcdr (tail))
{
***************
*** 967,975 ****
p = XPROCESS (proc);
if (NILP (p->childp))
continue;
Finsert (1, &p->name);
! Findent_to (make_number (13), minspace);
if (!NILP (p->raw_status_low))
update_status (p);
--- 1129,1139 ----
p = XPROCESS (proc);
if (NILP (p->childp))
continue;
+ if (!NILP (query_only) && !NILP (p->kill_without_query))
+ continue;
Finsert (1, &p->name);
! Findent_to (i_status, minspace);
if (!NILP (p->raw_status_low))
update_status (p);
***************
*** 989,1000 ****
#endif
Fprinc (symbol, Qnil);
}
! else if (NETCONN_P (proc))
{
! if (EQ (symbol, Qrun))
! write_string ("open", -1);
! else if (EQ (symbol, Qexit))
write_string ("closed", -1);
else
Fprinc (symbol, Qnil);
}
--- 1153,1166 ----
#endif
Fprinc (symbol, Qnil);
}
! else if (NETCONN1_P (p))
{
! if (EQ (symbol, Qexit))
write_string ("closed", -1);
+ else if (EQ (p->command, Qt))
+ write_string ("stopped", -1);
+ else if (EQ (symbol, Qrun))
+ write_string ("open", -1);
else
Fprinc (symbol, Qnil);
}
***************
*** 1015,1021 ****
if (EQ (symbol, Qsignal) || EQ (symbol, Qexit))
remove_process (proc);
! Findent_to (make_number (22), minspace);
if (NILP (p->buffer))
insert_string ("(none)");
else if (NILP (XBUFFER (p->buffer)->name))
--- 1181,1187 ----
if (EQ (symbol, Qsignal) || EQ (symbol, Qexit))
remove_process (proc);
! Findent_to (i_buffer, minspace);
if (NILP (p->buffer))
insert_string ("(none)");
else if (NILP (XBUFFER (p->buffer)->name))
***************
*** 1023,1041 ****
else
Finsert (1, &XBUFFER (p->buffer)->name);
! Findent_to (make_number (37), minspace);
!
! if (STRINGP (p->tty_name))
! Finsert (1, &p->tty_name);
! else
! insert_string ("(none)");
! Findent_to (make_number (49), minspace);
! if (NETCONN_P (proc))
{
! sprintf (tembuf, "(network stream connection to %s)\n",
! XSTRING (XCAR (p->childp))->data);
insert_string (tembuf);
}
else
--- 1189,1227 ----
else
Finsert (1, &XBUFFER (p->buffer)->name);
! if (!NILP (i_tty))
! {
! Findent_to (i_tty, minspace);
! if (STRINGP (p->tty_name))
! Finsert (1, &p->tty_name);
! }
! Findent_to (i_command, minspace);
! if (EQ (p->status, Qlisten))
! {
! Lisp_Object port = Fplist_get (p->childp, QCservice);
! if (INTEGERP (port))
! port = Fnumber_to_string (port);
! sprintf (tembuf, "(network %s server on %s)\n",
! (DATAGRAM_CHAN_P (p->infd) ? "datagram" : "stream"),
! XSTRING (port)->data);
! insert_string (tembuf);
! }
! else if (NETCONN1_P (p))
{
! /* For a local socket, there is no host name,
! so display service instead. */
! Lisp_Object host = Fplist_get (p->childp, QChost);
! if (!STRINGP (host))
! {
! host = Fplist_get (p->childp, QCservice);
! if (INTEGERP (host))
! host = Fnumber_to_string (host);
! }
! sprintf (tembuf, "(network %s connection to %s)\n",
! (DATAGRAM_CHAN_P (p->infd) ? "datagram" : "stream"),
! XSTRING (host)->data);
insert_string (tembuf);
}
else
***************
*** 1056,1069 ****
return Qnil;
}
! DEFUN ("list-processes", Flist_processes, Slist_processes, 0, 0, "",
doc: /* Display a list of all processes.
Any process listed as exited or signaled is actually eliminated
after the listing is made. */)
! ()
{
internal_with_output_to_temp_buffer ("*Process List*",
! list_processes_1, Qnil);
return Qnil;
}
--- 1242,1258 ----
return Qnil;
}
! DEFUN ("list-processes", Flist_processes, Slist_processes, 0, 1, "P",
doc: /* Display a list of all processes.
+ If optional argument QUERY-ONLY is non-nil, only processes with
+ the query-on-exit flag set will be listed.
Any process listed as exited or signaled is actually eliminated
after the listing is made. */)
! (query_only)
! Lisp_Object query_only;
{
internal_with_output_to_temp_buffer ("*Process List*",
! list_processes_1, query_only);
return Qnil;
}
***************
*** 1776,1829 ****
}
#endif /* not VMS */
#ifdef HAVE_SOCKETS
! /* open a TCP network connection to a given HOST/SERVICE. Treated
! exactly like a normal process when reading and writing. Only
differences are in status display and process deletion. A network
connection has no PID; you cannot signal it. All you can do is
! deactivate and close it via delete-process */
!
! DEFUN ("open-network-stream", Fopen_network_stream, Sopen_network_stream,
! 4, 7, 0,
! doc: /* Open a TCP connection for a service to a host.
! Returns a subprocess-object to represent the connection.
! Returns nil if a non-blocking connect is attempted on a system which
! cannot support that; in that case, the caller should attempt a
! normal connect instead.
! Input and output work as for subprocesses; `delete-process' closes it.
! Args are NAME BUFFER HOST SERVICE FILTER SENTINEL NON-BLOCKING.
! NAME is name for process. It is modified if necessary to make it unique.
! BUFFER is the buffer (or buffer-name) to associate with the process.
! Process output goes at end of that buffer, unless you specify
! an output stream or filter function to handle the output.
! BUFFER may be also nil, meaning that this process is not associated
! with any buffer.
! HOST is name of the host to connect to, or its IP address.
! SERVICE is name of the service desired, or an integer specifying a
! port number to connect to.
! FILTER and SENTINEL are optional args specifying the filter and
! sentinel functions associated with the network stream.
! NON-BLOCKING is optional arg requesting an non-blocking connect.
! When non-nil, open-network-stream will return immediately without
! waiting for the connection to be made. Instead, the sentinel function
! will be called with second matching "open" (if successful) or
! "failed" when the connect completes. */)
! (name, buffer, host, service, filter, sentinel, non_blocking)
! Lisp_Object name, buffer, host, service, filter, sentinel, non_blocking;
{
Lisp_Object proc;
#ifdef HAVE_GETADDRINFO
! struct addrinfo hints, *res, *lres;
! char *portstring, portbuf[128];
#else /* HAVE_GETADDRINFO */
- struct sockaddr_in address;
- struct servent *svc_info;
- struct hostent *host_info_ptr, host_info;
- char *(addr_list[2]);
- IN_ADDR numeric_addr;
- int port;
struct _emacs_addrinfo
{
int ai_family;
--- 1965,2625 ----
}
#endif /* not VMS */
+
#ifdef HAVE_SOCKETS
! /* Convert an internal struct sockaddr to a lisp object (vector or string).
! The address family of sa is not included in the result. */
!
! static Lisp_Object
! conv_sockaddr_to_lisp (sa, len)
! struct sockaddr *sa;
! int len;
! {
! Lisp_Object address;
! int i;
! unsigned char *cp;
! register struct Lisp_Vector *p;
!
! switch (sa->sa_family)
! {
! case AF_INET:
! {
! struct sockaddr_in *sin = (struct sockaddr_in *) sa;
! len = sizeof (sin->sin_addr) + 1;
! address = Fmake_vector (make_number (len), Qnil);
! p = XVECTOR (address);
! p->contents[--len] = make_number (ntohs (sin->sin_port));
! cp = (unsigned char *)&sin->sin_addr;
! break;
! }
! #ifdef HAVE_LOCAL_SOCKETS
! case AF_LOCAL:
! {
! struct sockaddr_un *sun = (struct sockaddr_un *) sa;
! for (i = 0; i < sizeof (sun->sun_path); i++)
! if (sun->sun_path[i] == 0)
! break;
! return make_unibyte_string (sun->sun_path, i);
! }
! #endif
! default:
! len -= sizeof (sa->sa_family);
! address = Fcons (make_number (sa->sa_family),
! Fmake_vector (make_number (len), Qnil));
! p = XVECTOR (XCDR (address));
! cp = (unsigned char *) sa + sizeof (sa->sa_family);
! break;
! }
!
! i = 0;
! while (i < len)
! p->contents[i++] = make_number (*cp++);
!
! return address;
! }
!
!
! /* Get family and required size for sockaddr structure to hold ADDRESS. */
!
! static int
! get_lisp_to_sockaddr_size (address, familyp)
! Lisp_Object address;
! int *familyp;
! {
! register struct Lisp_Vector *p;
!
! if (VECTORP (address))
! {
! p = XVECTOR (address);
! if (p->size == 5)
! {
! *familyp = AF_INET;
! return sizeof (struct sockaddr_in);
! }
! }
! #ifdef HAVE_LOCAL_SOCKETS
! else if (STRINGP (address))
! {
! *familyp = AF_LOCAL;
! return sizeof (struct sockaddr_un);
! }
! #endif
! else if (CONSP (address) && INTEGERP (XCAR (address)) && VECTORP (XCDR
(address)))
! {
! struct sockaddr *sa;
! *familyp = XINT (XCAR (address));
! p = XVECTOR (XCDR (address));
! return p->size + sizeof (sa->sa_family);
! }
! return 0;
! }
!
! /* Convert an address object (vector or string) to an internal sockaddr.
! Format of address has already been validated by size_lisp_to_sockaddr. */
!
! static void
! conv_lisp_to_sockaddr (family, address, sa, len)
! int family;
! Lisp_Object address;
! struct sockaddr *sa;
! int len;
! {
! register struct Lisp_Vector *p;
! register unsigned char *cp;
! register int i;
!
! bzero (sa, len);
! sa->sa_family = family;
!
! if (VECTORP (address))
! {
! p = XVECTOR (address);
! if (family == AF_INET)
! {
! struct sockaddr_in *sin = (struct sockaddr_in *) sa;
! len = sizeof (sin->sin_addr) + 1;
! i = XINT (p->contents[--len]);
! sin->sin_port = htons (i);
! cp = (unsigned char *)&sin->sin_addr;
! }
! }
! else if (STRINGP (address))
! {
! #ifdef HAVE_LOCAL_SOCKETS
! if (family == AF_LOCAL)
! {
! struct sockaddr_un *sun = (struct sockaddr_un *) sa;
! cp = XSTRING (address)->data;
! for (i = 0; i < sizeof (sun->sun_path) && *cp; i++)
! sun->sun_path[i] = *cp++;
! }
! #endif
! return;
! }
! else
! {
! p = XVECTOR (XCDR (address));
! cp = (unsigned char *)sa + sizeof (sa->sa_family);
! }
!
! for (i = 0; i < len; i++)
! if (INTEGERP (p->contents[i]))
! *cp++ = XFASTINT (p->contents[i]) & 0xff;
! }
!
! #ifdef DATAGRAM_SOCKETS
! DEFUN ("process-datagram-address", Fprocess_datagram_address,
Sprocess_datagram_address,
! 1, 1, 0,
! doc: /* Get the current datagram address associated with PROCESS. */)
! (process)
! Lisp_Object process;
! {
! int channel;
!
! CHECK_PROCESS (process);
!
! if (!DATAGRAM_CONN_P (process))
! return Qnil;
!
! channel = XPROCESS (process)->infd;
! return conv_sockaddr_to_lisp (datagram_address[channel].sa,
! datagram_address[channel].len);
! }
!
! DEFUN ("set-process-datagram-address", Fset_process_datagram_address,
Sset_process_datagram_address,
! 2, 2, 0,
! doc: /* Set the datagram address for PROCESS to ADDRESS.
! Returns nil upon error setting address, ADDRESS otherwise. */)
! (process, address)
! Lisp_Object process, address;
! {
! int channel;
! int family, len;
!
! CHECK_PROCESS (process);
!
! if (!DATAGRAM_CONN_P (process))
! return Qnil;
!
! channel = XPROCESS (process)->infd;
!
! len = get_lisp_to_sockaddr_size (address, &family);
! if (datagram_address[channel].len != len)
! return Qnil;
! conv_lisp_to_sockaddr (family, address, datagram_address[channel].sa, len);
! return address;
! }
! #endif
!
!
! static struct socket_options {
! /* The name of this option. Should be lowercase version of option
! name without SO_ prefix. */
! char *name;
! /* Length of name. */
! int nlen;
! /* Option level SOL_... */
! int optlevel;
! /* Option number SO_... */
! int optnum;
! enum { SOPT_UNKNOWN, SOPT_BOOL, SOPT_INT, SOPT_STR, SOPT_LINGER } opttype;
! } socket_options[] =
! {
! #ifdef SO_BINDTODEVICE
! { "bindtodevice", 12, SOL_SOCKET, SO_BINDTODEVICE, SOPT_STR },
! #endif
! #ifdef SO_BROADCAST
! { "broadcast", 9, SOL_SOCKET, SO_BROADCAST, SOPT_BOOL },
! #endif
! #ifdef SO_DONTROUTE
! { "dontroute", 9, SOL_SOCKET, SO_DONTROUTE, SOPT_BOOL },
! #endif
! #ifdef SO_KEEPALIVE
! { "keepalive", 9, SOL_SOCKET, SO_KEEPALIVE, SOPT_BOOL },
! #endif
! #ifdef SO_LINGER
! { "linger", 6, SOL_SOCKET, SO_LINGER, SOPT_LINGER },
! #endif
! #ifdef SO_OOBINLINE
! { "oobinline", 9, SOL_SOCKET, SO_OOBINLINE, SOPT_BOOL },
! #endif
! #ifdef SO_PRIORITY
! { "priority", 8, SOL_SOCKET, SO_PRIORITY, SOPT_INT },
! #endif
! #ifdef SO_REUSEADDR
! { "reuseaddr", 9, SOL_SOCKET, SO_REUSEADDR, SOPT_BOOL },
! #endif
! { 0, 0, 0, 0, SOPT_UNKNOWN }
! };
!
! /* Process list of socket options OPTS on socket S.
! Only check if options are supported is S < 0.
! If NO_ERROR is non-zero, continue silently if an option
! cannot be set.
!
! Each element specifies one option. An element is either a string
! "OPTION=VALUE" or a cons (OPTION . VALUE) where OPTION is a string
! or a symbol. */
!
! static int
! set_socket_options (s, opts, no_error)
! int s;
! Lisp_Object opts;
! int no_error;
! {
! if (!CONSP (opts))
! opts = Fcons (opts, Qnil);
!
! while (CONSP (opts))
! {
! Lisp_Object opt;
! Lisp_Object val;
! char *name, *arg;
! struct socket_options *sopt;
! int optnum, opttype;
! int ret = 0;
!
! opt = XCAR (opts);
! opts = XCDR (opts);
!
! name = 0;
! val = Qt;
! if (CONSP (opt))
! {
! val = XCDR (opt);
! opt = XCAR (opt);
! }
! if (STRINGP (opt))
! name = (char *) XSTRING (opt)->data;
! else if (SYMBOLP (opt))
! name = (char *) XSYMBOL (opt)->name->data;
! else {
! error ("Mal-formed option list");
! return 0;
! }
!
! if (strncmp (name, "no", 2) == 0)
! {
! val = Qnil;
! name += 2;
! }
!
! arg = 0;
! for (sopt = socket_options; sopt->name; sopt++)
! if (strncmp (name, sopt->name, sopt->nlen) == 0)
! {
! if (name[sopt->nlen] == 0)
! break;
! if (name[sopt->nlen] == '=')
! {
! arg = name + sopt->nlen + 1;
! break;
! }
! }
!
! switch (sopt->opttype)
! {
! case SOPT_BOOL:
! {
! int optval;
! if (s < 0)
! return 1;
! if (arg)
! optval = (*arg == '0' || *arg == 'n') ? 0 : 1;
! else if (INTEGERP (val))
! optval = XINT (val) == 0 ? 0 : 1;
! else
! optval = NILP (val) ? 0 : 1;
! ret = setsockopt (s, sopt->optlevel, sopt->optnum,
! &optval, sizeof (optval));
! break;
! }
!
! case SOPT_INT:
! {
! int optval;
! if (arg)
! optval = atoi(arg);
! else if (INTEGERP (val))
! optval = XINT (val);
! else
! error ("Bad option argument for %s", name);
! if (s < 0)
! return 1;
! ret = setsockopt (s, sopt->optlevel, sopt->optnum,
! &optval, sizeof (optval));
! break;
! }
!
! case SOPT_STR:
! {
! if (!arg)
! {
! if (NILP (val))
! arg = "";
! else if (STRINGP (val))
! arg = (char *) XSTRING (val)->data;
! else if (XSYMBOL (val))
! arg = (char *) XSYMBOL (val)->name->data;
! else
! error ("Invalid argument to %s option", name);
! }
! ret = setsockopt (s, sopt->optlevel, sopt->optnum,
! arg, strlen (arg));
! }
!
! #ifdef SO_LINGER
! case SOPT_LINGER:
! {
! struct linger linger;
!
! linger.l_onoff = 1;
! linger.l_linger = 0;
!
! if (s < 0)
! return 1;
!
! if (arg)
! {
! if (*arg == 'n' || *arg == 't' || *arg == 'y')
! linger.l_onoff = (*arg == 'n') ? 0 : 1;
! else
! linger.l_linger = atoi(arg);
! }
! else if (INTEGERP (val))
! linger.l_linger = XINT (val);
! else
! linger.l_onoff = NILP (val) ? 0 : 1;
! ret = setsockopt (s, sopt->optlevel, sopt->optnum,
! &linger, sizeof (linger));
! break;
! }
! #endif
! default:
! if (s < 0)
! return 0;
! if (no_error)
! continue;
! error ("Unsupported option: %s", name);
! }
! if (ret < 0 && ! no_error)
! report_file_error ("Cannot set network option: %s", opt);
! }
! return 1;
! }
!
! DEFUN ("set-network-process-options",
! Fset_network_process_options, Sset_network_process_options,
! 1, MANY, 0,
! doc: /* Set one or more options for network process PROCESS.
! Arguments are PROCESS &rest OPTIONS.
! Each option is either a string "OPT=VALUE" or a cons (OPT . VALUE).
! A boolean value is false if it either zero or nil, true otherwise.
!
! The following options are known. Consult the relevant system manual
! pages for more information.
!
! bindtodevice=NAME -- bind to interface NAME, or remove binding if nil.
! broadcast=BOOL -- Allow send and receive of datagram broadcasts.
! dontroute=BOOL -- Only send to directly connected hosts.
! keepalive=BOOL -- Send keep-alive messages on network stream.
! linger=BOOL or TIMEOUT -- Send queued messages before closing.
! oobinline=BOOL -- Place out-of-band data in receive data stream.
! priority=INT -- Set protocol defined priority for sent packets.
! reuseaddr=BOOL -- Allow reusing a recently used address. */)
! (nargs, args)
! int nargs;
! Lisp_Object *args;
! {
! Lisp_Object process;
! Lisp_Object opts;
!
! process = args[0];
! CHECK_PROCESS (process);
! if (nargs > 1 && XPROCESS (process)->infd >= 0)
! {
! opts = Flist (nargs, args);
! set_socket_options (XPROCESS (process)->infd, opts, 0);
! }
! return process;
! }
!
! /* Check whether a given KEY VALUE pair is supported on this system. */
!
! static int
! network_process_featurep (key, value)
! Lisp_Object key, value;
! {
!
! if (EQ (key, QCnowait))
! {
! #ifdef NON_BLOCKING_CONNECT
! return 1;
! #else
! return NILP (value);
! #endif
! }
!
! if (EQ (key, QCdatagram))
! {
! #ifdef DATAGRAM_SOCKETS
! return 1;
! #else
! return NILP (value);
! #endif
! }
!
! if (EQ (key, QCfamily))
! {
! if (NILP (value))
! return 1;
! #ifdef HAVE_LOCAL_SOCKETS
! if (EQ (key, Qlocal))
! return 1;
! #endif
! return 0;
! }
!
! if (EQ (key, QCname))
! return STRINGP (value);
!
! if (EQ (key, QCbuffer))
! return (NILP (value) || STRINGP (value) || BUFFERP (value));
!
! if (EQ (key, QClocal) || EQ (key, QCremote))
! {
! int family;
! return get_lisp_to_sockaddr_size (value, &family);
! }
!
! if (EQ (key, QChost))
! return (NILP (value) || STRINGP (value));
!
! if (EQ (key, QCservice))
! {
! #ifdef HAVE_GETSOCKNAME
! if (EQ (value, Qt))
! return 1;
! #endif
! return (INTEGERP (value) || STRINGP (value));
! }
!
! if (EQ (key, QCserver))
! {
! #ifndef TERM
! return 1;
! #else
! return NILP (value);
! #endif
! }
!
! if (EQ (key, QCoptions))
! return set_socket_options (-1, value, 0);
!
! if (EQ (key, QCcoding))
! return 1;
! if (EQ (key, QCsentinel))
! return 1;
! if (EQ (key, QCfilter))
! return 1;
! if (EQ (key, QClog))
! return 1;
! if (EQ (key, QCnoquery))
! return 1;
! if (EQ (key, QCstop))
! return 1;
!
! return 0;
! }
!
! /* A version of request_sigio suitable for a record_unwind_protect. */
!
! Lisp_Object
! unwind_request_sigio (dummy)
! Lisp_Object dummy;
! {
! if (interrupt_input)
! request_sigio ();
! return Qnil;
! }
!
! /* Create a network stream/datagram client/server process. Treated
! exactly like a normal process when reading and writing. Primary
differences are in status display and process deletion. A network
connection has no PID; you cannot signal it. All you can do is
! stop/continue it and deactivate/close it via delete-process */
! DEFUN ("make-network-process", Fmake_network_process, Smake_network_process,
! 0, MANY, 0,
! doc: /* Create and return a network server or client process.
!
! In emacs, network connections are represented by process objects, so
! input and output work as for subprocesses and `delete-process' closes
! a network connection. However, a network process has no process id,
! it cannot be signalled, and the status codes are different from normal
! processes.
!
! Arguments are specified as keyword/argument pairs. The following
! arguments are defined:
!
! :name NAME -- NAME is name for process. It is modified if necessary
! to make it unique.
!
! :buffer BUFFER -- BUFFER is the buffer (or buffer-name) to associate
! with the process. Process output goes at end of that buffer, unless
! you specify an output stream or filter function to handle the output.
! BUFFER may be also nil, meaning that this process is not associated
! with any buffer.
!
! :host HOST -- HOST is name of the host to connect to, or its IP
! address. The symbol `local' specifies the local host. If specified
! for a server process, it must be a valid name or address for the local
! host, and only clients connecting to that address will be accepted.
!
! :service SERVICE -- SERVICE is name of the service desired, or an
! integer specifying a port number to connect to. If SERVICE is t,
! a random port number is selected for the server.
!
! :family FAMILY -- FAMILY is the address (and protocol) family for the
! service specified by HOST and SERVICE. The default address family is
! Inet (or IPv4) for the host and port number specified by HOST and
! SERVICE. Other address families supported are:
! local -- for a local (i.e. UNIX) address specified by SERVICE.
!
! :local ADDRESS -- ADDRESS is the local address used for the connection.
! This parameter is ignored when opening a client process. When specified
! for a server process, the FAMILY, HOST and SERVICE args are ignored.
!
! :remote ADDRESS -- ADDRESS is the remote partner's address for the
! connection. This parameter is ignored when opening a stream server
! process. For a datagram server process, it specifies the initial
! setting of the remote datagram address. When specified for a client
! process, the FAMILY, HOST, and SERVICE args are ignored.
!
! The format of ADDRESS depends on the address family:
! - An IPv4 address is represented as an vector of integers [A B C D P]
! corresponding to numeric IP address A.B.C.D and port number P.
! - A local address is represented as a string with the address in the
! local address space.
! - An "unsupported family" address is represented by a cons (F . AV)
! where F is the family number and AV is a vector containing the socket
! address data with one element per address data byte. Do not rely on
! this format in portable code, as it may depend on implementation
! defined constants, data sizes, and data structure alignment.
!
! :coding CODING -- CODING is coding system for this process.
!
! :datagram BOOL -- Create a datagram type connection if BOOL is
! non-nil. Default is a stream type connection.
!
! :options OPTIONS -- Set the specified options for the network process.
! See `set-process-options' for details.
!
! :nowait BOOL -- If BOOL is non-nil for a stream type client process,
! return without waiting for the connection to complete; instead, the
! sentinel function will be called with second arg matching "open" (if
! successful) or "failed" when the connect completes. Default is to use
! a blocking connect (i.e. wait) for stream type connections.
!
! :noquery BOOL -- Query the user unless BOOL is non-nil, and process is
! running when emacs is exited.
!
! :stop BOOL -- Start process in the `stopped' state if BOOL non-nil.
! In the stopped state, a server process does not accept new
! connections, and a client process does not handle incoming traffic.
! The stopped state is cleared by `continue-process' and set by
! `stop-process'.
!
! :filter FILTER -- Install FILTER as the process filter.
!
! :sentinel SENTINEL -- Install SENTINEL as the process sentinel.
!
! :log LOG -- Install LOG as the server process log function. This
! function is called as when the server accepts a network connection from a
! client. The arguments are SERVER, CLIENT, and MESSAGE, where SERVER
! is the server process, CLIENT is the new process for the connection,
! and MESSAGE is a string.
!
! :server BOOL -- if BOOL is non-nil, create a server process for the
! specified FAMILY, SERVICE, and connection type (stream or datagram).
! Default is a client process.
!
! A server process will listen for and accept connections from
! clients. When a client connection is accepted, a new network process
! is created for the connection with the following parameters:
! - The client's process name is constructed by concatenating the server
! process' NAME and a client identification string.
! - If the FILTER argument is non-nil, the client process will not get a
! separate process buffer; otherwise, the client's process buffer is a newly
! created buffer named after the server process' BUFFER name or process
! NAME concatenated with the client identification string.
! - The connection type and the process filter and sentinel parameters are
! inherited from the server process' TYPE, FILTER and SENTINEL.
! - The client process' contact info is set according to the client's
! addressing information (typically an IP address and a port number).
!
! Notice that the FILTER and SENTINEL args are never used directly by
! the server process. Also, the BUFFER argument is not used directly by
! the server process, but via `network-server-log-function' hook, a log
! of the accepted (and failed) connections may be recorded in the server
! process' buffer.
!
! The following special call returns t iff a given KEY VALUE
! pair is supported on this system:
! (make-network-process :feature KEY VALUE) */)
! (nargs, args)
! int nargs;
! Lisp_Object *args;
{
Lisp_Object proc;
+ Lisp_Object contact;
+ struct Lisp_Process *p;
#ifdef HAVE_GETADDRINFO
! struct addrinfo ai, *res, *lres;
! struct addrinfo hints;
! char *portstring, portbuf[128];
#else /* HAVE_GETADDRINFO */
struct _emacs_addrinfo
{
int ai_family;
***************
*** 1834,1983 ****
struct _emacs_addrinfo *ai_next;
} ai, *res, *lres;
#endif /* HAVE_GETADDRINFO */
int ret = 0;
int xerrno = 0;
int s = -1, outch, inch;
! struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
int retry = 0;
int count = specpdl_ptr - specpdl;
int count1;
! int is_non_blocking = 0;
! if (!NILP (non_blocking))
{
! #ifndef NON_BLOCKING_CONNECT
! return Qnil;
! #else
! non_blocking = Qt; /* Instead of GCPRO */
! is_non_blocking = 1;
! #endif
}
#ifdef WINDOWSNT
/* Ensure socket support is loaded if available. */
init_winsock (TRUE);
#endif
! /* Can only GCPRO 5 variables */
! GCPRO6 (name, buffer, host, service, sentinel, filter);
! CHECK_STRING (name);
! CHECK_STRING (host);
! #ifdef HAVE_GETADDRINFO
! /* SERVICE can either be a string or int.
! Convert to a C string for later use by getaddrinfo. */
! if (INTEGERP (service))
{
! sprintf (portbuf, "%ld", (long) XINT (service));
! portstring = portbuf;
}
! else
{
! CHECK_STRING (service);
! portstring = XSTRING (service)->data;
}
! #else /* HAVE_GETADDRINFO */
if (INTEGERP (service))
port = htons ((unsigned short) XINT (service));
else
{
CHECK_STRING (service);
svc_info = getservbyname (XSTRING (service)->data, "tcp");
if (svc_info == 0)
! error ("Unknown service \"%s\"", XSTRING (service)->data);
port = svc_info->s_port;
}
- #endif /* HAVE_GETADDRINFO */
/* Slow down polling to every ten seconds.
Some kernels have a bug which causes retrying connect to fail
after a connect. Polling can interfere with gethostbyname too. */
#ifdef POLL_FOR_INPUT
! record_unwind_protect (unwind_stop_other_atimers, Qnil);
! bind_polling_period (10);
#endif
- #ifndef TERM
#ifdef HAVE_GETADDRINFO
! immediate_quit = 1;
! QUIT;
! memset (&hints, 0, sizeof (hints));
! hints.ai_flags = 0;
! hints.ai_family = AF_UNSPEC;
! hints.ai_socktype = SOCK_STREAM;
! hints.ai_protocol = 0;
! ret = getaddrinfo (XSTRING (host)->data, portstring, &hints, &res);
! if (ret)
#ifdef HAVE_GAI_STRERROR
! error ("%s/%s %s", XSTRING (host)->data, portstring, gai_strerror(ret));
#else
! error ("%s/%s getaddrinfo error %d", XSTRING (host)->data, portstring,
! ret);
#endif
! immediate_quit = 0;
! #else /* not HAVE_GETADDRINFO */
! while (1)
{
! #if 0
! #ifdef TRY_AGAIN
! h_errno = 0;
! #endif
! #endif
immediate_quit = 1;
QUIT;
host_info_ptr = gethostbyname (XSTRING (host)->data);
immediate_quit = 0;
- #if 0
- #ifdef TRY_AGAIN
- if (! (host_info_ptr == 0 && h_errno == TRY_AGAIN))
- #endif
- #endif
- break;
- Fsleep_for (make_number (1), Qnil);
- }
! if (host_info_ptr == 0)
! /* Attempt to interpret host as numeric inet address */
! {
! numeric_addr = inet_addr ((char *) XSTRING (host)->data);
! if (NUMERIC_ADDR_ERROR)
! error ("Unknown host \"%s\"", XSTRING (host)->data);
!
! host_info_ptr = &host_info;
! host_info.h_name = 0;
! host_info.h_aliases = 0;
! host_info.h_addrtype = AF_INET;
! #ifdef h_addr
! /* Older machines have only one address slot called h_addr.
! Newer machines have h_addr_list, but #define h_addr to
! be its first element. */
! host_info.h_addr_list = &(addr_list[0]);
! #endif
! host_info.h_addr = (char*)(&numeric_addr);
! addr_list[1] = 0;
! /* numeric_addr isn't null-terminated; it has fixed length. */
! host_info.h_length = sizeof (numeric_addr);
! }
!
! bzero (&address, sizeof address);
! bcopy (host_info_ptr->h_addr, (char *) &address.sin_addr,
! host_info_ptr->h_length);
! address.sin_family = host_info_ptr->h_addrtype;
! address.sin_port = port;
!
! /* Emulate HAVE_GETADDRINFO for the loop over `res' below. */
! ai.ai_family = host_info_ptr->h_addrtype;
! ai.ai_socktype = SOCK_STREAM;
! ai.ai_protocol = 0;
! ai.ai_addr = (struct sockaddr *) &address;
! ai.ai_addrlen = sizeof address;
! ai.ai_next = NULL;
! res = &ai;
#endif /* not HAVE_GETADDRINFO */
/* Do this in case we never enter the for-loop below. */
count1 = specpdl_ptr - specpdl;
s = -1;
--- 2630,2942 ----
struct _emacs_addrinfo *ai_next;
} ai, *res, *lres;
#endif /* HAVE_GETADDRINFO */
+ struct sockaddr *sa = 0;
+ struct sockaddr_in address_in;
+ #ifdef HAVE_LOCAL_SOCKETS
+ struct sockaddr_un address_un;
+ #endif
+ int port;
int ret = 0;
int xerrno = 0;
int s = -1, outch, inch;
! struct gcpro gcpro1;
int retry = 0;
int count = specpdl_ptr - specpdl;
int count1;
! Lisp_Object QCaddress; /* one of QClocal or QCremote */
! Lisp_Object tem;
! Lisp_Object name, buffer, host, service, address;
! Lisp_Object filter, sentinel;
! int is_non_blocking_client = 0;
! int is_server = 0;
! int socktype = SOCK_STREAM;
! int family = -1;
! if (nargs == 0)
! return Qnil;
!
! /* Handle :feature KEY VALUE query. */
! if (EQ (args[0], QCfeature))
{
! if (nargs != 3)
! return Qnil;
! return network_process_featurep (args[1], args[2]) ? Qt : Qnil;
}
+ /* Save arguments for process-contact and clone-process. */
+ contact = Flist (nargs, args);
+ GCPRO1 (contact);
+
#ifdef WINDOWSNT
/* Ensure socket support is loaded if available. */
init_winsock (TRUE);
#endif
! /* :datagram BOOL */
! tem = Fplist_get (contact, QCdatagram);
! if (!NILP (tem))
! {
! #ifndef DATAGRAM_SOCKETS
! error ("Datagram connections not supported");
! #else
! socktype = SOCK_DGRAM;
! #endif
! }
! /* :server BOOL */
! tem = Fplist_get (contact, QCserver);
! if (!NILP (tem))
{
! #ifdef TERM
! error ("Network servers not supported");
! #else
! is_server = 1;
! #endif
}
!
! /* Make QCaddress an alias for :local (server) or :remote (client). */
! QCaddress = is_server ? QClocal : QCremote;
!
! /* :wait BOOL */
! if (!is_server && socktype == SOCK_STREAM
! && (tem = Fplist_get (contact, QCnowait), !NILP (tem)))
{
! #ifndef NON_BLOCKING_CONNECT
! error ("Non-blocking connect not supported");
! #else
! is_non_blocking_client = 1;
! #endif
}
!
! name = Fplist_get (contact, QCname);
! buffer = Fplist_get (contact, QCbuffer);
! filter = Fplist_get (contact, QCfilter);
! sentinel = Fplist_get (contact, QCsentinel);
!
! CHECK_STRING (name);
!
! #ifdef TERM
! /* Let's handle TERM before things get complicated ... */
! host = Fplist_get (contact, QChost);
! CHECK_STRING (host);
!
! service = Fplist_get (contact, QCservice);
if (INTEGERP (service))
port = htons ((unsigned short) XINT (service));
else
{
+ struct servent *svc_info;
CHECK_STRING (service);
svc_info = getservbyname (XSTRING (service)->data, "tcp");
if (svc_info == 0)
! error ("Unknown service: %s", XSTRING (service)->data);
port = svc_info->s_port;
}
+ s = connect_server (0);
+ if (s < 0)
+ report_file_error ("error creating socket", Fcons (name, Qnil));
+ send_command (s, C_PORT, 0, "%s:%d", XSTRING (host)->data, ntohs (port));
+ send_command (s, C_DUMB, 1, 0);
+
+ #else /* not TERM */
+
+ /* Initialize addrinfo structure in case we don't use getaddrinfo. */
+ ai.ai_socktype = socktype;
+ ai.ai_protocol = 0;
+ ai.ai_next = NULL;
+ res = &ai;
+
+ /* :local ADDRESS or :remote ADDRESS */
+ address = Fplist_get (contact, QCaddress);
+ if (!NILP (address))
+ {
+ host = service = Qnil;
+
+ if (!(ai.ai_addrlen = get_lisp_to_sockaddr_size (address, &family)))
+ error ("Malformed :address");
+ ai.ai_family = family;
+ ai.ai_addr = alloca (ai.ai_addrlen);
+ conv_lisp_to_sockaddr (family, address, ai.ai_addr, ai.ai_addrlen);
+ goto open_socket;
+ }
+
+ /* :family FAMILY -- nil (for Inet), local, or integer. */
+ tem = Fplist_get (contact, QCfamily);
+ if (INTEGERP (tem))
+ family = XINT (tem);
+ else
+ {
+ if (NILP (tem))
+ family = AF_INET;
+ #ifdef HAVE_LOCAL_SOCKETS
+ else if (EQ (tem, Qlocal))
+ family = AF_LOCAL;
+ #endif
+ }
+ if (family < 0)
+ error ("Unknown address family");
+ ai.ai_family = family;
+
+ /* :service SERVICE -- string, integer (port number), or t (random port).
*/
+ service = Fplist_get (contact, QCservice);
+
+ #ifdef HAVE_LOCAL_SOCKETS
+ if (family == AF_LOCAL)
+ {
+ /* Host is not used. */
+ host = Qnil;
+ CHECK_STRING (service);
+ bzero (&address_un, sizeof address_un);
+ address_un.sun_family = AF_LOCAL;
+ strncpy (address_un.sun_path, XSTRING (service)->data, sizeof
address_un.sun_path);
+ ai.ai_addr = (struct sockaddr *) &address_un;
+ ai.ai_addrlen = sizeof address_un;
+ goto open_socket;
+ }
+ #endif
+
+ /* :host HOST -- hostname, ip address, or 'local for localhost. */
+ host = Fplist_get (contact, QChost);
+ if (!NILP (host))
+ {
+ if (EQ (host, Qlocal))
+ host = build_string ("localhost");
+ CHECK_STRING (host);
+ }
/* Slow down polling to every ten seconds.
Some kernels have a bug which causes retrying connect to fail
after a connect. Polling can interfere with gethostbyname too. */
#ifdef POLL_FOR_INPUT
! if (socktype == SOCK_STREAM)
! {
! record_unwind_protect (unwind_stop_other_atimers, Qnil);
! bind_polling_period (10);
! }
#endif
#ifdef HAVE_GETADDRINFO
! /* If we have a host, use getaddrinfo to resolve both host and service.
! Otherwise, use getservbyname to lookup the service. */
! if (!NILP (host))
! {
!
! /* SERVICE can either be a string or int.
! Convert to a C string for later use by getaddrinfo. */
! if (EQ (service, Qt))
! portstring = "0";
! else if (INTEGERP (service))
! {
! sprintf (portbuf, "%ld", (long) XINT (service));
! portstring = portbuf;
! }
! else
! {
! CHECK_STRING (service);
! portstring = XSTRING (service)->data;
! }
!
! immediate_quit = 1;
! QUIT;
! memset (&hints, 0, sizeof (hints));
! hints.ai_flags = 0;
! hints.ai_family = NILP (Fplist_member (contact, QCfamily)) ? AF_UNSPEC
: family;
! hints.ai_socktype = socktype;
! hints.ai_protocol = 0;
! ret = getaddrinfo (XSTRING (host)->data, portstring, &hints, &res);
! if (ret)
#ifdef HAVE_GAI_STRERROR
! error ("%s/%s %s", XSTRING (host)->data, portstring, gai_strerror(ret));
#else
! error ("%s/%s getaddrinfo error %d", XSTRING (host)->data,
portstring, ret);
#endif
! immediate_quit = 0;
! goto open_socket;
! }
! #endif /* HAVE_GETADDRINFO */
! /* We end up here if getaddrinfo is not defined, or in case no hostname
! has been specified (e.g. for a local server process). */
!
! if (EQ (service, Qt))
! port = 0;
! else if (INTEGERP (service))
! port = htons ((unsigned short) XINT (service));
! else
{
! struct servent *svc_info;
! CHECK_STRING (service);
! svc_info = getservbyname (XSTRING (service)->data,
! (socktype == SOCK_DGRAM ? "udp" : "tcp"));
! if (svc_info == 0)
! error ("Unknown service: %s", XSTRING (service)->data);
! port = svc_info->s_port;
! }
!
! bzero (&address_in, sizeof address_in);
! address_in.sin_family = family;
! address_in.sin_addr.s_addr = INADDR_ANY;
! address_in.sin_port = port;
!
! #ifndef HAVE_GETADDRINFO
! if (!NILP (host))
! {
! struct hostent *host_info_ptr;
!
! /* gethostbyname may fail with TRY_AGAIN, but we don't honour that,
! as it may `hang' emacs for a very long time. */
immediate_quit = 1;
QUIT;
host_info_ptr = gethostbyname (XSTRING (host)->data);
immediate_quit = 0;
! if (host_info_ptr)
! {
! bcopy (host_info_ptr->h_addr, (char *) &address_in.sin_addr,
! host_info_ptr->h_length);
! family = host_info_ptr->h_addrtype;
! address_in.sin_family = family;
! }
! else
! /* Attempt to interpret host as numeric inet address */
! {
! IN_ADDR numeric_addr;
! numeric_addr = inet_addr ((char *) XSTRING (host)->data);
! if (NUMERIC_ADDR_ERROR)
! error ("Unknown host \"%s\"", XSTRING (host)->data);
!
! bcopy ((char *)&numeric_addr, (char *) &address_in.sin_addr,
! sizeof (address_in.sin_addr));
! }
!
! }
#endif /* not HAVE_GETADDRINFO */
+ ai.ai_family = family;
+ ai.ai_addr = (struct sockaddr *) &address_in;
+ ai.ai_addrlen = sizeof address_in;
+
+ open_socket:
+
+ /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
+ when connect is interrupted. So let's not let it get interrupted.
+ Note we do not turn off polling, because polling is only used
+ when not interrupt_input, and thus not normally used on the systems
+ which have this bug. On systems which use polling, there's no way
+ to quit if polling is turned off. */
+ if (interrupt_input
+ && !is_server && socktype == SOCK_STREAM)
+ {
+ /* Comment from KFS: The original open-network-stream code
+ didn't unwind protect this, but it seems like the proper
+ thing to do. In any case, I don't see how it could harm to
+ do this -- and it makes cleanup (using unbind_to) easier. */
+ record_unwind_protect (unwind_request_sigio, Qnil);
+ unrequest_sigio ();
+ }
+
/* Do this in case we never enter the for-loop below. */
count1 = specpdl_ptr - specpdl;
s = -1;
***************
*** 1991,1998 ****
continue;
}
#ifdef NON_BLOCKING_CONNECT
! if (is_non_blocking)
{
#ifdef O_NONBLOCK
ret = fcntl (s, F_SETFL, O_NONBLOCK);
--- 2950,2962 ----
continue;
}
+ #ifdef DATAGRAM_SOCKETS
+ if (!is_server && socktype == SOCK_DGRAM)
+ break;
+ #endif /* DATAGRAM_SOCKETS */
+
#ifdef NON_BLOCKING_CONNECT
! if (is_non_blocking_client)
{
#ifdef O_NONBLOCK
ret = fcntl (s, F_SETFL, O_NONBLOCK);
***************
*** 2008,2028 ****
}
}
#endif
!
! /* Kernel bugs (on Ultrix at least) cause lossage (not just EINTR)
! when connect is interrupted. So let's not let it get interrupted.
! Note we do not turn off polling, because polling is only used
! when not interrupt_input, and thus not normally used on the systems
! which have this bug. On systems which use polling, there's no way
! to quit if polling is turned off. */
! if (interrupt_input)
! unrequest_sigio ();
!
/* Make us close S if quit. */
- count1 = specpdl_ptr - specpdl;
record_unwind_protect (close_file_unwind, make_number (s));
! loop:
immediate_quit = 1;
QUIT;
--- 2972,3017 ----
}
}
#endif
!
/* Make us close S if quit. */
record_unwind_protect (close_file_unwind, make_number (s));
! if (is_server)
! {
! /* Configure as a server socket. */
! #ifdef HAVE_LOCAL_SOCKETS
! if (family != AF_LOCAL)
! #endif
! {
! int optval = 1;
! if (setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof
optval))
! report_file_error ("Cannot set reuse option on server socket.",
Qnil);
! }
!
! if (bind (s, lres->ai_addr, lres->ai_addrlen))
! report_file_error ("Cannot bind server socket", Qnil);
!
! #ifdef HAVE_GETSOCKNAME
! if (EQ (service, Qt))
! {
! struct sockaddr_in sa1;
! int len1 = sizeof (sa1);
! if (getsockname (s, (struct sockaddr *)&sa1, &len1) == 0)
! {
! ((struct sockaddr_in *)(lres->ai_addr))->sin_port =
sa1.sin_port;
! service = make_number (sa1.sin_port);
! contact = Fplist_put (contact, QCservice, service);
! }
! }
! #endif
!
! if (socktype == SOCK_STREAM && listen (s, 5))
! report_file_error ("Cannot listen on server socket", Qnil);
!
! break;
! }
!
! retry_connect:
immediate_quit = 1;
QUIT;
***************
*** 2046,2052 ****
if (ret == 0 || xerrno == EISCONN)
{
- is_non_blocking = 0;
/* The unwind-protect will be discarded afterwards.
Likewise for immediate_quit. */
break;
--- 3035,3040 ----
***************
*** 2054,2064 ****
#ifdef NON_BLOCKING_CONNECT
#ifdef EINPROGRESS
! if (is_non_blocking && xerrno == EINPROGRESS)
break;
#else
#ifdef EWOULDBLOCK
! if (is_non_blocking && xerrno == EWOULDBLOCK)
break;
#endif
#endif
--- 3042,3052 ----
#ifdef NON_BLOCKING_CONNECT
#ifdef EINPROGRESS
! if (is_non_blocking_client && xerrno == EINPROGRESS)
break;
#else
#ifdef EWOULDBLOCK
! if (is_non_blocking_client && xerrno == EWOULDBLOCK)
break;
#endif
#endif
***************
*** 2067,2073 ****
immediate_quit = 0;
if (xerrno == EINTR)
! goto loop;
if (xerrno == EADDRINUSE && retry < 20)
{
/* A delay here is needed on some FreeBSD systems,
--- 3055,3061 ----
immediate_quit = 0;
if (xerrno == EINTR)
! goto retry_connect;
if (xerrno == EADDRINUSE && retry < 20)
{
/* A delay here is needed on some FreeBSD systems,
***************
*** 2075,2136 ****
and should be infrequent. */
Fsleep_for (make_number (1), Qnil);
retry++;
! goto loop;
}
/* Discard the unwind protect closing S. */
specpdl_ptr = specpdl + count1;
- count1 = specpdl_ptr - specpdl;
-
emacs_close (s);
s = -1;
}
#ifdef HAVE_GETADDRINFO
! freeaddrinfo (res);
#endif
if (s < 0)
{
- if (interrupt_input)
- request_sigio ();
-
/* If non-blocking got this far - and failed - assume non-blocking is
not supported after all. This is probably a wrong assumption, but
! the normal blocking calls to open-network-stream handles this error
! better. */
! if (is_non_blocking)
! {
! #ifdef POLL_FOR_INPUT
! unbind_to (count, Qnil);
! #endif
return Qnil;
- }
errno = xerrno;
! report_file_error ("connection failed",
! Fcons (host, Fcons (name, Qnil)));
}
-
- immediate_quit = 0;
-
- /* Discard the unwind protect, if any. */
- specpdl_ptr = specpdl + count1;
-
- #ifdef POLL_FOR_INPUT
- unbind_to (count, Qnil);
- #endif
! if (interrupt_input)
! request_sigio ();
! #else /* TERM */
! s = connect_server (0);
! if (s < 0)
! report_file_error ("error creating socket", Fcons (name, Qnil));
! send_command (s, C_PORT, 0, "%s:%d", XSTRING (host)->data, ntohs (port));
! send_command (s, C_DUMB, 1, 0);
! #endif /* TERM */
inch = s;
outch = s;
--- 3063,3141 ----
and should be infrequent. */
Fsleep_for (make_number (1), Qnil);
retry++;
! goto retry_connect;
}
/* Discard the unwind protect closing S. */
specpdl_ptr = specpdl + count1;
emacs_close (s);
s = -1;
}
+ if (s >= 0)
+ {
+ #ifdef DATAGRAM_SOCKETS
+ if (socktype == SOCK_DGRAM)
+ {
+ if (datagram_address[s].sa)
+ abort ();
+ datagram_address[s].sa = (struct sockaddr *) xmalloc
(lres->ai_addrlen);
+ datagram_address[s].len = lres->ai_addrlen;
+ if (is_server)
+ {
+ Lisp_Object remote;
+ bzero (datagram_address[s].sa, lres->ai_addrlen);
+ if (remote = Fplist_get (contact, QCremote), !NILP (remote))
+ {
+ int rfamily, rlen;
+ rlen = get_lisp_to_sockaddr_size (remote, &rfamily);
+ if (rfamily == lres->ai_family && rlen == lres->ai_addrlen)
+ conv_lisp_to_sockaddr (rfamily, remote,
+ datagram_address[s].sa, rlen);
+ }
+ }
+ else
+ bcopy (lres->ai_addr, datagram_address[s].sa, lres->ai_addrlen);
+ }
+ #endif
+ contact = Fplist_put (contact, QCaddress,
+ conv_sockaddr_to_lisp (lres->ai_addr,
lres->ai_addrlen));
+ }
+
#ifdef HAVE_GETADDRINFO
! if (res != &ai)
! freeaddrinfo (res);
#endif
+ immediate_quit = 0;
+
+ /* Discard the unwind protect for closing S, if any. */
+ specpdl_ptr = specpdl + count1;
+
+ /* Unwind bind_polling_period and request_sigio. */
+ unbind_to (count, Qnil);
+
if (s < 0)
{
/* If non-blocking got this far - and failed - assume non-blocking is
not supported after all. This is probably a wrong assumption, but
! the normal blocking calls to open-network-stream handles this error
! better. */
! if (is_non_blocking_client)
return Qnil;
errno = xerrno;
! if (is_server)
! report_file_error ("make server process failed", contact);
! else
! report_file_error ("make client process failed", contact);
}
! tem = Fplist_get (contact, QCoptions);
! if (!NILP (tem))
! set_socket_options (s, tem, 1);
! #endif /* not TERM */
inch = s;
outch = s;
***************
*** 2149,2172 ****
#endif
#endif
! XPROCESS (proc)->childp = Fcons (host, Fcons (service, Qnil));
! XPROCESS (proc)->command_channel_p = Qnil;
! XPROCESS (proc)->buffer = buffer;
! XPROCESS (proc)->sentinel = sentinel;
! XPROCESS (proc)->filter = filter;
! XPROCESS (proc)->command = Qnil;
! XPROCESS (proc)->pid = Qnil;
! XSETINT (XPROCESS (proc)->infd, inch);
! XSETINT (XPROCESS (proc)->outfd, outch);
! XPROCESS (proc)->status = Qrun;
#ifdef NON_BLOCKING_CONNECT
! if (!NILP (non_blocking))
{
/* We may get here if connect did succeed immediately. However,
in that case, we still need to signal this like a non-blocking
connection. */
! XPROCESS (proc)->status = Qconnect;
if (!FD_ISSET (inch, &connect_wait_mask))
{
FD_SET (inch, &connect_wait_mask);
--- 3154,3183 ----
#endif
#endif
! p = XPROCESS (proc);
!
! p->childp = contact;
! p->buffer = buffer;
! p->sentinel = sentinel;
! p->filter = filter;
! p->log = Fplist_get (contact, QClog);
! if (tem = Fplist_get (contact, QCnoquery), !NILP (tem))
! p->kill_without_query = Qt;
! if ((tem = Fplist_get (contact, QCstop), !NILP (tem)))
! p->command = Qt;
! p->pid = Qnil;
! XSETINT (p->infd, inch);
! XSETINT (p->outfd, outch);
! if (is_server && socktype == SOCK_STREAM)
! p->status = Qlisten;
#ifdef NON_BLOCKING_CONNECT
! if (is_non_blocking_client)
{
/* We may get here if connect did succeed immediately. However,
in that case, we still need to signal this like a non-blocking
connection. */
! p->status = Qconnect;
if (!FD_ISSET (inch, &connect_wait_mask))
{
FD_SET (inch, &connect_wait_mask);
***************
*** 2175,2181 ****
}
else
#endif
! if (!EQ (XPROCESS (proc)->filter, Qt))
{
FD_SET (inch, &input_wait_mask);
FD_SET (inch, &non_keyboard_wait_mask);
--- 3186,3195 ----
}
else
#endif
! /* A server may have a client filter setting of Qt, but it must
! still listen for incoming connects unless it is stopped. */
! if ((!EQ (p->filter, Qt) && !EQ (p->command, Qt))
! || (EQ (p->status, Qlisten) && NILP (p->command)))
{
FD_SET (inch, &input_wait_mask);
FD_SET (inch, &non_keyboard_wait_mask);
***************
*** 2184,2189 ****
--- 3198,3207 ----
if (inch > max_process_desc)
max_process_desc = inch;
+ tem = Fplist_member (contact, QCcoding);
+ if (!NILP (tem) && (!CONSP (tem) || !CONSP (XCDR (tem))))
+ tem = Qnil; /* No error message (too late!). */
+
{
/* Setup coding systems for communicating with the network stream. */
struct gcpro gcpro1;
***************
*** 2191,2197 ****
Lisp_Object coding_systems = Qt;
Lisp_Object args[5], val;
! if (!NILP (Vcoding_system_for_read))
val = Vcoding_system_for_read;
else if ((!NILP (buffer) && NILP (XBUFFER
(buffer)->enable_multibyte_characters))
|| (NILP (buffer) && NILP
(buffer_defaults.enable_multibyte_characters)))
--- 3209,3217 ----
Lisp_Object coding_systems = Qt;
Lisp_Object args[5], val;
! if (!NILP (tem))
! val = XCAR (XCDR (tem));
! else if (!NILP (Vcoding_system_for_read))
val = Vcoding_system_for_read;
else if ((!NILP (buffer) && NILP (XBUFFER
(buffer)->enable_multibyte_characters))
|| (NILP (buffer) && NILP
(buffer_defaults.enable_multibyte_characters)))
***************
*** 2214,2222 ****
else
val = Qnil;
}
! XPROCESS (proc)->decode_coding_system = val;
! if (!NILP (Vcoding_system_for_write))
val = Vcoding_system_for_write;
else if (NILP (current_buffer->enable_multibyte_characters))
val = Qnil;
--- 3234,3244 ----
else
val = Qnil;
}
! p->decode_coding_system = val;
! if (!NILP (tem))
! val = XCAR (XCDR (tem));
! else if (!NILP (Vcoding_system_for_write))
val = Vcoding_system_for_write;
else if (NILP (current_buffer->enable_multibyte_characters))
val = Qnil;
***************
*** 2237,2263 ****
else
val = Qnil;
}
! XPROCESS (proc)->encode_coding_system = val;
}
if (!proc_decode_coding_system[inch])
proc_decode_coding_system[inch]
= (struct coding_system *) xmalloc (sizeof (struct coding_system));
! setup_coding_system (XPROCESS (proc)->decode_coding_system,
proc_decode_coding_system[inch]);
if (!proc_encode_coding_system[outch])
proc_encode_coding_system[outch]
= (struct coding_system *) xmalloc (sizeof (struct coding_system));
! setup_coding_system (XPROCESS (proc)->encode_coding_system,
proc_encode_coding_system[outch]);
! XPROCESS (proc)->decoding_buf = make_uninit_string (0);
! XPROCESS (proc)->decoding_carryover = make_number (0);
! XPROCESS (proc)->encoding_buf = make_uninit_string (0);
! XPROCESS (proc)->encoding_carryover = make_number (0);
! XPROCESS (proc)->inherit_coding_system_flag
! = (NILP (buffer) || !inherit_process_coding_system
? Qnil : Qt);
UNGCPRO;
--- 3259,3285 ----
else
val = Qnil;
}
! p->encode_coding_system = val;
}
if (!proc_decode_coding_system[inch])
proc_decode_coding_system[inch]
= (struct coding_system *) xmalloc (sizeof (struct coding_system));
! setup_coding_system (p->decode_coding_system,
proc_decode_coding_system[inch]);
if (!proc_encode_coding_system[outch])
proc_encode_coding_system[outch]
= (struct coding_system *) xmalloc (sizeof (struct coding_system));
! setup_coding_system (p->encode_coding_system,
proc_encode_coding_system[outch]);
! p->decoding_buf = make_uninit_string (0);
! p->decoding_carryover = make_number (0);
! p->encoding_buf = make_uninit_string (0);
! p->encoding_carryover = make_number (0);
! p->inherit_coding_system_flag
! = (!NILP (tem) || NILP (buffer) || !inherit_process_coding_system
? Qnil : Qt);
UNGCPRO;
***************
*** 2295,2300 ****
--- 3317,3330 ----
XSETINT (p->infd, -1);
XSETINT (p->outfd, -1);
+ #ifdef DATAGRAM_SOCKETS
+ if (DATAGRAM_CHAN_P (inchannel))
+ {
+ xfree (datagram_address[inchannel].sa);
+ datagram_address[inchannel].sa = 0;
+ datagram_address[inchannel].len = 0;
+ }
+ #endif
chan_process[inchannel] = Qnil;
FD_CLR (inchannel, &input_wait_mask);
FD_CLR (inchannel, &non_keyboard_wait_mask);
***************
*** 2411,2416 ****
--- 3441,3642 ----
? Qt : Qnil);
}
+ /* Accept a connection for server process SERVER on CHANNEL. */
+
+ static int connect_counter = 0;
+
+ static void
+ server_accept_connection (server, channel)
+ Lisp_Object server;
+ int channel;
+ {
+ Lisp_Object proc, caller, name, buffer;
+ Lisp_Object contact, host, service;
+ struct Lisp_Process *ps= XPROCESS (server);
+ struct Lisp_Process *p;
+ int s;
+ union u_sockaddr {
+ struct sockaddr sa;
+ struct sockaddr_in in;
+ #ifdef HAVE_LOCAL_SOCKETS
+ struct sockaddr_un un;
+ #endif
+ } saddr;
+ int len = sizeof saddr;
+
+ s = accept (channel, &saddr.sa, &len);
+
+ if (s < 0)
+ {
+ int code = errno;
+
+ if (code == EAGAIN)
+ return;
+ #ifdef EWOULDBLOCK
+ if (code == EWOULDBLOCK)
+ return;
+ #endif
+
+ if (!NILP (ps->log))
+ call3 (ps->log, server, Qnil,
+ concat3 (build_string ("accept failed with code"),
+ Fnumber_to_string (make_number (code)),
+ build_string ("\n")));
+ return;
+ }
+
+ connect_counter++;
+
+ /* Setup a new process to handle the connection. */
+
+ /* Generate a unique identification of the caller, and build contact
+ information for this process. */
+ host = Qt;
+ service = Qnil;
+ switch (saddr.sa.sa_family)
+ {
+ case AF_INET:
+ {
+ Lisp_Object args[5];
+ unsigned char *ip = (unsigned char *)&saddr.in.sin_addr.s_addr;
+ args[0] = build_string ("%d.%d.%d.%d");
+ args[1] = make_number (*ip++);
+ args[2] = make_number (*ip++);
+ args[3] = make_number (*ip++);
+ args[4] = make_number (*ip++);
+ host = Fformat (5, args);
+ service = make_number (ntohs (saddr.in.sin_port));
+
+ args[0] = build_string (" <%s:%d>");
+ args[1] = host;
+ args[2] = service;
+ caller = Fformat (3, args);
+ }
+ break;
+
+ #ifdef HAVE_LOCAL_SOCKETS
+ case AF_LOCAL:
+ #endif
+ default:
+ caller = Fnumber_to_string (make_number (connect_counter));
+ caller = concat3 (build_string (" <*"), caller, build_string ("*>"));
+ break;
+ }
+
+ /* Create a new buffer name for this process if it doesn't have a
+ filter. The new buffer name is based on the buffer name or
+ process name of the server process concatenated with the caller
+ identification. */
+
+ if (!NILP (ps->filter) && !EQ (ps->filter, Qt))
+ buffer = Qnil;
+ else
+ {
+ buffer = ps->buffer;
+ if (!NILP (buffer))
+ buffer = Fbuffer_name (buffer);
+ else
+ buffer = ps->name;
+ if (!NILP (buffer))
+ {
+ buffer = concat2 (buffer, caller);
+ buffer = Fget_buffer_create (buffer);
+ }
+ }
+
+ /* Generate a unique name for the new server process. Combine the
+ server process name with the caller identification. */
+
+ name = concat2 (ps->name, caller);
+ proc = make_process (name);
+
+ chan_process[s] = proc;
+
+ #ifdef O_NONBLOCK
+ fcntl (s, F_SETFL, O_NONBLOCK);
+ #else
+ #ifdef O_NDELAY
+ fcntl (s, F_SETFL, O_NDELAY);
+ #endif
+ #endif
+
+ p = XPROCESS (proc);
+
+ /* Build new contact information for this setup. */
+ contact = Fcopy_sequence (ps->childp);
+ contact = Fplist_put (contact, QCserver, Qnil);
+ contact = Fplist_put (contact, QChost, host);
+ if (!NILP (service))
+ contact = Fplist_put (contact, QCservice, service);
+ contact = Fplist_put (contact, QCremote,
+ conv_sockaddr_to_lisp (&saddr.sa, len));
+ #ifdef HAVE_GETSOCKNAME
+ len = sizeof saddr;
+ if (getsockname (channel, &saddr.sa, &len) == 0)
+ contact = Fplist_put (contact, QClocal,
+ conv_sockaddr_to_lisp (&saddr.sa, len));
+ #endif
+
+ p->childp = contact;
+ p->buffer = buffer;
+ p->sentinel = ps->sentinel;
+ p->filter = ps->filter;
+ p->command = Qnil;
+ p->pid = Qnil;
+ XSETINT (p->infd, s);
+ XSETINT (p->outfd, s);
+ p->status = Qrun;
+
+ /* Client processes for accepted connections are not stopped initially. */
+ if (!EQ (p->filter, Qt))
+ {
+ FD_SET (s, &input_wait_mask);
+ FD_SET (s, &non_keyboard_wait_mask);
+ }
+
+ if (s > max_process_desc)
+ max_process_desc = s;
+
+ /* Setup coding system for new process based on server process.
+ This seems to be the proper thing to do, as the coding system
+ of the new process should reflect the settings at the time the
+ server socket was opened; not the current settings. */
+
+ p->decode_coding_system = ps->decode_coding_system;
+ p->encode_coding_system = ps->encode_coding_system;
+
+ if (!proc_decode_coding_system[s])
+ proc_decode_coding_system[s]
+ = (struct coding_system *) xmalloc (sizeof (struct coding_system));
+ setup_coding_system (p->decode_coding_system,
+ proc_decode_coding_system[s]);
+ if (!proc_encode_coding_system[s])
+ proc_encode_coding_system[s]
+ = (struct coding_system *) xmalloc (sizeof (struct coding_system));
+ setup_coding_system (p->encode_coding_system,
+ proc_encode_coding_system[s]);
+
+ p->decoding_buf = make_uninit_string (0);
+ p->decoding_carryover = make_number (0);
+ p->encoding_buf = make_uninit_string (0);
+ p->encoding_carryover = make_number (0);
+
+ p->inherit_coding_system_flag
+ = (NILP (buffer) ? Qnil : ps->inherit_coding_system_flag);
+
+ if (!NILP (ps->log))
+ call3 (ps->log, server, proc,
+ concat3 (build_string ("accept from "),
+ (STRINGP (host) ? host : build_string ("-")),
+ build_string ("\n")));
+
+ if (p->sentinel)
+ exec_sentinel (proc,
+ concat3 (build_string ("open from "),
+ (STRINGP (host) ? host : build_string ("-")),
+ build_string ("\n")));
+ }
+
/* This variable is different from waiting_for_input in keyboard.c.
It is used to communicate to a lisp process-filter/sentinel (via the
function Fwaiting_for_user_input_p below) whether emacs was waiting
***************
*** 2909,2914 ****
--- 4135,4147 ----
if (NILP (proc))
continue;
+ /* If this is a server stream socket, accept connection. */
+ if (EQ (XPROCESS (proc)->status, Qlisten))
+ {
+ server_accept_connection (proc, channel);
+ continue;
+ }
+
/* Read data from the process, starting with our
buffered-ahead character if we have one. */
***************
*** 2983,2989 ****
{
struct Lisp_Process *p;
struct sockaddr pname;
! socklen_t pnamelen = sizeof(pname);
FD_CLR (channel, &connect_wait_mask);
if (--num_pending_connects < 0)
--- 4216,4222 ----
{
struct Lisp_Process *p;
struct sockaddr pname;
! int pnamelen = sizeof(pname);
FD_CLR (channel, &connect_wait_mask);
if (--num_pending_connects < 0)
***************
*** 2999,3005 ****
/* getsockopt(,,SO_ERROR,,) is said to hang on some systems.
So only use it on systems where it is known to work. */
{
! socklen_t xlen = sizeof(xerrno);
if (getsockopt(channel, SOL_SOCKET, SO_ERROR, &xerrno, &xlen))
xerrno = errno;
}
--- 4232,4238 ----
/* getsockopt(,,SO_ERROR,,) is said to hang on some systems.
So only use it on systems where it is known to work. */
{
! int xlen = sizeof(xerrno);
if (getsockopt(channel, SOL_SOCKET, SO_ERROR, &xerrno, &xlen))
xerrno = errno;
}
***************
*** 3028,3034 ****
status_notify to do it later, it will read input
from the process before calling the sentinel. */
exec_sentinel (proc, build_string ("open\n"));
! if (!EQ (p->filter, Qt))
{
FD_SET (XINT (p->infd), &input_wait_mask);
FD_SET (XINT (p->infd), &non_keyboard_wait_mask);
--- 4261,4267 ----
status_notify to do it later, it will read input
from the process before calling the sentinel. */
exec_sentinel (proc, build_string ("open\n"));
! if (!EQ (p->filter, Qt) && !EQ (p->command, Qt))
{
FD_SET (XINT (p->infd), &input_wait_mask);
FD_SET (XINT (p->infd), &non_keyboard_wait_mask);
***************
*** 3106,3111 ****
--- 4339,4345 ----
register int opoint;
struct coding_system *coding = proc_decode_coding_system[channel];
int carryover = XINT (p->decoding_carryover);
+ int readmax = 1024;
#ifdef VMS
VMS_PROC_STUFF *vs, *get_vms_process_pointer();
***************
*** 3137,3154 ****
bcopy (vs->inputBuffer, chars + carryover, nbytes);
}
#else /* not VMS */
! chars = (char *) alloca (carryover + 1024);
if (carryover)
/* See the comment above. */
bcopy (XSTRING (p->decoding_buf)->data, chars, carryover);
if (proc_buffered_char[channel] < 0)
! nbytes = emacs_read (channel, chars + carryover, 1024 - carryover);
else
{
chars[carryover] = proc_buffered_char[channel];
proc_buffered_char[channel] = -1;
! nbytes = emacs_read (channel, chars + carryover + 1, 1023 - carryover);
if (nbytes < 0)
nbytes = 1;
else
--- 4371,4409 ----
bcopy (vs->inputBuffer, chars + carryover, nbytes);
}
#else /* not VMS */
!
! #ifdef DATAGRAM_SOCKETS
! /* A datagram is one packet; allow at least 1500+ bytes of data
! corresponding to the typical Ethernet frame size. */
! if (DATAGRAM_CHAN_P (channel))
! {
! /* carryover = 0; */ /* Does carryover make sense for datagrams? */
! readmax += 1024;
! }
! #endif
!
! chars = (char *) alloca (carryover + readmax);
if (carryover)
/* See the comment above. */
bcopy (XSTRING (p->decoding_buf)->data, chars, carryover);
+ #ifdef DATAGRAM_SOCKETS
+ /* We have a working select, so proc_buffered_char is always -1. */
+ if (DATAGRAM_CHAN_P (channel))
+ {
+ int len = datagram_address[channel].len;
+ nbytes = recvfrom (channel, chars + carryover, readmax - carryover,
+ 0, datagram_address[channel].sa, &len);
+ }
+ else
+ #endif
if (proc_buffered_char[channel] < 0)
! nbytes = emacs_read (channel, chars + carryover, readmax - carryover);
else
{
chars[carryover] = proc_buffered_char[channel];
proc_buffered_char[channel] = -1;
! nbytes = emacs_read (channel, chars + carryover + 1, readmax - 1 -
carryover);
if (nbytes < 0)
nbytes = 1;
else
***************
*** 3614,3622 ****
/* Send this batch, using one or more write calls. */
while (this > 0)
{
old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE,
send_process_trap);
! rv = emacs_write (XINT (XPROCESS (proc)->outfd),
! (char *) buf, this);
signal (SIGPIPE, old_sigpipe);
if (rv < 0)
--- 4869,4888 ----
/* Send this batch, using one or more write calls. */
while (this > 0)
{
+ int outfd = XINT (XPROCESS (proc)->outfd);
old_sigpipe = (SIGTYPE (*) ()) signal (SIGPIPE,
send_process_trap);
! #ifdef DATAGRAM_SOCKETS
! if (DATAGRAM_CHAN_P (outfd))
! {
! rv = sendto (outfd, (char *) buf, this,
! 0, datagram_address[outfd].sa,
! datagram_address[outfd].len);
! if (rv < 0 && errno == EMSGSIZE)
! report_file_error ("sending datagram", Fcons (proc, Qnil));
! }
! else
! #endif
! rv = emacs_write (outfd, (char *) buf, this);
signal (SIGPIPE, old_sigpipe);
if (rv < 0)
***************
*** 4071,4080 ****
DEFUN ("stop-process", Fstop_process, Sstop_process, 0, 2, 0,
doc: /* Stop process PROCESS. May be process or name of one.
! See function `interrupt-process' for more details on usage. */)
(process, current_group)
Lisp_Object process, current_group;
{
#ifndef SIGTSTP
error ("no SIGTSTP support");
#else
--- 5337,5363 ----
DEFUN ("stop-process", Fstop_process, Sstop_process, 0, 2, 0,
doc: /* Stop process PROCESS. May be process or name of one.
! See function `interrupt-process' for more details on usage.
! If PROCESS is a network process, inhibit handling of incoming traffic. */)
(process, current_group)
Lisp_Object process, current_group;
{
+ #ifdef HAVE_SOCKETS
+ if (PROCESSP (process) && NETCONN_P (process))
+ {
+ struct Lisp_Process *p;
+
+ p = XPROCESS (process);
+ if (NILP (p->command)
+ && XINT (p->infd) >= 0)
+ {
+ FD_CLR (XINT (p->infd), &input_wait_mask);
+ FD_CLR (XINT (p->infd), &non_keyboard_wait_mask);
+ }
+ p->command = Qt;
+ return process;
+ }
+ #endif
#ifndef SIGTSTP
error ("no SIGTSTP support");
#else
***************
*** 4085,4094 ****
DEFUN ("continue-process", Fcontinue_process, Scontinue_process, 0, 2, 0,
doc: /* Continue process PROCESS. May be process or name of one.
! See function `interrupt-process' for more details on usage. */)
(process, current_group)
Lisp_Object process, current_group;
{
#ifdef SIGCONT
process_send_signal (process, SIGCONT, current_group, 0);
#else
--- 5368,5395 ----
DEFUN ("continue-process", Fcontinue_process, Scontinue_process, 0, 2, 0,
doc: /* Continue process PROCESS. May be process or name of one.
! See function `interrupt-process' for more details on usage.
! If PROCESS is a network process, resume handling of incoming traffic. */)
(process, current_group)
Lisp_Object process, current_group;
{
+ #ifdef HAVE_SOCKETS
+ if (PROCESSP (process) && NETCONN_P (process))
+ {
+ struct Lisp_Process *p;
+
+ p = XPROCESS (process);
+ if (EQ (p->command, Qt)
+ && XINT (p->infd) >= 0
+ && (!EQ (p->filter, Qt) || EQ (p->status, Qlisten)))
+ {
+ FD_SET (XINT (p->infd), &input_wait_mask);
+ FD_SET (XINT (p->infd), &non_keyboard_wait_mask);
+ }
+ p->command = Qnil;
+ return process;
+ }
+ #endif
#ifdef SIGCONT
process_send_signal (process, SIGCONT, current_group, 0);
#else
***************
*** 4235,4240 ****
--- 5536,5544 ----
Lisp_Object proc;
struct coding_system *coding;
+ if (DATAGRAM_CONN_P (process))
+ return process;
+
proc = get_process (process);
coding = proc_encode_coding_system[XINT (XPROCESS (proc)->outfd)];
***************
*** 4619,4624 ****
--- 5923,5930 ----
/* If process is still active, read any output that remains. */
while (! EQ (p->filter, Qt)
&& ! EQ (p->status, Qconnect)
+ && ! EQ (p->status, Qlisten)
+ && ! EQ (p->command, Qt) /* Network process not stopped. */
&& XINT (p->infd) >= 0
&& read_process_output (proc, XINT (p->infd)) > 0);
***************
*** 4829,4834 ****
--- 6135,6143 ----
}
bzero (proc_decode_coding_system, sizeof proc_decode_coding_system);
bzero (proc_encode_coding_system, sizeof proc_encode_coding_system);
+ #ifdef DATAGRAM_SOCKETS
+ bzero (datagram_address, sizeof datagram_address);
+ #endif
}
void
***************
*** 4857,4863 ****
staticpro (&Qconnect);
Qfailed = intern ("failed");
staticpro (&Qfailed);
!
Qlast_nonmenu_event = intern ("last-nonmenu-event");
staticpro (&Qlast_nonmenu_event);
--- 6166,6213 ----
staticpro (&Qconnect);
Qfailed = intern ("failed");
staticpro (&Qfailed);
! Qlisten = intern ("listen");
! staticpro (&Qlisten);
! Qlocal = intern ("local");
! staticpro (&Qlocal);
!
! QCname = intern (":name");
! staticpro (&QCname);
! QCbuffer = intern (":buffer");
! staticpro (&QCbuffer);
! QChost = intern (":host");
! staticpro (&QChost);
! QCservice = intern (":service");
! staticpro (&QCservice);
! QCfamily = intern (":family");
! staticpro (&QCfamily);
! QClocal = intern (":local");
! staticpro (&QClocal);
! QCremote = intern (":remote");
! staticpro (&QCremote);
! QCcoding = intern (":coding");
! staticpro (&QCcoding);
! QCserver = intern (":server");
! staticpro (&QCserver);
! QCdatagram = intern (":datagram");
! staticpro (&QCdatagram);
! QCnowait = intern (":nowait");
! staticpro (&QCnowait);
! QCfilter = intern (":filter");
! staticpro (&QCfilter);
! QCsentinel = intern (":sentinel");
! staticpro (&QCsentinel);
! QClog = intern (":log");
! staticpro (&QClog);
! QCnoquery = intern (":noquery");
! staticpro (&QCnoquery);
! QCstop = intern (":stop");
! staticpro (&QCstop);
! QCoptions = intern (":options");
! staticpro (&QCoptions);
! QCfeature = intern (":feature");
! staticpro (&QCfeature);
!
Qlast_nonmenu_event = intern ("last-nonmenu-event");
staticpro (&Qlast_nonmenu_event);
***************
*** 4897,4910 ****
defsubr (&Sset_process_window_size);
defsubr (&Sset_process_inherit_coding_system_flag);
defsubr (&Sprocess_inherit_coding_system_flag);
! defsubr (&Sprocess_kill_without_query);
defsubr (&Sprocess_contact);
defsubr (&Slist_processes);
defsubr (&Sprocess_list);
defsubr (&Sstart_process);
#ifdef HAVE_SOCKETS
! defsubr (&Sopen_network_stream);
#endif /* HAVE_SOCKETS */
defsubr (&Saccept_process_output);
defsubr (&Sprocess_send_region);
defsubr (&Sprocess_send_string);
--- 6247,6266 ----
defsubr (&Sset_process_window_size);
defsubr (&Sset_process_inherit_coding_system_flag);
defsubr (&Sprocess_inherit_coding_system_flag);
! defsubr (&Sset_process_query_on_exit_flag);
! defsubr (&Sprocess_query_on_exit_flag);
defsubr (&Sprocess_contact);
defsubr (&Slist_processes);
defsubr (&Sprocess_list);
defsubr (&Sstart_process);
#ifdef HAVE_SOCKETS
! defsubr (&Sset_network_process_options);
! defsubr (&Smake_network_process);
#endif /* HAVE_SOCKETS */
+ #ifdef DATAGRAM_SOCKETS
+ defsubr (&Sprocess_datagram_address);
+ defsubr (&Sset_process_datagram_address);
+ #endif
defsubr (&Saccept_process_output);
defsubr (&Sprocess_send_region);
defsubr (&Sprocess_send_string);
- [Emacs-diffs] Changes to emacs/src/process.c, Kim F. Storm, 2002/03/01
- [Emacs-diffs] Changes to emacs/src/process.c, Kim F. Storm, 2002/03/02
- [Emacs-diffs] Changes to emacs/src/process.c,
Kim F. Storm <=
- [Emacs-diffs] Changes to emacs/src/process.c, Pavel Janík, 2002/03/18
- [Emacs-diffs] Changes to emacs/src/process.c, Kim F. Storm, 2002/03/18
- [Emacs-diffs] Changes to emacs/src/process.c, Pavel Janík, 2002/03/18
- [Emacs-diffs] Changes to emacs/src/process.c, Jason Rumney, 2002/03/20
- [Emacs-diffs] Changes to emacs/src/process.c, Eli Zaretskii, 2002/03/20
- [Emacs-diffs] Changes to emacs/src/process.c, Kim F. Storm, 2002/03/21
- [Emacs-diffs] Changes to emacs/src/process.c, Kim F. Storm, 2002/03/21
- [Emacs-diffs] Changes to emacs/src/process.c, Pavel Janík, 2002/03/27
- [Emacs-diffs] Changes to emacs/src/process.c, Miles Bader, 2002/03/28