home *** CD-ROM | disk | FTP | other *** search
- /* unix_server.c -- client/server file handling
- Copyright (C) 1994 John Harper <jsh@ukc.ac.uk>
-
- This file is part of Jade.
-
- Jade is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
-
- Jade is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with Jade; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "jade.h"
- #include "jade_protos.h"
-
- #include <fcntl.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/socket.h>
- #include <sys/un.h>
-
- _PR void server_init(void);
- _PR void server_kill(void);
-
- #define JADE_SOCK_NAME "~/.Jade_rendezvous"
-
- /* List of (FILE-NAME . SOCK-FD) */
- static VALUE client_list;
-
- static VALUE sym_server_open_file;
-
- /* fd of the socket which clients connect to, or zero. */
- static int socket_fd = -1;
-
- /* pathname of the socket. */
- static VALUE socket_name;
-
- static void
- server_accept_connection(int unused_fd)
- {
- int confd = accept(socket_fd, NULL, NULL);
- if(confd >= 0)
- {
- /* 1. read length field
- 2. read LENGTH bytes for the filename
- 3. read the line number
- 4. add (FILE . SOCK-FD) to list of client files
- 5. call client-open-file with FILE and LINE */
- u_short filenamelen;
- u_long tmp;
- VALUE filename, linenum;
- if(read(confd, &filenamelen, sizeof(u_short)) != sizeof(u_short))
- goto readerror;
- filename = make_string(filenamelen + 1);
- if(read(confd, VSTR(filename), filenamelen) != filenamelen)
- goto readerror;
- VSTR(filename)[filenamelen] = 0;
- if(read(confd, &tmp, sizeof(u_long)) != sizeof(u_long))
- {
- readerror:
- cmd_signal(sym_error,
- LIST_1(MKSTR("server_make_connection:read")));
- return;
- }
- linenum = make_number(tmp - 1);
- client_list = cmd_cons(cmd_cons(filename, make_number(confd)),
- client_list);
- /* lose this on exec() */
- fcntl(confd, F_SETFD, 1);
- cursor(curr_vw, CURS_OFF);
- call_lisp2(sym_server_open_file, filename, linenum);
- cursor(curr_vw, CURS_ON);
- }
- }
-
- _PR VALUE cmd_server_open_p(void);
- DEFUN("server-open-p", cmd_server_open_p, subr_server_open_p, (void), V_Subr0, DOC_server_open_p) /*
- ::doc:server_open_p::
- server-open-p
-
- t if the edit-server is open.
- ::end:: */
- {
- if(socket_fd >= 0)
- return(sym_t);
- return(sym_nil);
- }
-
- _PR VALUE cmd_server_open(void);
- DEFUN_INT("server-open", cmd_server_open, subr_server_open, (void), V_Subr0, DOC_server_open, "") /*
- ::doc:server_open::
- server-open
-
- Creates the socket (or whatever) so that the editor's client program can
- send us messages.
- ::end:: */
- {
- VALUE name;
- if(socket_fd >= 0)
- return(sym_t);
- name = cmd_expand_file_name(MKSTR(JADE_SOCK_NAME), sym_nil);
- if(name && STRINGP(name))
- {
- VALUE tmp = cmd_file_exists_p(name);
- if(!tmp || !NILP(tmp))
- {
- message("A server is already open.");
- return(sym_nil);
- }
- socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
- if(socket_fd >= 0)
- {
- struct sockaddr_un addr;
- addr.sun_family = AF_UNIX;
- strcpy(addr.sun_path, VSTR(name));
- if(bind(socket_fd, (struct sockaddr *)&addr,
- sizeof(addr.sun_family) + strlen(addr.sun_path)) == 0)
- {
- if(listen(socket_fd, 5) == 0)
- {
- /* lose this on exec() */
- fcntl(socket_fd, F_SETFD, 1);
- fcntl(socket_fd, F_SETFL, O_NONBLOCK);
- #ifdef HAVE_X11
- /* for the x11 eventloop */
- x11_fd_read_action[socket_fd] = server_accept_connection;
- FD_SET(socket_fd, &x11_fd_read_set);
- #endif
- socket_name = name;
- return(sym_t);
- }
- else
- signal_file_error(MKSTR("bind()"));
- }
- else
- signal_file_error(MKSTR("listen()"));
- }
- else
- cmd_signal(sym_error, LIST_1(MKSTR("Can't make socket name")));
- close(socket_fd);
- socket_fd = -1;
- }
- else
- signal_file_error(MKSTR("socket()"));
- return(NULL);
- }
-
- _PR VALUE cmd_server_close(void);
- DEFUN_INT("server-close", cmd_server_close, subr_server_close, (void), V_Subr0, DOC_server_close, "") /*
- ::doc:server_close::
- server-close
-
- Stops listening for client messages.
- ::end:: */
- {
- if(socket_fd > 0)
- {
- #ifdef HAVE_X11
- x11_fd_read_action[socket_fd] = NULL;
- FD_CLR(socket_fd, &x11_fd_read_set);
- #endif
- close(socket_fd);
- socket_fd = -1;
- unlink(VSTR(socket_name));
- socket_name = NULL;
- }
- return(sym_t);
- }
-
- _PR VALUE cmd_server_reply(VALUE file, VALUE rc);
- DEFUN("server-reply", cmd_server_reply, subr_server_reply, (VALUE file, VALUE rc), V_Subr2, DOC_server_reply) /*
- ::doc:server_reply::
- server-reply [FILE-NAME] [RETURN-CODE]
-
- Replies to the editor client which asked us to edit the file FILE-NAME.
- RETURN-CODE is the optional result for the client, by default it is zero
- which denotes no errors. Returns nil if the file doesn't have a client.
- ::end:: */
- {
- VALUE res = sym_nil;
- VALUE tmp = client_list;
- if(BUFFERP(file))
- file = VTX(file)->tx_FileName;
- else if(!STRINGP(file))
- file = curr_vw->vw_Tx->tx_FileName;
- client_list = sym_nil;
- while(CONSP(tmp))
- {
- register VALUE car = VCAR(tmp);
- VALUE next = VCDR(tmp);
- if(!VALUE_CMP(file, VCAR(car)))
- {
- /* Send the result to our client. */
- int con_fd = VNUM(VCDR(car));
- u_long result = NUMBERP(rc) ? VNUM(rc) : 0;
- if(write(con_fd, &result, sizeof(result)) != sizeof(result))
- res = signal_file_error(file);
- else
- res = sym_t;
- close(con_fd);
- }
- else
- {
- VCDR(tmp) = client_list;
- client_list = tmp;
- }
- tmp = next;
- }
- return(res);
- }
-
- void
- server_init(void)
- {
- client_list = sym_nil;
- mark_static(&client_list);
- mark_static(&socket_name);
- INTERN(sym_server_open_file, "server-open-file");
- ADD_SUBR(subr_server_open_p);
- ADD_SUBR(subr_server_open);
- ADD_SUBR(subr_server_close);
- ADD_SUBR(subr_server_reply);
- }
-
- void
- server_kill(void)
- {
- /* clean up */
- VALUE tmp = client_list;
- while(CONSP(tmp))
- {
- /* Any client-opened files still around are replied to with
- a result of 5 (fail). */
- static u_long failrc = 5;
- int fd = VNUM(VCDR(VCAR(tmp)));
- write(fd, &failrc, sizeof(u_long));
- close(fd);
- tmp = VCDR(tmp);
- }
- client_list = sym_nil;
- cmd_server_close();
- }
-