1 /*============================================================================
2 FILE    IPCaegis.c
3 
4 MEMBER OF process XSPICE
5 
6 Public Domain
7 
8 Georgia Tech Research Corporation
9 Atlanta, Georgia 30332
10 PROJECT A-8503
11 
12 AUTHORS
13 
14     9/12/91  Steve Tynor
15 
16 MODIFICATIONS
17 
18     <date> <person name> <nature of modifications>
19 
20 SUMMARY
21 
22     Provides compatibility for the new XSPICE simulator to both the MSPICE user
23     interface and BCP via ATESSE v.1 style AEGIS mailboxes.
24 
25 INTERFACES
26 
27 
28 REFERENCED FILES
29 
30     None.
31 
32 NON-STANDARD FEATURES
33 
34     None.
35 
36 ============================================================================*/
37 
38 #ifdef IPC_AEGIS_MAILBOXES
39 
40 #include <assert.h>
41 #include <apollo/base.h>
42 #include <apollo/mbx.h>
43 #include <apollo/error.h>
44 #include "ngspice/memory.h"
45 
46 #include "ngspice/ipc.h"
47 
48 
49 typedef unsigned char Buffer_char_t;
50 
51 static status_$t        status;
52 typedef enum {
53    IPC_MBX_UNINITIALIZED,
54    IPC_MBX_INITIALIZED,
55    IPC_MBX_CONNECTED_TO_CLIENT,
56 } Ipc_Mbx_State_t;
57 
58 static void                     *mbx_handle;
59 static Ipc_Mbx_State_t          mbx_state = IPC_MBX_UNINITIALIZED;
60 static mbx_$server_msg_t        mbx_send_msg_buf;
61 static mbx_$server_msg_t        mbx_recieve_msg_buf;
62 static mbx_$server_msg_t        *mbx_ret_ptr;
63 static int                      mbx_ret_len;
64 static short                    mbx_chan;
65 
66 #include "ngspice/ipcproto.h"
67 
68 /*---------------------------------------------------------------------------*/
69 
70 /*
71 ipc_transport_initialize_server
72 
73 This function creates an Aegis mailbox, and if successful,
74 calls ipc_get_line to wait for the first record sent which is
75 assumed to be the batch output filename.
76 */
77 
78 
79 
ipc_transport_initialize_server(server_name,m,p,batch_filename)80 Ipc_Status_t ipc_transport_initialize_server (server_name, m, p,
81                                               batch_filename)
82      char               *server_name;    /* The mailbox pathname */
83      Ipc_Mode_t         m;               /* Mode - interactive or batch */
84      Ipc_Protocol_t     p;               /* Protocol type */
85      char               *batch_filename; /* Batch filename returned */
86 {
87    int len;
88 /*   extern void *malloc(); */
89 
90    assert (p == IPC_PROTOCOL_V1);
91 
92    mbx_$create_server (server_name, strlen (server_name), mbx_$serv_msg_max,
93                        1, &mbx_handle, &status);
94 
95    if (status.all != status_$ok) {
96       fprintf (stderr,
97                "ERROR: IPC: Error creating mailbox server \"%s\"\n",
98                server_name);
99       error_$print (status);
100       mbx_state = IPC_MBX_UNINITIALIZED;
101       return IPC_STATUS_ERROR;
102    } else {
103       mbx_state = IPC_MBX_INITIALIZED;
104       /*
105        * First record is the name of the batch filename - whether we're in
106        * batch mode or not:
107        */
108       return ipc_get_line (batch_filename, &len, IPC_WAIT);
109    }
110    /*
111     * shouldn't get here
112     */
113    assert (0);
114    return IPC_STATUS_ERROR;
115 }
116 /*---------------------------------------------------------------------------*/
extract_msg(str,len)117 Ipc_Status_t extract_msg (str, len)
118      char *str;
119      int  *len;
120 {
121    *len = mbx_ret_len - mbx_$serv_msg_hdr_len;
122    assert (*len >= 0);
123 
124    /*
125     * null terminate before copy:
126     */
127    mbx_ret_ptr->data [*len] = '\0';
128    strcpy (str, mbx_ret_ptr->data);
129 
130    return IPC_STATUS_OK;
131 }
132 
133 /*---------------------------------------------------------------------------*/
134 
135 /*
136 ipc_transport_get_line
137 
138 This function reads data sent by a client over the mailbox
139 channel.  It also handles the initial opening of the
140 mailbox channel when requested by a client.
141 */
142 
143 
144 
ipc_transport_get_line(str,len,wait)145 Ipc_Status_t ipc_transport_get_line (str, len, wait)
146      char               *str;   /* The string text read from IPC channel */
147      int                *len;   /* The length of str */
148      Ipc_Wait_t         wait;   /* Blocking or non-blocking */
149 {
150    if (mbx_state == IPC_MBX_UNINITIALIZED) {
151       fprintf (stderr,
152                "ERROR: IPC: Attempted to read from non-initialized mailbox\n");
153       return IPC_STATUS_ERROR;
154    }
155 
156    assert ((mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) ||
157            (mbx_state == IPC_MBX_INITIALIZED));
158 
159    for (;;) {
160       if (wait == IPC_WAIT) {
161          mbx_$get_rec (mbx_handle, &mbx_recieve_msg_buf, mbx_$serv_msg_max,
162                        &mbx_ret_ptr, &mbx_ret_len, &status);
163       } else {
164          mbx_$get_conditional (mbx_handle, &mbx_recieve_msg_buf,
165                                mbx_$serv_msg_max, &mbx_ret_ptr, &mbx_ret_len,
166                                &status);
167          if (status.all == mbx_$channel_empty) {
168             return IPC_STATUS_NO_DATA;
169          }
170       }
171 
172       if (status.all != status_$ok) {
173          fprintf (stderr, "ERROR: IPC: Error reading from mailbox\n");
174          error_$print (status);
175          return IPC_STATUS_ERROR;
176       }
177 
178       switch (mbx_ret_ptr->mt) {
179       case mbx_$channel_open_mt:
180          if (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT) {
181             /*
182              * we're already connected to a client... refuse the connection
183              */
184             mbx_send_msg_buf.mt = mbx_$reject_open_mt;
185          } else {
186             mbx_send_msg_buf.mt = mbx_$accept_open_mt;
187             mbx_state = IPC_MBX_CONNECTED_TO_CLIENT;
188          }
189          mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len;
190          mbx_chan = mbx_ret_ptr->chan;
191          mbx_send_msg_buf.chan = mbx_chan;
192 
193          mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, mbx_$serv_msg_hdr_len,
194                        &status);
195 
196          if (status.all != status_$ok) {
197             fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n");
198             error_$print (status);
199             return IPC_STATUS_ERROR;
200          }
201 
202          /*
203           * check to see if there was a message buried in the open request:
204           */
205          if (mbx_ret_len > mbx_$serv_msg_hdr_len) {
206             return extract_msg (str, len);
207          }
208          break;
209       case mbx_$eof_mt:
210          mbx_chan = mbx_ret_ptr->chan;
211 	 mbx_$deallocate(mbx_handle, mbx_chan, &status);
212 
213          if (status.all != status_$ok) {
214             fprintf (stderr, "ERROR: IPC: Error deallocating mailbox\n");
215             error_$print (status);
216             return IPC_STATUS_ERROR;
217          }
218 
219          mbx_state = IPC_MBX_INITIALIZED;
220          return IPC_STATUS_EOF;
221          break;
222       case mbx_$data_mt:
223          assert (mbx_state == IPC_MBX_CONNECTED_TO_CLIENT);
224          return extract_msg (str, len);
225          break;
226       case mbx_$data_partial_mt:
227          fprintf (stderr, "ERROR: IPC: Recieved partial data message - ignored\n");
228          break;
229       default:
230          fprintf (stderr, "ERROR: IPC: Bad message type (0x%x) recieved\n",
231                   mbx_ret_ptr->mt);
232       }
233    }
234    return IPC_STATUS_ERROR;
235 }
236 
237 /*---------------------------------------------------------------------------*/
238 
239 /*
240 ipc_transport_terminate_server
241 
242 This function calls ipc\_transport\_get\_line until it
243 receives an EOF from the client, which concludes the
244 communication.
245 */
246 
247 
ipc_transport_terminate_server()248 Ipc_Status_t ipc_transport_terminate_server ()
249 {
250    char buffer[300];
251    int len;
252    Ipc_Status_t status;
253 
254    do {
255       status = ipc_transport_get_line (buffer, &len, IPC_WAIT);
256    } while ((status != IPC_STATUS_ERROR) &&
257 	    (status != IPC_STATUS_EOF));
258    return status;
259 }
260 
261 /*---------------------------------------------------------------------------*/
262 
263 /*
264 ipc_transport_send_line
265 
266 This function sends a message to the current client through
267 the mailbox channel.
268 */
269 
270 
ipc_transport_send_line(str,len)271 Ipc_Status_t ipc_transport_send_line (str, len)
272      char *str;    /* The bytes to send */
273      int len;      /* The number of bytes from str to send */
274 {
275    long cnt;
276 
277    if (mbx_state != IPC_MBX_CONNECTED_TO_CLIENT) {
278       fprintf (stderr,
279                "ERROR: IPC: Attempted to write to non-open mailbox\n");
280       return IPC_STATUS_ERROR;
281    }
282 
283    mbx_send_msg_buf.mt = mbx_$data_mt;
284    if (mbx_$serv_msg_hdr_len + len > mbx_$serv_msg_max) {
285       fprintf (stderr,
286 	       "ERROR: IPC: send_line message too long - truncating\n");
287       len = mbx_$serv_msg_max - mbx_$serv_msg_hdr_len;
288    }
289 
290    mbx_send_msg_buf.cnt = mbx_$serv_msg_hdr_len + len;
291    mbx_send_msg_buf.chan = mbx_chan;
292    memcpy (mbx_send_msg_buf.data, str, len);
293 
294    cnt = mbx_send_msg_buf.cnt;
295    mbx_$put_rec (mbx_handle, &mbx_send_msg_buf, cnt, &status);
296 
297    if (status.all != status_$ok) {
298       fprintf (stderr, "ERROR: IPC: Error writing to mailbox\n");
299       error_$print (status);
300       return IPC_STATUS_ERROR;
301    }
302    return IPC_STATUS_OK;
303 }
304 
305 #else
306 
307 int intDummy1;
308 
309 #endif  /* IPC_AEGIS_MAILBOXES */
310