assuan/
[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, see <http://www.gnu.org/licenses/>.
18  */
19
20 #include <config.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <unistd.h>
26 #ifdef HAVE_W32_SYSTEM
27 #include <windows.h>
28 #include <fcntl.h>
29 #endif
30
31 #include "assuan-defs.h"
32
33
34 static void
35 deinit_pipe_server (assuan_context_t ctx)
36 {
37   /* nothing to do for this simple server */
38 }
39
40 static int
41 accept_connection (assuan_context_t ctx)
42 {
43   /* This is a NOP for a pipe server */
44   return 0;
45 }
46
47 static int
48 finish_connection (assuan_context_t ctx)
49 {
50   /* This is a NOP for a pipe server */
51   return 0;
52 }
53
54 /* Create a new context.  Note that the handlers are set up for a pipe
55    server/client - this way we don't need extra dummy functions */
56 int
57 _assuan_new_context (assuan_context_t *r_ctx)
58 {
59   static struct assuan_io io = { _assuan_simple_read,
60                                  _assuan_simple_write,
61                                  0, 0 };
62
63   assuan_context_t ctx;
64   int rc;
65
66   *r_ctx = NULL;
67   ctx = xtrycalloc (1, sizeof *ctx);
68   if (!ctx)
69     return _assuan_error (ASSUAN_Out_Of_Core);
70   ctx->input_fd = ASSUAN_INVALID_FD;
71   ctx->output_fd = ASSUAN_INVALID_FD;
72
73   ctx->inbound.fd = ASSUAN_INVALID_FD;
74   ctx->outbound.fd = ASSUAN_INVALID_FD;
75   ctx->io = &io;
76
77   ctx->listen_fd = ASSUAN_INVALID_FD;
78   /* Use the pipe server handler as a default.  */
79   ctx->deinit_handler = deinit_pipe_server;
80   ctx->accept_handler = accept_connection;
81   ctx->finish_handler = finish_connection;
82
83   rc = _assuan_register_std_commands (ctx);
84   if (rc)
85     xfree (ctx);
86   else
87     *r_ctx = ctx;
88   return rc;
89 }
90
91
92 /* Returns true if atoi(S) denotes a valid socket. */
93 #ifndef HAVE_W32_SYSTEM
94 static int
95 is_valid_socket (const char *s)
96 {
97   struct stat buf;
98
99   if ( fstat (atoi (s), &buf ) )
100     return 0;
101   return S_ISSOCK (buf.st_mode);
102 }
103 #endif /*!HAVE_W32_SYSTEM*/
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 file descriptors are in binary mode.  */
123       setmode (filedes[0], O_BINARY);
124       setmode (filedes[1], O_BINARY);
125       ctx->inbound.fd  = (void*)_get_osfhandle (filedes[0]);
126       ctx->outbound.fd = (void*)_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] != ASSUAN_INVALID_FD 
139                && filedes[1] != ASSUAN_INVALID_FD )
140         {
141           /* Standard pipe server. */
142           ctx->inbound.fd  = filedes[0];
143           ctx->outbound.fd = filedes[1];
144         }
145       else
146         {
147           _assuan_release_context (*r_ctx);
148           *r_ctx = NULL;
149           return ASSUAN_Problem_Starting_Server;
150         }
151 #endif
152       ctx->pipe_mode = 1;
153
154       s = getenv ("_assuan_pipe_connect_pid");
155       if (s && (ul=strtoul (s, NULL, 10)) && ul)
156         ctx->pid = (pid_t)ul;
157       else
158         ctx->pid = (pid_t)-1;
159
160     }
161   return rc;
162 }
163
164
165 void
166 _assuan_release_context (assuan_context_t ctx)
167 {
168   if (ctx)
169     {
170       _assuan_inquire_release (ctx);
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 }