Chnages to supporta pinnetry notification
[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 #ifndef HAVE_W32_SYSTEM
96 static int
97 is_valid_socket (const char *s)
98 {
99   struct stat buf;
100
101   if ( fstat (atoi (s), &buf ) )
102     return 0;
103   return S_ISSOCK (buf.st_mode);
104 }
105 #endif /*!HAVE_W32_SYSTEM*/
106
107
108 int
109 assuan_init_pipe_server (assuan_context_t *r_ctx, int filedes[2])
110 {
111   int rc;
112
113   rc = _assuan_new_context (r_ctx);
114   if (!rc)
115     {
116       assuan_context_t ctx = *r_ctx;
117       const char *s;
118       unsigned long ul;
119
120       ctx->is_server = 1;
121 #ifdef HAVE_W32_SYSTEM
122       /* MS Windows has so many different types of handle that one
123          needs to tranlsate them at many place forth and back.  Also
124          make sure that the fiel descriptos are in binary mode.  */
125       setmode (filedes[0], O_BINARY);
126       setmode (filedes[1], O_BINARY);
127       ctx->inbound.fd  = _get_osfhandle (filedes[0]);
128       ctx->outbound.fd = _get_osfhandle (filedes[1]);
129 #else
130       s = getenv ("_assuan_connection_fd");
131       if (s && *s && is_valid_socket (s) )
132         {
133           /* Well, we are called with an bi-directional file
134              descriptor.  Prepare for using sendmsg/recvmsg.  In this
135              case we ignore the passed file descriptors. */
136           ctx->inbound.fd  = ctx->outbound.fd = atoi (s);
137           _assuan_init_uds_io (ctx);
138           ctx->deinit_handler = _assuan_uds_deinit;
139         }
140       else if (filedes && filedes[0] != -1 && filedes[1] != -1 )
141         {
142           /* Standard pipe server. */
143           ctx->inbound.fd  = filedes[0];
144           ctx->outbound.fd = filedes[1];
145         }
146       else
147         {
148           _assuan_release_context (*r_ctx);
149           *r_ctx = NULL;
150           return ASSUAN_Problem_Starting_Server;
151         }
152 #endif
153       ctx->pipe_mode = 1;
154
155       s = getenv ("_assuan_pipe_connect_pid");
156       if (s && (ul=strtoul (s, NULL, 10)) && ul)
157         ctx->pid = (pid_t)ul;
158       else
159         ctx->pid = (pid_t)-1;
160
161     }
162   return rc;
163 }
164
165
166 void
167 _assuan_release_context (assuan_context_t ctx)
168 {
169   if (ctx)
170     {
171       xfree (ctx->hello_line);
172       xfree (ctx->okay_line);
173       xfree (ctx->cmdtbl);
174       xfree (ctx);
175     }
176 }
177
178 void
179 assuan_deinit_server (assuan_context_t ctx)
180 {
181   if (ctx)
182     {
183       /* We use this function pointer to avoid linking other server
184          when not needed but still allow for a generic deinit function.  */
185       ctx->deinit_handler (ctx);
186       ctx->deinit_handler = NULL;
187       _assuan_release_context (ctx);
188     }
189 }