2 * $TOG: spc-proto.c /main/12 1999/10/14 16:00:27 mgreess $
5 * (c) Copyright 1996 Digital Equipment Corporation.
6 * (c) Copyright 1989,1993,1994,1996 Hewlett-Packard Company.
7 * (c) Copyright 1993,1994,1996 International Business Machines Corp.
8 * (c) Copyright 1993,1994,1996 Sun Microsystems, Inc.
9 * (c) Copyright 1993,1994,1996 Novell, Inc.
10 * (c) Copyright 1996 FUJITSU LIMITED.
11 * (c) Copyright 1996 Hitachi.
14 #define __need_timeval
15 #define __need_all_errors
17 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
20 #include <sys/utsname.h>
23 #define X_INCLUDE_PWD_H
24 #define XOS_USE_XT_LOCKING
25 #include <X11/Xos_r.h>
29 #include <bms/MemoryMgr.h>
31 #include <SPC/spc-proto.h>
34 #include "DtSvcLock.h"
39 extern struct termios *XeTermioStruct; /* In pty.c */
41 extern XeString *environ;
42 extern SPC_Channel_Ptr spc_activation_list;
47 /* FILE *SPC_Print_Protocol=NULL; -- now in bmsglob.c */
49 SPC_Connection_Ptr connection_list = NULL;
50 protocol_request_ptr free_protocol_requests = NULL;
55 static int SPC_Send_Termios(protocol_request_ptr prot_request);
56 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
57 protocol_request_ptr prot,
63 /*----------------------------------------------------------------------+*/
64 buffered_data_ptr SPC_New_Buffered_Data_Ptr(void)
65 /*----------------------------------------------------------------------+*/
67 buffered_data_ptr bdata;
69 bdata=(buffered_data_ptr)XeMalloc(sizeof(buffered_data));
70 bdata->len = bdata->offset = 0;
75 /*----------------------------------------------------------------------+*/
76 void SPC_Reset_Protocol_Ptr (protocol_request_ptr prot,
77 SPC_Channel_Ptr channel,
80 /*----------------------------------------------------------------------+*/
82 buffered_data_ptr dptr=prot->dataptr;
87 prot->request_type = req;
88 prot->channel = channel;
90 memset(dptr->data, (XeChar)' ', REQUEST_HEADER_LENGTH);
93 /*----------------------------------------------------------------------+*/
94 protocol_request_ptr SPC_New_Protocol_Ptr (SPC_Channel_Ptr channel,
97 /*----------------------------------------------------------------------+*/
99 protocol_request_ptr prot;
102 if(free_protocol_requests) {
103 prot = free_protocol_requests;
104 free_protocol_requests = free_protocol_requests->next;
106 prot = (protocol_request_ptr)XeMalloc(sizeof(protocol_request));
107 prot->dataptr = SPC_New_Buffered_Data_Ptr();
109 SPC_Reset_Protocol_Ptr(prot, channel, req, len);
110 _DtSvcProcessUnlock();
114 /*----------------------------------------------------------------------+*/
115 void SPC_Free_Protocol_Ptr(protocol_request_ptr prot)
116 /*----------------------------------------------------------------------+*/
119 prot->next = free_protocol_requests;
120 free_protocol_requests = prot;
121 _DtSvcProcessUnlock();
125 /*----------------------------------------------------------------------+*/
126 SPC_Channel_Ptr SPC_Lookup_Channel(int cid,
127 SPC_Connection_Ptr connection)
128 /*----------------------------------------------------------------------+*/
137 for(spc=spc_activation_list; spc; spc=spc->next)
138 /* This test is here because:
139 a. Only remote channels have cid's
140 b. It is possible for multiple remote servers to have
141 the same cid (which is simply the address of the channel),
142 so we need to distinguish among remote channels, but
143 c. channels on the remote daemon have cid's, but a null connection.
145 if((spc->cid == cid) &&
147 (spc->connection == connection))) {
148 _DtSvcProcessUnlock();
152 _DtSvcProcessUnlock();
157 * Connection management routines
161 /*----------------------------------------------------------------------+*/
162 SPC_Connection_Ptr SPC_Alloc_Connection(void)
163 /*----------------------------------------------------------------------+*/
165 SPC_Connection_Ptr conn;
168 conn=(SPC_Connection_Ptr) XeMalloc(sizeof(SPC_Connection));
169 /* Zero the connection */
170 memset(conn, NULL, sizeof(SPC_Connection));
171 conn->queued_remote_data = Xe_make_queue(FALSE);
172 conn->termination_id = (-1);
173 /* Init the socket id to "-1" because "0" is a valid file descriptor. */
175 _DtSvcProcessUnlock();
180 /*----------------------------------------------------------------------+*/
181 SPC_Connection_Ptr SPC_Lookup_Connection(XeString hostname)
182 /*----------------------------------------------------------------------+*/
184 /* Search for an existing connection to a server */
185 SPC_Connection_Ptr conn;
188 for (conn = connection_list; conn != NULL; conn = conn->next) {
190 /* Look for a connection with the same hostname */
191 if (!strcmp(conn->hostname, hostname)) {
192 _DtSvcProcessUnlock();
197 _DtSvcProcessUnlock();
201 /*----------------------------------------------------------------------+*/
202 SPC_Connection_Ptr SPC_Lookup_Connection_Fd(int fd)
203 /*----------------------------------------------------------------------+*/
205 /* Search for an existing connection to a server, using fd (file descriptor)
207 SPC_Connection_Ptr conn;
210 for (conn = connection_list; conn != NULL; conn = conn->next) {
212 /* Look for a connection with the same hostname */
214 _DtSvcProcessUnlock();
219 _DtSvcProcessUnlock();
223 /*----------------------------------------------------------------------+*/
224 SPC_Connection_Ptr SPC_Make_Connection(XeString hostname)
225 /*----------------------------------------------------------------------+*/
227 /* Search for a connection to hostname, create one if none exists */
229 SPC_Connection_Ptr conn;
231 /* Searching for connected host maintains only one connection per remote */
233 if(hostname && (conn=SPC_Lookup_Connection(hostname)))
236 /* Not found, so make one */
238 if((conn = SPC_Alloc_Connection())==SPC_ERROR)
242 strcpy(conn->hostname, hostname);
244 SPC_Add_Connection(conn);
248 /*----------------------------------------------------------------------+*/
249 void SPC_Add_Connection(SPC_Connection_Ptr connection)
250 /*----------------------------------------------------------------------+*/
253 /* Add a connection to the connection_list */
255 connection->next = connection_list;
256 connection_list = connection;
257 _DtSvcProcessUnlock();
260 /*----------------------------------------------------------------------+*/
261 void SPC_Close_Connection(SPC_Connection_Ptr connection)
262 /*----------------------------------------------------------------------+*/
264 SPC_Channel_Ptr channel;
265 SPC_Channel_Ptr next;
266 SPC_Connection_Ptr trail, ptr;
268 /* We have to be careful here. SPC_Input_Handler may call the users
269 termination handler, which in turn might close the channel, which
270 may deallocate the channel. Therefore, we grab the next channel
271 from the list while we are still alive. */
274 channel=spc_activation_list;
275 connection->connected = FALSE;
279 if(channel->connection == connection) {
280 if(!IS_SPCIO_DELAY_CLOSE(channel->IOMode))
281 SPC_Channel_Terminated(channel);
282 channel->connection = NULL;
287 SPC_XtRemoveInput(&connection->termination_id, SPC_Terminator);
289 spc_close(connection->sid);
290 connection->sid = (-1);
292 if (connection->hostinfo)
293 XeFree(connection->hostinfo);
295 /* Remove the connection from the connection list */
297 if(connection_list == connection)
298 connection_list = connection->next;
300 trail = connection_list;
303 if(ptr == connection) {
304 trail->next = ptr->next;
310 /* Here if no such connection found. */
314 free((char *)connection);
315 _DtSvcProcessUnlock();
320 ** Read the specified number of characters, or die trying.
324 /*----------------------------------------------------------------------+*/
325 int SPC_Read_Chars(SPC_Connection_Ptr connection,
328 /*----------------------------------------------------------------------+*/
331 int numchars, numread;
332 int numtoread=request_len;
333 int sid=connection->sid;
337 while(numread<request_len) {
339 numchars=read(sid, charptr, numtoread);
340 while(numchars == ERROR && errno == EINTR);
341 if(numchars == ERROR) {
342 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
343 if(errno == ECONNRESET)
344 SPC_Error(SPC_Connection_Reset, connection_hostname);
346 SPC_Error(SPC_Reading, connection_hostname);
347 XeFree(connection_hostname);
351 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
352 SPC_Error(SPC_Connection_EOF, connection_hostname);
353 XeFree(connection_hostname);
354 return(SPC_ERROR); /* Bad news, EOF on incoming channel */
358 numtoread -= numchars;
360 *charptr=(XeChar)'\0';
364 /* Write len chars, or die trying */
366 /*----------------------------------------------------------------------+*/
367 int SPC_Write_Chars(int fd,
370 /*----------------------------------------------------------------------+*/
372 int numchars, numwritten;
373 int numtowrite=request_len;
377 while(numwritten<request_len) {
379 numchars=write(fd, charptr, numtowrite);
380 while(numchars == ERROR && errno == EINTR);
384 if(SPC_Print_Protocol)
385 fprintf(SPC_Print_Protocol,
386 "SPC_Write_Chars -- wrote: %d of %d, expected: %d, errno: %d\n",
387 numchars, request_len, numtowrite, errno);
388 _DtSvcProcessUnlock();
391 if(numchars == ERROR)
395 numwritten += numchars;
396 numtowrite -= numchars;
404 ** Read a single protocol request from the passed channel.
408 /*----------------------------------------------------------------------+*/
409 protocol_request_ptr SPC_Read_Protocol(SPC_Connection_Ptr connection)
410 /*----------------------------------------------------------------------+*/
413 protocol_request_ptr prot;
414 buffered_data_ptr dptr;
417 if(!connection->connected)
420 if((prot=SPC_New_Protocol_Ptr(NULL, NULL, NULL))==SPC_ERROR) {
421 SPC_Close_Connection(connection);
429 len=SPC_Read_Chars(connection, REQUEST_HEADER_LENGTH, dptr->data);
430 if(len != REQUEST_HEADER_LENGTH) {
431 SPC_Close_Connection(connection);
432 SPC_Free_Protocol_Ptr(prot);
436 /* we have the header. Parse out the fields */
439 &channel_id, &prot->request_type, &dptr->len, &prot->seqno);
440 prot->channel=SPC_Lookup_Channel(channel_id, connection);
444 len=SPC_Read_Chars(connection, dptr->len, dptr->data+REQUEST_HEADER_LENGTH);
445 if(len != dptr->len) {
446 SPC_Close_Connection(connection);
447 SPC_Free_Protocol_Ptr(prot);
451 dptr->offset=REQUEST_HEADER_LENGTH;
458 ** Filter the connection for the desired type of protocol request.
459 ** If there is a protocol request of the desired type already queued,
460 ** return it. If not, read a new one. If we read requests destined
461 ** for another channel, or for our channel but not the correct
462 ** request type, queue it up. If the deletep flag is TRUE, remove it
467 /*----------------------------------------------------------------------+*/
468 protocol_request_ptr SPC_Filter_Connection(SPC_Connection_Ptr connection,
469 SPC_Channel_Ptr channel,
472 /*----------------------------------------------------------------------+*/
474 SPC_Connection_Ptr connptr=NULL;
475 SPC_Channel_Ptr conn_channel;
477 protocol_request_ptr retval;
480 /* check if there are any queued prot. requests. If so,
481 check for their having the type we want */
483 if(channel && (tmpqueue=channel->queued_remote_data)) {
484 tmpqueue=channel->queued_remote_data;
486 Xe_for_queue(protocol_request_ptr, retval, tmpqueue) {
487 /* found a queued packet. Is it what we are looking for? */
488 if(retval->request_type == reqtype) {
491 Xe_delete_queue_element(channel->queued_remote_data, retval);
498 /* No queued elements. Read until we get the reply we
501 if((retval=SPC_Read_Protocol(connection))==SPC_ERROR)
504 protreqtype=retval->request_type;
505 conn_channel=retval->channel;
507 if(protreqtype == ABORT) {
508 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
509 SPC_Error(SPC_Protocol_Abort, connection_hostname);
510 XeFree (connection_hostname);
515 if(protreqtype == SERVER_ERROR) {
516 READ_ERROR(retval->dataptr, XeSPCErrorNumber);
517 SPC_Error(XeSPCErrorNumber, XeString_NULL, 0);
518 _DtSvcProcessUnlock();
521 _DtSvcProcessUnlock();
526 if((conn_channel == channel) && (protreqtype == reqtype)) {
527 /* We found one that matches. Check if we need to queue it up. */
529 Xe_push_queue(conn_channel->queued_remote_data, retval);
533 /* No match. Queue it up */
534 if(IS_SPCIO_SYNC_TERM(channel->IOMode))
535 Xe_push_queue(connection->queued_remote_data, retval);
537 Xe_push_queue(conn_channel->queued_remote_data, retval);
542 /*----------------------------------------------------------------------+*/
543 void SPC_Flush_Queued_Data(SPC_Channel_Ptr channel)
544 /*----------------------------------------------------------------------+*/
547 protocol_request_ptr prot;
549 if(tmpqueue=channel->queued_remote_data) {
550 while(prot=(protocol_request_ptr)Xe_pop_queue(tmpqueue))
551 SPC_Free_Protocol_Ptr(prot);
554 if(channel->connection && (tmpqueue=channel->connection->queued_remote_data))
556 Xe_for_queue(protocol_request_ptr, prot, tmpqueue) {
557 if(prot->channel == channel) {
558 Xe_delete_queue_element(tmpqueue, prot);
559 SPC_Free_Protocol_Ptr(prot);
565 /*----------------------------------------------------------------------+*/
566 int SPC_Read_Remote_Data(SPC_Channel_Ptr channel,
568 XeString client_buffer,
570 /*----------------------------------------------------------------------+*/
574 SPC_Connection_Ptr connection=channel->connection;
575 protocol_request_ptr prot;
576 buffered_data_ptr pdata;
577 int req_type=CONNECTOR_TO_PROT(connector);
579 prot=SPC_Filter_Connection(connection, channel, req_type, FALSE);
585 ret_len = min(nbytes, pdata->len);
587 memcpy(client_buffer, pdata->data+pdata->offset, ret_len);
588 pdata->offset += ret_len;
589 pdata->len -= ret_len;
590 if(pdata->len == 0) {
591 SPC_Filter_Connection(connection, channel, req_type, TRUE);
592 SPC_Free_Protocol_Ptr(prot);
598 /* Dump out a protocol request */
600 /*----------------------------------------------------------------------+*/
601 int print_protocol_request(XeString name, protocol_request_ptr proto)
602 /*----------------------------------------------------------------------+*/
604 buffered_data_ptr dptr = proto->dataptr;
607 if(!SPC_Print_Protocol) {
608 _DtSvcProcessUnlock();
612 dptr->data[dptr->offset+dptr->len]=0;
614 fprintf(SPC_Print_Protocol,
615 "%s channel: %x, request: %d, length: %d, seq: %d data: %s\n",
616 name, proto->channel, proto->request_type, dptr->len, proto->seqno,
617 dptr->data+dptr->offset);
619 fflush(SPC_Print_Protocol);
621 _DtSvcProcessUnlock();
626 * Write a protocol request to the given channel
630 int current_sequence_number=1;
632 /*----------------------------------------------------------------------+*/
633 int SPC_Write_Protocol_Request (SPC_Connection_Ptr connection,
634 SPC_Channel_Ptr channel,
637 /*----------------------------------------------------------------------+*/
640 protocol_request_ptr prot_request;
641 buffered_data_ptr pdata;
643 XeString prot_name=NULL;
645 prot_request=SPC_New_Protocol_Ptr(channel, request, 0);
646 pdata=prot_request->dataptr;
648 prot_request->seqno = current_sequence_number++;
649 _DtSvcProcessUnlock();
651 /* We are overloading the "channel" field. We put the cid rather */
652 /* than the actual channel pointer in when we pass it to the other */
653 /* side of the connection. */
654 prot_request->channel=(SPC_Channel_Ptr)(channel ? channel->cid : 0);
659 pdata->len=WRITE_ABORT(pdata, 0);
660 prot_name=(XeString)" <-- ABORT";
670 va_start(ap, request);
671 username=va_arg(ap, XeString );
672 passwd=va_arg(ap, XeString );
673 proto_ver=va_arg(ap, XeString );
674 hostinfo=va_arg(ap, XeString );
676 pdata->len=WRITE_REGISTER(pdata, username, passwd, proto_ver, hostinfo);
677 prot_name=(XeString)" <-- REGISTER";
683 prot_name=(XeString)" <-- UNREGISTER";
687 va_start(ap, request);
688 pdata->len=WRITE_OPEN(pdata, va_arg(ap, int));
690 prot_name=(XeString)" <-- CHANNEL_OPEN";
694 /* This is correct. This protocol request takes no args */
695 prot_name=(XeString)" <-- CHANNEL_CLOSE";
699 /* This one, either */
700 prot_name=(XeString)" <-- CHANNEL_RESET";
704 prot_name=(XeString)" <-- CHANNEL_ATTACH";
705 va_start(ap, request);
706 pdata->len=WRITE_ATTACH(pdata, va_arg(ap, int));
710 case APPLICATION_SPAWN:
717 va_start(ap, request);
719 /* It is left as an exercise to the reader to figure out
720 what would happen if we didn't use these temp. variables
721 and instead used the va_arg macros directly in the
722 WRITE_APPLICATION_SPAWN... */
724 path=va_arg(ap, XeString );
725 dir =va_arg(ap, XeString );
726 argv=va_arg(ap, XeString *);
727 envp=va_arg(ap, XeString *);
729 pdata->len=WRITE_APPLICATION_SPAWN(pdata, path, dir, argv, envp);
730 if(pdata->len == SPC_ERROR)
732 prot_name=(XeString)" <-- APPLICATION_SPAWN";
736 case APPLICATION_SIGNAL:
738 if (connection->protocol_version >= 2)
742 va_start(ap, request);
743 signame = va_arg(ap, XeString);
746 pdata->len=WRITE_STRING(pdata, signame);
752 va_start(ap, request);
753 sig = va_arg(ap, int);
756 pdata->len=WRITE_INT(pdata, sig);
759 prot_name=(XeString)" <-- APPLICATION_SIGNAL";
763 case APPLICATION_DIED:
764 va_start(ap, request);
765 pdata->len=WRITE_APPLICATION_DIED(pdata, va_arg(ap, int));
767 prot_name=(XeString)" <-- APPLICATION_DIED";
770 case APPLICATION_DATA:
771 prot_name=(XeString)" <-- APPLICATION_DATA";
773 case APPLICATION_STDOUT:
775 prot_name=(XeString)" <-- APPLICATION_STDOUT";
777 case APPLICATION_STDERR:
783 prot_name=(XeString)" <-- APPLICATION_STDERR";
785 va_start(ap, request);
786 buffer=va_arg(ap, XeString );
787 buflen=va_arg(ap, int);
790 pdata->len=WRITE_APP_DATA(pdata, buffer, buflen);
796 va_start(ap, request);
797 pdata->len=WRITE_ERROR(pdata, va_arg(ap, int));
799 prot_name=(XeString)" <-- SERVER_ERROR";
804 int replyval, errval;
806 va_start(ap, request);
807 prot_request->seqno=va_arg(ap, int);
808 replyval=va_arg(ap, int);
809 errval=va_arg(ap, int);
811 pdata->len=WRITE_REPLY(pdata, replyval, errval);
812 prot_name=(XeString)" <-- REPLY";
825 va_start(ap, request);
826 m0=va_arg(ap, XeString );
827 s0=va_arg(ap, XeString );
828 m1=va_arg(ap, XeString );
829 s1=va_arg(ap, XeString );
830 m2=va_arg(ap, XeString );
831 s2=va_arg(ap, XeString );
833 pdata->len=WRITE_DEVICE_REPLY(pdata, m0, s0, m1, s1, m2, s2);
834 prot_name=(XeString)" <-- DEVICE_REPLY";
839 prot_name=(XeString)" <-- QUERY_DEVICES";
848 va_start(ap, request);
849 fname=va_arg(ap, XeString );
850 proto_ver=va_arg(ap, XeString );
851 hostinfo=va_arg(ap, XeString );
853 pdata->len=WRITE_LOGFILE_REPLY(pdata, fname, proto_ver, hostinfo);
854 prot_name=(XeString)" <-- LOGFILE_REPLY";
859 prot_name=(XeString)" <-- QUERY_LOGFILE";
863 prot_name=(XeString)" <-- DELETE_LOGFILE";
867 va_start(ap, request);
868 pdata->len=WRITE_DEBUG(pdata, va_arg(ap, XeString));
870 prot_name=(XeString)" <-- SERVER_DEBUG";
874 return(SPC_Send_Environ(connection, prot_request));
876 /* We used to send the hp-ux version of a termio struct */
877 /* This is non-portable, so we don't do it anymore. */
880 pdata->len=SPC_Send_Termios(prot_request);
881 prot_name=(XeString)" <-- RESET_TERMIOS";
884 /* B.00 (protocol version 3) requests */
886 case CHANNEL_SEND_EOF:
888 if(connection->protocol_version < 3) {
889 SPC_Error(SPC_Protocol_Version_Error,
890 3, channel->connection->protocol_version);
894 prot_name = (XeString)" <-- CHANNEL_SEND_EOF";
897 case CHANNEL_TERMIOS:
899 if(connection->protocol_version < 3) {
900 SPC_Error(SPC_Protocol_Version_Error,
901 3, channel->connection->protocol_version);
907 struct termios *termios_ptr;
910 va_start(ap, request);
912 connector = va_arg(ap, int);
913 side = va_arg(ap, int);
914 termios_ptr = va_arg(ap, struct termios *);
917 buffer = SPC_Decode_Termios(termios_ptr);
918 pdata->len=WRITE_TERMIOS(pdata, connector, side, buffer);
919 prot_name=(XeString)" <-- CHANNEL_TERMIOS";
924 if(connection->protocol_version < 3) {
925 SPC_Error(SPC_Protocol_Version_Error,
926 3, channel->connection->protocol_version);
937 va_start(ap, request);
939 /* It is left as an exercise to the reader to figure out
940 what would happen if we didn't use these temp. variables
941 and instead used the va_arg macros directly in the
942 WRITE_APPLICATION_SPAWN... */
944 path=va_arg(ap, XeString );
945 dir =va_arg(ap, XeString );
946 argv=va_arg(ap, XeString *);
947 envp=va_arg(ap, XeString *);
951 SPC_Send_B00_Spawn(connection, prot_request, path, dir, argv, envp);
958 SPC_Write_Single_Prot_Request(connection, prot_name, prot_request);
960 SPC_Free_Protocol_Ptr(prot_request);
961 return(reply_expected);
965 /*----------------------------------------------------------------------+*/
966 int SPC_Write_Single_Prot_Request(SPC_Connection_Ptr connection,
968 protocol_request_ptr prot)
969 /*----------------------------------------------------------------------+*/
971 int reply_expected, length;
972 buffered_data_ptr pdata=prot->dataptr;
974 if(!connection->connected)
978 REPLY_EXPECTED(prot->request_type, prot->seqno);
979 length=WRITE_HEADER(pdata, prot->channel,
983 pdata->data[length]=(XeChar)' ';
985 length=pdata->len+REQUEST_HEADER_LENGTH;
986 if(SPC_Write_Chars(connection->sid, pdata->data, length) == ERROR) {
987 XeString connection_hostname = CONNECTION_HOSTNAME(connection);
988 SPC_Close_Connection(connection);
989 SPC_Error(SPC_Write_Prot, connection_hostname);
990 XeFree(connection_hostname);
991 reply_expected = (SPC_ERROR);
994 pdata->offset=REQUEST_HEADER_LENGTH;
995 print_protocol_request(name, prot);
997 return(reply_expected);
1000 /*----------------------------------------------------------------------+*/
1001 int SPC_Waitfor_Reply(SPC_Connection_Ptr connection,
1002 SPC_Channel_Ptr channel,
1004 /*----------------------------------------------------------------------+*/
1007 protocol_request_ptr prot;
1011 if(seqno == NO_REPLY_VAL)
1014 if(seqno==SPC_ERROR)
1017 prot=SPC_Filter_Connection(connection, channel, REPLY, TRUE);
1022 thisseq = prot->seqno;
1023 READ_REPLY(prot->dataptr, retval, errval);
1025 SPC_Free_Protocol_Ptr(prot);
1027 if(thisseq != seqno) {
1028 SPC_Error(SPC_Unexpected_Reply);
1035 if(retval != SPC_Protocol_Abort) {
1036 if (retval == SPC_Cannot_Create_Netfilename)
1037 SPC_Error(retval, channel->context_dir, connection->hostname);
1038 else if (retval == SPC_Cannot_Exec)
1039 SPC_Error(retval, channel->path, 0);
1040 else if (retval == SPC_cannot_Chdir)
1041 SPC_Error(retval, channel->context_dir, 0);
1043 SPC_Error(retval, XeString_NULL, 0);
1051 /*----------------------------------------------------------------------+*/
1052 int SPC_Dispatch_Protocol(protocol_request_ptr proto,
1053 protocol_request_handler *table)
1054 /*----------------------------------------------------------------------+*/
1060 req_type=proto->request_type;
1062 if(req_type<0 || req_type>NREQS)
1065 return((* table[req_type])(proto));
1068 /*----------------------------------------------------------------------+*/
1069 int SPC_Write_Reply(SPC_Connection_Ptr conn,
1070 protocol_request_ptr proto,
1073 /*----------------------------------------------------------------------+*/
1075 _DtSvcProcessLock();
1077 retval=(-XeSPCErrorNumber);
1078 _DtSvcProcessUnlock();
1080 return(SPC_Write_Protocol_Request(conn, proto->channel, REPLY,
1081 proto->seqno, retval, errval));
1086 ** Send the current environment out to the world.
1090 #define valid_str(x) (((x) != NULL) && (*(x) != 0))
1091 #define NULL_STR "\001\001\001"
1092 #define EMPTY_STR "\001\002\003"
1094 int SPC_Send_Multi_Packet(SPC_Connection_Ptr connection,
1095 protocol_request_ptr prot,
1102 int counter, tmp_len;
1103 int bytes_left, numbytes;
1110 _DtSvcProcessLock();
1111 this_seqno=current_sequence_number;
1112 numbytes=WRITE_ENVIRON_RESET(prot->dataptr, num_str);
1113 bytes_left=SPC_BUFSIZ-numbytes;
1114 buf=(PDRP(prot->dataptr) + numbytes);
1115 reply_seqno=prot->seqno;
1117 for(counter=0; counter<num_str; counter++) {
1118 this_str = str_vect[counter];
1120 if(this_str == NULL)
1121 this_str = NULL_STR;
1122 if(*this_str == NULL)
1123 this_str = EMPTY_STR;
1125 tmp_len=strlen(this_str)+1; /* Room for NULL char */
1126 if((bytes_left-tmp_len) < 1) {
1128 prot->dataptr->len=numbytes+1;
1129 SPC_Write_Single_Prot_Request(connection, name, prot);
1130 SPC_Free_Protocol_Ptr(prot);
1131 prot=SPC_New_Protocol_Ptr(0, req, 0);
1132 prot->seqno=current_sequence_number++;
1134 bytes_left=SPC_BUFSIZ;
1135 buf=(PDRP(prot->dataptr) + numbytes);
1138 if(tmp_len>SPC_BUFSIZ-1) {
1142 SPC_Free_Protocol_Ptr(prot);
1143 if(this_seqno != current_sequence_number)
1144 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1145 _DtSvcProcessUnlock();
1146 return(reply_seqno);
1149 strncpy(buf, this_str, tmp_len);
1150 bytes_left -= tmp_len;
1151 numbytes += tmp_len;
1157 prot->dataptr->len=numbytes+1;
1158 SPC_Write_Single_Prot_Request(connection, (XeString)" <-- ENVIRON_RESET", prot);
1159 SPC_Free_Protocol_Ptr(prot);
1162 _DtSvcProcessUnlock();
1163 return(reply_seqno);
1167 char **SPC_Get_Multi_Packet(SPC_Connection_Ptr connection,
1168 protocol_request_ptr prot,
1175 int num_vars, i, len;
1177 protocol_request_ptr localprot = NULL;
1179 print_protocol_request(name, prot);
1180 READ_ENVIRON_RESET(prot->dataptr, num_vars);
1181 bufptr=strchr(PDRP(prot->dataptr), Space)+1;
1183 out = (char **)malloc((num_vars+1) * sizeof(char **));
1185 for(i=0; i<num_vars; i++) {
1189 SPC_Free_Protocol_Ptr(localprot);
1190 prot=SPC_Filter_Connection(connection, NULL, request, TRUE);
1193 print_protocol_request(name, prot);
1195 bufptr=PDRP(prot->dataptr);
1198 if(strcmp(bufptr, NULL_STR) == 0)
1201 if(strcmp(bufptr, EMPTY_STR) == 0)
1202 out[i] = strdup("");
1204 out[i] = strdup(bufptr);
1209 SPC_Free_Protocol_Ptr(localprot);
1212 out[num_vars] = NULL;
1217 /*----------------------------------------------------------------------+*/
1218 int SPC_Send_Environ(SPC_Connection_Ptr connection,
1219 protocol_request_ptr prot)
1220 /*----------------------------------------------------------------------+*/
1226 _DtSvcProcessLock();
1227 while(environ[ep_count])
1230 result = SPC_Send_Multi_Packet(connection, prot, environ, ep_count,
1231 ENVIRON_RESET, " <-- ENVIRON_RESET",
1233 _DtSvcProcessUnlock();
1237 /*----------------------------------------------------------------------+*/
1238 int sprint_counted_string(XeString buf,
1242 /*----------------------------------------------------------------------+*/
1244 XeString bufptr=buf;
1247 int limit=orig_limit;
1248 #define ERRBUFLEN 100
1249 char errbuf[ERRBUFLEN];
1251 len=sprintf_len(bufptr, (XeString)"%x ", count)+1;
1253 sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1254 SPC_Error(SPC_Arg_Too_Long,
1262 for(i=0; i<count; (i++, vect++)) {
1264 len = strlen(*vect)+1;
1269 sprintf(errbuf, "(%d chars), max. length is %d", len, orig_limit);
1270 SPC_Error(SPC_Arg_Too_Long,
1275 sprintf(bufptr, "%s", *vect ? *vect : "");
1283 /*----------------------------------------------------------------------+*/
1284 XeString *sscan_counted_string(XeString buf,
1286 /*----------------------------------------------------------------------+*/
1289 int i, numstrings, len;
1294 sscanf(buf, (XeString)"%x", &numstrings);
1298 tmpptr=(XeString*)XeMalloc((numstrings+1) * sizeof(XeString *));
1301 for(i=0; i<numstrings; (i++, tmpidx++)){
1302 len=strlen(bufptr)+1; /* len is string SIZE (with room for NULL) */
1303 *tmpidx=(XeString)XeMalloc(len);
1304 strncpy(*tmpidx, bufptr, len);
1305 (*tmpidx)[len-1]=NULL;
1314 /*----------------------------------------------------------------------+*/
1316 sprint_application_data(XeString buf,
1317 XeString UNUSED_PARM(fmt),
1322 int UNUSED_PARM(chars_used))
1323 /*----------------------------------------------------------------------+*/
1333 while(argv[av_count]) av_count++;
1336 while(envp[ep_count]) ep_count++;
1340 tmp_len = sprint_counted_string(buf, 1, &path, limit);
1341 if(tmp_len == SPC_ERROR)
1345 data_len += tmp_len;
1347 tmp_len = sprint_counted_string(buf, 1, &dir, limit);
1348 if(tmp_len == SPC_ERROR)
1352 data_len += tmp_len;
1354 tmp_len = sprint_counted_string(buf, av_count, argv, limit);
1355 if(tmp_len == SPC_ERROR)
1359 data_len += tmp_len;
1361 tmp_len = sprint_counted_string(buf, ep_count, envp, limit);
1362 if(tmp_len == SPC_ERROR)
1366 data_len += tmp_len;
1371 /*----------------------------------------------------------------------+*/
1373 sscan_application_data(XeString buf,
1374 XeString UNUSED_PARM(fmt),
1379 int UNUSED_PARM(offset))
1380 /*----------------------------------------------------------------------+*/
1387 tmp_vect=sscan_counted_string(bufptr, &bufptr);
1388 if(tmp_vect==SPC_ERROR)
1390 *path = (*tmp_vect);
1392 tmp_vect=sscan_counted_string(bufptr, &bufptr);
1393 if(tmp_vect==SPC_ERROR)
1397 *argv=sscan_counted_string(bufptr, &bufptr);
1398 if(*argv==SPC_ERROR)
1401 *envp=sscan_counted_string(bufptr, &bufptr);
1402 if(*envp==SPC_ERROR)
1406 /*----------------------------------------------------------------------+*/
1408 sprint_device_data(XeString buf,
1415 /*----------------------------------------------------------------------+*/
1427 i=sprint_counted_string(buf, 6, args, SPC_BUFSIZ);
1433 /*----------------------------------------------------------------------+*/
1435 sscan_device_data(XeString buf,
1442 /*----------------------------------------------------------------------+*/
1446 args=sscan_counted_string(buf, NULL);
1463 /*----------------------------------------------------------------------+*/
1465 sprint_logfile_data(XeString buf,
1469 /*----------------------------------------------------------------------+*/
1478 i=sprint_counted_string(buf, 3, args, SPC_BUFSIZ);
1484 /*----------------------------------------------------------------------+*/
1486 sscan_logfile_data(XeString buf,
1488 XeString *proto_ver,
1490 /*----------------------------------------------------------------------+*/
1494 args=sscan_counted_string(buf, NULL);
1500 /* args[1] and args[2] will only be around for protocol revision 2 or later */
1502 *proto_ver = *hostinfo = XeString_NULL;
1505 *proto_ver = args[1];
1506 *hostinfo = args[2];
1509 *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);
1516 /*----------------------------------------------------------------------+*/
1518 sprint_register_data(XeString buf,
1523 /*----------------------------------------------------------------------+*/
1533 i=sprint_counted_string(buf, 4, args, SPC_BUFSIZ);
1539 /*----------------------------------------------------------------------+*/
1541 sscan_register_data(XeString buf,
1544 XeString *proto_ver,
1546 /*----------------------------------------------------------------------+*/
1550 args=sscan_counted_string(buf, NULL);
1558 /* args[2] and args[3] will only be around for protocol revision 2 or later */
1560 *proto_ver = *hostinfo = XeString_NULL;
1563 *proto_ver = args[2];
1564 *hostinfo = args[3];
1567 *hostinfo = strdup(SPC_UNKNOWN_HOSTINFO_STR);
1576 ** Request / reply protocol requests
1580 /*----------------------------------------------------------------------+*/
1581 int SPC_Query_Devices(SPC_Channel_Ptr channel)
1582 /*----------------------------------------------------------------------+*/
1584 SPC_Connection_Ptr connection=channel->connection;
1585 protocol_request_ptr prot;
1587 SPC_Write_Protocol_Request(connection, channel, QUERY_DEVICES);
1588 prot=SPC_Filter_Connection(connection, channel, DEVICE_REPLY, TRUE);
1592 READ_DEVICE_REPLY(prot->dataptr,
1593 &(channel->wires[STDIN]->master_name),
1594 &(channel->wires[STDIN]->slave_name),
1595 &(channel->wires[STDOUT]->master_name),
1596 &(channel->wires[STDOUT]->slave_name),
1597 &(channel->wires[STDERR]->master_name),
1598 &(channel->wires[STDERR]->slave_name));
1600 SPC_Free_Protocol_Ptr(prot);
1604 /*----------------------------------------------------------------------+*/
1605 int SPC_Query_Logfile(SPC_Channel_Ptr channel)
1606 /*----------------------------------------------------------------------+*/
1608 SPC_Connection_Ptr connection=channel->connection;
1609 protocol_request_ptr prot;
1610 XeString junk1, junk2;
1612 SPC_Write_Protocol_Request(connection, channel, QUERY_LOGFILE);
1613 prot=SPC_Filter_Connection(connection, channel, LOGFILE_REPLY, TRUE);
1617 READ_LOGFILE_REPLY(prot->dataptr, &channel->logfile, &junk1, &junk2);
1618 if (junk1) XeFree(junk1);
1619 if (junk1) XeFree(junk2);
1621 SPC_Free_Protocol_Ptr(prot);
1625 #define UNK_TOKEN "unknown"
1627 /*----------------------------------------------------------------------+*/
1628 XeString SPC_LocalHostinfo(void)
1629 /*----------------------------------------------------------------------+*/
1631 struct utsname name;
1633 static XeString s = 0;
1635 _DtSvcProcessLock();
1637 if (uname(&name) >= 0) {
1638 s_len = strlen(name.sysname) +
1639 strlen(name.nodename) +
1640 strlen(name.release) +
1641 strlen(name.machine) + 4;
1642 s = (XeString) XeMalloc(s_len * sizeof(XeChar));
1643 sprintf(s, "%s:%s:%s:%s", name.nodename, name.sysname, name.release, name.machine);
1646 s_len = 4 * strlen(UNK_TOKEN) + 4;
1647 s = (XeString) XeMalloc(s_len * sizeof(XeChar));
1648 sprintf(s, "%s:%s:%s:%s", UNK_TOKEN, UNK_TOKEN, UNK_TOKEN, UNK_TOKEN);
1652 _DtSvcProcessUnlock();
1656 /*----------------------------------------------------------------------+*/
1658 SPC_Validate_User(XeString hostname,
1659 SPC_Connection_Ptr connection)
1660 /*----------------------------------------------------------------------+*/
1661 /* Called by client to register itself to spcd */
1663 XeString username = XeString_NULL;
1668 protocol_request_ptr prot;
1669 int open_status, chmod_status;
1670 XeString logfile = NULL;
1671 XeString junk1 = NULL, junk2 = NULL;
1672 XeString connection_hostname=CONNECTION_HOSTNAME(connection);
1673 _Xgetpwparams pwd_buf;
1674 struct passwd * pwd_ret;
1676 hostinfo = SPC_LocalHostinfo();
1679 * We are now including the user ID to generate the LOGFILE
1680 * (i.e., the authentication file)
1684 if((pwd_ret = _XGetpwuid(this_uid, pwd_buf)) == NULL) {
1686 * Very strange situation - the uid isn't in the passwd file
1688 username = XeString_NULL; /* we'll use the original /tmp subdirectory */
1691 username=(XeString)(pwd_ret->pw_name);
1694 SPC_Write_Protocol_Request(connection, NULL, REGISTER,
1695 username, XeString_Empty,
1696 SPC_PROTOCOL_VERSION_STR, hostinfo);
1699 prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1700 if(prot==SPC_ERROR) {
1701 XeFree(connection_hostname);
1705 /* In repsonse to the register, the daemon will send back a LOGFILE_REPLY */
1706 /* message that contains the name of a logfile to be used to do user */
1707 /* authentication. For A.02 and later daemons, it will also contain */
1708 /* the spc protocol version and info about the host the daemon is on. */
1710 READ_LOGFILE_REPLY(prot->dataptr, &logfile, &proto_ver, &hostinfo);
1712 /* For Pre A.01, this will be defaulted to (hpux 7.0 s300) */
1713 connection->hostinfo = hostinfo;
1716 sscanf(proto_ver, "%d", &connection->protocol_version);
1720 SPC_Free_Protocol_Ptr(prot);
1722 if(!strcmp(logfile, PASSED_FILE_NAME))
1724 if(!strcmp(logfile, FAILED_FILE_NAME)) {
1725 SPC_Error(SPC_Register_Username,
1726 (username) ? username : (XeString)"<empty user>",
1727 connection_hostname);
1728 XeFree(connection_hostname);
1729 if (logfile) XeFree(logfile);
1734 * Get a pathname to the authentication file.
1736 path=tt_netfile_file(logfile);
1738 if(tt_ptr_error (path) != TT_OK) {
1739 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1740 SPC_Error(SPC_Register_Netrc,
1742 connection_hostname);
1743 XeFree(connection_hostname);
1744 if (logfile) XeFree(logfile);
1748 open_status=open(path, O_CREAT, S_ISUID);
1749 if(open_status==ERROR) {
1750 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1751 SPC_Error(SPC_Register_Open,
1753 connection_hostname);
1755 XeFree(connection_hostname);
1756 if (logfile) XeFree(logfile);
1760 /* We need to also do a chmod because of an apparent Domain/OS bug
1761 where the open call does not properly set the UID bit. We
1762 let chmod set the bit. */
1764 chmod_status=chmod(path, S_ISUID);
1765 if(chmod_status==ERROR) {
1766 SPC_Write_Protocol_Request(connection, NULL, ABORT);
1767 SPC_Error(SPC_Register_Open,
1769 connection_hostname);
1771 XeFree(connection_hostname);
1772 if (logfile) XeFree(logfile);
1776 SPC_Write_Protocol_Request(connection, NULL, REGISTER, logfile, NULL, NULL, NULL);
1777 prot=SPC_Filter_Connection(connection, NULL, LOGFILE_REPLY, TRUE);
1783 if(prot==SPC_ERROR) {
1784 XeFree(connection_hostname);
1789 * Free logfile before it gets malloc'd again.
1793 READ_LOGFILE_REPLY(prot->dataptr, &logfile, &junk1, &junk2);
1794 if (junk1) XeFree(junk1);
1795 if (junk2) XeFree(junk2);
1797 SPC_Free_Protocol_Ptr(prot);
1799 if(!strcmp(logfile, PASSED_FILE_NAME)) {
1800 XeFree(connection_hostname);
1801 if (logfile) XeFree(logfile);
1804 if(!strcmp(logfile, FAILED_FILE_NAME)) {
1805 SPC_Error(SPC_Register_Handshake,
1807 connection_hostname);
1808 XeFree(connection_hostname);
1809 if (logfile) XeFree(logfile);
1813 if (logfile) XeFree(logfile);
1814 XeFree(connection_hostname);
1815 SPC_Error(SPC_Protocol);
1820 /*----------------------------------------------------------------------+*/
1821 static int SPC_Send_Termios(protocol_request_ptr prot_request)
1822 /*----------------------------------------------------------------------+*/
1824 struct termios *tio;
1828 tio = SPC_Get_Current_Termio(); /* Gets a (malloced) copy */
1829 s = SPC_Decode_Termios( tio ); /* Get ASCII representation */
1831 retval = WRITE_STRING(prot_request->dataptr, s);
1840 /*----------------------------------------------------------------------+*/
1841 int SPC_Get_Termios(protocol_request_ptr prot_request)
1842 /*----------------------------------------------------------------------+*/
1847 _DtSvcProcessLock();
1848 if(XeTermioStruct == NULL) {
1849 XeTermioStruct = (struct termios *)XeMalloc(sizeof(struct termios));
1851 for(i=0; i<NCCS; i++)
1852 XeTermioStruct->c_cc[i] = 0;
1855 READ_STRING_NO_COPY(prot_request->dataptr, s);
1857 SPC_Encode_Termios(s, XeTermioStruct);
1859 _DtSvcProcessUnlock();
1860 return(XeSetpgrp(FALSE));
1865 /*----------------------------------------------------------------------+*/
1866 int SPC_Get_Termio(protocol_request_ptr UNUSED_PARM(prot_request))
1867 /*----------------------------------------------------------------------+*/
1869 /* This is for old 1.0, 1.1 versions of the SPC code. We used to */
1870 /* pass an HPUX version of the termio struct around. This was not */
1871 /* portable. If we get one of these requests, just bit bucket it */
1872 /* as we do not know how to deal with it. */
1874 return(XeSetpgrp(FALSE));
1877 static int SPC_Send_B00_Spawn(SPC_Connection_Ptr connection,
1878 protocol_request_ptr prot,
1885 int num_elts=0, this_elt, num_argv, num_envp;
1886 char argv_buf[20], envp_buf[20];
1890 while(argv && argv[num_argv++])
1894 while(envp && envp[num_envp++])
1897 merged_ptr = (char **)malloc((num_elts+6) * sizeof(char *));
1899 sprintf(argv_buf, "%d", num_argv);
1900 sprintf(envp_buf, "%d", num_envp);
1903 merged_ptr[num_elts++] = path;
1904 merged_ptr[num_elts++] = dir;
1905 merged_ptr[num_elts++] = argv_buf;
1906 merged_ptr[num_elts++] = envp_buf;
1909 while(argv && argv[this_elt])
1910 merged_ptr[num_elts++] = argv[this_elt++];
1912 merged_ptr[num_elts++] = "DUMMY";
1915 while(envp && envp[this_elt])
1916 merged_ptr[num_elts++] = envp[this_elt++];
1918 merged_ptr[num_elts] = NULL;
1920 retval = SPC_Send_Multi_Packet(connection, prot,
1921 merged_ptr, num_elts,
1922 APP_B00_SPAWN, " <-- APP_B00_SPAWN",
1925 free((char *)merged_ptr);