Update to rev 231 of libassuan.
[gpgme.git] / assuan / assuan-pipe-server.c
1 /* assuan-pipe-server.c - Assuan server working over a pipe 
2  *      Copyright (C) 2001, 2002 Free Software Foundation, Inc.
3  *
4  * This file is part of Assuan.
5  *
6  * Assuan is free software; you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Assuan is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
19  * USA. 
20  */
21
22 #include <config.h>
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #ifdef HAVE_W32_SYSTEM
29 #include <windows.h>
30 #include <fcntl.h>
31 #endif
32
33 #include "assuan-defs.h"
34
35
36 static void
37 deinit_pipe_server (assuan_context_t ctx)
38 {
39   /* nothing to do for this simple server */
40 }
41
42 static int
43 accept_connection (assuan_context_t ctx)
44 {
45   /* This is a NOP for a pipe server */
46   return 0;
47 }
48
49 static int
50 finish_connection (assuan_context_t ctx)
51 {
52   /* This is a NOP for a pipe server */
53   return 0;
54 }
55
56 /* Create a new context.  Note that the handlers are set up for a pipe
57    server/client - this way we don't need extra dummy functions */
58 int
59 _assuan_new_context (assuan_context_t *r_ctx)
60 {
61   static struct assuan_io io = { _assuan_simple_read,
62                                  _assuan_simple_write,
63                                  0, 0 };
64
65   assuan_context_t ctx;
66   int rc;
67
68   *r_ctx = NULL;
69   ctx = xtrycalloc (1, sizeof *ctx);
70   if (!ctx)
71     return _assuan_error (ASSUAN_Out_Of_Core);
72   ctx->input_fd = -1;
73   ctx->output_fd = -1;
74
75   ctx->inbound.fd = -1;
76   ctx->outbound.fd = -1;
77   ctx->io = &io;
78
79   ctx->listen_fd = -1;
80   /* Use the pipe server handler as a default.  */
81   ctx->deinit_handler = deinit_pipe_server;
82   ctx->accept_handler = accept_connection;
83   ctx->finish_handler = finish_connection;
84
85   rc = _assuan_register_std_commands (ctx);
86   if (rc)
87     xfree (ctx);
88   else
89     *r_ctx = ctx;
90   return rc;
91 }
92
93
94 /* Returns true if atoi(S) denotes a valid socket. */
95 static int
96 is_valid_socket (const char *s)
97 {
98   struct stat buf;
99
100   if ( fstat (atoi (s), &buf ) )
101     return 0;
102   return S_ISSOCK (buf.st_mode);
103 }
104
105
106 int
107 assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2])
108 {
109   int rc;
110
111   rc = _assuan_new_context (r_ctx);
112   if (!rc)
113     {
114       assuan_context_t ctx = *r_ctx;
115       const char *s;
116       unsigned long ul;
117
118       ctx->is_server = 1;
119 #ifdef HAVE_W32_SYSTEM
120       /* MS Windows has so many different types of handle that one
121          needs to tranlsate them at many place forth and back.  Also
122          make sure that the fiel descriptos are in binary mode.  */
123       setmode (filedes[0], O_BINARY);
124       setmode (filedes[1], O_BINARY);
125       ctx->inbound.fd  = _get_osfhandle (filedes[0]);
126       ctx->outbound.fd = _get_osfhandle (filedes[1]);
127 #else
128       s = getenv ("_assuan_connection_fd");
129       if (s && *s && is_valid_socket (s) )
130         {
131           /* Well, we are called with an bi-directional file
132              descriptor.  Prepare for using sendmsg/recvmsg.  In this
133              case we ignore the passed file descriptors. */
134           ctx->inbound.fd  = ctx->outbound.fd = atoi (s);
135           _assuan_init_uds_io (ctx);
136           ctx->deinit_handler = _assuan_uds_deinit;
137         }
138       else if (filedes && filedes[0] != -1 && filedes[1] != -1 )
139         {
140           /* Standard pipe server. */
141           ctx->inbound.fd  = filedes[0];
142           ctx->outbound.fd = filedes[1];
143         }
144       else
145         {
146           _assuan_release_context (*r_ctx);
147           *r_ctx = NULL;
148           return ASSUAN_Problem_Starting_Server;
149         }
150 #endif
151       ctx->pipe_mode = 1;
152
153       s = getenv ("_assuan_pipe_connect_pid");
154       if (s && (ul=strtoul (s, NULL, 10)) && ul)
155         ctx->pid = (pid_t)ul;
156       else
157         ctx->pid = (pid_t)-1;
158
159     }
160   return rc;
161 }
162
163
164 void
165 _assuan_release_context (assuan_context_t ctx)
166 {
167   if (ctx)
168     {
169       xfree (ctx->hello_line);
170       xfree (ctx->okay_line);
171       xfree (ctx->cmdtbl);
172       xfree (ctx);
173     }
174 }
175
176 void
177 assuan_deinit_server (assuan_context_t ctx)
178 {
179   if (ctx)
180     {
181       /* We use this function pointer to avoid linking other server
182          when not needed but still allow for a generic deinit function.  */
183       ctx->deinit_handler (ctx);
184       ctx->deinit_handler = NULL;
185       _assuan_release_context (ctx);
186     }
187 }