+
+ 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 = XINT (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 = XINT (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
+\f
+
+static struct socket_options {
+ /* The name of this option. Should be lowercase version of option
+ name without SO_ prefix. */
+ char *name;
+ /* Option level SOL_... */
+ int optlevel;
+ /* Option number SO_... */
+ int optnum;
+ enum { SOPT_UNKNOWN, SOPT_BOOL, SOPT_INT, SOPT_IFNAME, SOPT_LINGER } opttype;
+ enum { OPIX_NONE=0, OPIX_MISC=1, OPIX_REUSEADDR=2 } optbit;
+} socket_options[] =
+ {
+#ifdef SO_BINDTODEVICE
+ { ":bindtodevice", SOL_SOCKET, SO_BINDTODEVICE, SOPT_IFNAME, OPIX_MISC },
+#endif
+#ifdef SO_BROADCAST
+ { ":broadcast", SOL_SOCKET, SO_BROADCAST, SOPT_BOOL, OPIX_MISC },
+#endif
+#ifdef SO_DONTROUTE
+ { ":dontroute", SOL_SOCKET, SO_DONTROUTE, SOPT_BOOL, OPIX_MISC },
+#endif
+#ifdef SO_KEEPALIVE
+ { ":keepalive", SOL_SOCKET, SO_KEEPALIVE, SOPT_BOOL, OPIX_MISC },
+#endif
+#ifdef SO_LINGER
+ { ":linger", SOL_SOCKET, SO_LINGER, SOPT_LINGER, OPIX_MISC },
+#endif
+#ifdef SO_OOBINLINE
+ { ":oobinline", SOL_SOCKET, SO_OOBINLINE, SOPT_BOOL, OPIX_MISC },
+#endif
+#ifdef SO_PRIORITY
+ { ":priority", SOL_SOCKET, SO_PRIORITY, SOPT_INT, OPIX_MISC },
+#endif
+#ifdef SO_REUSEADDR
+ { ":reuseaddr", SOL_SOCKET, SO_REUSEADDR, SOPT_BOOL, OPIX_REUSEADDR },
+#endif
+ { 0, 0, 0, SOPT_UNKNOWN, OPIX_NONE }
+ };
+
+/* Set option OPT to value VAL on socket S.
+
+ Returns (1<<socket_options[OPT].optbit) if option is known, 0 otherwise.
+ Signals an error if setting a known option fails.
+*/
+
+static int
+set_socket_option (s, opt, val)
+ int s;
+ Lisp_Object opt, val;
+{
+ char *name;
+ struct socket_options *sopt;
+ int ret = 0;
+
+ CHECK_SYMBOL (opt);
+
+ name = (char *) SDATA (SYMBOL_NAME (opt));
+ for (sopt = socket_options; sopt->name; sopt++)
+ if (strcmp (name, sopt->name) == 0)
+ break;
+
+ switch (sopt->opttype)
+ {
+ case SOPT_BOOL:
+ {
+ int optval;
+ optval = NILP (val) ? 0 : 1;
+ ret = setsockopt (s, sopt->optlevel, sopt->optnum,
+ &optval, sizeof (optval));
+ break;
+ }
+
+ case SOPT_INT:
+ {
+ int optval;
+ if (INTEGERP (val))
+ optval = XINT (val);
+ else
+ error ("Bad option value for %s", name);
+ ret = setsockopt (s, sopt->optlevel, sopt->optnum,
+ &optval, sizeof (optval));
+ break;
+ }
+
+#ifdef SO_BINDTODEVICE
+ case SOPT_IFNAME:
+ {
+ char devname[IFNAMSIZ+1];
+
+ /* This is broken, at least in the Linux 2.4 kernel.
+ To unbind, the arg must be a zero integer, not the empty string.
+ This should work on all systems. KFS. 2003-09-23. */
+ bzero (devname, sizeof devname);
+ if (STRINGP (val))
+ {
+ char *arg = (char *) SDATA (val);
+ int len = min (strlen (arg), IFNAMSIZ);
+ bcopy (arg, devname, len);
+ }
+ else if (!NILP (val))
+ error ("Bad option value for %s", name);
+ ret = setsockopt (s, sopt->optlevel, sopt->optnum,
+ devname, IFNAMSIZ);
+ break;
+ }
+#endif
+
+#ifdef SO_LINGER
+ case SOPT_LINGER:
+ {
+ struct linger linger;
+
+ linger.l_onoff = 1;
+ linger.l_linger = 0;
+ 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:
+ return 0;
+ }
+
+ if (ret < 0)
+ report_file_error ("Cannot set network option",
+ Fcons (opt, Fcons (val, Qnil)));
+ return (1 << sopt->optbit);
+}
+
+
+DEFUN ("set-network-process-option",
+ Fset_network_process_option, Sset_network_process_option,
+ 3, 4, 0,
+ doc: /* For network process PROCESS set option OPTION to value VALUE.
+See `make-network-process' for a list of options and values.
+If optional fourth arg NO-ERROR is non-nil, don't signal an error if
+OPTION is not a supported option, return nil instead; otherwise return t. */)
+ (process, option, value, no_error)
+ Lisp_Object process, option, value;
+ Lisp_Object no_error;
+{
+ int s;
+ struct Lisp_Process *p;
+
+ CHECK_PROCESS (process);
+ p = XPROCESS (process);
+ if (!NETCONN1_P (p))
+ error ("Process is not a network process");
+
+ s = XINT (p->infd);
+ if (s < 0)
+ error ("Process is not running");
+
+ if (set_socket_option (s, option, value))
+ {
+ p->childp = Fplist_put (p->childp, option, value);
+ return Qt;
+ }
+
+ if (NILP (no_error))
+ error ("Unknown or unsupported option");
+
+ return Qnil;
+}
+
+\f
+/* 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.
+
+:type TYPE -- TYPE is the type of connection. The default (nil) is a
+stream type connection, `datagram' creates a datagram type connection.
+
+: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 -- If CODING is a symbol, it specifies the coding
+system used for both reading and writing for this process. If CODING
+is a cons (DECODING . ENCODING), DECODING is used for reading, and
+ENCODING is used for writing.
+
+: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.
+
+:filter-multibyte BOOL -- If BOOL is non-nil, strings given to the
+process filter are multibyte, otherwise they are unibyte.
+If this keyword is not specified, the strings are multibyte iff
+`default-enable-multibyte-characters' is non-nil.
+
+:sentinel SENTINEL -- Install SENTINEL as the process sentinel.
+
+:log LOG -- Install LOG as the server process log function. This
+function is called 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.
+
+:plist PLIST -- Install PLIST as the new process' initial plist.
+
+:server QLEN -- if QLEN is non-nil, create a server process for the
+specified FAMILY, SERVICE, and connection type (stream or datagram).
+If QLEN is an integer, it is used as the max. length of the server's
+pending connection queue (also known as the backlog); the default
+queue length is 5. Default is to create a client process.
+
+The following network options can be specified for this connection:
+
+: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 local address
+ (this is allowed by default for a server process).
+:bindtodevice NAME -- bind to interface NAME. Using this may require
+ special privileges on some systems.
+
+Consult the relevant system programmer's manual pages for more
+information on using these options.
+
+
+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).
+- The client process' plist is initialized from the server's plist.
+
+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 the optional :log function, accepted (and
+failed) connections may be logged in the server process' buffer.
+
+The original argument list, modified with the actual connection
+information, is available via the `process-contact' function.
+
+usage: (make-network-process &rest ARGS) */)
+ (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];