aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJuanma Barranquero2006-10-30 23:24:18 +0000
committerJuanma Barranquero2006-10-30 23:24:18 +0000
commit337e3c70f820aae9e34fccef009cfaaec7bd3cb2 (patch)
tree506f3c0423d3702cffc06f56ea713211e5ad9e27
parent41c98a5ec03967dfb58dd7a3864bbf387745cd29 (diff)
downloademacs-337e3c70f820aae9e34fccef009cfaaec7bd3cb2.tar.gz
emacs-337e3c70f820aae9e34fccef009cfaaec7bd3cb2.zip
Add support for TCP sockets.
(server-use-tcp, server-host, server-auth-dir): New options. (server-auth-key): New variable. (server-ensure-safe-dir): Create nonexistent parent dirs. Ignore Unix-style file modes on Windows. (server-start): Crete a TCP or Unix socket according to the value of `server-use-tcp'. For TCP sockets, create the id/auth file in `server-auth-dir' directory. (server-process-filter): Delete process if authentication fails (which never happens for Unix sockets).
-rw-r--r--lisp/ChangeLog13
-rw-r--r--lisp/server.el209
2 files changed, 154 insertions, 68 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index c1902d0a1a4..38a904eee9c 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,16 @@
12006-10-31 Juanma Barranquero <lekktu@gmail.com>
2
3 * server.el: Add support for TCP sockets.
4 (server-use-tcp, server-host, server-auth-dir): New options.
5 (server-auth-key): New variable.
6 (server-ensure-safe-dir): Create nonexistent parent dirs. Ignore
7 Unix-style file modes on Windows.
8 (server-start): Crete a TCP or Unix socket according to the value
9 of `server-use-tcp'. For TCP sockets, create the id/auth file in
10 `server-auth-dir' directory.
11 (server-process-filter): Delete process if authentication
12 fails (which never happens for Unix sockets).
13
12006-10-30 David Kastrup <dak@gnu.org> 142006-10-30 David Kastrup <dak@gnu.org>
2 15
3 * subr.el (add-to-list): Don't continue checking if a match has 16 * subr.el (add-to-list): Don't continue checking if a match has
diff --git a/lisp/server.el b/lisp/server.el
index 4b770b2caeb..c5abf38c2b9 100644
--- a/lisp/server.el
+++ b/lisp/server.el
@@ -82,6 +82,40 @@
82 "Emacs running as a server process." 82 "Emacs running as a server process."
83 :group 'external) 83 :group 'external)
84 84
85(defcustom server-use-tcp nil
86 "If non-nil, use TCP sockets instead of local sockets."
87 :set #'(lambda (sym val)
88 (unless (featurep 'make-network-process '(:family local))
89 (setq val t)
90 (unless load-in-progress
91 (message "Local sockets unsupported, using TCP sockets")))
92 (when val (random t))
93 (set-default sym val))
94 :group 'server
95 :type 'boolean
96 :version "22.1")
97
98(defcustom server-host nil
99 "The name or IP address to use as host address of the server process.
100If set, the server accepts remote connections; otherwise it is local."
101 :group 'server
102 :type '(choice
103 (string :tag "Name or IP address")
104 (const :tag "Local" nil))
105 :version "22.1")
106(put 'server-host 'risky-local-variable t)
107
108(defcustom server-auth-dir "~/.emacs.d/server/"
109 "Directory for server authentication files."
110 :group 'server
111 :type 'directory
112 :version "22.1")
113(put 'server-auth-dir 'risky-local-variable t)
114
115(defvar server-auth-key nil
116 "The current server authentication key.")
117(put 'server-auth-key 'risky-local-variable t)
118
85(defcustom server-visit-hook nil 119(defcustom server-visit-hook nil
86 "*Hook run when visiting a file for the Emacs server." 120 "*Hook run when visiting a file for the Emacs server."
87 :group 'server 121 :group 'server
@@ -166,13 +200,13 @@ are done with it in the server.")
166 200
167(defun server-log (string &optional client) 201(defun server-log (string &optional client)
168 "If a *server* buffer exists, write STRING to it for logging purposes." 202 "If a *server* buffer exists, write STRING to it for logging purposes."
169 (if (get-buffer "*server*") 203 (when (get-buffer "*server*")
170 (with-current-buffer "*server*" 204 (with-current-buffer "*server*"
171 (goto-char (point-max)) 205 (goto-char (point-max))
172 (insert (current-time-string) 206 (insert (current-time-string)
173 (if client (format " %s:" client) " ") 207 (if client (format " %s:" client) " ")
174 string) 208 string)
175 (or (bolp) (newline))))) 209 (or (bolp) (newline)))))
176 210
177(defun server-sentinel (proc msg) 211(defun server-sentinel (proc msg)
178 (let ((client (assq proc server-clients))) 212 (let ((client (assq proc server-clients)))
@@ -253,11 +287,12 @@ Creates the directory if necessary and makes sure:
253 (setq dir (directory-file-name dir)) 287 (setq dir (directory-file-name dir))
254 (let ((attrs (file-attributes dir))) 288 (let ((attrs (file-attributes dir)))
255 (unless attrs 289 (unless attrs
256 (letf (((default-file-modes) ?\700)) (make-directory dir)) 290 (letf (((default-file-modes) ?\700)) (make-directory dir t))
257 (setq attrs (file-attributes dir))) 291 (setq attrs (file-attributes dir)))
258 ;; Check that it's safe for use. 292 ;; Check that it's safe for use.
259 (unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid)) 293 (unless (and (eq t (car attrs)) (eq (nth 2 attrs) (user-uid))
260 (zerop (logand ?\077 (file-modes dir)))) 294 (or (eq system-type 'windows-nt)
295 (zerop (logand ?\077 (file-modes dir)))))
261 (error "The directory %s is unsafe" dir)))) 296 (error "The directory %s is unsafe" dir))))
262 297
263;;;###autoload 298;;;###autoload
@@ -270,13 +305,15 @@ Emacs distribution as your standard \"editor\".
270 305
271Prefix arg means just kill any existing server communications subprocess." 306Prefix arg means just kill any existing server communications subprocess."
272 (interactive "P") 307 (interactive "P")
308 (when server-process
273 ;; kill it dead! 309 ;; kill it dead!
274 (if server-process 310 (ignore-errors (delete-process server-process))
275 (condition-case () (delete-process server-process) (error nil))) 311 (ignore-errors
276 ;; Delete the socket files made by previous server invocations. 312 ;; Delete the socket or authentication files made by previous server invocations.
277 (condition-case () 313 (if (eq (process-contact server-process :family) 'local)
278 (delete-file (expand-file-name server-name server-socket-dir)) 314 (delete-file (expand-file-name server-name server-socket-dir))
279 (error nil)) 315 (setq server-auth-key nil)
316 (delete-file (expand-file-name server-name server-auth-dir)))))
280 ;; If this Emacs already had a server, clear out associated status. 317 ;; If this Emacs already had a server, clear out associated status.
281 (while server-clients 318 (while server-clients
282 (let ((buffer (nth 1 (car server-clients)))) 319 (let ((buffer (nth 1 (car server-clients))))
@@ -284,19 +321,43 @@ Prefix arg means just kill any existing server communications subprocess."
284 ;; Now any previous server is properly stopped. 321 ;; Now any previous server is properly stopped.
285 (unless leave-dead 322 (unless leave-dead
286 ;; Make sure there is a safe directory in which to place the socket. 323 ;; Make sure there is a safe directory in which to place the socket.
287 (server-ensure-safe-dir server-socket-dir) 324 (server-ensure-safe-dir (if server-use-tcp server-auth-dir server-socket-dir))
288 (if server-process 325 (when server-process
289 (server-log (message "Restarting server"))) 326 (server-log (message "Restarting server")))
290 (letf (((default-file-modes) ?\700)) 327 (letf (((default-file-modes) ?\700))
291 (setq server-process 328 (setq server-process
292 (make-network-process 329 (apply #'make-network-process
293 :name "server" :family 'local :server t :noquery t 330 :name server-name
294 :service (expand-file-name server-name server-socket-dir) 331 :server t
295 :sentinel 'server-sentinel :filter 'server-process-filter 332 :noquery t
333 :sentinel 'server-sentinel
334 :filter 'server-process-filter
296 ;; We must receive file names without being decoded. 335 ;; We must receive file names without being decoded.
297 ;; Those are decoded by server-process-filter according 336 ;; Those are decoded by server-process-filter according
298 ;; to file-name-coding-system. 337 ;; to file-name-coding-system.
299 :coding 'raw-text))))) 338 :coding 'raw-text
339 ;; The rest of the arguments depend on the kind of socket used
340 (if server-use-tcp
341 (list :family nil
342 :service t
343 :host (or server-host 'local)
344 :plist '(:authenticated nil))
345 (list :family 'local
346 :service (expand-file-name server-name server-socket-dir)
347 :plist '(:authenticated t))))))
348 (unless server-process (error "Could not start server process"))
349 (when server-use-tcp
350 (setq server-auth-key
351 (loop
352 ;; The auth key is a 64-byte string of random chars in the range `!'..`~'.
353 for i below 64
354 collect (+ 33 (random 94)) into auth
355 finally return (concat auth)))
356 (with-temp-file (expand-file-name server-name server-auth-dir)
357 (set-buffer-multibyte nil)
358 (setq buffer-file-coding-system 'no-conversion)
359 (insert (format-network-address (process-contact server-process :local))
360 "\n" server-auth-key)))))
300 361
301;;;###autoload 362;;;###autoload
302(define-minor-mode server-mode 363(define-minor-mode server-mode
@@ -311,14 +372,26 @@ Server mode runs a process that accepts commands from the
311 ;; nothing if there is one (for multiple Emacs sessions)? 372 ;; nothing if there is one (for multiple Emacs sessions)?
312 (server-start (not server-mode))) 373 (server-start (not server-mode)))
313 374
314(defun server-process-filter (proc string) 375(defun* server-process-filter (proc string)
315 "Process a request from the server to edit some files. 376 "Process a request from the server to edit some files.
316PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"." 377PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
378 ;; First things first: let's check the authentication
379 (unless (process-get proc :authenticated)
380 (if (and (string-match "-auth \\(.*?\\)\n" string)
381 (string= (match-string 1 string) server-auth-key))
382 (progn
383 (setq string (substring string (match-end 0)))
384 (process-put proc :authenticated t)
385 (server-log "Authentication successful" proc))
386 (server-log "Authentication failed" proc)
387 (delete-process proc)
388 ;; We return immediately
389 (return-from server-process-filter)))
317 (server-log string proc) 390 (server-log string proc)
318 (let ((prev (process-get proc 'previous-string))) 391 (let ((prev (process-get proc :previous-string)))
319 (when prev 392 (when prev
320 (setq string (concat prev string)) 393 (setq string (concat prev string))
321 (process-put proc 'previous-string nil))) 394 (process-put proc :previous-string nil)))
322 ;; If the input is multiple lines, 395 ;; If the input is multiple lines,
323 ;; process each line individually. 396 ;; process each line individually.
324 (while (string-match "\n" string) 397 (while (string-match "\n" string)
@@ -329,7 +402,7 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
329 client nowait eval 402 client nowait eval
330 (files nil) 403 (files nil)
331 (lineno 1) 404 (lineno 1)
332 (tmp-frame nil) ; Sometimes used to embody the selected display. 405 (tmp-frame nil) ;; Sometimes used to embody the selected display.
333 (columnno 0)) 406 (columnno 0))
334 ;; Remove this line from STRING. 407 ;; Remove this line from STRING.
335 (setq string (substring string (match-end 0))) 408 (setq string (substring string (match-end 0)))
@@ -359,8 +432,8 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
359 ;; for certain special characters. 432 ;; for certain special characters.
360 (setq arg (server-unquote-arg arg)) 433 (setq arg (server-unquote-arg arg))
361 ;; Now decode the file name if necessary. 434 ;; Now decode the file name if necessary.
362 (if coding-system 435 (when coding-system
363 (setq arg (decode-coding-string arg coding-system))) 436 (setq arg (decode-coding-string arg coding-system)))
364 (if eval 437 (if eval
365 (let* (errorp 438 (let* (errorp
366 (v (condition-case errobj 439 (v (condition-case errobj
@@ -407,13 +480,13 @@ PROC is the server process. Format of STRING is \"PATH PATH PATH... \\n\"."
407 (server-unselect-display tmp-frame)))) 480 (server-unselect-display tmp-frame))))
408 ;; Save for later any partial line that remains. 481 ;; Save for later any partial line that remains.
409 (when (> (length string) 0) 482 (when (> (length string) 0)
410 (process-put proc 'previous-string string))) 483 (process-put proc :previous-string string)))
411 484
412(defun server-goto-line-column (file-line-col) 485(defun server-goto-line-column (file-line-col)
413 (goto-line (nth 1 file-line-col)) 486 (goto-line (nth 1 file-line-col))
414 (let ((column-number (nth 2 file-line-col))) 487 (let ((column-number (nth 2 file-line-col)))
415 (if (> column-number 0) 488 (when (> column-number 0)
416 (move-to-column (1- column-number))))) 489 (move-to-column (1- column-number)))))
417 490
418(defun server-visit-files (files client &optional nowait) 491(defun server-visit-files (files client &optional nowait)
419 "Find FILES and return the list CLIENT with the buffers nconc'd. 492 "Find FILES and return the list CLIENT with the buffers nconc'd.
@@ -485,33 +558,33 @@ FOR-KILLING if non-nil indicates that we are called from `kill-buffer'."
485 (server-log "Close" (car client)) 558 (server-log "Close" (car client))
486 (setq server-clients (delq client server-clients)))) 559 (setq server-clients (delq client server-clients))))
487 (setq old-clients (cdr old-clients))) 560 (setq old-clients (cdr old-clients)))
488 (if (and (bufferp buffer) (buffer-name buffer)) 561 (when (and (bufferp buffer) (buffer-name buffer))
489 ;; We may or may not kill this buffer; 562 ;; We may or may not kill this buffer;
490 ;; if we do, do not call server-buffer-done recursively 563 ;; if we do, do not call server-buffer-done recursively
491 ;; from kill-buffer-hook. 564 ;; from kill-buffer-hook.
492 (let ((server-kill-buffer-running t)) 565 (let ((server-kill-buffer-running t))
493 (with-current-buffer buffer 566 (with-current-buffer buffer
494 (setq server-buffer-clients nil) 567 (setq server-buffer-clients nil)
495 (run-hooks 'server-done-hook)) 568 (run-hooks 'server-done-hook))
496 ;; Notice whether server-done-hook killed the buffer. 569 ;; Notice whether server-done-hook killed the buffer.
497 (if (null (buffer-name buffer)) 570 (if (null (buffer-name buffer))
571 (setq killed t)
572 ;; Don't bother killing or burying the buffer
573 ;; when we are called from kill-buffer.
574 (unless for-killing
575 (when (and (not killed)
576 server-kill-new-buffers
577 (with-current-buffer buffer
578 (not server-existing-buffer)))
498 (setq killed t) 579 (setq killed t)
499 ;; Don't bother killing or burying the buffer 580 (bury-buffer buffer)
500 ;; when we are called from kill-buffer. 581 (kill-buffer buffer))
501 (unless for-killing 582 (unless killed
502 (when (and (not killed) 583 (if (server-temp-file-p buffer)
503 server-kill-new-buffers 584 (progn
504 (with-current-buffer buffer 585 (kill-buffer buffer)
505 (not server-existing-buffer))) 586 (setq killed t))
506 (setq killed t) 587 (bury-buffer buffer)))))))
507 (bury-buffer buffer)
508 (kill-buffer buffer))
509 (unless killed
510 (if (server-temp-file-p buffer)
511 (progn
512 (kill-buffer buffer)
513 (setq killed t))
514 (bury-buffer buffer)))))))
515 (list next-buffer killed))) 588 (list next-buffer killed)))
516 589
517(defun server-temp-file-p (&optional buffer) 590(defun server-temp-file-p (&optional buffer)
@@ -538,10 +611,10 @@ specifically for the clients and did not exist before their request for it."
538 (let ((version-control nil) 611 (let ((version-control nil)
539 (buffer-backed-up nil)) 612 (buffer-backed-up nil))
540 (save-buffer)) 613 (save-buffer))
541 (if (and (buffer-modified-p) 614 (when (and (buffer-modified-p)
542 buffer-file-name 615 buffer-file-name
543 (y-or-n-p (concat "Save file " buffer-file-name "? "))) 616 (y-or-n-p (concat "Save file " buffer-file-name "? ")))
544 (save-buffer))) 617 (save-buffer)))
545 (server-buffer-done (current-buffer)))) 618 (server-buffer-done (current-buffer))))
546 619
547;; Ask before killing a server buffer. 620;; Ask before killing a server buffer.
@@ -561,8 +634,8 @@ specifically for the clients and did not exist before their request for it."
561 (tail server-clients)) 634 (tail server-clients))
562 ;; See if any clients have any buffers that are still alive. 635 ;; See if any clients have any buffers that are still alive.
563 (while tail 636 (while tail
564 (if (memq t (mapcar 'stringp (mapcar 'buffer-name (cdr (car tail))))) 637 (when (memq t (mapcar 'stringp (mapcar 'buffer-name (cdr (car tail)))))
565 (setq live-client t)) 638 (setq live-client t))
566 (setq tail (cdr tail))) 639 (setq tail (cdr tail)))
567 (or (not live-client) 640 (or (not live-client)
568 (yes-or-no-p "Server buffers still have clients; exit anyway? ")))) 641 (yes-or-no-p "Server buffers still have clients; exit anyway? "))))
@@ -628,8 +701,8 @@ Arg NEXT-BUFFER is a suggestion; if it is a live buffer, use it."
628 (if (and win (not server-window)) 701 (if (and win (not server-window))
629 ;; The buffer is already displayed: just reuse the window. 702 ;; The buffer is already displayed: just reuse the window.
630 (let ((frame (window-frame win))) 703 (let ((frame (window-frame win)))
631 (if (eq (frame-visible-p frame) 'icon) 704 (when (eq (frame-visible-p frame) 'icon)
632 (raise-frame frame)) 705 (raise-frame frame))
633 (select-window win) 706 (select-window win)
634 (set-buffer next-buffer)) 707 (set-buffer next-buffer))
635 ;; Otherwise, let's find an appropriate window. 708 ;; Otherwise, let's find an appropriate window.
@@ -637,11 +710,11 @@ Arg NEXT-BUFFER is a suggestion; if it is a live buffer, use it."
637 (window-live-p server-window)) 710 (window-live-p server-window))
638 (select-window server-window)) 711 (select-window server-window))
639 ((framep server-window) 712 ((framep server-window)
640 (if (not (frame-live-p server-window)) 713 (unless (frame-live-p server-window)
641 (setq server-window (make-frame))) 714 (setq server-window (make-frame)))
642 (select-window (frame-selected-window server-window)))) 715 (select-window (frame-selected-window server-window))))
643 (if (window-minibuffer-p (selected-window)) 716 (when (window-minibuffer-p (selected-window))
644 (select-window (next-window nil 'nomini 0))) 717 (select-window (next-window nil 'nomini 0)))
645 ;; Move to a non-dedicated window, if we have one. 718 ;; Move to a non-dedicated window, if we have one.
646 (when (window-dedicated-p (selected-window)) 719 (when (window-dedicated-p (selected-window))
647 (select-window 720 (select-window