Mercurial > hg > xemacs-beta
comparison lib-src/gnuslib.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | 8de8e3f6228a |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* -*-C-*- | |
2 Common library code for the GNU Emacs server and client. | |
3 | |
4 This file is part of GNU Emacs. | |
5 | |
6 Copying is permitted under those conditions described by the GNU | |
7 General Public License. | |
8 | |
9 Copyright (C) 1989 Free Software Foundation, Inc. | |
10 | |
11 Author: Andy Norman (ange@hplb.hpl.hp.com), based on | |
12 'etc/server.c' and 'etc/emacsclient.c' from the 18.52 GNU | |
13 Emacs distribution. | |
14 | |
15 Please mail bugs and suggestions to the author at the above address. | |
16 */ | |
17 | |
18 /* HISTORY | |
19 * 11-Nov-1990 bristor@simba | |
20 * Added EOT stuff. | |
21 */ | |
22 | |
23 /* | |
24 * This file incorporates new features added by Bob Weiner <weiner@mot.com>, | |
25 * Darrell Kindred <dkindred@cmu.edu> and Arup Mukherjee <arup@cmu.edu>. | |
26 * Please see the note at the end of the README file for details. | |
27 * | |
28 * (If gnuserv came bundled with your emacs, the README file is probably | |
29 * ../etc/gnuserv.README relative to the directory containing this file) | |
30 */ | |
31 | |
32 #if 0 | |
33 static char rcsid [] = "!Header: gnuslib.c,v 2.4 95/02/16 11:57:37 arup alpha !"; | |
34 #endif | |
35 | |
36 #include "gnuserv.h" | |
37 #include <errno.h> | |
38 | |
39 #ifdef SYSV_IPC | |
40 static int connect_to_ipc_server (void); | |
41 #endif | |
42 #ifdef UNIX_DOMAIN_SOCKETS | |
43 static int connect_to_unix_server (void); | |
44 #endif | |
45 #ifdef INTERNET_DOMAIN_SOCKETS | |
46 static int connect_to_internet_server (char *serverhost, u_short port); | |
47 #endif | |
48 | |
49 /* On some systems, e.g. DGUX, inet_addr returns a 'struct in_addr'. */ | |
50 #ifdef HAVE_BROKEN_INET_ADDR | |
51 # define IN_ADDR struct in_addr | |
52 # define NUMERIC_ADDR_ERROR (numeric_addr.s_addr == -1) | |
53 #else | |
54 # if (LONGBITS > 32) | |
55 # define IN_ADDR unsigned int | |
56 # else | |
57 # define IN_ADDR unsigned long | |
58 # endif | |
59 # define NUMERIC_ADDR_ERROR (numeric_addr == (IN_ADDR) -1) | |
60 #endif | |
61 | |
62 #include <stdlib.h> | |
63 #include <stdio.h> | |
64 #include <sys/types.h> | |
65 #include <sys/stat.h> | |
66 #ifdef HAVE_UNISTD_H | |
67 #include <unistd.h> | |
68 #endif /* HAVE_UNISTD_H */ | |
69 #ifdef HAVE_STRING_H | |
70 #include <string.h> | |
71 #endif /* HAVE_STRING_H */ | |
72 | |
73 #include <arpa/inet.h> | |
74 | |
75 char *tmpdir = NULL; | |
76 | |
77 char *progname = NULL; | |
78 | |
79 int make_connection(hostarg, portarg, s) | |
80 char *hostarg; | |
81 int portarg; | |
82 int *s; | |
83 { | |
84 #ifdef INTERNET_DOMAIN_SOCKETS | |
85 char *ptr; | |
86 if (hostarg == NULL) | |
87 hostarg = getenv("GNU_HOST"); | |
88 if (portarg == 0 && (ptr=getenv("GNU_PORT")) != NULL) | |
89 portarg = atoi(ptr); | |
90 #endif | |
91 | |
92 if (hostarg != NULL) { | |
93 /* hostname was given explicitly, via cmd line arg or GNU_HOST, | |
94 * so obey it. */ | |
95 #ifdef UNIX_DOMAIN_SOCKETS | |
96 if (!strcmp(hostarg, "unix")) { | |
97 *s = connect_to_unix_server(); | |
98 return (int) CONN_UNIX; | |
99 } | |
100 #endif /* UNIX_DOMAIN_SOCKETS */ | |
101 #ifdef INTERNET_DOMAIN_SOCKETS | |
102 *s = connect_to_internet_server(hostarg, portarg); | |
103 return (int) CONN_INTERNET; | |
104 #endif | |
105 #ifdef SYSV_IPC | |
106 return -1; /* hostarg should always be NULL for SYSV_IPC */ | |
107 #endif | |
108 } else { | |
109 /* no hostname given. Use unix-domain/sysv-ipc, or | |
110 * internet-domain connection to local host if they're not available. */ | |
111 #if defined(UNIX_DOMAIN_SOCKETS) | |
112 *s = connect_to_unix_server(); | |
113 return (int) CONN_UNIX; | |
114 #elif defined(SYSV_IPC) | |
115 *s = connect_to_ipc_server(); | |
116 return (int) CONN_IPC; | |
117 #elif defined(INTERNET_DOMAIN_SOCKETS) | |
118 { | |
119 char localhost[HOSTNAMSZ]; | |
120 gethostname(localhost,HOSTNAMSZ); /* use this host by default */ | |
121 *s = connect_to_internet_server(localhost, portarg); | |
122 return (int) CONN_INTERNET; | |
123 } | |
124 #endif /* IPC type */ | |
125 } | |
126 } | |
127 | |
128 #ifdef SYSV_IPC | |
129 /* | |
130 connect_to_ipc_server -- establish connection with server process via SYSV IPC | |
131 Returns msqid for server if successful. | |
132 */ | |
133 static int connect_to_ipc_server (void) | |
134 { | |
135 int s; /* connected msqid */ | |
136 key_t key; /* message key */ | |
137 char buf[GSERV_BUFSZ+1]; /* buffer for filename */ | |
138 | |
139 sprintf(buf,"%s/gsrv%d",tmpdir,(int)geteuid()); | |
140 creat(buf,0600); | |
141 if ((key = ftok(buf,1)) == -1) { | |
142 perror(progname); | |
143 fprintf(stderr, "%s: unable to get ipc key from %s\n", | |
144 progname, buf); | |
145 exit(1); | |
146 } | |
147 | |
148 if ((s = msgget(key,0600)) == -1) { | |
149 perror(progname); | |
150 fprintf(stderr,"%s: unable to access msg queue\n",progname); | |
151 exit(1); | |
152 }; /* if */ | |
153 | |
154 return(s); | |
155 | |
156 } /* connect_to_ipc_server */ | |
157 | |
158 | |
159 /* | |
160 disconnect_from_ipc_server -- inform the server that sending has finished, | |
161 and wait for its reply. | |
162 */ | |
163 void disconnect_from_ipc_server(s,msgp,echo) | |
164 int s; | |
165 struct msgbuf *msgp; | |
166 int echo; | |
167 { | |
168 int len; /* length of received message */ | |
169 | |
170 send_string(s,EOT_STR); /* EOT terminates this message */ | |
171 msgp->mtype = 1; | |
172 | |
173 if(msgsnd(s,msgp,strlen(msgp->mtext)+1,0) < 0) { | |
174 perror(progname); | |
175 fprintf(stderr,"%s: unable to send message to server\n",progname); | |
176 exit(1); | |
177 }; /* if */ | |
178 | |
179 if((len = msgrcv(s,msgp,GSERV_BUFSZ,getpid(),0)) < 0) { | |
180 perror(progname); | |
181 fprintf(stderr,"%s: unable to receive message from server\n",progname); | |
182 exit(1); | |
183 }; /* if */ | |
184 | |
185 if (echo) { | |
186 msgp->mtext[len] = '\0'; /* string terminate message */ | |
187 fputs(msgp->mtext, stdout); | |
188 if (msgp->mtext[len-1] != '\n') putchar ('\n'); | |
189 }; /* if */ | |
190 | |
191 } /* disconnect_from_ipc_server */ | |
192 #endif /* SYSV_IPC */ | |
193 | |
194 | |
195 #if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS) | |
196 /* | |
197 send_string -- send string to socket. | |
198 */ | |
199 void send_string(s,msg) | |
200 int s; | |
201 CONST char *msg; | |
202 { | |
203 #if 0 | |
204 if (send(s,msg,strlen(msg),0) < 0) { | |
205 perror(progname); | |
206 fprintf(stderr,"%s: unable to send\n",progname); | |
207 exit(1); | |
208 }; /* if */ | |
209 #else | |
210 int len, left=strlen(msg); | |
211 while (left > 0) { | |
212 if ((len=write(s,msg,min2(left,GSERV_BUFSZ))) < 0) { | |
213 /* XEmacs addition: robertl@arnet.com */ | |
214 if (errno == EPIPE) { | |
215 return ; | |
216 } | |
217 perror(progname); | |
218 fprintf(stderr,"%s: unable to send\n",progname); | |
219 exit(1); | |
220 }; /* if */ | |
221 left -= len; | |
222 msg += len; | |
223 }; /* while */ | |
224 #endif | |
225 } /* send_string */ | |
226 | |
227 /* | |
228 read_line -- read a \n terminated line from a socket | |
229 */ | |
230 int read_line(int s, char *dest) | |
231 { | |
232 int length; | |
233 int offset=0; | |
234 char buffer[GSERV_BUFSZ+1]; | |
235 | |
236 while ((length=read(s,buffer+offset,1)>0) && buffer[offset]!='\n' | |
237 && buffer[offset] != EOT_CHR) { | |
238 offset += length; | |
239 if (offset >= GSERV_BUFSZ) | |
240 break; | |
241 } | |
242 buffer[offset] = '\0'; | |
243 strcpy(dest,buffer); | |
244 return 1; | |
245 } /* read_line */ | |
246 #endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */ | |
247 | |
248 | |
249 #ifdef UNIX_DOMAIN_SOCKETS | |
250 /* | |
251 connect_to_unix_server -- establish connection with server process via a unix- | |
252 domain socket. Returns socket descriptor for server | |
253 if successful. | |
254 */ | |
255 static int connect_to_unix_server (void) | |
256 { | |
257 int s; /* connected socket descriptor */ | |
258 struct sockaddr_un server; /* for unix connections */ | |
259 | |
260 if ((s = socket(AF_UNIX,SOCK_STREAM,0)) < 0) { | |
261 perror(progname); | |
262 fprintf(stderr,"%s: unable to create socket\n",progname); | |
263 exit(1); | |
264 }; /* if */ | |
265 | |
266 server.sun_family = AF_UNIX; | |
267 #ifdef HIDE_UNIX_SOCKET | |
268 sprintf(server.sun_path,"%s/gsrvdir%d/gsrv",tmpdir,(int)geteuid()); | |
269 #else /* HIDE_UNIX_SOCKET */ | |
270 sprintf(server.sun_path,"%s/gsrv%d",tmpdir,(int)geteuid()); | |
271 #endif /* HIDE_UNIX_SOCKET */ | |
272 if (connect(s,(struct sockaddr *)&server,strlen(server.sun_path)+2) < 0) { | |
273 perror(progname); | |
274 fprintf(stderr,"%s: unable to connect to local\n",progname); | |
275 exit(1); | |
276 }; /* if */ | |
277 | |
278 return(s); | |
279 | |
280 } /* connect_to_unix_server */ | |
281 #endif /* UNIX_DOMAIN_SOCKETS */ | |
282 | |
283 | |
284 #ifdef INTERNET_DOMAIN_SOCKETS | |
285 /* | |
286 internet_addr -- return the internet addr of the hostname or | |
287 internet address passed. Return -1 on error. | |
288 */ | |
289 int internet_addr(host) | |
290 char *host; | |
291 { | |
292 struct hostent *hp; /* pointer to host info for remote host */ | |
293 IN_ADDR numeric_addr; /* host address */ | |
294 | |
295 numeric_addr = inet_addr(host); | |
296 if (!NUMERIC_ADDR_ERROR) | |
297 return numeric_addr; | |
298 else if ((hp = gethostbyname(host)) != NULL) | |
299 return ((struct in_addr *)(hp->h_addr))->s_addr; | |
300 else | |
301 return -1; | |
302 | |
303 } /* internet_addr */ | |
304 | |
305 #ifdef AUTH_MAGIC_COOKIE | |
306 # include <X11/X.h> | |
307 # include <X11/Xauth.h> | |
308 | |
309 static Xauth *server_xauth = NULL; | |
310 #endif | |
311 | |
312 /* | |
313 connect_to_internet_server -- establish connection with server process via | |
314 an internet domain socket. Returns socket | |
315 descriptor for server if successful. | |
316 */ | |
317 static int connect_to_internet_server (char *serverhost, u_short port) | |
318 { | |
319 int s; /* connected socket descriptor */ | |
320 struct servent *sp; /* pointer to service information */ | |
321 struct sockaddr_in peeraddr_in; /* for peer socket address */ | |
322 char buf[512]; /* temporary buffer */ | |
323 | |
324 /* clear out address structures */ | |
325 memset((char *)&peeraddr_in,0,sizeof(struct sockaddr_in)); | |
326 | |
327 /* Set up the peer address to which we will connect. */ | |
328 peeraddr_in.sin_family = AF_INET; | |
329 | |
330 /* look up the server host's internet address */ | |
331 if ((peeraddr_in.sin_addr.s_addr = internet_addr(serverhost)) == -1) { | |
332 fprintf(stderr,"%s: unable to find %s in /etc/hosts or from YP\n", | |
333 progname,serverhost); | |
334 exit(1); | |
335 }; /* if */ | |
336 | |
337 if (port == 0) { | |
338 if ((sp = getservbyname ("gnuserv","tcp")) == NULL) | |
339 peeraddr_in.sin_port = htons(DEFAULT_PORT+getuid()); | |
340 else | |
341 peeraddr_in.sin_port = sp->s_port; | |
342 } /* if */ | |
343 else | |
344 peeraddr_in.sin_port = htons(port); | |
345 | |
346 /* Create the socket. */ | |
347 if ((s = socket (AF_INET,SOCK_STREAM, 0))== -1) { | |
348 perror(progname); | |
349 fprintf(stderr,"%s: unable to create socket\n",progname); | |
350 exit(1); | |
351 }; /* if */ | |
352 | |
353 /* Try to connect to the remote server at the address | |
354 * which was just built into peeraddr. | |
355 */ | |
356 if (connect(s, (struct sockaddr *)&peeraddr_in, | |
357 sizeof(struct sockaddr_in)) == -1) { | |
358 perror(progname); | |
359 fprintf(stderr, "%s: unable to connect to remote\n",progname); | |
360 exit(1); | |
361 }; /* if */ | |
362 | |
363 #ifdef AUTH_MAGIC_COOKIE | |
364 | |
365 /* send credentials using MIT-MAGIC-COOKIE-1 protocol */ | |
366 | |
367 server_xauth = | |
368 XauGetAuthByAddr(FamilyInternet, | |
369 sizeof(peeraddr_in.sin_addr.s_addr), | |
370 (char *) &peeraddr_in.sin_addr.s_addr, | |
371 strlen(MCOOKIE_SCREEN), MCOOKIE_SCREEN, | |
372 strlen(MCOOKIE_X_NAME), MCOOKIE_X_NAME); | |
373 | |
374 if (server_xauth && server_xauth->data) { | |
375 sprintf(buf, "%s\n%d\n", MCOOKIE_NAME, server_xauth->data_length); | |
376 write (s, buf, strlen(buf)); | |
377 write (s, server_xauth->data, server_xauth->data_length); | |
378 | |
379 return (s); | |
380 } | |
381 | |
382 #endif /* AUTH_MAGIC_COOKIE */ | |
383 | |
384 sprintf (buf, "%s\n", DEFAUTH_NAME); | |
385 write (s, buf, strlen(buf)); | |
386 | |
387 return(s); | |
388 | |
389 } /* connect_to_internet_server */ | |
390 #endif /* INTERNET_DOMAIN_SOCKETS */ | |
391 | |
392 | |
393 #if defined(INTERNET_DOMAIN_SOCKETS) || defined(UNIX_DOMAIN_SOCKETS) | |
394 /* | |
395 disconnect_from_server -- inform the server that sending has finished, and wait for | |
396 its reply. | |
397 */ | |
398 void disconnect_from_server(s,echo) | |
399 int s; | |
400 int echo; | |
401 { | |
402 #if 0 | |
403 char buffer[REPLYSIZ+1]; | |
404 #else | |
405 char buffer[GSERV_BUFSZ+1]; | |
406 #endif | |
407 int add_newline = 1; | |
408 int length; | |
409 | |
410 send_string(s,EOT_STR); /* make sure server gets string */ | |
411 | |
412 #if !defined (linux) && !defined (_SCO_DS) | |
413 /* | |
414 * shutdown is completely hozed under linux. If s is a unix domain socket, | |
415 * you'll get EOPNOTSUPP back from it. If s is an internet socket, you get | |
416 * a broken pipe when you try to read a bit later. The latter | |
417 * problem is fixed for linux versions >= 1.1.46, but the problem | |
418 * with unix sockets persists. Sigh. | |
419 */ | |
420 | |
421 if (shutdown(s,1) == -1) { | |
422 perror(progname); | |
423 fprintf(stderr, "%s: unable to shutdown socket\n",progname); | |
424 exit(1); | |
425 }; /* if */ | |
426 #endif | |
427 | |
428 #if 0 | |
429 while((length = recv(s,buffer,REPLYSIZ,0)) > 0) { | |
430 buffer[length] = '\0'; | |
431 if (echo) fputs(buffer,stdout); | |
432 add_newline = (buffer[length-1] != '\n'); | |
433 }; /* while */ | |
434 #else | |
435 while ((length = read(s,buffer,GSERV_BUFSZ)) > 0 || | |
436 (length == -1 && errno == EINTR)) { | |
437 if (length) { | |
438 buffer[length] = '\0'; | |
439 if (echo) { | |
440 fputs(buffer,stdout); | |
441 add_newline = (buffer[length-1] != '\n'); | |
442 }; /* if */ | |
443 }; /* if */ | |
444 }; /* while */ | |
445 #endif | |
446 | |
447 if (echo && add_newline) putchar('\n'); | |
448 | |
449 if(length < 0) { | |
450 perror(progname); | |
451 fprintf(stderr,"%s: unable to read the reply from the server\n",progname); | |
452 exit(1); | |
453 }; /* if */ | |
454 | |
455 } /* disconnect_from_server */ | |
456 #endif /* INTERNET_DOMAIN_SOCKETS || UNIX_DOMAIN_SOCKETS */ |