* Re: Non-blocking open-network-stream
@ 2002-02-27 17:49 Helmut Eller
0 siblings, 0 replies; 17+ messages in thread
From: Helmut Eller @ 2002-02-27 17:49 UTC (permalink / raw)
Cc: emacs-devel
storm@cua.dk (Kim F. Storm) writes:
> Does this sound acceptable (since there is currently no code supporting
> non-blocking connect, this cannot break anything :-)
This sounds much cleaner, at least to me.
Helmut
_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/emacs-devel
^ permalink raw reply [flat|nested] 17+ messages in thread
[parent not found: <m2u1sa7819.fsf@xaital.online-marketwatch.com>]
* Re: Non-blocking open-network-stream [not found] <m2u1sa7819.fsf@xaital.online-marketwatch.com> @ 2002-02-21 23:45 ` Kim F. Storm 2002-02-22 16:04 ` Stefan Monnier 2002-02-25 22:38 ` Kim F. Storm 0 siblings, 2 replies; 17+ messages in thread From: Kim F. Storm @ 2002-02-21 23:45 UTC (permalink / raw) Cc: emacs-devel Helmut Eller <helmut@xaital.km4u.net> writes: > Hi, > > I read your post about non-blocking open-network-stream in the web > archive of the emacs-devel list and would like to make some comments. > I write to you directly because I'm not subscribed and I have the > impression the list is "For Developers Only". > Thanks a lot for your feedback. I've copied my response to the list. > I tried the code a bit and I noticed that the sentinel is sometimes > not invoked with "run" when the connections completes successfully but > is closed shortly afterwards by the peer. The sentinel was sometimes > invoked sometimes not. The scenario was very simple: a server > accepted the connection and wrote "hello" to the socket and closed the > connection. Emacs executed this: > > (open-network-stream "nb" "x.x" "localhost" 34567 > nil > (lambda (s msg) > (with-current-buffer (process-buffer s) > (insert msg "\n") > (when (equal "failed" msg) > (message "deleting %S" s) > (delete-process s)))) > t) > This seems to be related to the problem you describe below: reading the process output before checking for the completion of the connect. I'll look into it. > You wrote: > > [...] > > The initial process-state is `connecting' which changes to `open' > > or `failed' depending on whether the connect succeeded or failed. > > Notice that the sentinel string for `open' is "run". > > You could modify status_message to return something more meaningful. > Preferably the symbol 'open. > Yes, I considered doing that. However, I didn't know whether existing code may depend on the current behaviour, and although I couldn't find any in CVS, I decided against changing it. > [...] > > + /* Number of bits set in connect_wait_mask. */ > > + int num_pending_connects; > > + > > Any reason to make this non-static? No. I just forgot it. > > [...] > > ! non_blocking = (NILP (non_blocking) ? Qnil : Qt); > > ! #ifdef NON_BLOCKING_CONNECT > > ! is_non_blocking = !NILP (non_blocking); > > ! #else > > ! is_non_blocking = 0; > > ! #endif > > Wouldn't non_blocking_p be a more lispy name? :-) Yes - but is_non_blocking is not a lisp object :-) > > [...] > > --- 1948,1971 ---- > > turn_on_atimers (1); > > > > if (ret == 0 || xerrno == EISCONN) > > ! { > > ! is_non_blocking = 0; > > ! /* The unwind-protect will be discarded afterwards. > > ! Likewise for immediate_quit. */ > > ! break; > > ! } > > Why do you set is_non_blocking to 0? I can see no later use. For > documentation? It is defensive programming -- in case it ever becomes necessary to test on it later in the code, it contains the proper value. > > > ! > > ! #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 > > What does it mean when connect returns EWOULDBLOCK? My man page > doesn't mention it. > Neither does mine -- but I saw some references on the Web which mentions this as one of the possible error codes from a non-blocking connect. So I included the test in case EINPROGRESS is not defined. > [...] > > --- 2176,2202 ---- > [...] > > ! if (!NILP (non_blocking)) > > ! { > > ! XPROCESS (proc)->status = Qconnecting; > > ! if (!FD_ISSET (inch, &connect_wait_mask)) > > ! { > > ! FD_SET (inch, &connect_wait_mask); > > ! num_pending_connects++; > > ! } > > ! } > > Why is if(!FD_ISET...) necessary? Because num_pending_connects would be updated incorrectly if it is already set. Defensive programming... > > [...] > > + #ifdef NON_BLOCKING_CONNECT > > + if (check_connect && FD_ISSET (channel, &Connecting)) > > + { > > Isn't it possible that channel becomes readable and writable at the > same time? If yes, wouldn't that mean that read_process_output (and > hence the filter) was already called before we get here? It seems you are right. Maybe the easiest fix would be for read_process_output to just return 0 if the process state is Qconnecting. I'll look into that. > > > + struct Lisp_Process *p; > > + struct sockaddr pname; > > + socklen_t pnamelen = sizeof(pname); > > + > > + FD_CLR (channel, &connect_wait_mask); > > + if (--num_pending_connects < 0) > > + abort (); > > + > > + proc = chan_process[channel]; > > + if (NILP (proc)) > > + continue; > > Is it safe to decrement num_pending_connects even if proc is nil? > > [...] Yes, because we only get here if channel is in the Connecting mask which is a subset of connect_wait_mask. Whether there really is a corresponding process doesn't matter. (there should be one, but I'm playing safe here -- cleaning up the connect_wait_mask in any case). > > + > > + p = XPROCESS (proc); > > + XSETINT (p->tick, ++process_tick); > > + > > + /* If connection failed, getpeername fails */ > > + if (getpeername(channel, &pname, &pnamelen) < 0) > > + { > > + /* Preserve status of processes already terminated. */ > > + p->status = Qfailed; > > + deactivate_process (proc); > > + } > > + else > > It would be nice if the error message (obtained with getsockopt > (channel, SOL_SCOKET, SO_ERROR ...)) would be passed to the sentinel. > That would be reasonable. I'll look into that. > A minor note: open-network-stream contains a large chunk of duplicated > code (starting from "/* Kernel bugs (on Ultrix..." to > "report_file_error ("connection failed...))). This are about 70 lines; > should they be in a separate function? Maybe, or the #ifdefs could be rearranged to avoid the duplication. I'll take a look. -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-02-21 23:45 ` Kim F. Storm @ 2002-02-22 16:04 ` Stefan Monnier 2002-02-25 22:38 ` Kim F. Storm 1 sibling, 0 replies; 17+ messages in thread From: Stefan Monnier @ 2002-02-22 16:04 UTC (permalink / raw) Cc: Helmut Eller, emacs-devel > > > ! non_blocking = (NILP (non_blocking) ? Qnil : Qt); > > > ! #ifdef NON_BLOCKING_CONNECT > > > ! is_non_blocking = !NILP (non_blocking); > > > ! #else > > > ! is_non_blocking = 0; > > > ! #endif > > > > Wouldn't non_blocking_p be a more lispy name? :-) > Yes - but is_non_blocking is not a lisp object :-) Actually the answer was `no'. The `p' postfix stands for `predicate'. A predicate is not a mere boolean value but a function that returns a boolean. Stefan _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-02-21 23:45 ` Kim F. Storm 2002-02-22 16:04 ` Stefan Monnier @ 2002-02-25 22:38 ` Kim F. Storm 2002-02-26 22:46 ` Helmut Eller 1 sibling, 1 reply; 17+ messages in thread From: Kim F. Storm @ 2002-02-25 22:38 UTC (permalink / raw) Cc: Helmut Eller Here is my second attempt at a patch to support non-blocking open-network-stream. If I don't receive any comments on this, I'll install it later this week. Index: process.c =================================================================== RCS file: /cvs/emacs/src/process.c,v retrieving revision 1.351 diff -c -r1.351 process.c *** process.c 7 Jan 2002 21:16:38 -0000 1.351 --- process.c 25 Feb 2002 22:33:22 -0000 *************** *** 1,6 **** /* Asynchronous subprocess control for GNU Emacs. ! Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 96, 98, 1999, 2001 ! Free Software Foundation, Inc. This file is part of GNU Emacs. --- 1,6 ---- /* Asynchronous subprocess control for GNU Emacs. ! Copyright (C) 1985, 86, 87, 88, 93, 94, 95, 96, 98, 1999, ! 2001, 2002 Free Software Foundation, Inc. This file is part of GNU Emacs. *************** *** 112,118 **** #include "atimer.h" Lisp_Object Qprocessp; ! Lisp_Object Qrun, Qstop, Qsignal, Qopen, Qclosed; Lisp_Object Qlast_nonmenu_event; /* Qexit is declared and initialized in eval.c. */ --- 112,119 ---- #include "atimer.h" 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. */ *************** *** 173,178 **** --- 174,199 ---- /* Number of events for which the user or sentinel has been notified. */ int update_tick; + /* Define NON_BLOCKING_CONNECT if we can support non-blocking connects. */ + + #ifdef BROKEN_NON_BLOCKING_CONNECT + #undef NON_BLOCKING_CONNECT + #else + #ifndef NON_BLOCKING_CONNECT + #ifdef HAVE_SOCKETS + #ifdef HAVE_SELECT + #if defined (HAVE_GETPEERNAME) || defined (GNU_LINUX) + #if defined (O_NONBLOCK) || defined (O_NDELAY) + #if defined (EWOULDBLOCK) || defined (EINPROGRESS) + #define NON_BLOCKING_CONNECT + #endif /* EWOULDBLOCK || EINPROGRESS */ + #endif /* O_NONBLOCK || O_NDELAY */ + #endif /* HAVE_GETPEERNAME || GNU_LINUX */ + #endif /* HAVE_SELECT */ + #endif /* HAVE_SOCKETS */ + #endif /* NON_BLOCKING_CONNECT */ + #endif /* BROKEN_NON_BLOCKING_CONNECT */ + #include "sysselect.h" extern int keyboard_bit_set P_ ((SELECT_TYPE *)); *************** *** 195,200 **** --- 216,230 ---- static SELECT_TYPE non_process_wait_mask; + /* Mask of bits indicating the descriptors that we wait for connect to + complete on. Once they complete, they are removed from this mask + and added to the input_wait_mask and non_keyboard_wait_mask. */ + + static SELECT_TYPE connect_wait_mask; + + /* Number of bits set in connect_wait_mask. */ + static int num_pending_connects; + /* The largest descriptor currently in use for a process object. */ static int max_process_desc; *************** *** 335,340 **** --- 365,377 ---- 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)); } *************** *** 1741,1762 **** deactivate and close it via delete-process */ DEFUN ("open-network-stream", Fopen_network_stream, Sopen_network_stream, ! 4, 4, 0, doc: /* Open a TCP connection for a service to a host. Returns a subprocess-object to represent the connection. Input and output work as for subprocesses; `delete-process' closes it. ! Args are NAME BUFFER HOST SERVICE. 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 ! Third arg is name of the host to connect to, or its IP address. ! Fourth arg SERVICE is name of the service desired, or an integer ! specifying a port number to connect to. */) ! (name, buffer, host, service) ! Lisp_Object name, buffer, host, service; { Lisp_Object proc; #ifdef HAVE_GETADDRINFO --- 1778,1809 ---- 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. 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 arg equal to "run" (if successful) or ! "failed" when the connect completes. ! On systems without non-blocking connect, this function waits ! for the connect to complete and then proceeds emulating a ! non-blocking connect. */) ! (name, buffer, host, service, filter, sentinel, non_blocking) ! Lisp_Object name, buffer, host, service, filter, sentinel, non_blocking; { Lisp_Object proc; #ifdef HAVE_GETADDRINFO *************** *** 1773,1789 **** int port; #endif /* HAVE_GETADDRINFO */ int s = -1, outch, inch; ! struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; int retry = 0; int count = specpdl_ptr - specpdl; int count1; #ifdef WINDOWSNT /* Ensure socket support is loaded if available. */ init_winsock (TRUE); #endif ! GCPRO4 (name, buffer, host, service); CHECK_STRING (name); CHECK_STRING (host); --- 1820,1846 ---- int port; #endif /* HAVE_GETADDRINFO */ int s = -1, outch, inch; ! struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; int retry = 0; int count = specpdl_ptr - specpdl; int count1; + int is_non_blocking; #ifdef WINDOWSNT /* Ensure socket support is loaded if available. */ init_winsock (TRUE); #endif ! non_blocking = (NILP (non_blocking) ? Qnil : Qt); ! #ifdef NON_BLOCKING_CONNECT ! is_non_blocking = !NILP (non_blocking); ! #else ! is_non_blocking = 0; ! #endif ! ! /* Can only GCPRO 5 variables */ ! sentinel = Fcons (sentinel, filter); ! GCPRO5 (name, buffer, host, service, sentinel); CHECK_STRING (name); CHECK_STRING (host); *************** *** 1867,1872 **** --- 1924,1942 ---- count1 = specpdl_ptr - specpdl; record_unwind_protect (close_file_unwind, make_number (s)); + #ifdef NON_BLOCKING_CONNECT + if (is_non_blocking) + { + #ifdef O_NONBLOCK + ret = fcntl (s, F_SETFL, O_NONBLOCK); + #else + ret = fcntl (s, F_SETFL, O_NDELAY); + #endif + if (ret < 0) + is_non_blocking = 0; + } + #endif + loop: immediate_quit = 1; *************** *** 1885,1893 **** turn_on_atimers (1); if (ret == 0 || xerrno == EISCONN) ! /* The unwind-protect will be discarded afterwards. ! Likewise for immediate_quit. */ break; immediate_quit = 0; --- 1955,1978 ---- turn_on_atimers (1); if (ret == 0 || xerrno == EISCONN) ! { ! is_non_blocking = 0; ! /* The unwind-protect will be discarded afterwards. ! Likewise for immediate_quit. */ ! break; ! } ! ! #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 + #endif immediate_quit = 0; *************** *** 1989,2001 **** if (interrupt_input) unrequest_sigio (); loop: immediate_quit = 1; QUIT; ! if (connect (s, (struct sockaddr *) &address, sizeof address) == -1 ! && errno != EISCONN) { int xerrno = errno; --- 2074,2115 ---- if (interrupt_input) unrequest_sigio (); + #ifdef NON_BLOCKING_CONNECT + if (is_non_blocking) + { + #ifdef O_NONBLOCK + ret = fcntl (s, F_SETFL, O_NONBLOCK); + #else + ret = fcntl (s, F_SETFL, O_NDELAY); + #endif + if (ret < 0) + is_non_blocking = 0; + } + #endif /* NON_BLOCKING_CONNECT */ + loop: immediate_quit = 1; QUIT; ! ret = connect (s, (struct sockaddr *) &address, sizeof address); ! ! if (ret == 0 || errno == EISCONN) ! { ! is_non_blocking = 0; ! } ! #ifdef NON_BLOCKING_CONNECT ! #ifdef EINPROGRESS ! else if (is_non_blocking && ret == -1 && errno == EINPROGRESS) ! ; ! #else ! #ifdef EWOULDBLOCK ! else if (is_non_blocking && ret == -1 && errno == EWOULDBLOCK) ! ; ! #endif ! #endif ! #endif ! else { int xerrno = errno; *************** *** 2041,2046 **** --- 2155,2161 ---- request_sigio (); #else /* TERM */ + is_non_blocking = 0; s = connect_server (0); if (s < 0) report_file_error ("error creating socket", Fcons (name, Qnil)); *************** *** 2068,2082 **** XPROCESS (proc)->childp = Fcons (host, Fcons (service, Qnil)); XPROCESS (proc)->command_channel_p = Qnil; XPROCESS (proc)->buffer = buffer; ! XPROCESS (proc)->sentinel = Qnil; ! XPROCESS (proc)->filter = Qnil; XPROCESS (proc)->command = Qnil; XPROCESS (proc)->pid = Qnil; XSETINT (XPROCESS (proc)->infd, inch); XSETINT (XPROCESS (proc)->outfd, outch); XPROCESS (proc)->status = Qrun; ! FD_SET (inch, &input_wait_mask); ! FD_SET (inch, &non_keyboard_wait_mask); if (inch > max_process_desc) max_process_desc = inch; --- 2183,2209 ---- XPROCESS (proc)->childp = Fcons (host, Fcons (service, Qnil)); XPROCESS (proc)->command_channel_p = Qnil; XPROCESS (proc)->buffer = buffer; ! XPROCESS (proc)->sentinel = XCAR (sentinel); ! XPROCESS (proc)->filter = XCDR (sentinel); XPROCESS (proc)->command = Qnil; XPROCESS (proc)->pid = Qnil; XSETINT (XPROCESS (proc)->infd, inch); XSETINT (XPROCESS (proc)->outfd, outch); XPROCESS (proc)->status = Qrun; ! if (!NILP (non_blocking)) ! { ! XPROCESS (proc)->status = Qconnect; ! if (!FD_ISSET (inch, &connect_wait_mask)) ! { ! FD_SET (inch, &connect_wait_mask); ! num_pending_connects++; ! } ! } ! else if (!EQ (XPROCESS (proc)->filter, Qt)) ! { ! FD_SET (inch, &input_wait_mask); ! FD_SET (inch, &non_keyboard_wait_mask); ! } if (inch > max_process_desc) max_process_desc = inch; *************** *** 2194,2199 **** --- 2321,2332 ---- chan_process[inchannel] = Qnil; FD_CLR (inchannel, &input_wait_mask); FD_CLR (inchannel, &non_keyboard_wait_mask); + if (FD_ISSET (inchannel, &connect_wait_mask)) + { + FD_CLR (inchannel, &connect_wait_mask); + if (--num_pending_connects < 0) + abort (); + } if (inchannel == max_process_desc) { int i; *************** *** 2358,2367 **** { register int channel, nfds; static SELECT_TYPE Available; int xerrno; Lisp_Object proc; EMACS_TIME timeout, end_time; - SELECT_TYPE Atemp; int wait_channel = -1; struct Lisp_Process *wait_proc = 0; int got_some_input = 0; --- 2491,2501 ---- { register int channel, nfds; static SELECT_TYPE Available; + static SELECT_TYPE Connecting; + int check_connect, no_avail; int xerrno; Lisp_Object proc; EMACS_TIME timeout, end_time; int wait_channel = -1; struct Lisp_Process *wait_proc = 0; int got_some_input = 0; *************** *** 2370,2375 **** --- 2504,2510 ---- Lisp_Object wait_for_cell = Qnil; FD_ZERO (&Available); + FD_ZERO (&Connecting); /* If read_kbd is a process to watch, set wait_proc and wait_channel accordingly. */ *************** *** 2511,2521 **** timeout to get our attention. */ if (update_tick != process_tick && do_display) { Atemp = input_wait_mask; EMACS_SET_SECS_USECS (timeout, 0, 0); if ((select (max (max_process_desc, max_keyboard_desc) + 1, ! &Atemp, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ! &timeout) <= 0)) { /* It's okay for us to do this and then continue with --- 2646,2660 ---- timeout to get our attention. */ if (update_tick != process_tick && do_display) { + SELECT_TYPE Atemp, Ctemp; + Atemp = input_wait_mask; + Ctemp = connect_wait_mask; EMACS_SET_SECS_USECS (timeout, 0, 0); if ((select (max (max_process_desc, max_keyboard_desc) + 1, ! &Atemp, ! (num_pending_connects > 0 ? &Ctemp : (SELECT_TYPE *)0), ! (SELECT_TYPE *)0, &timeout) <= 0)) { /* It's okay for us to do this and then continue with *************** *** 2525,2535 **** } } ! /* Don't wait for output from a non-running process. */ if (wait_proc != 0 && !NILP (wait_proc->raw_status_low)) update_status (wait_proc); if (wait_proc != 0 ! && ! EQ (wait_proc->status, Qrun)) { int nread, total_nread = 0; --- 2664,2676 ---- } } ! /* Don't wait for output from a non-running process. Just ! read whatever data has already been received. */ if (wait_proc != 0 && !NILP (wait_proc->raw_status_low)) update_status (wait_proc); if (wait_proc != 0 ! && ! EQ (wait_proc->status, Qrun) ! && ! EQ (wait_proc->status, Qconnect)) { int nread, total_nread = 0; *************** *** 2568,2578 **** /* Wait till there is something to do */ if (!NILP (wait_for_cell)) ! Available = non_process_wait_mask; ! else if (! XINT (read_kbd)) ! Available = non_keyboard_wait_mask; else ! Available = input_wait_mask; /* If frame size has changed or the window is newly mapped, redisplay now, before we start to wait. There is a race --- 2709,2726 ---- /* Wait till there is something to do */ if (!NILP (wait_for_cell)) ! { ! Available = non_process_wait_mask; ! check_connect = 0; ! } else ! { ! if (! XINT (read_kbd)) ! Available = non_keyboard_wait_mask; ! else ! Available = input_wait_mask; ! check_connect = (num_pending_connects > 0); ! } /* If frame size has changed or the window is newly mapped, redisplay now, before we start to wait. There is a race *************** *** 2587,2601 **** set_waiting_for_input (&timeout); } if (XINT (read_kbd) && detect_input_pending ()) { nfds = 0; ! FD_ZERO (&Available); } else ! nfds = select (max (max_process_desc, max_keyboard_desc) + 1, ! &Available, (SELECT_TYPE *)0, (SELECT_TYPE *)0, ! &timeout); xerrno = errno; --- 2735,2755 ---- set_waiting_for_input (&timeout); } + no_avail = 0; if (XINT (read_kbd) && detect_input_pending ()) { nfds = 0; ! no_avail = 1; } else ! { ! if (check_connect) ! Connecting = connect_wait_mask; ! nfds = select (max (max_process_desc, max_keyboard_desc) + 1, ! &Available, ! (check_connect ? &Connecting : (SELECT_TYPE *)0), ! (SELECT_TYPE *)0, &timeout); ! } xerrno = errno; *************** *** 2611,2617 **** if (nfds < 0) { if (xerrno == EINTR) ! FD_ZERO (&Available); #ifdef ultrix /* Ultrix select seems to return ENOMEM when it is interrupted. Treat it just like EINTR. Bleah. Note --- 2765,2771 ---- if (nfds < 0) { if (xerrno == EINTR) ! no_avail = 1; #ifdef ultrix /* Ultrix select seems to return ENOMEM when it is interrupted. Treat it just like EINTR. Bleah. Note *************** *** 2619,2631 **** "__ultrix__"; the latter is only defined under GCC, but not by DEC's bundled CC. -JimB */ else if (xerrno == ENOMEM) ! FD_ZERO (&Available); #endif #ifdef ALLIANT /* This happens for no known reason on ALLIANT. I am guessing that this is the right response. -- RMS. */ else if (xerrno == EFAULT) ! FD_ZERO (&Available); #endif else if (xerrno == EBADF) { --- 2773,2785 ---- "__ultrix__"; the latter is only defined under GCC, but not by DEC's bundled CC. -JimB */ else if (xerrno == ENOMEM) ! no_avail = 1; #endif #ifdef ALLIANT /* This happens for no known reason on ALLIANT. I am guessing that this is the right response. -- RMS. */ else if (xerrno == EFAULT) ! no_avail = 1; #endif else if (xerrno == EBADF) { *************** *** 2637,2643 **** So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF in m/ibmrt-aix.h), and here we just ignore the select error. Cleanup occurs c/o status_notify after SIGCLD. */ ! FD_ZERO (&Available); /* Cannot depend on values returned */ #else abort (); #endif --- 2791,2797 ---- So, SIGHUP is ignored (see def of PTY_TTY_NAME_SPRINTF in m/ibmrt-aix.h), and here we just ignore the select error. Cleanup occurs c/o status_notify after SIGCLD. */ ! no_avail = 1; /* Cannot depend on values returned */ #else abort (); #endif *************** *** 2645,2653 **** else error ("select error: %s", emacs_strerror (xerrno)); } #if defined(sun) && !defined(USG5_4) ! else if (nfds > 0 && keyboard_bit_set (&Available) ! && interrupt_input) /* System sometimes fails to deliver SIGIO. David J. Mackenzie says that Emacs doesn't compile under --- 2799,2814 ---- else error ("select error: %s", emacs_strerror (xerrno)); } + + if (no_avail) + { + FD_ZERO (&Available); + check_connect = 0; + } + #if defined(sun) && !defined(USG5_4) ! if (nfds > 0 && keyboard_bit_set (&Available) ! && interrupt_input) /* System sometimes fails to deliver SIGIO. David J. Mackenzie says that Emacs doesn't compile under *************** *** 2746,2751 **** --- 2907,2915 ---- do_pending_window_change (0); /* Check for data from a process. */ + if (no_avail || nfds == 0) + continue; + /* Really FIRST_PROC_DESC should be 0 on Unix, but this is safer in the short run. */ for (channel = 0; channel <= max_process_desc; channel++) *************** *** 2837,2842 **** --- 3001,3047 ---- = Fcons (Qexit, Fcons (make_number (256), Qnil)); } } + #ifdef NON_BLOCKING_CONNECT + if (check_connect && FD_ISSET (channel, &Connecting)) + { + struct Lisp_Process *p; + struct sockaddr pname; + socklen_t pnamelen = sizeof(pname); + + FD_CLR (channel, &connect_wait_mask); + if (--num_pending_connects < 0) + abort (); + + proc = chan_process[channel]; + if (NILP (proc)) + continue; + + p = XPROCESS (proc); + XSETINT (p->tick, ++process_tick); + + /* If connection failed, getpeername fails */ + if (getpeername(channel, &pname, &pnamelen) < 0) + { + char dummy; + + xerrno = errno; + /* Obtain connect failure code through error slippage. */ + if (errno == ENOTCONN && read(channel, &dummy, 1) < 0) + xerrno = errno; + p->status = Fcons (Qfailed, Fcons (make_number (xerrno), Qnil)); + deactivate_process (proc); + } + else + { + p->status = Qrun; + if (!EQ (p->filter, Qt)) + { + FD_SET (XINT (p->infd), &input_wait_mask); + FD_SET (XINT (p->infd), &non_keyboard_wait_mask); + } + } + } + #endif /* NON_BLOCKING_CONNECT */ } /* end for each file descriptor */ } /* end while exit conditions not met */ *************** *** 4419,4424 **** --- 4624,4630 ---- /* If process is still active, read any output that remains. */ while (! EQ (p->filter, Qt) + && ! EQ (p->status, Qconnect) && XINT (p->infd) >= 0 && read_process_output (proc, XINT (p->infd)) > 0); *************** *** 4653,4658 **** --- 4859,4868 ---- staticpro (&Qopen); Qclosed = intern ("closed"); staticpro (&Qclosed); + Qconnect = intern ("connect"); + staticpro (&Qconnect); + Qfailed = intern ("failed"); + staticpro (&Qfailed); Qlast_nonmenu_event = intern ("last-nonmenu-event"); staticpro (&Qlast_nonmenu_event); -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-02-25 22:38 ` Kim F. Storm @ 2002-02-26 22:46 ` Helmut Eller 2002-02-27 11:59 ` Kim F. Storm 0 siblings, 1 reply; 17+ messages in thread From: Helmut Eller @ 2002-02-26 22:46 UTC (permalink / raw) Cc: emacs-devel storm@cua.dk (Kim F. Storm) writes: > Here is my second attempt at a patch to support non-blocking > open-network-stream. I think the problem I described last time is still present. The problem is that the filter is invoked before the sentinel. This happens when the stream is readable immediately after the transition from connect state to open state. Consider wait_reading_process_input: > --- 3001,3047 ---- [...] > + XSETINT (p->tick, ++process_tick); > + if (getpeername(channel, &pname, &pnamelen) < 0) [...] > + else > + { > + p->status = Qrun; Tick is incremented and status is set to Qrun. Incrementing tick causes status_notify to be invoked during the next iteration. But status_notify ... > --- 4624,4630 ---- [...] > while (! EQ (p->filter, Qt) > + && ! EQ (p->status, Qconnect) > && XINT (p->infd) >= 0 > && read_process_output (proc, XINT (p->infd)) > 0); ... calls read_process_output (and the filter) before the sentinel. A simple solution is to call the sentinel in wait_reading_process_input without incrementing tick, e.g.: --- 3001,3047 ---- ... + if (getpeername(channel, &pname, &pnamelen) < 0) + XSETINT (p->tick, ++process_tick); ... + else + { + p->status = Qrun; + exec_sentinel (proc, Qopen); Another point: is it a problem to pass the error message and not just the error number to the sentinel? Helmut. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-02-26 22:46 ` Helmut Eller @ 2002-02-27 11:59 ` Kim F. Storm 2002-02-28 4:08 ` Richard Stallman 0 siblings, 1 reply; 17+ messages in thread From: Kim F. Storm @ 2002-02-27 11:59 UTC (permalink / raw) Cc: emacs-devel Helmut Eller <helmut@xaital.km4u.net> writes: > storm@cua.dk (Kim F. Storm) writes: > > > Here is my second attempt at a patch to support non-blocking > > open-network-stream. > > I think the problem I described last time is still present. The > problem is that the filter is invoked before the sentinel. This > happens when the stream is readable immediately after the transition > from connect state to open state. I've made the chage you suggested. Thanks. There is a general problem with handling a request for non-blocking connect on systems which does not support this. As I have specified this now, open-network-stream will proceed to emulate a non-blocking connect -- which means that it will block. And when the connect completes, it continues to pretend that the connect was non-blocking, so it setup the sentinel to be called after return, and all that jazz. I think it would be much cleaner if (open-network-stream ... t) simply returns nil if it doesn't support non-blocking connect. Then the code can do some smarter things (like delaying the connect), and I don't have to mess up the C code with all sorts of hacks to delay the delivery of a "failed to connect" message on a process which would not otherwise have to exist. Does this sound acceptable (since there is currently no code supporting non-blocking connect, this cannot break anything :-) -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-02-27 11:59 ` Kim F. Storm @ 2002-02-28 4:08 ` Richard Stallman 2002-03-01 0:21 ` Kim F. Storm 0 siblings, 1 reply; 17+ messages in thread From: Richard Stallman @ 2002-02-28 4:08 UTC (permalink / raw) Cc: helmut, emacs-devel I think it would be much cleaner if (open-network-stream ... t) simply returns nil if it doesn't support non-blocking connect. I think that is ok. The program could immediately try a blocking connect if that is the right thing to do. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-02-28 4:08 ` Richard Stallman @ 2002-03-01 0:21 ` Kim F. Storm 2002-03-01 8:01 ` Juanma Barranquero ` (2 more replies) 0 siblings, 3 replies; 17+ messages in thread From: Kim F. Storm @ 2002-03-01 0:21 UTC (permalink / raw) Cc: helmut, emacs-devel Richard Stallman <rms@gnu.org> writes: > I think it would be much cleaner if (open-network-stream ... t) simply > returns nil if it doesn't support non-blocking connect. > > I think that is ok. The program could immediately try a blocking > connect if that is the right thing to do. I have committed the changes to process.c which add the non-blocking connect support to open-network-stream. The next "project" in this area is to add Helmut's server sockets. (do we have papers for that?) However, I think it can be done via open-network-stream: If the HOST argument is nil, a server socket is opened which accepts connections. The sentinel is called - with a newly created process - whenever a connections is accepted. There are some details to be worked out here, but we need to discuss whether we should use this approach or the approach suggested by Helmut. -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-01 0:21 ` Kim F. Storm @ 2002-03-01 8:01 ` Juanma Barranquero 2002-03-01 10:50 ` Kim F. Storm 2002-03-01 21:23 ` Richard Stallman 2002-03-02 7:59 ` Helmut Eller 2 siblings, 1 reply; 17+ messages in thread From: Juanma Barranquero @ 2002-03-01 8:01 UTC (permalink / raw) Cc: rms, helmut, emacs-devel On 01 Mar 2002 01:21:39 +0100, storm@cua.dk (Kim F. Storm) wrote: > The next "project" in this area is to add Helmut's server sockets. > (do we have papers for that?) > > However, I think it can be done via open-network-stream: > > If the HOST argument is nil, a server socket is opened which > accepts connections. The sentinel is called - with a newly > created process - whenever a connections is accepted. There will be any support for Emacs to act as a server for UDP? /L/e/k/t/u _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-01 8:01 ` Juanma Barranquero @ 2002-03-01 10:50 ` Kim F. Storm 2002-03-01 17:10 ` Pavel Janík 0 siblings, 1 reply; 17+ messages in thread From: Kim F. Storm @ 2002-03-01 10:50 UTC (permalink / raw) Cc: helmut, emacs-devel Juanma Barranquero <lektu@terra.es> writes: > On 01 Mar 2002 01:21:39 +0100, storm@cua.dk (Kim F. Storm) wrote: > > > The next "project" in this area is to add Helmut's server sockets. > > (do we have papers for that?) > > > > However, I think it can be done via open-network-stream: > > > > If the HOST argument is nil, a server socket is opened which > > accepts connections. The sentinel is called - with a newly > > created process - whenever a connections is accepted. > > There will be any support for Emacs to act as a server for UDP? I don't even think it can act as a client for UDP currently, so there is really two tasks here. I'd like to look into that later if others think that's something we should support. -- Kim F. Storm http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-01 10:50 ` Kim F. Storm @ 2002-03-01 17:10 ` Pavel Janík 0 siblings, 0 replies; 17+ messages in thread From: Pavel Janík @ 2002-03-01 17:10 UTC (permalink / raw) Cc: Juanma Barranquero, helmut, emacs-devel From: storm@cua.dk (Kim F. Storm) Date: 01 Mar 2002 11:50:46 +0100 Hi Kim, > I don't even think it can act as a client for UDP currently, so > there is really two tasks here. I'd like to look into that later > if others think that's something we should support. I think that UDP can wait for some time. The most important thing now is IMHO some examples for people who would like to use it and extend Emacs. Multiplication effect... -- Pavel Janík So calm down guys. And improving the benchmark might not be a bad idea. -- Linus Torvalds in linux-kernel _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-01 0:21 ` Kim F. Storm 2002-03-01 8:01 ` Juanma Barranquero @ 2002-03-01 21:23 ` Richard Stallman 2002-03-02 7:59 ` Helmut Eller 2 siblings, 0 replies; 17+ messages in thread From: Richard Stallman @ 2002-03-01 21:23 UTC (permalink / raw) Cc: helmut, emacs-devel If the HOST argument is nil, a server socket is opened which accepts connections. The sentinel is called - with a newly created process - whenever a connections is accepted. That sounds good to me in principle, if the details work ok. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-01 0:21 ` Kim F. Storm 2002-03-01 8:01 ` Juanma Barranquero 2002-03-01 21:23 ` Richard Stallman @ 2002-03-02 7:59 ` Helmut Eller 2002-03-03 0:12 ` Kim F. Storm 2002-03-03 14:39 ` Richard Stallman 2 siblings, 2 replies; 17+ messages in thread From: Helmut Eller @ 2002-03-02 7:59 UTC (permalink / raw) Cc: emacs-devel storm@cua.dk (Kim F. Storm) writes: > (do we have papers for that?) No. If needed, I will sign papers. > However, I think it can be done via open-network-stream: > > If the HOST argument is nil, a server socket is opened which > accepts connections. The sentinel is called - with a newly > created process - whenever a connections is accepted. I see several problems with this approach: - What is the process-name for the connections? The same as for the server socket? All connections with the same name? - How do you open a Unix server socket? - It's possible to open Unix server sockets. It would be reasonable to support Unix client sockets too. How can this be done? - What should NON-BLOCKING mean for server sockets? - open-network-stream takes already 7 arguments. Putting even more functionality in makes it hard to document. Server sockets are IMHO different enough to merit a separate function. What is the advantage of merging those concepts? _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-02 7:59 ` Helmut Eller @ 2002-03-03 0:12 ` Kim F. Storm 2002-03-03 10:46 ` Helmut Eller 2002-03-03 16:44 ` Mario Lang 2002-03-03 14:39 ` Richard Stallman 1 sibling, 2 replies; 17+ messages in thread From: Kim F. Storm @ 2002-03-03 0:12 UTC (permalink / raw) Cc: emacs-devel Helmut Eller <helmut@xaital.km4u.net> writes: > storm@cua.dk (Kim F. Storm) writes: > > > (do we have papers for that?) > > No. If needed, I will sign papers. > > > However, I think it can be done via open-network-stream: > > > > If the HOST argument is nil, a server socket is opened which > > accepts connections. The sentinel is called - with a newly > > created process - whenever a connections is accepted. > > I see several problems with this approach: > > - What is the process-name for the connections? The same as for the > server socket? All connections with the same name? My idea is to name it as the server process concatenated with the ip address and source port of the client, i.e. something like "service <10.20.30.40:3248>" I prefer this to manually having to give each connection a unique name in advance (as would be necessary with your accept-connection API). > > - How do you open a Unix server socket? > I intent do rename the NON-BLOCKING argument to a more generic TYPE argument. Eventually, it could be things like: If HOST specified - connect to that host: nil - blocking connect (tcp) to SERVICE on HOST t - non-blocking connect (tcp) to SERVICE on HOST udp - open udp socket with target SERVICE on HOST unix - connect to unix socket on address SERVICE If HOST is nil - open a server socket: nil - open tcp socket listning on SERVICE port t - same as nil udp - open udp socket bound to SERVICE port unix - open unix socket bound to address SERVICE > - It's possible to open Unix server sockets. It would be reasonable > to support Unix client sockets too. How can this be done? > See above. (IIRC, Your patch didn't cover unix sockets) > - What should NON-BLOCKING mean for server sockets? See above. > > - open-network-stream takes already 7 arguments. Putting even more > functionality in makes it hard to document. I don't agree. Renaming NON-BLOCKING to TYPE and switching on whether HOST is non-nil (connect) or nil (start server) seems fairly clean and simple to me. > > Server sockets are IMHO different enough to merit a separate > function. What is the advantage of merging those concepts? > Most of the necessary functionality is already in open-network-stream, so adding the server part there is pretty orthogonal I think. -- Kim F. Storm <storm@cua.dk> http://www.cua.dk _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-03 0:12 ` Kim F. Storm @ 2002-03-03 10:46 ` Helmut Eller 2002-03-03 16:44 ` Mario Lang 1 sibling, 0 replies; 17+ messages in thread From: Helmut Eller @ 2002-03-03 10:46 UTC (permalink / raw) Cc: emacs-devel storm@cua.dk (Kim F. Storm) writes: > I intent do rename the NON-BLOCKING argument to a more generic TYPE > argument. Eventually, it could be things like: > > If HOST specified - connect to that host: > > nil - blocking connect (tcp) to SERVICE on HOST > t - non-blocking connect (tcp) to SERVICE on HOST > udp - open udp socket with target SERVICE on HOST > unix - connect to unix socket on address SERVICE > > If HOST is nil - open a server socket: > > nil - open tcp socket listning on SERVICE port > t - same as nil > udp - open udp socket bound to SERVICE port > unix - open unix socket bound to address SERVICE If you overload NON-BLOCKING in this way, you lose the ability to make a non-blocking connects to Unix sockets. The distinction between INET or Unix sockets should be made with an optional PROTOCOL-FAMILY argument. Also, mixing up UDP with Unix sockets is not a good idea. The main difference between TCP and UPD is that UDP is packet oriented and TCP is stream oriented. You can also have packet oriented Unix sockets. Packet or stream orientedness should probably be specified with a separate STYLE argument. > See above. (IIRC, Your patch didn't cover unix sockets) I added Unix sockets when RMS said that Unix sockets are required to replace emacsserver. > > - open-network-stream takes already 7 arguments. Putting even more > > functionality in makes it hard to document. > > I don't agree. Renaming NON-BLOCKING to TYPE and switching on > whether HOST is non-nil (connect) or nil (start server) seems > fairly clean and simple to me. I cannot help, but your TYPE argument looks like a kludge to me. The HOST, BUFFER, and NON-BLOCKING arguments are not even used for server sockets. > > Server sockets are IMHO different enough to merit a separate > > function. What is the advantage of merging those concepts? > > > > Most of the necessary functionality is already in open-network-stream, > so adding the server part there is pretty orthogonal I think. I think there is not much shared functionality. open-network-stream does basically this: gethostbyname/socket/connect/coding-system-magic For the server socket case it should do: socket/bind/listen Only the call to socket could be shared. Below is my updated patch that supports Unix sockets. Perhaps you can reuse some parts. Index: process.c =================================================================== RCS file: /cvsroot/emacs/emacs/src/process.c,v retrieving revision 1.353 diff -c -r1.353 process.c *** process.c 28 Feb 2002 23:59:19 -0000 1.353 --- process.c 3 Mar 2002 10:36:17 -0000 *************** *** 51,59 **** --- 51,69 ---- #ifdef HAVE_SOCKETS /* TCP connection support, if kernel can do it */ #include <sys/socket.h> + #include <sys/un.h> #include <netdb.h> #include <netinet/in.h> #include <arpa/inet.h> + + /* Union of all socket address types we support. */ + union sockaddr_union + { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_un sun; + }; + #ifdef NEED_NET_ERRNO_H #include <net/errno.h> #endif /* NEED_NET_ERRNO_H */ *************** *** 114,119 **** --- 124,130 ---- Lisp_Object Qprocessp; Lisp_Object Qrun, Qstop, Qsignal; Lisp_Object Qopen, Qclosed, Qconnect, Qfailed; + Lisp_Object Qserver_socket, Qlisten, Qinet, Qunix; Lisp_Object Qlast_nonmenu_event; /* Qexit is declared and initialized in eval.c. */ *************** *** 122,129 **** --- 133,142 ---- #ifdef HAVE_SOCKETS #define NETCONN_P(p) (GC_CONSP (XPROCESS (p)->childp)) + #define SERVER_SOCKET_P(p) ((XPROCESS (p)->childp) == Qserver_socket) #else #define NETCONN_P(p) 0 + #define SERVER_SOCKET_P(p) 0 #endif /* HAVE_SOCKETS */ /* Define first descriptor number available for subprocesses. */ *************** *** 258,264 **** static struct coding_system *proc_encode_coding_system[MAXDESC]; static Lisp_Object get_process (); ! static void exec_sentinel (); extern EMACS_TIME timer_check (); extern int timers_run; --- 271,282 ---- static struct coding_system *proc_encode_coding_system[MAXDESC]; static Lisp_Object get_process (); ! static void exec_sentinel (Lisp_Object proc, Lisp_Object reason); ! static Lisp_Object read_process_output_error_handler (Lisp_Object error); ! static Lisp_Object read_process_output_call (Lisp_Object fun_and_args); ! #ifdef HAVE_SOCKETS ! static Lisp_Object decode_sockaddr_union (union sockaddr_union *u); ! #endif extern EMACS_TIME timer_check (); extern int timers_run; *************** *** 614,619 **** --- 632,642 ---- XPROCESS (process)->status = Fcons (Qexit, Fcons (make_number (0), Qnil)); XSETINT (XPROCESS (process)->tick, ++process_tick); } + else if (SERVER_SOCKET_P (process)) + { + XPROCESS (process)->status = list2 (Qexit, make_number (0)); + XSETINT (XPROCESS (process)->tick, ++process_tick); + } else if (XINT (XPROCESS (process)->infd) >= 0) { Fkill_process (process, Qnil); *************** *** 638,643 **** --- 661,667 ---- 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. + listen -- for a server socket that is listening. nil -- if arg is a process name and no such process exists. PROCESS may be a process, a buffer, the name of a process, or nil, indicating the current buffer's process. */) *************** *** 668,673 **** --- 692,706 ---- else if (EQ (status, Qexit)) status = Qclosed; } + else if (SERVER_SOCKET_P (process)) + { + if (EQ (status, Qrun)) + status = Qlisten; + else if (EQ (status, Qexit)) + status = Qclosed; + else + abort (); + } return status; } *************** *** 919,930 **** 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 --- 952,974 ---- 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). ! For a server socket a cons cell of the form (server-socket . ADDRESS). */) (process) register Lisp_Object process; { CHECK_PROCESS (process); ! #ifdef HAVE_SOCKETS ! if (SERVER_SOCKET_P (process)) ! { ! union sockaddr_union u; ! socklen_t length = sizeof u; ! getsockname (XPROCESS (process)->infd, &u.sa, &length); ! return Fcons (Qserver_socket, decode_sockaddr_union (&u)); ! } ! else ! #endif ! return XPROCESS (process)->childp; } #if 0 /* Turned off because we don't currently record this info *************** *** 998,1003 **** --- 1042,1056 ---- else Fprinc (symbol, Qnil); } + else if (SERVER_SOCKET_P (proc)) + { + if (EQ (symbol, Qrun)) + write_string ("listen", -1); + else if (EQ (symbol, Qexit)) + write_string ("closed", -1); + else + Fprinc (symbol, Qnil); + } else Fprinc (symbol, Qnil); *************** *** 1038,1043 **** --- 1091,1115 ---- XSTRING (XCAR (p->childp))->data); insert_string (tembuf); } + else if (SERVER_SOCKET_P (proc)) + { + union sockaddr_union u; + socklen_t length = sizeof u; + getsockname (p->infd, &u.sa, &length); + switch (u.sa.sa_family) + { + case AF_INET: + sprintf (tembuf, "(inet socket on port %d)\n", + ntohs (u.sin.sin_port)); + break; + case AF_LOCAL: + sprintf (tembuf, "(unix socket %s)\n", u.sun.sun_path); + break; + default: + abort (); + } + insert_string (tembuf); + } else { tem = p->command; *************** *** 1778,1783 **** --- 1850,1986 ---- #ifdef HAVE_SOCKETS + /* Setup coding systems for communicating with the network stream. */ + static void + select_coding_system (proc) + Lisp_Object proc; + { + Lisp_Object buffer = XPROCESS (proc)->buffer; + Lisp_Object name = XPROCESS (proc)->name; + Lisp_Object host = XCAR (XPROCESS (proc)->childp); + Lisp_Object service = XCAR (XCDR (XPROCESS (proc)->childp)); + int inch = XINT (XPROCESS (proc)->infd); + int outch = XINT (XPROCESS (proc)->outfd); + { + struct gcpro gcpro1; + /* Qt denotes we have not yet called Ffind_operation_coding_system. */ + 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))) + /* We dare not decode end-of-line format by setting VAL to + Qraw_text, because the existing Emacs Lisp libraries + assume that they receive bare code including a sequene of + CR LF. */ + val = Qnil; + else + { + args[0] = Qopen_network_stream, args[1] = name, + args[2] = buffer, args[3] = host, args[4] = service; + GCPRO1 (proc); + coding_systems = Ffind_operation_coding_system (5, args); + UNGCPRO; + if (CONSP (coding_systems)) + val = XCAR (coding_systems); + else if (CONSP (Vdefault_process_coding_system)) + val = XCAR (Vdefault_process_coding_system); + 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; + else + { + if (EQ (coding_systems, Qt)) + { + args[0] = Qopen_network_stream, args[1] = name, + args[2] = buffer, args[3] = host, args[4] = service; + GCPRO1 (proc); + coding_systems = Ffind_operation_coding_system (5, args); + UNGCPRO; + } + if (CONSP (coding_systems)) + val = XCDR (coding_systems); + else if (CONSP (Vdefault_process_coding_system)) + val = XCDR (Vdefault_process_coding_system); + 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); + + } + + /* create and initialize a process representing a socket. */ + static Lisp_Object + make_socket_process (fd, name, childp, status, buffer) + int fd; + Lisp_Object name, childp, status, buffer; + { + struct gcpro gcpro1, gcpro2, gcpro3, gcpro4; + GCPRO4 (name, childp, status, buffer); + { + Lisp_Object proc = make_process (name); + chan_process[fd] = proc; + XPROCESS (proc)->childp = childp; + XPROCESS (proc)->command_channel_p = Qnil; + XPROCESS (proc)->buffer = buffer; + XPROCESS (proc)->sentinel = Qnil; + XPROCESS (proc)->filter = Qnil; + XPROCESS (proc)->command = Qnil; + XPROCESS (proc)->pid = Qnil; + XSETINT (XPROCESS (proc)->infd, fd); + XSETINT (XPROCESS (proc)->outfd, fd); + XPROCESS (proc)->status = status; + if (fd > max_process_desc) + max_process_desc = fd; + return proc; + } + } + + /* Make FD non-blocking and add it to the input fd-sets. */ + static void + register_fd_for_input (fd) + int fd; + { + #ifdef O_NONBLOCK + fcntl (fd, F_SETFL, O_NONBLOCK); + #else + #ifdef O_NDELAY + fcntl (fd, F_SETFL, O_NDELAY); + #endif + #endif + FD_SET (fd, &input_wait_mask); + FD_SET (fd, &non_keyboard_wait_mask); + } + /* 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 *************** *** 1836,1842 **** #endif /* HAVE_GETADDRINFO */ int ret = 0; int xerrno = 0; ! int s = -1, outch, inch; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; int retry = 0; int count = specpdl_ptr - specpdl; --- 2039,2045 ---- #endif /* HAVE_GETADDRINFO */ int ret = 0; int xerrno = 0; ! int s = -1; struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; int retry = 0; int count = specpdl_ptr - specpdl; *************** *** 2135,2167 **** send_command (s, C_DUMB, 1, 0); #endif /* TERM */ - inch = s; - outch = s; - if (!NILP (buffer)) buffer = Fget_buffer_create (buffer); - proc = make_process (name); - - chan_process[inch] = proc; - - #ifdef O_NONBLOCK - fcntl (inch, F_SETFL, O_NONBLOCK); - #else - #ifdef O_NDELAY - fcntl (inch, F_SETFL, O_NDELAY); - #endif - #endif ! XPROCESS (proc)->childp = Fcons (host, Fcons (service, Qnil)); ! XPROCESS (proc)->command_channel_p = Qnil; ! XPROCESS (proc)->buffer = buffer; XPROCESS (proc)->sentinel = XCAR (sentinel); XPROCESS (proc)->filter = XCDR (sentinel); - 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)) --- 2338,2349 ---- send_command (s, C_DUMB, 1, 0); #endif /* TERM */ if (!NILP (buffer)) buffer = Fget_buffer_create (buffer); ! proc = make_socket_process (s, name, list2 (host, service), Qrun, buffer); XPROCESS (proc)->sentinel = XCAR (sentinel); XPROCESS (proc)->filter = XCDR (sentinel); #ifdef NON_BLOCKING_CONNECT if (!NILP (non_blocking)) *************** *** 2170,2271 **** 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); num_pending_connects++; } } else #endif ! if (!EQ (XPROCESS (proc)->filter, Qt)) { ! FD_SET (inch, &input_wait_mask); ! FD_SET (inch, &non_keyboard_wait_mask); } ! if (inch > max_process_desc) ! max_process_desc = inch; { ! /* Setup coding systems for communicating with the network stream. */ ! struct gcpro gcpro1; ! /* Qt denotes we have not yet called Ffind_operation_coding_system. */ ! 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))) ! /* We dare not decode end-of-line format by setting VAL to ! Qraw_text, because the existing Emacs Lisp libraries ! assume that they receive bare code including a sequene of ! CR LF. */ ! val = Qnil; ! else ! { ! args[0] = Qopen_network_stream, args[1] = name, ! args[2] = buffer, args[3] = host, args[4] = service; ! GCPRO1 (proc); ! coding_systems = Ffind_operation_coding_system (5, args); ! UNGCPRO; ! if (CONSP (coding_systems)) ! val = XCAR (coding_systems); ! else if (CONSP (Vdefault_process_coding_system)) ! val = XCAR (Vdefault_process_coding_system); ! 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; ! else { ! if (EQ (coding_systems, Qt)) { ! args[0] = Qopen_network_stream, args[1] = name, ! args[2] = buffer, args[3] = host, args[4] = service; ! GCPRO1 (proc); ! coding_systems = Ffind_operation_coding_system (5, args); ! UNGCPRO; } - if (CONSP (coding_systems)) - val = XCDR (coding_systems); - else if (CONSP (Vdefault_process_coding_system)) - val = XCDR (Vdefault_process_coding_system); - 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; ! return proc; } #endif /* HAVE_SOCKETS */ void --- 2352,2618 ---- in that case, we still need to signal this like a non-blocking connection. */ XPROCESS (proc)->status = Qconnect; ! if (!FD_ISSET (s, &connect_wait_mask)) ! { ! FD_SET (s, &connect_wait_mask); num_pending_connects++; } } else #endif ! register_fd_for_input (s); ! ! select_coding_system (proc); ! ! UNGCPRO; ! return proc; ! } ! ! #define BACKLOG 5 ! ! /* Open a listening socket on PORT and return the socket descriptor. */ ! static int ! open_inet_socket (int port) ! { ! int fd = socket (PF_INET, SOCK_STREAM, 0); ! if (fd <= 0) goto error; ! { ! int err; ! int optval = 1; ! struct sockaddr_in servaddr; ! bzero (&servaddr, sizeof servaddr); ! servaddr.sin_family = AF_INET; ! servaddr.sin_port = htons (port); ! servaddr.sin_addr.s_addr = htonl (INADDR_ANY); ! err = setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof optval); ! if (err != 0) goto error; ! err = bind (fd, (struct sockaddr *)&servaddr, sizeof servaddr); ! if (err != 0) goto error; ! err = listen (fd, BACKLOG); ! if (err != 0) goto error; ! return fd; ! } ! error: ! if (fd > 0) ! close (fd); ! report_file_error ("open-server-socket", Qnil); ! abort (); ! } ! ! static int ! open_unix_socket (char *filename) ! { ! int fd = socket (PF_LOCAL, SOCK_STREAM, 0); ! if (fd <= 0) goto error; ! { ! int err; ! struct sockaddr_un servaddr; ! bzero (&servaddr, sizeof servaddr); ! servaddr.sun_family = AF_LOCAL; ! strncpy (servaddr.sun_path, filename, sizeof servaddr.sun_path); ! err = bind (fd, (struct sockaddr *)&servaddr, sizeof servaddr); ! if (err != 0) goto error; ! err = listen (fd, BACKLOG); ! if (err != 0) goto error; ! return fd; ! } ! error: ! if (fd > 0) ! close (fd); ! report_file_error ("open-server-socket", Qnil); ! abort (); ! } ! ! /* Open a server socket on a given port. The filter function must be ! set before accepting connections with `accept-connection'. The ! process-buffer is not used. */ ! ! DEFUN ("open-server-socket", Fopen_server_socket, Sopen_server_socket, ! 3, 3, 0, ! doc: /* Open a server socket on a port. ! ! Returns a process object to represent the socket. The filter function ! can be used to accept connections. See `accept-connection'. ! `delete-process' closes the server socket. ! ! NAME is the name for the process. ! PROTOCOL either 'inet or 'unix. ! PORT is the port number resp. filename for the socket. */ ) ! (name, protocol, port) ! Lisp_Object name, protocol, port; ! { ! int fd; ! CHECK_STRING (name); ! CHECK_SYMBOL (protocol); ! if (protocol == Qinet) ! { ! CHECK_NATNUM (port); ! if ((XINT (port) < 0) || ((1 << 16) <= XINT (port))) ! error ("Port number out of range"); ! fd = open_inet_socket (XINT (port)); ! } ! else if (protocol == Qunix) ! { ! CHECK_STRING (port); ! fd = open_unix_socket (XSTRING (port)->data); ! } ! else ! error ("Unsupported protocol %s", XSYMBOL (protocol)->name->data); ! return make_socket_process (fd, name, Qserver_socket, Qrun, Qnil); ! } ! ! /* return a Lisp representation for U: ! (HOST PORT) for AF_INET ! (unix FILENAME) for AF_UNIX. */ ! static Lisp_Object ! decode_sockaddr_union (union sockaddr_union *u) ! { ! switch (u->sa.sa_family) ! { ! case AF_INET: { ! char string[INET_ADDRSTRLEN]; ! inet_ntop (AF_INET, &u->sin.sin_addr, string, sizeof string); ! return list2 (build_string (string), ! make_number (ntohs (u->sin.sin_port))); } + case AF_LOCAL: + return list2 (Qunix, build_string (u->sun.sun_path)); + default: + abort (); + } + } + + /* Accept a connection on SERVER_SOCKET. Remove SERVER_SOCKET from + the input fd-set so that only the first waiting client is accepted. + Then create a process representing the new connection and pass it + to PROCESS's filter function. */ + static void + accept_client (process, server_socket) + Lisp_Object process; + int server_socket; + { + struct gcpro gcpro1, gcpro2; + union sockaddr_union u; + socklen_t length = sizeof u; + int fd = accept (server_socket, (struct sockaddr*)&u, &length); + FD_CLR (server_socket, &input_wait_mask); + FD_CLR (server_socket, &non_keyboard_wait_mask); + if (fd == -1) + { + if (NILP (XPROCESS (process)->sentinel)) + report_file_error ("accept", process); + else + exec_sentinel (process, build_string (emacs_strerror (errno))); + } + else + { + Lisp_Object childp = decode_sockaddr_union (&u); + Lisp_Object proc = make_socket_process (fd, XPROCESS (process)->mark, + childp, Qrun, Qnil); + GCPRO2 (process, proc); + select_coding_system (proc); + register_fd_for_input (fd); + internal_condition_case_1 (read_process_output_call, + list3 (XPROCESS (process)->filter, + process, + proc), + NILP (Vdebug_on_error) ? Qerror : Qnil, + read_process_output_error_handler); + UNGCPRO; + } + } ! DEFUN ("accept-connection", Faccept_connection, Saccept_connection, ! 2, 2, 0, ! doc: /* Accept a connection on the server socket. + This function is non-blocking and returns nil. The next incoming + connection will be accepted and passed to the process filter. The + process filter function receives 2 arguments: the server socket and a + process representing the new connection. The new process is treated + exactly like a network connection opened with `open-network-stream'. + + PROCESS a process representing a server socket. + NAME is the name for the new connection. */ ) + (process, name) + Lisp_Object process, name; + { + CHECK_PROCESS (process); + if (! (SERVER_SOCKET_P (process))) + error ("Process %s is not a server socket process", + XSTRING (XPROCESS (process)->name)->data); + CHECK_STRING (name); { ! int fd = XINT (XPROCESS (process)->infd); ! XPROCESS (process)->mark = name; /* kludge: field is otherwise unused */ ! register_fd_for_input (fd); ! return Qnil; ! } ! } ! DEFUN ("gethostbyname", Fgethostbyname, Sgethostbyname, ! 1, 1, 0, ! doc: /* Look up a host by name. ! Return the IP address and aliases for NAME. The result is a vector of ! this form: [hostent CANONICAL-NAME ALIASES ADDRTYPE ADDRLIST] ! ! CANONICAL-NAME is a string. ! ALIASES is a list of strings. ! ADDRTYPE is the symbol inet. ! ADDRLIST is a list of this form ((INT INT INT INT)* ) ! each INT correspond to 1 byte of the 32 bit address. */) ! (name) ! Lisp_Object name; ! { ! int gcpro1; ! struct hostent *hostent; ! CHECK_STRING (name); ! hostent = gethostbyname (XSTRING (name)->data); ! if (hostent == 0) ! error ("%s", hstrerror (h_errno)); ! else ! { ! Lisp_Object host_info = Fmake_vector (make_number (5), Qnil); ! Lisp_Object *vector = XVECTOR (host_info)->contents; ! GCPRO1 (host_info); ! vector[0] = intern ("hostent"); ! vector[1] = build_string (hostent->h_name); { ! char **p = hostent->h_aliases; ! while (*p != 0) { ! vector[2] = Fcons (build_string (*p), vector[2]); ! p++; } } ! switch (hostent->h_addrtype) ! { ! case AF_INET: ! { ! struct in_addr **p = (struct in_addr **)hostent->h_addr_list; ! vector[3] = Qinet; ! while (*p != 0) ! { ! uint32_t a = ntohl ((**p).s_addr); ! vector[4] = Fcons (list4 (make_number ((a >> 24) & 0xff), ! make_number ((a >> 16) & 0xff), ! make_number ((a >> 8) & 0xff), ! make_number ((a >> 0) & 0xff)), ! vector[4]); ! p++; ! } ! break; ! } ! default: ! abort (); ! } ! UNGCPRO; ! return host_info; ! } } + #endif /* HAVE_SOCKETS */ void *************** *** 2911,2916 **** --- 3258,3268 ---- proc = chan_process[channel]; if (NILP (proc)) continue; + if (SERVER_SOCKET_P (proc)) + { + accept_client (proc, channel); + continue; + } /* Read data from the process, starting with our buffered-ahead character if we have one. */ *************** *** 3469,3474 **** --- 3821,3828 ---- if (XINT (XPROCESS (proc)->outfd) < 0) error ("Output file descriptor of %s is closed", XSTRING (XPROCESS (proc)->name)->data); + if (SERVER_SOCKET_P (proc)) + error ("Cannot write to server socket"); coding = proc_encode_coding_system[XINT (XPROCESS (proc)->outfd)]; Vlast_coding_system_used = coding->symbol; *************** *** 4246,4251 **** --- 4600,4607 ---- update_status (XPROCESS (proc)); if (! EQ (XPROCESS (proc)->status, Qrun)) error ("Process %s not running", XSTRING (XPROCESS (proc)->name)->data); + if (SERVER_SOCKET_P (proc)) + error ("Cannot write to server socket", XSTRING (XPROCESS (proc)->name)); if (CODING_REQUIRE_FLUSHING (coding)) { *************** *** 4311,4316 **** --- 4667,4674 ---- { if (NETCONN_P (proc)) Fdelete_process (proc); + else if (SERVER_SOCKET_P (proc)) + Fdelete_process (proc); else if (XINT (XPROCESS (proc)->infd) >= 0) process_send_signal (proc, SIGHUP, Qnil, 1); } *************** *** 4861,4866 **** --- 5219,5234 ---- Qfailed = intern ("failed"); staticpro (&Qfailed); + Qlisten = intern ("listen"); + staticpro (&Qlisten); + + Qserver_socket = intern ("server-socket"); + staticpro (&Qserver_socket); + Qinet = intern ("inet"); + staticpro (&Qinet); + Qunix = intern ("unix"); + staticpro (&Qunix); + Qlast_nonmenu_event = intern ("last-nonmenu-event"); staticpro (&Qlast_nonmenu_event); *************** *** 4907,4912 **** --- 5275,5283 ---- defsubr (&Sstart_process); #ifdef HAVE_SOCKETS defsubr (&Sopen_network_stream); + defsubr (&Sopen_server_socket); + defsubr (&Saccept_connection); + defsubr (&Sgethostbyname); #endif /* HAVE_SOCKETS */ defsubr (&Saccept_process_output); defsubr (&Sprocess_send_region); _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-03 0:12 ` Kim F. Storm 2002-03-03 10:46 ` Helmut Eller @ 2002-03-03 16:44 ` Mario Lang 1 sibling, 0 replies; 17+ messages in thread From: Mario Lang @ 2002-03-03 16:44 UTC (permalink / raw) storm@cua.dk (Kim F. Storm) writes: > I intent do rename the NON-BLOCKING argument to a more generic TYPE > argument. Eventually, it could be things like: > > If HOST specified - connect to that host: > > nil - blocking connect (tcp) to SERVICE on HOST > t - non-blocking connect (tcp) to SERVICE on HOST > udp - open udp socket with target SERVICE on HOST > unix - connect to unix socket on address SERVICE > > If HOST is nil - open a server socket: > > nil - open tcp socket listning on SERVICE port > t - same as nil > udp - open udp socket bound to SERVICE port > unix - open unix socket bound to address SERVICE Isn't this quite limiting? What comes into mind first is that binding a server socket to a specific interface is not possible then. Also, as I discussed privately with Helmut, it should be possible to specify either 0 or nil (not sure) for the PORT to be able to assign a arbitrary free port (dynamic server socket for e.g. DCC). I didn't look very closely at both approaches yet, but it seems to me from first impression that merging non-blocking connects and server sockets into one single function is quite messy. -- CYa, Mario <mlang@delysid.org> _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: Non-blocking open-network-stream 2002-03-02 7:59 ` Helmut Eller 2002-03-03 0:12 ` Kim F. Storm @ 2002-03-03 14:39 ` Richard Stallman 1 sibling, 0 replies; 17+ messages in thread From: Richard Stallman @ 2002-03-03 14:39 UTC (permalink / raw) Cc: storm, emacs-devel Server sockets are IMHO different enough to merit a separate function. What is the advantage of merging those concepts? A priori it is a simplification to merge them. But if merging them is painful in the details, then we are better off not merging them. _______________________________________________ Emacs-devel mailing list Emacs-devel@gnu.org http://mail.gnu.org/mailman/listinfo/emacs-devel ^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2002-03-03 16:44 UTC | newest] Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2002-02-27 17:49 Non-blocking open-network-stream Helmut Eller [not found] <m2u1sa7819.fsf@xaital.online-marketwatch.com> 2002-02-21 23:45 ` Kim F. Storm 2002-02-22 16:04 ` Stefan Monnier 2002-02-25 22:38 ` Kim F. Storm 2002-02-26 22:46 ` Helmut Eller 2002-02-27 11:59 ` Kim F. Storm 2002-02-28 4:08 ` Richard Stallman 2002-03-01 0:21 ` Kim F. Storm 2002-03-01 8:01 ` Juanma Barranquero 2002-03-01 10:50 ` Kim F. Storm 2002-03-01 17:10 ` Pavel Janík 2002-03-01 21:23 ` Richard Stallman 2002-03-02 7:59 ` Helmut Eller 2002-03-03 0:12 ` Kim F. Storm 2002-03-03 10:46 ` Helmut Eller 2002-03-03 16:44 ` Mario Lang 2002-03-03 14:39 ` Richard Stallman
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).