1 /* $NetBSD: scmio.c,v 1.18 2009/10/17 22:26:13 christos Exp $ */
4 * Copyright (c) 1992 Carnegie Mellon University
7 * Permission to use, copy, modify and distribute this software and its
8 * documentation is hereby granted, provided that both the copyright
9 * notice and this permission notice appear in all copies of the
10 * software, derivative works or modified versions, and any portions
11 * thereof, and that both notices appear in supporting documentation.
13 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
14 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
15 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17 * Carnegie Mellon requests users of this software to return to
19 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
20 * School of Computer Science
21 * Carnegie Mellon University
22 * Pittsburgh PA 15213-3890
24 * any improvements or extensions that they make and grant Carnegie Mellon
25 * the rights to redistribute these changes.
28 * SUP Communication Module for 4.3 BSD
30 * SUP COMMUNICATION MODULE SPECIFICATIONS:
37 * writemsg (msg) start message
38 * int msg; message type
39 * writemend () end message and flush data to network
42 * writeint (i) write int
43 * int i; integer to write
44 * writestring (p) write string
45 * char *p; string pointer
46 * writefile (f) write open file
47 * int f; open file descriptor
49 * COMPLETE MESSAGE (start, one data block, end)
50 * writemnull (msg) write message with no data
51 * int msg; message type
52 * writemint (msg,i) write int message
53 * int msg; message type
54 * int i; integer to write
55 * writemstr (msg,p) write string message
56 * int msg; message type
57 * char *p; string pointer
61 * readflush () flush any unread data (close)
62 * readmsg (msg) read specified message type
63 * int msg; message type
64 * readmend () read message end
67 * readskip () skip over one input data block
68 * readint (i) read int
69 * int *i; pointer to integer
70 * readstring (p) read string
71 * char **p; pointer to string pointer
72 * readfile (f) read into open file
73 * int f; open file descriptor
75 * COMPLETE MESSAGE (start, one data block, end)
76 * readmnull (msg) read message with no data
77 * int msg; message type
78 * readmint (msg,i) read int message
79 * int msg; message type
80 * int *i; pointer to integer
81 * readmstr (msg,p) read string message
82 * int msg; message type
83 * char **p; pointer to string pointer
86 * All routines normally return SCMOK. SCMERR may be returned
87 * by any routine on abnormal (usually fatal) errors. An
88 * unexpected MSGGOAWAY will result in SCMEOF being returned.
90 * COMMUNICATION PROTOCOL
91 * Messages always alternate, with the first message after
92 * connecting being sent by the client process.
94 * At the end of the conversation, the client process will
95 * send a message to the server telling it to go away. Then,
96 * both processes will close the network connection.
98 * Any time a process receives a message it does not expect,
99 * the "readmsg" routine will send a MSGGOAWAY message and
102 * Each message has this format:
103 * ---------- ------------ ------------ ----------
104 * |msg type| |count|data| |count|data| ... |ENDCOUNT|
105 * ---------- ------------ ------------ ----------
106 * size: int int var. int var. int
108 * All ints are assumed to be 32-bit quantities. A message
109 * with no data simply has a message type followed by ENDCOUNT.
111 **********************************************************************
113 * Revision 1.7 92/09/09 22:04:41 mrt
114 * Removed the data encryption routines from here to netcrypt.c
117 * Revision 1.6 92/08/11 12:05:57 mrt
118 * Brad's changes: Delinted,Added forward declarations of
119 * static functions. Added copyright.
122 * 27-Dec-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
123 * Added crosspatch support.
125 * 28-Jun-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
126 * Found error in debugging code for readint().
128 * 01-Apr-87 Glenn Marcy (gm0w) at Carnegie-Mellon University
129 * Added code to readdata to "push" data back into the data buffer.
130 * Added prereadcount() to return the message count size after
131 * reading it and then pushing it back into the buffer. Clear
132 * any encryption when a GOAWAY message is detected before reading
133 * the reason string. [V5.19]
135 * 02-Oct-86 Rudy Nedved (ern) at Carnegie-Mellon University
136 * Put a timeout on reading from the network.
138 * 25-May-86 Jonathan J. Chew (jjc) at Carnegie-Mellon University
139 * Renamed "howmany" parameter to routines "encode" and "decode" from
140 * to "count" to avoid conflict with 4.3BSD macro.
142 * 15-Feb-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
143 * Added readflush() to flush any unread data from the input
144 * buffer. Called by requestend() in scm.c module.
146 * 19-Jan-86 Glenn Marcy (gm0w) at Carnegie-Mellon University
147 * Added register variables to decode() for speedup. Added I/O
148 * buffering to reduce the number or read/write system calls.
149 * Removed readmfil/writemfil routines which were not used and were
150 * not compatible with the other similarly defined routines anyway.
152 * 19-Dec-85 Glenn Marcy (gm0w) at Carnegie-Mellon University
153 * Created from scm.c I/O and crypt routines.
155 **********************************************************************
161 #include <sys/types.h>
162 #include <sys/stat.h>
163 #include <sys/file.h>
164 #include <sys/time.h>
165 #include <sys/poll.h>
166 #include "supcdefs.h"
167 #include "supextern.h"
173 /*************************
175 *************************/
178 #define ENDCOUNT (-1) /* end of message marker */
179 #define NULLCOUNT (-2) /* used for sending NULL pointer */
181 #define RETRIES 15 /* # of times to retry io */
182 #define FILEXFER 2048 /* block transfer size */
183 #define XFERSIZE(count) ((count > FILEXFER) ? FILEXFER : count)
185 /*********************************************
186 *** G L O B A L V A R I A B L E S ***
187 *********************************************/
189 extern int netfile
; /* network file descriptor */
191 int scmdebug
; /* scm debug flag */
193 int cryptflag
; /* whether to encrypt/decrypt data */
194 char *cryptbuf
; /* buffer for data encryption/decryption */
196 extern char *goawayreason
; /* reason for goaway message */
199 char b_data
[FILEXFER
]; /* buffered data */
200 char *b_ptr
; /* pointer to end of buffer */
201 int b_cnt
; /* number of bytes in buffer */
203 struct buf
*gblbufptr
; /* buffer pointer */
205 static int writedata(size_t, void *);
206 static int writeblock(size_t, void *);
207 static int readdata(size_t, void *, bool);
208 static int readcount(int *);
211 /***********************************************
212 *** O U T P U T T O N E T W O R K ***
213 ***********************************************/
216 writedata(size_t count
, void *data
)
217 { /* write raw data to network */
222 if (gblbufptr
->b_cnt
+ count
<= FILEXFER
) {
223 memcpy(gblbufptr
->b_ptr
, data
, count
);
224 gblbufptr
->b_cnt
+= count
;
225 gblbufptr
->b_ptr
+= count
;
228 bp
= (gblbufptr
== buffers
) ? &buffers
[1] : buffers
;
229 memcpy(bp
->b_data
, data
, count
);
231 bp
->b_ptr
= bp
->b_data
+ count
;
232 data
= gblbufptr
->b_data
;
233 count
= gblbufptr
->b_cnt
;
234 gblbufptr
->b_cnt
= 0;
235 gblbufptr
->b_ptr
= gblbufptr
->b_data
;
241 x
= write(netfile
, data
, count
);
246 if (++tries
> RETRIES
)
249 logerr("SCM Retrying failed network write");
253 return (scmerr(-1, "Network write timed out"));
255 return (scmerr(errno
, "Write error on network"));
256 return (scmerr(-1, "Write retries failed"));
259 return (scmerr(-1, "Write error on network returned %d "
260 "on write of %zu", x
, count
));
265 writeblock(size_t count
, void *data
)
266 { /* write data block */
268 int y
= byteswap((int)count
);
270 x
= writedata(sizeof(int), &y
);
272 x
= writedata(count
, data
);
278 { /* write start of message */
282 loginfo("SCM Writing message %d", msg
);
284 return (scmerr(-1, "Buffering already enabled"));
286 gblbufptr
->b_ptr
= gblbufptr
->b_data
;
287 gblbufptr
->b_cnt
= 0;
289 return (writedata(sizeof(int), &x
));
294 { /* write end of message */
299 x
= byteswap(ENDCOUNT
);
300 x
= writedata(sizeof(int), &x
);
303 if (gblbufptr
== NULL
)
304 return (scmerr(-1, "Buffering already disabled"));
305 if (gblbufptr
->b_cnt
== 0) {
309 data
= gblbufptr
->b_data
;
310 count
= gblbufptr
->b_cnt
;
312 return (writedata(count
, data
));
317 { /* write int as data block */
320 loginfo("SCM Writing integer %d", i
);
322 return (writeblock(sizeof(int), &x
));
327 { /* write string as data block */
331 int y
= byteswap(NULLCOUNT
);
333 loginfo("SCM Writing string NULL");
334 return (writedata(sizeof(int), &y
));
337 loginfo("SCM Writing string %s", p
);
340 x
= getcryptbuf(len
+ 1);
343 encode(p
, cryptbuf
, len
);
346 return (writeblock((size_t)len
, p
));
351 { /* write open file as a data block */
353 int number
= 0, sum
= 0, filesize
, x
;
357 if (fstat(f
, &statbuf
) < 0)
358 return (scmerr(errno
, "Can't access open file for message"));
359 filesize
= (int)statbuf
.st_size
;
360 y
= byteswap(filesize
);
361 x
= writedata(sizeof(int), &y
);
364 x
= getcryptbuf(FILEXFER
);
369 number
= read(f
, buf
, FILEXFER
);
372 encode(buf
, cryptbuf
, number
);
373 x
= writedata((size_t)number
, cryptbuf
);
375 x
= writedata((size_t)number
, buf
);
379 } while (x
== SCMOK
&& number
> 0);
382 return (scmerr(-1, "File size error on output message"));
384 return (scmerr(errno
, "Read error on file output message"));
390 { /* write message with no data */
399 writemint(int msg
, int i
)
400 { /* write message of one int */
411 writemstr(int msg
, char *p
)
412 { /* write message of one string */
421 /*************************************************
422 *** I N P U T F R O M N E T W O R K ***
423 *************************************************/
426 readdata(size_t count
, void *vdata
, bool push
)
427 { /* read raw data from network */
430 static int bufcnt
= 0;
432 static char buffer
[FILEXFER
];
433 struct pollfd set
[1];
437 if (bufptr
+ count
< buffer
)
438 return (scmerr(-1, "No space in buffer %zu", count
));
441 memcpy(bufptr
, data
, -count
);
444 if (count
== 0 && data
== NULL
) {
448 if (count
<= bufcnt
) {
449 memcpy(data
, bufptr
, count
);
455 memcpy(data
, bufptr
, (size_t)bufcnt
);
462 set
[0].events
= POLLIN
;
467 while ((c
= poll(set
, 1, 2 * 60 * 60 * 1000)) < 1) {
469 return (scmerr(-1, "Timeout on network input"));
473 x
= read(netfile
, p
, (size_t)n
);
475 return (scmerr(-1, "Premature EOF on network input"));
477 return (scmerr(errno
, "Read error on network"));
483 memcpy(data
, bufptr
, (size_t)count
);
490 readcount(int *count
)
491 { /* read count of data block */
494 x
= readdata(sizeof(int), &y
, false);
497 *count
= byteswap(y
);
502 prereadcount(int *count
)
503 { /* preread count of data block */
506 x
= readdata(sizeof(int), &y
, false);
509 x
= readdata(sizeof(int), &y
, true);
512 *count
= byteswap(y
);
519 return readdata(0, NULL
, false);
524 { /* read header for expected message */
525 /* if message is unexpected, send back SCMHUH */
529 loginfo("SCM Reading message %d", msg
);
530 x
= readdata(sizeof(int), &m
, false); /* msg type */
537 /* check for MSGGOAWAY in case he noticed problems first */
539 return (scmerr(-1, "Received unexpected message %d", m
));
540 (void) netcrypt((char *) NULL
);
541 (void) readstring(&goawayreason
);
543 if (goawayreason
== NULL
)
545 logerr("SCM GOAWAY %s", goawayreason
);
554 x
= readdata(sizeof(int), &y
, false);
556 if (x
== SCMOK
&& y
!= ENDCOUNT
)
557 return (scmerr(-1, "Error reading end of message"));
563 { /* skip over one input block */
571 return (scmerr(-1, "Invalid message count %d", n
));
572 while (x
== SCMOK
&& n
> 0) {
573 x
= readdata((size_t)XFERSIZE(n
), buf
, false);
581 { /* read int data block */
588 return (scmerr(-1, "Invalid message count %d", y
));
589 if (y
!= sizeof(int))
590 return (scmerr(-1, "Size error for int message is %d", y
));
591 x
= readdata(sizeof(int), &y
, false);
592 (*buf
) = byteswap(y
);
594 loginfo("SCM Reading integer %d", *buf
);
599 readstring(char **buf
)
600 { /* read string data block */
605 x
= readcount(&count
);
608 if (count
== NULLCOUNT
) {
610 loginfo("SCM Reading string NULL");
615 return (scmerr(-1, "Invalid message count %d", count
));
617 loginfo("SCM Reading string count %d", count
);
618 if ((p
= (char *) malloc((unsigned) count
+ 1)) == NULL
)
619 return (scmerr(-1, "Can't malloc %d bytes for string", count
));
621 x
= getcryptbuf(count
+ 1);
623 x
= readdata((size_t)count
, cryptbuf
, false);
629 printf("SCM Reading encrypted string %s\n", cryptbuf
);
630 decode(cryptbuf
, p
, count
);
632 x
= readdata((size_t)count
, p
, false);
638 p
[count
] = 0; /* NULL at end of string */
641 loginfo("SCM Reading string %s", *buf
);
647 { /* read data block into open file */
653 x
= getcryptbuf(FILEXFER
);
657 x
= readcount(&count
);
661 return (scmerr(-1, "Invalid message count %d", count
));
662 while (x
== SCMOK
&& count
> 0) {
664 x
= readdata((size_t)XFERSIZE(count
), cryptbuf
, false);
666 decode(cryptbuf
, buf
, XFERSIZE(count
));
668 x
= readdata((size_t)XFERSIZE(count
), buf
, false);
670 (void) write(f
, buf
, (size_t)XFERSIZE(count
));
671 count
-= XFERSIZE(count
);
679 { /* read null message */
688 readmint(int msg
, int *buf
)
689 { /* read int message */
700 readmstr(int msg
, char **buf
)
701 { /* read string message */
710 /**********************************
711 *** C R O S S P A T C H ***
712 **********************************/
717 struct pollfd set
[2];
719 char buf
[STRINGLENGTH
];
721 set
[0].fd
= STDIN_FILENO
;
722 set
[0].events
= POLLIN
;
724 set
[1].events
= POLLIN
;
726 if ((c
= poll(set
, 2, INFTIM
)) < 1) {
728 if (errno
== EINTR
) {
735 if (set
[1].revents
& POLLIN
) {
736 c
= read(netfile
, buf
, sizeof(buf
));
737 if (c
< 0 && errno
== EWOULDBLOCK
)
743 (void) write(1, buf
, (size_t)c
);
746 if (set
[0].revents
& POLLIN
) {
747 c
= read(0, buf
, sizeof(buf
));
748 if (c
< 0 && errno
== EWOULDBLOCK
)
753 (void) write(netfile
, buf
, (size_t)c
);