1 // Copyright (c) 1999-2018 David Muse
2 // See the COPYING file for more information
3 
4 //#define DEBUG_PASSFD 1
5 //#define DEBUG_WRITE 1
6 //#define DEBUG_READ 1
7 //#define DEBUG_BUFFERING 1
8 
9 #if defined(DEBUG_PASSFD) || defined(DEBUG_WRITE) || \
10 	defined(DEBUG_READ) || defined(DEBUG_BUFFERING)
11 #ifdef _MSC_VER
12 	#define debugPrintf(ARGS,...) if (this!=&stdoutput) { stdoutput.printf(ARGS,__VA_ARGS__); }
13 #else
14 	#define debugPrintf(ARGS...) if (this!=&stdoutput) { stdoutput.printf(ARGS); }
15 #endif
16 #define debugSafePrint(string) if (this!=&stdoutput) { stdoutput.safePrint(string); }
17 #endif
18 
19 #include <rudiments/filedescriptor.h>
20 #include <rudiments/listener.h>
21 #include <rudiments/charstring.h>
22 #include <rudiments/character.h>
23 #include <rudiments/bytestring.h>
24 #include <rudiments/stringbuffer.h>
25 #include <rudiments/security.h>
26 #if defined(DEBUG_PASSFD) || defined(DEBUG_WRITE) || \
27 		defined(DEBUG_READ) || defined(RUDIMENTS_HAVE_DUPLICATEHANDLE)
28 	#include <rudiments/process.h>
29 #endif
30 #include <rudiments/thread.h>
31 #include <rudiments/semaphoreset.h>
32 #include <rudiments/file.h>
33 #include <rudiments/permissions.h>
34 #include <rudiments/error.h>
35 #include <rudiments/stdio.h>
36 
37 #include <rudiments/private/winsock.h>
38 
39 #ifdef RUDIMENTS_HAVE_IO_H
40 	#include <io.h>
41 #endif
42 #ifdef RUDIMENTS_HAVE_SYS_TIME_H
43 	#include <sys/time.h>
44 #endif
45 #ifdef RUDIMENTS_HAVE_UNISTD_H
46 	#include <unistd.h>
47 #endif
48 #ifdef RUDIMENTS_HAVE_FCNTL_H
49 	#include <fcntl.h>
50 #endif
51 #ifdef RUDIMENTS_HAVE_SYS_FCNTL_H
52 	#include <sys/fcntl.h>
53 #endif
54 #ifdef RUDIMENTS_HAVE_SYS_IOCTL_H
55 	#include <sys/ioctl.h>
56 #endif
57 
58 #include <stdio.h>
59 #if defined(RUDIMENTS_HAVE_VASPRINTF) && defined(RUDIMENTS_HAVE_STDLIB_H)
60 	#include <stdlib.h>
61 #endif
62 
63 // NOTE: These next two headers must be included in this order or LITTLE_ENDIAN
64 // will be multiply-defined on linux libc4 systems.  Other systems are
65 // unaffected.
66 #ifdef RUDIMENTS_HAVE_NETINET_TCP_H
67 	// some libc5 systems need this extern "C" wrapper
68 	extern "C" {
69 	#include <netinet/tcp.h>
70 	}
71 #endif
72 #ifdef RUDIMENTS_HAVE_NETINET_IN_H
73 	#include <netinet/in.h>
74 #endif
75 
76 
77 #ifdef RUDIMENTS_HAVE_SYS_UIO_H
78 	#include <sys/uio.h>
79 #endif
80 #ifdef RUDIMENTS_HAVE_LIMITS_H
81 	#include <limits.h>
82 #endif
83 #ifdef RUDIMENTS_HAVE_ARPA_INET_H
84 	#include <arpa/inet.h>
85 #endif
86 #ifdef RUDIMENTS_HAVE_BYTESWAP_H
87 	#ifdef RUDIMENTS_HAVE_SAFE_BYTESWAP_H_AFTER_NETINET_IN_H
88 		#include <byteswap.h>
89 	#endif
90 #endif
91 #ifdef RUDIMENTS_HAVE_MACHINE_ENDIAN_H
92 	#include <machine/endian.h>
93 #endif
94 #ifdef RUDIMENTS_HAVE_OSSWAPHOSTTOLITTLEINT64
95 	#include <libkern/OSByteOrder.h>
96 #endif
97 #ifdef RUDIMENTS_HAVE_SYS_BYTEORDER_H
98 	#include <sys/byteorder.h>
99 #endif
100 #ifdef RUDIMENTS_HAVE_OS_SUPPORT_BYTEORDER_H
101 	#include <os/support/ByteOrder.h>
102 #endif
103 
104 // apparently on windows, there are no byte-order macros of any kind
105 #ifdef _WIN32
106 	#define __LITTLE_ENDIAN	1234
107 	#define __BIG_ENDIAN	4321
108 	#define __BYTE_ORDER	__LITTLE_ENDIAN
109 #endif
110 
111 // On solaris (and probably others), BYTE_ORDER is undefined (even with
112 // underscore prefixes.  Either _BIG_ENDIAN or _LITTLE_ENDIAN is
113 // defined, but it's just "defined", not set to any value.
114 #if !defined(__BYTE_ORDER) && \
115 	!defined(_BYTE_ORDER) && \
116 	!defined(BYTE_ORDER) && \
117 	(defined(_BIG_ENDIAN) || defined(_LITTLE_ENDIAN))
118 
119 	#define __LITTLE_ENDIAN 1234
120 	#define __BIG_ENDIAN	4321
121 
122 	#ifdef _LITTLE_ENDIAN
123 		#define __BYTE_ORDER	__LITTLE_ENDIAN
124 	#else
125 		#define __BYTE_ORDER	__BIG_ENDIAN
126 	#endif
127 #endif
128 
129 #ifndef __BYTE_ORDER
130 	#if defined(BYTE_ORDER)
131 		#define __BYTE_ORDER BYTE_ORDER
132 	#elif defined (_BYTE_ORDER)
133 		#define __BYTE_ORDER _BYTE_ORDER
134 	#endif
135 #endif
136 
137 #ifndef __BIG_ENDIAN
138 	#if defined(BIG_ENDIAN)
139 		#define __BIG_ENDIAN BIG_ENDIAN
140 	#elif defined(_BIG_ENDIAN)
141 		#define __BIG_ENDIAN _BIG_ENDIAN
142 	#endif
143 #endif
144 
145 #ifndef __LITTLE_ENDIAN
146 	#if defined(LITTLE_ENDIAN)
147 		#define __LITTLE_ENDIAN LITTLE_ENDIAN
148 	#elif defined(_LITTLE_ENDIAN)
149 		#define __LITTLE_ENDIAN _LITTLE_ENDIAN
150 	#endif
151 #endif
152 
153 // for FD_SET (macro that uses memset) on solaris
154 #ifdef RUDIMENTS_HAVE_STRING_H
155 	#include <string.h>
156 #endif
157 
158 #ifdef RUDIMENTS_NEED_XNET_PROTOTYPES
159 extern ssize_t __xnet_recvmsg (int, struct msghdr *, int);
160 extern ssize_t __xnet_sendmsg (int, const struct msghdr *, int);
161 #endif
162 
163 // some platforms (solaris <= 9) don't have these macros
164 #ifndef CMSG_LEN
165 	#ifndef CMSG_ALIGN
166 		#define CMSG_ALIGN(len)	\
167 				(((len) + sizeof(size_t)-1) & \
168 				(size_t)~(sizeof(size_t)-1))
169 	#endif
170 	#define CMSG_LEN(len)	(CMSG_ALIGN(sizeof(struct cmsghdr))+(len))
171 #endif
172 
173 // SCO OpenServer < 5.0.7 has an error in the sys/socket.h header.
174 // Internally, libc supports accrights/accrightslen but the header defines
175 // the struct as having control/controllen components.  This hack works
176 // around the problem.
177 // http://www.linuxmisc.com/9-unix-programmer/af8e2f1e03a2b913.htm
178 #ifdef RUDIMENTS_HAVE_BAD_SCO_MSGHDR
179 	#undef RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN
180 	#define RUDIMENTS_HAVE_MSGHDR_MSG_ACCRIGHTS 1
181 	#define msg_accrights msg_control
182 	#define msg_accrightslen msg_controllen
183 #endif
184 
185 // if SSIZE_MAX is undefined...
186 #ifndef SSIZE_MAX
187 	#if defined(_WIN32)
188 		#define SSIZE_MAX LONG_MAX
189 	#else
190 		// a good safe value that should even work on 16-bit systems
191 		#define SSIZE_MAX 16383
192 	#endif
193 #endif
194 
195 // most platforms FILE struct have a member for the file descriptor,
196 // try to find it...
197 // some platforms, like solaris 11.2 hide it altogether
198 #undef FD
199 #if defined(RUDIMENTS_HAVE_FILE_FILENO)
200 	#define FD f->_fileno
201 #elif defined(RUDIMENTS_HAVE_FILE_FILE)
202 	#ifdef __VMS
203 		#define FD ((struct _iobuf *)f)->_file
204 	#else
205 		#define FD f->_file
206 	#endif
207 #elif defined(RUDIMENTS_HAVE_FILE__FILE)
208 	#define FD f->__file
209 #elif defined(RUDIMENTS_HAVE_FILE_FILEDES)
210 	#define FD f->__filedes
211 #elif defined(RUDIMENTS_HAVE_FILE__FD)
212 	#define FD f->_fd
213 #endif
214 
215 #ifdef RUDIMENTS_HAVE_UNDEFINED_SENDMSG
216 extern "C" ssize_t sendmsg(int, const struct msghdr *,int);
217 #endif
218 
219 #ifdef RUDIMENTS_HAVE_UNDEFINED_RECVMSG
220 extern "C" ssize_t recvmsg(int, struct msghdr *,int);
221 #endif
222 
223 #ifdef RUDIMENTS_HAVE_UNDEFINED_GETPEERNAME
224 extern "C" int getpeername(int, struct sockaddr *,socklen_t *);
225 #endif
226 
227 #ifdef RUDIMENTS_HAVE_UNDEFINED_GETSOCKOPT
228 extern "C" int getsockopt(int, int, int, void *, socklen_t *);
229 #endif
230 
231 #ifdef RUDIMENTS_HAVE_UNDEFINED_SETSOCKOPT
232 extern "C" int setsockopt(int, int, int, const void *, socklen_t);
233 #endif
234 
235 class filedescriptorprivate {
236 	friend class filedescriptor;
237 	private:
238 		bool	_retryinterruptedreads:1;
239 		bool	_retryinterruptedwrites:1;
240 		bool	_retryinterruptedwaits:1;
241 		bool	_retryinterruptedfcntl:1;
242 		bool	_retryinterruptedioctl:1;
243 		bool	_allowshortreads:1;
244 		bool	_allowshortwrites:1;
245 		bool	_translatebyteorder:1;
246 
247 		int32_t	_fd;
248 
249 		securitycontext	*_secctx;
250 
251 		const char	*_type;
252 
253 		listener	*_lstnr;
254 
255 		unsigned char	*_writebuffer;
256 		unsigned char	*_writebufferend;
257 		unsigned char	*_writebufferptr;
258 
259 		unsigned char	*_readbuffer;
260 		unsigned char	*_readbufferend;
261 		unsigned char	*_readbufferhead;
262 		unsigned char	*_readbuffertail;
263 
264 		thread		*_thr;
265 		semaphoreset	*_thrsem;
266 		bool		_threxit;
267 		bool		_threrror;
268 		bool		_asyncwrite;
269 		unsigned char	*_asyncbuf;
270 		uint32_t	_asyncbufsize;
271 		ssize_t		_asynccount;
272 };
273 
filedescriptor()274 filedescriptor::filedescriptor() {
275 	pvt=new filedescriptorprivate;
276 	filedescriptorInit();
277 }
278 
filedescriptor(int32_t fd)279 filedescriptor::filedescriptor(int32_t fd) {
280 	pvt=new filedescriptorprivate;
281 	filedescriptorInit();
282 	setFileDescriptor(fd);
283 }
284 
filedescriptor(const filedescriptor & f)285 filedescriptor::filedescriptor(const filedescriptor &f) {
286 	pvt=new filedescriptorprivate;
287 	filedescriptorClone(f);
288 }
289 
operator =(const filedescriptor & f)290 filedescriptor &filedescriptor::operator=(const filedescriptor &f) {
291 	if (this!=&f) {
292 		delete[] pvt->_writebuffer;
293 		filedescriptorClone(f);
294 	}
295 	return *this;
296 }
297 
filedescriptorInit()298 void filedescriptor::filedescriptorInit() {
299 	setFileDescriptor(-1);
300 	pvt->_retryinterruptedreads=false;
301 	pvt->_retryinterruptedwrites=false;
302 	pvt->_retryinterruptedwaits=true;
303 	pvt->_retryinterruptedfcntl=true;
304 	pvt->_retryinterruptedioctl=true;
305 	pvt->_allowshortreads=false;
306 	pvt->_allowshortwrites=false;
307 	pvt->_translatebyteorder=false;
308 	pvt->_secctx=NULL;
309 	pvt->_type="filedescriptor";
310 	pvt->_lstnr=NULL;
311 	pvt->_writebuffer=NULL;
312 	pvt->_writebufferend=NULL;
313 	pvt->_writebufferptr=NULL;
314 	pvt->_readbuffer=NULL;
315 	pvt->_readbufferend=NULL;
316 	pvt->_readbufferhead=NULL;
317 	pvt->_readbuffertail=NULL;
318 	pvt->_thr=NULL;
319 	pvt->_thrsem=NULL;
320 	pvt->_threxit=false;
321 	pvt->_threrror=false;
322 	pvt->_asyncwrite=false;
323 	pvt->_asyncbuf=NULL;
324 	pvt->_asyncbufsize=0;
325 	pvt->_asynccount=0;
326 }
327 
filedescriptorClone(const filedescriptor & f)328 void filedescriptor::filedescriptorClone(const filedescriptor &f) {
329 	setFileDescriptor(f.pvt->_fd);
330 	pvt->_translatebyteorder=f.pvt->_translatebyteorder;
331 	pvt->_retryinterruptedreads=f.pvt->_retryinterruptedreads;
332 	pvt->_retryinterruptedwrites=f.pvt->_retryinterruptedwrites;
333 	pvt->_retryinterruptedwaits=f.pvt->_retryinterruptedwaits;
334 	pvt->_retryinterruptedfcntl=f.pvt->_retryinterruptedfcntl;
335 	pvt->_retryinterruptedioctl=f.pvt->_retryinterruptedioctl;
336 	pvt->_allowshortreads=f.pvt->_allowshortreads;
337 	pvt->_allowshortwrites=f.pvt->_allowshortwrites;
338 	pvt->_secctx=f.pvt->_secctx;
339 	if (f.pvt->_writebuffer) {
340 		ssize_t	writebuffersize=f.pvt->_writebufferend-
341 						f.pvt->_writebuffer;
342 		pvt->_writebuffer=new unsigned char[writebuffersize];
343 		bytestring::copy(pvt->_writebuffer,
344 				f.pvt->_writebuffer,
345 				writebuffersize);
346 		pvt->_writebufferend=pvt->_writebuffer+writebuffersize;
347 		pvt->_writebufferptr=pvt->_writebuffer+
348 				(f.pvt->_writebufferptr-f.pvt->_writebuffer);
349 	} else {
350 		pvt->_writebuffer=NULL;
351 		pvt->_writebufferend=NULL;
352 		pvt->_writebufferptr=NULL;
353 	}
354 	pvt->_lstnr=NULL;
355 }
356 
~filedescriptor()357 filedescriptor::~filedescriptor() {
358 
359 	// see NOTE in ~threadmutex()
360 
361 	if (!pvt) {
362 		return;
363 	}
364 
365 	if (pvt->_thr) {
366 
367 		if (pvt->_thrsem) {
368 			pvt->_thrsem->wait(1);
369 			pvt->_threxit=true;
370 			pvt->_thrsem->signal(0);
371 			semaphoreset	*tmpthrsem=pvt->_thrsem;
372 			pvt->_thrsem=NULL;
373 			delete tmpthrsem;
374 		}
375 
376 		pvt->_thr->wait(NULL);
377 		thread	*tmpthr=pvt->_thr;
378 		pvt->_thr=NULL;
379 		delete tmpthr;
380 
381 		unsigned char	*tmpasyncbuf=pvt->_asyncbuf;
382 		pvt->_asyncbuf=NULL;
383 		delete[] tmpasyncbuf;
384 	}
385 
386 	unsigned char	*tmpbuffer=pvt->_readbuffer;
387 	pvt->_readbuffer=NULL;
388 	delete[] tmpbuffer;
389 
390 	tmpbuffer=pvt->_writebuffer;
391 	pvt->_writebuffer=NULL;
392 	delete[] tmpbuffer;
393 
394 	listener	*tmplstnr=pvt->_lstnr;
395 	pvt->_lstnr=NULL;
396 	delete tmplstnr;
397 
398 	close();
399 
400 	filedescriptorprivate	*tmppvt=pvt;
401 	pvt=NULL;
402 	delete tmppvt;
403 }
404 
setWriteBufferSize(ssize_t size) const405 bool filedescriptor::setWriteBufferSize(ssize_t size) const {
406 
407 	if (size>SSIZE_MAX) {
408 		size=SSIZE_MAX;
409 	}
410 
411 	#if defined(DEBUG_WRITE) && defined(DEBUG_BUFFERING)
412 		debugPrintf("setting write buffer size to %d\n",size);
413 	#endif
414 
415 	if (size<0) {
416 		#if defined(DEBUG_WRITE) && defined(DEBUG_BUFFERING)
417 			debugPrintf("invalid size: %d\n",size);
418 		#endif
419 		return false;
420 	}
421 
422 	delete[] pvt->_writebuffer;
423 	pvt->_writebuffer=(size)?new unsigned char[size]:NULL;
424 	pvt->_writebufferend=pvt->_writebuffer+size;
425 	pvt->_writebufferptr=pvt->_writebuffer;
426 
427 	#if defined(DEBUG_WRITE) && defined(DEBUG_BUFFERING)
428 		debugPrintf("done setting write buffer size\n");
429 	#endif
430 	return true;
431 }
432 
setReadBufferSize(ssize_t size) const433 bool filedescriptor::setReadBufferSize(ssize_t size) const {
434 
435 	if (size>SSIZE_MAX) {
436 		size=SSIZE_MAX;
437 	}
438 
439 	#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
440 		debugPrintf("setting read buffer size to %d\n",size);
441 	#endif
442 
443 	if (size<0) {
444 		#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
445 			debugPrintf("invalid size: %d\n",size);
446 		#endif
447 		return false;
448 	}
449 
450 	delete[] pvt->_readbuffer;
451 	pvt->_readbuffer=(size)?new unsigned char[size]:NULL;
452 	pvt->_readbufferend=pvt->_readbuffer+size;
453 	pvt->_readbufferhead=pvt->_readbuffer;
454 	pvt->_readbuffertail=pvt->_readbuffer;
455 
456 	#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
457 		debugPrintf("done setting read buffer size\n");
458 	#endif
459 	return true;
460 }
461 
getFileDescriptor() const462 int32_t filedescriptor::getFileDescriptor() const {
463 	return pvt->_fd;
464 }
465 
setFileDescriptor(int32_t filedesc)466 void filedescriptor::setFileDescriptor(int32_t filedesc) {
467 	pvt->_fd=filedesc;
468 }
469 
duplicate() const470 int32_t filedescriptor::duplicate() const {
471 	int32_t	result;
472 	error::clearError();
473 	do {
474 		#if defined(RUDIMENTS_HAVE__DUP)
475 			result=_dup(pvt->_fd);
476 		#elif defined(RUDIMENTS_HAVE_DUP)
477 			result=dup(pvt->_fd);
478 		#else
479 			#error no dup or anything like it
480 		#endif
481 	} while (result==-1 && error::getErrorNumber()==EINTR);
482 	return result;
483 }
484 
duplicate(int32_t newfd) const485 bool filedescriptor::duplicate(int32_t newfd) const {
486 	int32_t	result;
487 	error::clearError();
488 	do {
489 		#if defined(RUDIMENTS_HAVE__DUP2)
490 			result=_dup2(pvt->_fd,newfd);
491 		#elif defined(RUDIMENTS_HAVE_DUP2)
492 			result=dup2(pvt->_fd,newfd);
493 		#else
494 			#error no dup2 or anything like it
495 		#endif
496 	} while (result==-1 && error::getErrorNumber()==EINTR);
497 	return (result==newfd);
498 }
499 
setSecurityContext(securitycontext * ctx)500 void filedescriptor::setSecurityContext(securitycontext *ctx) {
501 	pvt->_secctx=ctx;
502 }
503 
getSecurityContext()504 securitycontext *filedescriptor::getSecurityContext() {
505 	return pvt->_secctx;
506 }
507 
supportsBlockingNonBlockingModes()508 bool filedescriptor::supportsBlockingNonBlockingModes() {
509 	#if defined(RUDIMENTS_HAVE_FCNTL) && \
510 		defined(F_SETFL) && defined (F_GETFL)
511 		return true;
512 	#else
513 		return false;
514 	#endif
515 }
516 
useNonBlockingMode() const517 bool filedescriptor::useNonBlockingMode() const {
518 	#if defined(RUDIMENTS_HAVE_FCNTL) && \
519 		defined(F_SETFL) && defined (F_GETFL)
520 		return (fCntl(F_SETFL,fCntl(F_GETFL,0)|O_NONBLOCK)!=-1);
521 	#else
522 		return false;
523 	#endif
524 }
525 
useBlockingMode() const526 bool filedescriptor::useBlockingMode() const {
527 	#if defined(RUDIMENTS_HAVE_FCNTL) && \
528 		defined(F_SETFL) && defined (F_GETFL)
529 		return (fCntl(F_SETFL,fCntl(F_GETFL,0)&(~O_NONBLOCK))!=-1);
530 	#else
531 		return false;
532 	#endif
533 }
534 
isUsingNonBlockingMode() const535 bool filedescriptor::isUsingNonBlockingMode() const {
536 	#if defined(RUDIMENTS_HAVE_FCNTL) && defined(F_GETFL)
537 		return (fCntl(F_GETFL,0)&O_NONBLOCK);
538 	#else
539 		return false;
540 	#endif
541 }
542 
useAsyncWrite()543 void filedescriptor::useAsyncWrite() {
544 	pvt->_asyncwrite=true;
545 }
546 
dontUseAsyncWrite()547 void filedescriptor::dontUseAsyncWrite() {
548 	pvt->_asyncwrite=false;
549 }
550 
write(uint16_t number)551 ssize_t filedescriptor::write(uint16_t number) {
552 	return write(number,-1,-1);
553 }
554 
write(uint32_t number)555 ssize_t filedescriptor::write(uint32_t number) {
556 	return write(number,-1,-1);
557 }
558 
write(uint64_t number)559 ssize_t filedescriptor::write(uint64_t number) {
560 	return write(number,-1,-1);
561 }
562 
write(int16_t number)563 ssize_t filedescriptor::write(int16_t number) {
564 	return write(number,-1,-1);
565 }
566 
write(int32_t number)567 ssize_t filedescriptor::write(int32_t number) {
568 	return write(number,-1,-1);
569 }
570 
write(int64_t number)571 ssize_t filedescriptor::write(int64_t number) {
572 	return write(number,-1,-1);
573 }
574 
write(float number)575 ssize_t filedescriptor::write(float number) {
576 	return write(number,-1,-1);
577 }
578 
write(double number)579 ssize_t filedescriptor::write(double number) {
580 	return write(number,-1,-1);
581 }
582 
write(unsigned char character)583 ssize_t filedescriptor::write(unsigned char character) {
584 	return write(character,-1,-1);
585 }
586 
write(bool value)587 ssize_t filedescriptor::write(bool value) {
588 	return write(value,-1,-1);
589 }
590 
write(char character)591 ssize_t filedescriptor::write(char character) {
592 	return write(character,-1,-1);
593 }
594 
write(const unsigned char * string,size_t size)595 ssize_t filedescriptor::write(const unsigned char *string, size_t size) {
596 	return write(string,size,-1,-1);
597 }
598 
write(const char * string,size_t size)599 ssize_t filedescriptor::write(const char *string, size_t size) {
600 	return write(string,size,-1,-1);
601 }
602 
write(const unsigned char * string)603 ssize_t filedescriptor::write(const unsigned char *string) {
604 	return write(string,charstring::length(string),-1,-1);
605 }
606 
write(const char * string)607 ssize_t filedescriptor::write(const char *string) {
608 	return write(string,charstring::length(string),-1,-1);
609 }
610 
write(const void * buffer,size_t size)611 ssize_t filedescriptor::write(const void *buffer, size_t size) {
612 	return write(buffer,size,-1,-1);
613 }
614 
write(uint16_t number,int32_t sec,int32_t usec)615 ssize_t filedescriptor::write(uint16_t number, int32_t sec, int32_t usec) {
616 	if (pvt->_translatebyteorder) {
617 		number=hostToNet(number);
618 	}
619 	return bufferedWrite(&number,sizeof(uint16_t),sec,usec);
620 }
621 
write(uint32_t number,int32_t sec,int32_t usec)622 ssize_t filedescriptor::write(uint32_t number, int32_t sec, int32_t usec) {
623 	if (pvt->_translatebyteorder) {
624 		number=hostToNet(number);
625 	}
626 	return bufferedWrite(&number,sizeof(uint32_t),sec,usec);
627 }
628 
write(uint64_t number,int32_t sec,int32_t usec)629 ssize_t filedescriptor::write(uint64_t number, int32_t sec, int32_t usec) {
630 	if (pvt->_translatebyteorder) {
631 		number=hostToNet(number);
632 	}
633 	return bufferedWrite(&number,sizeof(uint64_t),sec,usec);
634 }
635 
write(int16_t number,int32_t sec,int32_t usec)636 ssize_t filedescriptor::write(int16_t number, int32_t sec, int32_t usec) {
637 	if (pvt->_translatebyteorder) {
638 		number=hostToNet((uint16_t)number);
639 	}
640 	return bufferedWrite(&number,sizeof(int16_t),sec,usec);
641 }
642 
write(int32_t number,int32_t sec,int32_t usec)643 ssize_t filedescriptor::write(int32_t number, int32_t sec, int32_t usec) {
644 	if (pvt->_translatebyteorder) {
645 		number=hostToNet((uint32_t)number);
646 	}
647 	return bufferedWrite(&number,sizeof(int32_t),sec,usec);
648 }
649 
write(int64_t number,int32_t sec,int32_t usec)650 ssize_t filedescriptor::write(int64_t number, int32_t sec, int32_t usec) {
651 	if (pvt->_translatebyteorder) {
652 		number=hostToNet((uint64_t)number);
653 	}
654 	return bufferedWrite(&number,sizeof(int64_t),sec,usec);
655 }
656 
write(float number,int32_t sec,int32_t usec)657 ssize_t filedescriptor::write(float number, int32_t sec,int32_t usec) {
658 	return bufferedWrite(&number,sizeof(float),sec,usec);
659 }
660 
write(double number,int32_t sec,int32_t usec)661 ssize_t filedescriptor::write(double number, int32_t sec, int32_t usec) {
662 	return bufferedWrite(&number,sizeof(double),sec,usec);
663 }
664 
write(unsigned char character,int32_t sec,int32_t usec)665 ssize_t filedescriptor::write(unsigned char character,
666 				int32_t sec, int32_t usec) {
667 	return bufferedWrite(&character,sizeof(unsigned char),sec,usec);
668 }
669 
write(bool value,int32_t sec,int32_t usec)670 ssize_t filedescriptor::write(bool value, int32_t sec, int32_t usec) {
671 	return bufferedWrite(&value,sizeof(bool),sec,usec);
672 }
673 
write(char character,int32_t sec,int32_t usec)674 ssize_t filedescriptor::write(char character, int32_t sec, int32_t usec) {
675 	return bufferedWrite(&character,sizeof(char),sec,usec);
676 }
677 
write(const unsigned char * string,size_t size,int32_t sec,int32_t usec)678 ssize_t filedescriptor::write(const unsigned char *string, size_t size,
679 						int32_t sec, int32_t usec) {
680 	return bufferedWrite(string,size,sec,usec);
681 }
682 
write(const char * string,size_t size,int32_t sec,int32_t usec)683 ssize_t filedescriptor::write(const char *string, size_t size,
684 					int32_t sec, int32_t usec) {
685 	return bufferedWrite(string,size,sec,usec);
686 }
687 
write(const unsigned char * string,int32_t sec,int32_t usec)688 ssize_t filedescriptor::write(const unsigned char *string,
689 					int32_t sec, int32_t usec) {
690 	return bufferedWrite(string,charstring::length(string),sec,usec);
691 }
692 
write(const char * string,int32_t sec,int32_t usec)693 ssize_t filedescriptor::write(const char *string,
694 					int32_t sec, int32_t usec) {
695 	return bufferedWrite(string,charstring::length(string),sec,usec);
696 }
697 
write(const void * buffer,size_t size,int32_t sec,int32_t usec)698 ssize_t filedescriptor::write(const void *buffer, size_t size,
699 					int32_t sec, int32_t usec) {
700 	return bufferedWrite(buffer,size,sec,usec);
701 }
702 
read(uint16_t * buffer)703 ssize_t filedescriptor::read(uint16_t *buffer) {
704 	return read(buffer,-1,-1);
705 }
706 
read(uint32_t * buffer)707 ssize_t filedescriptor::read(uint32_t *buffer) {
708 	return read(buffer,-1,-1);
709 }
710 
read(uint64_t * buffer)711 ssize_t filedescriptor::read(uint64_t *buffer) {
712 	return read(buffer,-1,-1);
713 }
714 
read(int16_t * buffer)715 ssize_t filedescriptor::read(int16_t *buffer) {
716 	return read(buffer,-1,-1);
717 }
718 
read(int32_t * buffer)719 ssize_t filedescriptor::read(int32_t *buffer) {
720 	return read(buffer,-1,-1);
721 }
722 
read(int64_t * buffer)723 ssize_t filedescriptor::read(int64_t *buffer) {
724 	return read(buffer,-1,-1);
725 }
726 
read(float * buffer)727 ssize_t filedescriptor::read(float *buffer) {
728 	return read(buffer,-1,-1);
729 }
730 
read(double * buffer)731 ssize_t filedescriptor::read(double *buffer) {
732 	return read(buffer,-1,-1);
733 }
734 
read(unsigned char * buffer)735 ssize_t filedescriptor::read(unsigned char *buffer) {
736 	return read(buffer,-1,-1);
737 }
738 
read(bool * buffer)739 ssize_t filedescriptor::read(bool *buffer) {
740 	return read(buffer,-1,-1);
741 }
742 
read(char * buffer)743 ssize_t filedescriptor::read(char *buffer) {
744 	return read(buffer,-1,-1);
745 }
746 
read(unsigned char * buffer,size_t size)747 ssize_t filedescriptor::read(unsigned char *buffer, size_t size) {
748 	return read(buffer,size,-1,-1);
749 }
750 
read(char * buffer,size_t size)751 ssize_t filedescriptor::read(char *buffer, size_t size) {
752 	return read(buffer,size,-1,-1);
753 }
754 
read(void * buffer,size_t size)755 ssize_t filedescriptor::read(void *buffer, size_t size) {
756 	return read(buffer,size,-1,-1);
757 }
758 
read(char ** buffer,const char * terminator)759 ssize_t filedescriptor::read(char **buffer, const char *terminator) {
760 	return read(buffer,terminator,0,'\0',-1,-1);
761 }
762 
read(char ** buffer,const char * terminator,size_t maxbytes)763 ssize_t filedescriptor::read(char **buffer,
764 				const char *terminator, size_t maxbytes) {
765 	return read(buffer,terminator,maxbytes,'\0',-1,-1);
766 }
767 
read(char ** buffer,const char * terminator,int32_t sec,int32_t usec)768 ssize_t filedescriptor::read(char **buffer, const char *terminator,
769 						int32_t sec, int32_t usec) {
770 	return read(buffer,terminator,0,'\0',sec,usec);
771 }
772 
read(uint16_t * buffer,int32_t sec,int32_t usec)773 ssize_t filedescriptor::read(uint16_t *buffer,
774 				int32_t sec, int32_t usec) {
775 	ssize_t	retval=bufferedRead(buffer,sizeof(uint16_t),sec,usec);
776 	if (pvt->_translatebyteorder) {
777 		*buffer=netToHost(*buffer);
778 	}
779 	return retval;
780 }
781 
read(uint32_t * buffer,int32_t sec,int32_t usec)782 ssize_t filedescriptor::read(uint32_t *buffer,
783 				int32_t sec, int32_t usec) {
784 	ssize_t	retval=bufferedRead(buffer,sizeof(uint32_t),sec,usec);
785 	if (pvt->_translatebyteorder) {
786 		*buffer=netToHost(*buffer);
787 	}
788 	return retval;
789 }
790 
read(uint64_t * buffer,int32_t sec,int32_t usec)791 ssize_t filedescriptor::read(uint64_t *buffer,
792 				int32_t sec, int32_t usec) {
793 	ssize_t	retval=bufferedRead(buffer,sizeof(uint64_t),sec,usec);
794 	if (pvt->_translatebyteorder) {
795 		*buffer=netToHost(*buffer);
796 	}
797 	return retval;
798 }
799 
read(int16_t * buffer,int32_t sec,int32_t usec)800 ssize_t filedescriptor::read(int16_t *buffer,
801 				int32_t sec, int32_t usec) {
802 	ssize_t	retval=bufferedRead(buffer,sizeof(int16_t),sec,usec);
803 	if (pvt->_translatebyteorder) {
804 		*buffer=netToHost((uint16_t)*buffer);
805 	}
806 	return retval;
807 }
808 
read(int32_t * buffer,int32_t sec,int32_t usec)809 ssize_t filedescriptor::read(int32_t *buffer,
810 				int32_t sec, int32_t usec) {
811 	ssize_t	retval=bufferedRead(buffer,sizeof(int32_t),sec,usec);
812 	if (pvt->_translatebyteorder) {
813 		*buffer=netToHost((uint32_t)*buffer);
814 	}
815 	return retval;
816 }
817 
read(int64_t * buffer,int32_t sec,int32_t usec)818 ssize_t filedescriptor::read(int64_t *buffer,
819 				int32_t sec, int32_t usec) {
820 	ssize_t	retval=bufferedRead(buffer,sizeof(int64_t),sec,usec);
821 	if (pvt->_translatebyteorder) {
822 		*buffer=netToHost((uint64_t)*buffer);
823 	}
824 	return retval;
825 }
826 
read(float * buffer,int32_t sec,int32_t usec)827 ssize_t filedescriptor::read(float *buffer,
828 				int32_t sec, int32_t usec) {
829 	return bufferedRead(buffer,sizeof(float),sec,usec);
830 }
831 
read(double * buffer,int32_t sec,int32_t usec)832 ssize_t filedescriptor::read(double *buffer,
833 				int32_t sec, int32_t usec) {
834 	return bufferedRead(buffer,sizeof(double),sec,usec);
835 }
836 
read(unsigned char * buffer,int32_t sec,int32_t usec)837 ssize_t filedescriptor::read(unsigned char *buffer,
838 				int32_t sec, int32_t usec) {
839 	return bufferedRead(buffer,sizeof(unsigned char),sec,usec);
840 }
841 
read(bool * buffer,int32_t sec,int32_t usec)842 ssize_t filedescriptor::read(bool *buffer,
843 				int32_t sec, int32_t usec) {
844 	return bufferedRead(buffer,sizeof(bool),sec,usec);
845 }
846 
read(char * buffer,int32_t sec,int32_t usec)847 ssize_t filedescriptor::read(char *buffer,
848 				int32_t sec, int32_t usec) {
849 	return bufferedRead(buffer,sizeof(char),sec,usec);
850 }
851 
read(unsigned char * buffer,size_t size,int32_t sec,int32_t usec)852 ssize_t filedescriptor::read(unsigned char *buffer, size_t size,
853 					int32_t sec, int32_t usec) {
854 	return bufferedRead(buffer,size,sec,usec);
855 }
856 
read(char * buffer,size_t size,int32_t sec,int32_t usec)857 ssize_t filedescriptor::read(char *buffer, size_t size,
858 					int32_t sec, int32_t usec) {
859 	return bufferedRead(buffer,size,sec,usec);
860 }
861 
read(void * buffer,size_t size,int32_t sec,int32_t usec)862 ssize_t filedescriptor::read(void *buffer, size_t size,
863 					int32_t sec, int32_t usec) {
864 	return bufferedRead(buffer,size,sec,usec);
865 }
866 
close()867 bool filedescriptor::close() {
868 	if (pvt->_fd!=-1) {
869 		int32_t	result;
870 		error::clearError();
871 		do {
872 			result=lowLevelClose();
873 		} while (result==-1 && error::getErrorNumber()==EINTR);
874 		if (result==-1) {
875 			return false;
876 		}
877 		setFileDescriptor(-1);
878 	}
879 	return true;
880 }
881 
lowLevelClose()882 int32_t filedescriptor::lowLevelClose() {
883 	#if defined(RUDIMENTS_HAVE__CLOSE)
884 		return _close(pvt->_fd);
885 	#elif defined(RUDIMENTS_HAVE_CLOSE)
886 		return ::close(pvt->_fd);
887 	#else
888 		#error no close or anything like it
889 	#endif
890 }
891 
retryInterruptedReads()892 void filedescriptor::retryInterruptedReads() {
893 	pvt->_retryinterruptedreads=true;
894 }
895 
dontRetryInterruptedReads()896 void filedescriptor::dontRetryInterruptedReads() {
897 	pvt->_retryinterruptedreads=false;
898 }
899 
getRetryInterruptedReads() const900 bool filedescriptor::getRetryInterruptedReads() const {
901 	return pvt->_retryinterruptedreads;
902 }
903 
retryInterruptedWrites()904 void filedescriptor::retryInterruptedWrites() {
905 	pvt->_retryinterruptedwrites=true;
906 }
907 
dontRetryInterruptedWrites()908 void filedescriptor::dontRetryInterruptedWrites() {
909 	pvt->_retryinterruptedwrites=false;
910 }
911 
getRetryInterruptedWrites() const912 bool filedescriptor::getRetryInterruptedWrites() const {
913 	return pvt->_retryinterruptedwrites;
914 }
915 
retryInterruptedWaits()916 void filedescriptor::retryInterruptedWaits() {
917 	pvt->_retryinterruptedwaits=true;
918 }
919 
dontRetryInterruptedWaits()920 void filedescriptor::dontRetryInterruptedWaits() {
921 	pvt->_retryinterruptedwaits=false;
922 }
923 
getRetryInterruptedWaits() const924 bool filedescriptor::getRetryInterruptedWaits() const {
925 	return pvt->_retryinterruptedwaits;
926 }
927 
retryInterruptedFcntl()928 void filedescriptor::retryInterruptedFcntl() {
929 	pvt->_retryinterruptedfcntl=true;
930 }
931 
dontRetryInterruptedFcntl()932 void filedescriptor::dontRetryInterruptedFcntl() {
933 	pvt->_retryinterruptedfcntl=true;
934 }
935 
getRetryInterruptedFcntl() const936 bool filedescriptor::getRetryInterruptedFcntl() const {
937 	return pvt->_retryinterruptedfcntl;
938 }
939 
retryInterruptedIoctl()940 void filedescriptor::retryInterruptedIoctl() {
941 	pvt->_retryinterruptedioctl=true;
942 }
943 
dontRetryInterruptedIoctl()944 void filedescriptor::dontRetryInterruptedIoctl() {
945 	pvt->_retryinterruptedioctl=true;
946 }
947 
getRetryInterruptedIoctl() const948 bool filedescriptor::getRetryInterruptedIoctl() const {
949 	return pvt->_retryinterruptedioctl;
950 }
951 
allowShortReads()952 void filedescriptor::allowShortReads() {
953 	pvt->_allowshortreads=true;
954 }
955 
dontAllowShortReads()956 void filedescriptor::dontAllowShortReads() {
957 	pvt->_allowshortreads=false;
958 }
959 
allowShortWrites()960 void filedescriptor::allowShortWrites() {
961 	pvt->_allowshortwrites=true;
962 }
963 
dontAllowShortWrites()964 void filedescriptor::dontAllowShortWrites() {
965 	pvt->_allowshortwrites=false;
966 }
967 
read(char ** buffer,const char * terminator,size_t maxbytes,int32_t sec,int32_t usec)968 ssize_t filedescriptor::read(char **buffer, const char *terminator,
969 				size_t maxbytes, int32_t sec, int32_t usec) {
970 	return read(buffer,terminator,maxbytes,'\0',sec,usec);
971 }
972 
read(char ** buffer,const char * terminator,size_t maxbytes,char escapechar,int32_t sec,int32_t usec)973 ssize_t filedescriptor::read(char **buffer, const char *terminator,
974 				size_t maxbytes, char escapechar,
975 				int32_t sec, int32_t usec) {
976 
977 	// initialize the return buffer
978 	if (buffer) {
979 		*buffer=NULL;
980 	}
981 
982 	// initialize a temp buffer
983 	stringbuffer	temp;
984 
985 	// initialize termination detector
986 	int32_t	termlen=charstring::length(terminator);
987 	char	*term=new char[termlen];
988 	bytestring::zero(term,termlen);
989 
990 	// initialize some variables
991 	ssize_t	sizeread;
992 	char	charbuffer;
993 	bool	escaped=false;
994 	bool	copytobuffer;
995 	bool	copytoterm;
996 	ssize_t	retval=RESULT_SUCCESS;
997 
998 	// loop, getting 1 character at a time
999 	for (;;) {
1000 
1001 		// read from the file descriptor
1002 		sizeread=read(&charbuffer,sec,usec);
1003 		if (sizeread<=0) {
1004 			retval=sizeread;
1005 			break;
1006 		}
1007 
1008 		// handle escaping
1009 		if (escaped) {
1010 			copytobuffer=true;
1011 			copytoterm=false;
1012 			escaped=false;
1013 		} else {
1014 			escaped=((escapechar!='\0')?
1015 					(charbuffer==escapechar):false);
1016 			copytobuffer=!escaped;
1017 			copytoterm=!escaped;
1018 		}
1019 
1020 		// copy to return buffer
1021 		if (copytobuffer && buffer) {
1022 			temp.append(charbuffer);
1023 		}
1024 
1025 		if (copytoterm) {
1026 
1027 			// update terminator detector
1028 			for (int32_t i=0; i<termlen-1; i++) {
1029 				term[i]=term[i+1];
1030 			}
1031 			term[termlen-1]=charbuffer;
1032 
1033 			// check for termination
1034 			if (!charstring::compare(term,terminator,termlen)) {
1035 				break;
1036 			}
1037 
1038 		} else {
1039 
1040 			// clear terminator
1041 			bytestring::zero(term,termlen);
1042 		}
1043 
1044 		// max-bytes-read condition
1045 		if (maxbytes && temp.getSize()>maxbytes) {
1046 			retval=RESULT_MAX;
1047 			break;
1048 		}
1049 	}
1050 
1051 	if (retval>=RESULT_SUCCESS) {
1052 
1053 		// get the size to return
1054 		retval=temp.getSize();
1055 
1056 		// set the return buffer
1057 		if (buffer) {
1058 			*buffer=temp.detachString();
1059 		}
1060 	}
1061 
1062 	// clean up
1063 	delete[] term;
1064 
1065 	return retval;
1066 }
1067 
bufferedRead(void * buf,ssize_t count,int32_t sec,int32_t usec)1068 ssize_t filedescriptor::bufferedRead(void *buf, ssize_t count,
1069 					int32_t sec, int32_t usec) {
1070 
1071 	#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
1072 	debugPrintf("bufferedRead of %d bytes\n",(int)count);
1073 	#endif
1074 
1075 	if (!count) {
1076 		return 0;
1077 	}
1078 
1079 	if (!pvt->_readbuffer) {
1080 		#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
1081 		debugPrintf("no read buffer...\n");
1082 		#endif
1083 		return safeRead(buf,count,sec,usec);
1084 	}
1085 
1086 	unsigned char	*data=(unsigned char *)buf;
1087 	ssize_t		bytesread=0;
1088 	ssize_t		bytesunread=count;
1089 
1090 	for (;;) {
1091 
1092 		// copy what we can from the buffer
1093 		ssize_t	bytesavailabletocopy=pvt->_readbuffertail-
1094 						pvt->_readbufferhead;
1095 		if (bytesavailabletocopy) {
1096 
1097 			#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
1098 			debugPrintf("%d bytes in read buffer\n",
1099 						(int)bytesavailabletocopy);
1100 			#endif
1101 
1102 			ssize_t	bytestocopy=(bytesavailabletocopy<bytesunread)?
1103 						bytesavailabletocopy:
1104 						bytesunread;
1105 
1106 			#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
1107 			debugPrintf("copying %d bytes "
1108 						"out of read buffer\n",
1109 						(int)bytestocopy);
1110 			#endif
1111 
1112 			bytestring::copy(data,pvt->_readbufferhead,bytestocopy);
1113 			data=data+bytestocopy;
1114 			bytesread=bytesread+bytestocopy;
1115 			pvt->_readbufferhead=pvt->_readbufferhead+bytestocopy;
1116 			bytesunread=bytesunread-bytestocopy;
1117 
1118 			// return if we've read enough
1119 			if (bytesread==count) {
1120 				#if defined(DEBUG_READ) && \
1121 					 defined(DEBUG_BUFFERING)
1122 				debugPrintf("yay, we're done reading\n");
1123 				#endif
1124 				return bytesread;
1125 			}
1126 
1127 			#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
1128 			debugPrintf("need to read %d more bytes\n",
1129 							(int)bytesunread);
1130 			#endif
1131 		}
1132 
1133 		// if we've copied out everything in the buffer, read some more
1134 		if (pvt->_readbufferhead==pvt->_readbuffertail) {
1135 
1136 			#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
1137 			debugPrintf("attempting to fill read buffer, ");
1138 			debugPrintf("reading %d bytes...\n",
1139 						(int)(pvt->_readbufferend-
1140 							pvt->_readbuffer));
1141 			#endif
1142 
1143 			bool	saveasr=pvt->_allowshortreads;
1144 			pvt->_allowshortreads=true;
1145 			ssize_t	result=safeRead(pvt->_readbuffer,
1146 						pvt->_readbufferend-
1147 						pvt->_readbuffer,
1148 						sec,usec);
1149 			pvt->_allowshortreads=saveasr;
1150 
1151 			if (!result) {
1152 
1153 				if (pvt->_allowshortreads) {
1154 					#if defined(DEBUG_READ) && \
1155 						defined(DEBUG_BUFFERING)
1156 					debugPrintf("EOF\n");
1157 					#endif
1158 					return bytesread;
1159 				}
1160 
1161 				#if defined(DEBUG_READ) && \
1162 					defined(DEBUG_BUFFERING)
1163 				debugPrintf("still need %d bytes, "
1164 							"reading...\n",
1165 							(int)bytesunread);
1166 				#endif
1167 				result=safeRead(pvt->_readbuffer,
1168 						bytesunread,
1169 						sec,usec);
1170 
1171 				if (result>-1 && result!=bytesunread) {
1172 					#if defined(DEBUG_READ) && \
1173 						defined(DEBUG_BUFFERING)
1174 					debugPrintf("EOF\n");
1175 					#endif
1176 					return bytesread;
1177 				}
1178 			}
1179 
1180 			if (result<0) {
1181 				#if defined(DEBUG_READ) && \
1182 					defined(DEBUG_BUFFERING)
1183 				debugPrintf("error reading...\n");
1184 				#endif
1185 				return result;
1186 			}
1187 
1188 			pvt->_readbufferhead=pvt->_readbuffer;
1189 			pvt->_readbuffertail=pvt->_readbuffer+result;
1190 
1191 			#if defined(DEBUG_READ) && defined(DEBUG_BUFFERING)
1192 			debugPrintf("read %d bytes\n",(int)result);
1193 			#endif
1194 		}
1195 	}
1196 }
1197 
safeRead(void * buf,ssize_t count,int32_t sec,int32_t usec)1198 ssize_t filedescriptor::safeRead(void *buf, ssize_t count,
1199 					int32_t sec, int32_t usec) {
1200 
1201 	if (!buf) {
1202 		return 0;
1203 	}
1204 
1205 	#ifdef DEBUG_READ
1206 	debugPrintf("%d: safeRead(%d,(attempting %d bytes)",
1207 			(int)process::getProcessId(),(int)pvt->_fd,(int)count);
1208 	#endif
1209 
1210 	ssize_t	totalread=0;
1211 	ssize_t	sizetoread;
1212 	ssize_t	actualread;
1213 	ssize_t	sizemax=(pvt->_secctx)?pvt->_secctx->getSizeMax():SSIZE_MAX;
1214 	bool	isusingnonblockingmode=isUsingNonBlockingMode();
1215 	while (totalread<count) {
1216 
1217 		// limit size of individual reads
1218 		sizetoread=count-totalread;
1219 		if (sizetoread>sizemax) {
1220 			sizetoread=sizemax;
1221 		}
1222 
1223 		// wait if necessary
1224 		if (sec>-1 && usec>-1) {
1225 
1226 			int32_t	waitresult=waitForNonBlockingRead(sec,usec);
1227 
1228 			// return error or timeout
1229 			if (waitresult<0) {
1230 				#ifdef DEBUG_READ
1231 				debugPrintf(")\n");
1232 				#endif
1233 				return waitresult;
1234 			}
1235 		}
1236 
1237 		// set a pointer to the position in the buffer that we need
1238 		// to read data into
1239 		void	*ptr=(void *)((unsigned char *)buf+totalread);
1240 
1241 		// read...
1242 		error::clearError();
1243 		if (pvt->_secctx) {
1244 
1245 			#ifdef DEBUG_READ
1246 			debugPrintf(" (SecurityContext) ");
1247 			#endif
1248 
1249 			actualread=pvt->_secctx->read(ptr,sizetoread);
1250 		} else {
1251 			actualread=lowLevelRead(ptr,sizetoread);
1252 		}
1253 
1254 		#ifdef DEBUG_READ
1255 		for (int32_t i=0; i<actualread; i++) {
1256 			debugSafePrint(((unsigned char *)ptr)[i]);
1257 		}
1258 		debugPrintf("(%ld bytes) ",(long)actualread);
1259 		if (actualread==-1) {
1260 			debugPrintf("%s ",error::getErrorString());
1261 		}
1262 		stdoutput.flush();
1263 		#endif
1264 
1265 		// if we didn't read the number of bytes we expected to,
1266 		// handle that...
1267 		if (actualread!=sizetoread) {
1268 			if (isusingnonblockingmode &&
1269 				error::getErrorNumber()==EAGAIN) {
1270 				#ifdef DEBUG_READ
1271 				debugPrintf(" EAGAIN ");
1272 				#endif
1273 				// if we got an EAGAIN, and we're in
1274 				// non-blocking mode, there was nothing
1275 				// to read and we're done
1276 				break;
1277 			} else if (error::getErrorNumber()==EINTR) {
1278 				#ifdef DEBUG_READ
1279 				debugPrintf(" EINTR ");
1280 				#endif
1281 				// if we got an EINTR, then we may need to
1282 				// retry the read
1283 				if (pvt->_retryinterruptedreads) {
1284 					continue;
1285 				} else {
1286 					totalread=totalread+actualread;
1287 					break;
1288 				}
1289 			} else if (actualread==0 &&
1290 					error::getErrorNumber()==0) {
1291 				// eof condition
1292 				#ifdef DEBUG_READ
1293 				debugPrintf(" EOF ");
1294 				#endif
1295 				break;
1296 			} else if (actualread==-1) {
1297 				// error condition
1298 				#ifdef DEBUG_READ
1299 				debugPrintf(" ERROR )\n");
1300 				#endif
1301 				return RESULT_ERROR;
1302 			}
1303 		}
1304 
1305 		totalread=totalread+actualread;
1306 
1307 		// if we want to allow short reads, then break out here
1308 		if (pvt->_allowshortreads) {
1309 			#ifdef DEBUG_READ
1310 			debugPrintf(" SHORTREAD ");
1311 			#endif
1312 			break;
1313 		}
1314 	}
1315 
1316 	#ifdef DEBUG_READ
1317 	debugPrintf(",%d)\n",(int)totalread);
1318 	#endif
1319 	return totalread;
1320 }
1321 
lowLevelRead(void * buf,ssize_t count)1322 ssize_t filedescriptor::lowLevelRead(void *buf, ssize_t count) {
1323 	#if defined(RUDIMENTS_HAVE__READ)
1324 		return _read(pvt->_fd,buf,count);
1325 	#elif defined(RUDIMENTS_HAVE_READ)
1326 		return ::read(pvt->_fd,buf,count);
1327 	#else
1328 		#error no read or anything like it
1329 	#endif
1330 }
1331 
bufferedWrite(const void * buf,ssize_t count,int32_t sec,int32_t usec)1332 ssize_t filedescriptor::bufferedWrite(const void *buf, ssize_t count,
1333 						int32_t sec, int32_t usec) {
1334 
1335 	#if defined(DEBUG_WRITE) && defined(DEBUG_BUFFERING)
1336 	debugPrintf("bufferedWrite of %d bytes\n",(int)count);
1337 	#endif
1338 
1339 	if (!count) {
1340 		return 0;
1341 	}
1342 
1343 	if (!pvt->_writebuffer) {
1344 		#if defined(DEBUG_WRITE) && defined(DEBUG_BUFFERING)
1345 		debugPrintf("no write buffer...\n");
1346 		#endif
1347 		return safeWrite(buf,count,sec,usec);
1348 	}
1349 
1350 	const unsigned char	*data=(const unsigned char *)buf;
1351 
1352 	ssize_t	initialwritebuffersize=pvt->_writebufferptr-pvt->_writebuffer;
1353 	bool	first=true;
1354 
1355 	ssize_t	byteswritten=0;
1356 	ssize_t	bytesunwritten=count;
1357 	while (byteswritten<count) {
1358 
1359 		ssize_t	writebuffersize=pvt->_writebufferptr-
1360 						pvt->_writebuffer;
1361 		ssize_t	writebufferspace=pvt->_writebufferend-
1362 						pvt->_writebufferptr;
1363 
1364 		#if defined(DEBUG_WRITE) && defined(DEBUG_BUFFERING)
1365 		debugPrintf("	writebuffersize=%d\n",
1366 						(int)writebuffersize);
1367 		debugPrintf("	writebufferspace=%d\n",
1368 						(int)writebufferspace);
1369 		debugPrintf("	byteswritten=%d\n",
1370 						(int)byteswritten);
1371 		debugPrintf("	bytesunwritten=%d\n",
1372 						(int)bytesunwritten);
1373 		#endif
1374 
1375 		if (bytesunwritten<=writebufferspace) {
1376 
1377 			#if defined(DEBUG_WRITE) && defined(DEBUG_BUFFERING)
1378 			debugPrintf("buffering %d bytes\n",
1379 						(int)bytesunwritten);
1380 			#endif
1381 
1382 			bytestring::copy(pvt->_writebufferptr,
1383 					data,bytesunwritten);
1384 			pvt->_writebufferptr=pvt->_writebufferptr+
1385 							bytesunwritten;
1386 			byteswritten=byteswritten+bytesunwritten;
1387 
1388 		} else {
1389 
1390 			#if defined(DEBUG_WRITE) && defined(DEBUG_BUFFERING)
1391 			debugPrintf("just buffering %d bytes\n",
1392 						(int)writebufferspace);
1393 			#endif
1394 			#if defined(DEBUG_BUFFERING)
1395 			debugPrintf("auto-flush write buffer: %d bytes\n",
1396 				(int)(writebuffersize+writebufferspace));
1397 			#endif
1398 
1399 			bytestring::copy(pvt->_writebufferptr,
1400 					data,writebufferspace);
1401 
1402 			bool	saveasw=pvt->_allowshortwrites;
1403 			pvt->_allowshortwrites=true;
1404 			ssize_t	result=safeWrite(pvt->_writebuffer,
1405 					writebuffersize+writebufferspace,
1406 					sec,usec);
1407 			pvt->_allowshortwrites=saveasw;
1408 
1409 			if (result!=writebuffersize+writebufferspace) {
1410 				return result;
1411 			}
1412 
1413 			pvt->_writebufferptr=pvt->_writebuffer;
1414 			// The first time the buffer is written, the number of
1415 			// bytes that were already in the buffer need to be
1416 			// taken into account when calculating byteswritten,
1417 			// bytesunwritten and data.
1418 			ssize_t	adjustment=(first)?initialwritebuffersize:0;
1419 			if (first) {
1420 				first=false;
1421 			}
1422 			byteswritten=byteswritten+result-adjustment;
1423 			bytesunwritten=bytesunwritten-result+adjustment;
1424 			data=data+result-adjustment;
1425 		}
1426 	}
1427 
1428 	return byteswritten;
1429 }
1430 
flushWriteBuffer(int32_t sec,int32_t usec)1431 bool filedescriptor::flushWriteBuffer(int32_t sec, int32_t usec) {
1432 	if (!pvt->_writebuffer) {
1433 		return true;
1434 	}
1435 	ssize_t	writebuffersize=pvt->_writebufferptr-pvt->_writebuffer;
1436 	#if defined(DEBUG_BUFFERING)
1437 		debugPrintf("flush write buffer: %d bytes\n",
1438 						(int)writebuffersize);
1439 	#endif
1440 	bool	retval=(safeWrite(pvt->_writebuffer,writebuffersize,
1441 						sec,usec)==writebuffersize);
1442 	pvt->_writebufferptr=pvt->_writebuffer;
1443 	return retval;
1444 }
1445 
safeWrite(const void * buf,ssize_t count,int32_t sec,int32_t usec)1446 ssize_t filedescriptor::safeWrite(const void *buf, ssize_t count,
1447 						int32_t sec, int32_t usec) {
1448 
1449 	if (!buf) {
1450 		return 0;
1451 	}
1452 
1453 	#ifdef DEBUG_WRITE
1454 	debugPrintf("%d: safeWrite(%d,",
1455 			(int)process::getProcessId(),(int)pvt->_fd);
1456 	#endif
1457 
1458 	int32_t	olderrno=error::getErrorNumber();
1459 
1460 	ssize_t	totalwrite=0;
1461 	ssize_t	sizetowrite;
1462 	ssize_t	actualwrite;
1463 	ssize_t	sizemax=(pvt->_secctx)?pvt->_secctx->getSizeMax():SSIZE_MAX;
1464 	bool	isusingnonblockingmode=isUsingNonBlockingMode();
1465 	while (totalwrite<count) {
1466 
1467 		// limit size of individual writes
1468 		sizetowrite=count-totalwrite;
1469 		if (sizetowrite>sizemax) {
1470 			sizetowrite=sizemax;
1471 		}
1472 
1473 		// wait if necessary
1474 		if (sec>-1 && usec>-1) {
1475 
1476 			int32_t	waitresult=waitForNonBlockingWrite(sec,usec);
1477 
1478 			// return error or timeout
1479 			if (waitresult<0) {
1480 				#ifdef DEBUG_WRITE
1481 				debugPrintf(")\n");
1482 				#endif
1483 				return waitresult;
1484 			}
1485 		}
1486 
1487 		// set a pointer to the position in the buffer that we need
1488 		// to write data from
1489 		const void	*ptr=
1490 			(const void *)((const unsigned char *)buf+totalwrite);
1491 
1492 		error::clearError();
1493 		if (pvt->_secctx) {
1494 
1495 			#ifdef DEBUG_WRITE
1496 			debugPrintf(" (SecurityContext) ");
1497 			#endif
1498 
1499 			actualwrite=pvt->_secctx->write(ptr,sizetowrite);
1500 		} else {
1501 			actualwrite=midLevelWrite(ptr,sizetowrite);
1502 		}
1503 
1504 		#ifdef DEBUG_WRITE
1505 		for (int32_t i=0; i<actualwrite; i++) {
1506 			debugSafePrint(((const unsigned char *)(ptr))[i]);
1507 		}
1508 		debugPrintf("(%ld bytes) ",(long)actualwrite);
1509 		if (actualwrite==-1) {
1510 			debugPrintf("%s ",error::getErrorString());
1511 		}
1512 		stdoutput.flush();
1513 		#endif
1514 
1515 		// if we didn't read the number of bytes we expected to,
1516 		// handle that...
1517 		if (actualwrite!=sizetowrite) {
1518 			if (isusingnonblockingmode &&
1519 				error::getErrorNumber()==EAGAIN) {
1520 				#ifdef DEBUG_READ
1521 				debugPrintf(" EAGAIN ");
1522 				#endif
1523 				// if we got an EAGAIN, and we're in
1524 				// non-blocking mode, then try again
1525 				break;
1526 			} else if (error::getErrorNumber()==EINTR) {
1527 				#ifdef DEBUG_WRITE
1528 				debugPrintf(" EINTR ");
1529 				#endif
1530 				// if we got an EINTR, then we may need to
1531 				// retry the write
1532 				if (pvt->_retryinterruptedwrites) {
1533 					continue;
1534 				} else {
1535 					totalwrite=totalwrite+actualwrite;
1536 					break;
1537 				}
1538 			} else if (actualwrite==0 &&
1539 					error::getErrorNumber()==0) {
1540 				// eof condition
1541 				#ifdef DEBUG_WRITE
1542 				debugPrintf(" EOF ");
1543 				#endif
1544 				break;
1545 			} else if (actualwrite==-1) {
1546 				// error condition
1547 				#ifdef DEBUG_WRITE
1548 				debugPrintf(" ERROR )\n");
1549 				#endif
1550 				return RESULT_ERROR;
1551 			}
1552 		}
1553 
1554 		totalwrite=totalwrite+actualwrite;
1555 
1556 		// if we want to allow short writes, then break out here
1557 		if (pvt->_allowshortwrites) {
1558 			#ifdef DEBUG_WRITE
1559 			debugPrintf(" SHORTWRITE ");
1560 			#endif
1561 			break;
1562 		}
1563 	}
1564 
1565 	#ifdef DEBUG_WRITE
1566 	debugPrintf(",%d)\n",(int)totalwrite);
1567 	#endif
1568 	error::setErrorNumber(olderrno);
1569 	return totalwrite;
1570 }
1571 
lowLevelWriteWorker(void * attr)1572 void filedescriptor::lowLevelWriteWorker(void *attr) {
1573 
1574 	// get the filedescriptor
1575 	filedescriptor	*fd=(filedescriptor *)attr;
1576 
1577 	for (;;) {
1578 
1579 		// signal that we're ready for work
1580 		fd->pvt->_thrsem->signal(1);
1581 
1582 		// wait for work to do
1583 		fd->pvt->_thrsem->wait(0);
1584 
1585 		// handle exit
1586 		if (fd->pvt->_threxit) {
1587 			return;
1588 		}
1589 
1590 		// attempt to write all data
1591 		// FIXME: what about allowshortwrites?
1592 		ssize_t	bytestowrite=fd->pvt->_asynccount;
1593 		ssize_t	byteswritten=0;
1594 		do {
1595 			error::clearError();
1596 			ssize_t	result=fd->lowLevelWrite(
1597 						fd->pvt->_asyncbuf+byteswritten,
1598 						bytestowrite);
1599 			if (result==-1) {
1600 				if (error::getErrorNumber()==EINTR &&
1601 					fd->pvt->_retryinterruptedwrites) {
1602 					continue;
1603 				} else {
1604 					break;
1605 				}
1606 			}
1607 			bytestowrite-=result;
1608 			byteswritten+=result;
1609 		} while (byteswritten<fd->pvt->_asynccount);
1610 
1611 		// if we failed to write everything, then
1612 		// declare than an error has occurred
1613 		if (byteswritten!=fd->pvt->_asynccount) {
1614 			fd->pvt->_threrror=true;
1615 		}
1616 	}
1617 }
1618 
midLevelWrite(const void * buf,ssize_t count)1619 ssize_t filedescriptor::midLevelWrite(const void *buf, ssize_t count) {
1620 
1621 	if (pvt->_asyncwrite) {
1622 
1623 		if (!pvt->_thr) {
1624 
1625 			// create the worker thread semaphore
1626 			pvt->_thrsem=new semaphoreset;
1627 			int32_t	vals[2]={0,0};
1628 			if (!pvt->_thrsem->create(
1629 				IPC_PRIVATE,
1630 				permissions::evalPermString("rw-------"),
1631 				2,vals)) {
1632 				delete pvt->_thrsem;
1633 				pvt->_thrsem=NULL;
1634 				return RESULT_ERROR;
1635 			}
1636 
1637 			// create the worker thread
1638 			pvt->_thr=new thread;
1639 			if (!pvt->_thr->spawn(
1640 				(void *(*)(void *))lowLevelWriteWorker,
1641 				(void *)this,false)) {
1642 
1643 				delete pvt->_thrsem;
1644 				pvt->_thrsem=NULL;
1645 				delete pvt->_thr;
1646 				pvt->_thr=NULL;
1647 				return RESULT_ERROR;
1648 			}
1649 		}
1650 
1651 		// wait for the worker thread to be ready
1652 		pvt->_thrsem->wait(1);
1653 
1654 		// if a previous write failed, then return an error
1655 		if (pvt->_threrror) {
1656 			pvt->_threrror=false;
1657 			// FIXME: RESULT_ASYNC_ERROR or something...
1658 			return RESULT_ERROR;
1659 		}
1660 
1661 		// copy the buffer
1662 		if ((ssize_t)pvt->_asyncbufsize<count) {
1663 			delete[] pvt->_asyncbuf;
1664 			// pad to 1024-byte boundary to reduce the need to
1665 			// re-allocate this buffer
1666 			pvt->_asyncbufsize=count+((1024-(count%1024))%1024);
1667 			pvt->_asyncbuf=new unsigned char[pvt->_asyncbufsize];
1668 		}
1669 		bytestring::copy(pvt->_asyncbuf,buf,count);
1670 		pvt->_asynccount=count;
1671 
1672 		// signal the worker thread to do work
1673 		pvt->_thrsem->signal(0);
1674 
1675 		// return success
1676 		return count;
1677 
1678 	} else {
1679 		return lowLevelWrite(buf,count);
1680 	}
1681 }
1682 
lowLevelWrite(const void * buf,ssize_t count)1683 ssize_t filedescriptor::lowLevelWrite(const void *buf, ssize_t count) {
1684 	#if defined(RUDIMENTS_HAVE__WRITE)
1685 		return _write(pvt->_fd,buf,count);
1686 	#elif defined(RUDIMENTS_HAVE_WRITE)
1687 		return ::write(pvt->_fd,buf,count);
1688 	#else
1689 		#error no write or anything like it
1690 	#endif
1691 }
1692 
waitForNonBlockingRead(int32_t sec,int32_t usec) const1693 int32_t filedescriptor::waitForNonBlockingRead(
1694 				int32_t sec, int32_t usec) const {
1695 	if (!pvt->_lstnr) {
1696 		pvt->_lstnr=new listener();
1697 	} else {
1698 		pvt->_lstnr->removeAllFileDescriptors();
1699 	}
1700 	pvt->_lstnr->addReadFileDescriptor((filedescriptor *)this);
1701 	return pvt->_lstnr->listen(sec,usec);
1702 }
1703 
waitForNonBlockingWrite(int32_t sec,int32_t usec) const1704 int32_t filedescriptor::waitForNonBlockingWrite(
1705 				int32_t sec, int32_t usec) const {
1706 	if (!pvt->_lstnr) {
1707 		pvt->_lstnr=new listener();
1708 	} else {
1709 		pvt->_lstnr->removeAllFileDescriptors();
1710 	}
1711 	pvt->_lstnr->addWriteFileDescriptor((filedescriptor *)this);
1712 	return pvt->_lstnr->listen(sec,usec);
1713 }
1714 
translateByteOrder()1715 void filedescriptor::translateByteOrder() {
1716 	pvt->_translatebyteorder=true;
1717 }
1718 
dontTranslateByteOrder()1719 void filedescriptor::dontTranslateByteOrder() {
1720 	pvt->_translatebyteorder=false;
1721 }
1722 
createPipe(filedescriptor * readfd,filedescriptor * writefd)1723 bool filedescriptor::createPipe(filedescriptor *readfd,
1724 				filedescriptor *writefd) {
1725 	int32_t	result;
1726 	int	fd[2];
1727 	error::clearError();
1728 	do {
1729 		#if defined(RUDIMENTS_HAVE_PIPE)
1730 			result=pipe(fd);
1731 		#elif defined(RUDIMENTS_HAVE__PIPE)
1732 			result=_pipe(fd,1024,0);
1733 		#else
1734 			#error no pipe or anything like it
1735 		#endif
1736 	} while (result==-1 && error::getErrorNumber()==EINTR);
1737 	if (!result) {
1738 		if (readfd) {
1739 			readfd->setFileDescriptor(fd[0]);
1740 		}
1741 		if (writefd) {
1742 			writefd->setFileDescriptor(fd[1]);
1743 		}
1744 	}
1745 	return !result;
1746 }
1747 
hostToNet(uint16_t value)1748 uint16_t filedescriptor::hostToNet(uint16_t value) {
1749 	return htons(value);
1750 }
1751 
hostToNet(uint32_t value)1752 uint32_t filedescriptor::hostToNet(uint32_t value) {
1753 	return htonl(value);
1754 }
1755 
hostToNet(uint64_t value)1756 uint64_t filedescriptor::hostToNet(uint64_t value) {
1757 	#if defined(RUDIMENTS_HAVE_HTONLL)
1758 		return htonll(value);
1759 	#elif __BYTE_ORDER == __BIG_ENDIAN
1760 		return value;
1761 	#elif defined(RUDIMENTS_HAVE_BSWAP_64)
1762 		return bswap_64(value);
1763 	#elif defined(RUDIMENTS_HAVE___BSWAP64)
1764 		return __bswap64(value);
1765 	#elif defined(RUDIMENTS_HAVE_BSWAP64)
1766 		return bswap64(value);
1767 	#elif defined(RUDIMENTS_HAVE_SWAP64)
1768 		return swap64(value);
1769 	#elif defined(RUDIMENTS_HAVE_SWAP_INT64)
1770 		return __swap_int64(value);
1771 	#elif defined(RUDIMENTS_HAVE_OSSWAPHOSTTOLITTLEINT64)
1772 		return OSSwapHostToLittleInt64(value);
1773 	#else
1774 		#ifdef RUDIMENTS_HAVE_LONG_LONG
1775 			return
1776 			(((uint64_t)hostToNet(
1777 				(uint32_t)(value&0x00000000FFFFFFFFLL)))<<32)|
1778 			((uint64_t)hostToNet(
1779 				(uint32_t)((value&0xFFFFFFFF00000000LL)>>32)));
1780 		#else
1781 			return htonl(value);
1782 		#endif
1783 	#endif
1784 }
1785 
netToHost(uint16_t value)1786 uint16_t filedescriptor::netToHost(uint16_t value) {
1787 	return ntohs(value);
1788 }
1789 
netToHost(uint32_t value)1790 uint32_t filedescriptor::netToHost(uint32_t value) {
1791 	return ntohl(value);
1792 }
1793 
netToHost(uint64_t value)1794 uint64_t filedescriptor::netToHost(uint64_t value) {
1795 	#if defined(RUDIMENTS_HAVE_NTOHLL)
1796 		return ntohll(value);
1797 	#elif __BYTE_ORDER == __BIG_ENDIAN
1798 		return value;
1799 	#elif defined(RUDIMENTS_HAVE_BSWAP_64)
1800 		return bswap_64(value);
1801 	#elif defined(RUDIMENTS_HAVE___BSWAP64)
1802 		return __bswap64(value);
1803 	#elif defined(RUDIMENTS_HAVE_BSWAP64)
1804 		return bswap64(value);
1805 	#elif defined(RUDIMENTS_HAVE_SWAP64)
1806 		return swap64(value);
1807 	#elif defined(RUDIMENTS_HAVE_SWAP_INT64)
1808 		return __swap_int64(value);
1809 	#elif defined(RUDIMENTS_HAVE_OSSWAPLITTLETOHOSTINT64)
1810 		return OSSwapLittleToHostInt64(value);
1811 	#else
1812 		#ifdef RUDIMENTS_HAVE_LONG_LONG
1813 			return
1814 			(((uint64_t)netToHost(
1815 				(uint32_t)(value&0x00000000FFFFFFFFLL)))<<32)|
1816 			((uint64_t)netToHost(
1817 				(uint32_t)((value&0xFFFFFFFF00000000LL)>>32)));
1818 		#else
1819 			return ntohl(value);
1820 		#endif
1821 	#endif
1822 }
1823 
hostToLittleEndian(uint16_t value)1824 uint16_t filedescriptor::hostToLittleEndian(uint16_t value) {
1825 	#if __BYTE_ORDER == __LITTLE_ENDIAN
1826 		return value;
1827 	#else
1828 		return (((value&0x00FF)<<8)|((value&0xFF00)>>8));
1829 	#endif
1830 }
1831 
hostToLittleEndian(uint32_t value)1832 uint32_t filedescriptor::hostToLittleEndian(uint32_t value) {
1833 	#if __BYTE_ORDER == __LITTLE_ENDIAN
1834 		return value;
1835 	#else
1836 		return (((value&0x000000FF)<<24)|
1837 			((value&0x0000FF00)<<8)|
1838 			((value&0x00FF0000)>>8)|
1839 			((value&0xFF000000)>>24));
1840 	#endif
1841 }
1842 
hostToLittleEndian(uint64_t value)1843 uint64_t filedescriptor::hostToLittleEndian(uint64_t value) {
1844 	#if __BYTE_ORDER == __LITTLE_ENDIAN
1845 		return value;
1846 	#else
1847 		#ifdef RUDIMENTS_HAVE_LONG_LONG
1848 			uint32_t	low=(uint32_t)
1849 					(value&0x00000000FFFFFFFFLL);
1850 			uint32_t	high=(uint32_t)
1851 					((value&0xFFFFFFFF00000000LL)>>32);
1852 			low=(((low&0x000000FF)<<24)|
1853 				((low&0x0000FF00)<<8)|
1854 				((low&0x00FF0000)>>8)|
1855 				((low&0xFF000000)>>24));
1856 			high=(((high&0x000000FF)<<24)|
1857 				((high&0x0000FF00)<<8)|
1858 				((high&0x00FF0000)>>8)|
1859 				((high&0xFF000000)>>24));
1860 			return (((uint64_t)high)|(((uint64_t)low)<<32));
1861 		#else
1862 			return hostToLittleEndian((uint32_t)value);
1863 		#endif
1864 	#endif
1865 }
1866 
littleEndianToHost(uint16_t value)1867 uint16_t filedescriptor::littleEndianToHost(uint16_t value) {
1868 	#if __BYTE_ORDER == __LITTLE_ENDIAN
1869 		return value;
1870 	#else
1871 		return (((value&0x00FF)<<8)|((value&0xFF00)>>8));
1872 	#endif
1873 }
1874 
littleEndianToHost(uint32_t value)1875 uint32_t filedescriptor::littleEndianToHost(uint32_t value) {
1876 	#if __BYTE_ORDER == __LITTLE_ENDIAN
1877 		return value;
1878 	#else
1879 		return (((value&0x000000FF)<<24)|
1880 			((value&0x0000FF00)<<8)|
1881 			((value&0x00FF0000)>>8)|
1882 			((value&0xFF000000)>>24));
1883 	#endif
1884 }
1885 
littleEndianToHost(uint64_t value)1886 uint64_t filedescriptor::littleEndianToHost(uint64_t value) {
1887 	#if __BYTE_ORDER == __LITTLE_ENDIAN
1888 		return value;
1889 	#else
1890 		#ifdef RUDIMENTS_HAVE_LONG_LONG
1891 			uint32_t	low=(uint32_t)
1892 					(value&0x00000000FFFFFFFFLL);
1893 			uint32_t	high=(uint32_t)
1894 					((value&0xFFFFFFFF00000000LL)>>32);
1895 			low=(((low&0x000000FF)<<24)|
1896 				((low&0x0000FF00)<<8)|
1897 				((low&0x00FF0000)>>8)|
1898 				((low&0xFF000000)>>24));
1899 			high=(((high&0x000000FF)<<24)|
1900 				((high&0x0000FF00)<<8)|
1901 				((high&0x00FF0000)>>8)|
1902 				((high&0xFF000000)>>24));
1903 			return (((uint64_t)high)|(((uint64_t)low)<<32));
1904 		#else
1905 			return littleEndianToHost((uint32_t)value);
1906 		#endif
1907 	#endif
1908 }
1909 
fCntl(int32_t cmd,long arg) const1910 int32_t filedescriptor::fCntl(int32_t cmd, long arg) const {
1911 	#ifdef RUDIMENTS_HAVE_FCNTL
1912 		int32_t	result;
1913 		error::clearError();
1914 		do {
1915 			result=fcntl(pvt->_fd,cmd,arg);
1916 		} while (pvt->_retryinterruptedfcntl && result==-1 &&
1917 				error::getErrorNumber()==EINTR);
1918 		return result;
1919 	#else
1920 		return -1;
1921 	#endif
1922 }
1923 
ioCtl(int32_t cmd,void * arg) const1924 int32_t filedescriptor::ioCtl(int32_t cmd, void *arg) const {
1925 	#ifdef RUDIMENTS_HAVE_IOCTL
1926 		int32_t	result;
1927 		error::clearError();
1928 		do {
1929 			result=ioctl(pvt->_fd,cmd,arg);
1930 		} while (pvt->_retryinterruptedioctl && result==-1 &&
1931 					error::getErrorNumber()==EINTR);
1932 		return result;
1933 	#else
1934 		return -1;
1935 	#endif
1936 }
1937 
passFileDescriptor(int32_t fd)1938 bool filedescriptor::passFileDescriptor(int32_t fd) {
1939 
1940 #if (defined(RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN) && \
1941 		defined(RUDIMENTS_HAVE_CMSGHDR)) || \
1942 		defined(RUDIMENTS_HAVE_MSGHDR_MSG_ACCRIGHTS)
1943 
1944 	// have to use sendmsg to pass a file descriptor.
1945 	// sendmsg can only send a msghdr
1946 	struct	msghdr	messageheader;
1947 
1948 	// these must be null for stream sockets
1949 	messageheader.msg_name=NULL;
1950 	messageheader.msg_namelen=0;
1951 
1952 	#ifdef RUDIMENTS_HAVE_MSGHDR_MSG_FLAGS
1953 	// initialize flags to 0
1954 	messageheader.msg_flags=0;
1955 	#endif
1956 
1957 	// must send at least 1 iovector with 1 byte of real data
1958 	struct iovec	iovector[1];
1959 	iovector[0].iov_base=(RUDIMENTS_IOV_BASE_TYPE)" ";
1960 	iovector[0].iov_len=sizeof(char);
1961 	messageheader.msg_iov=iovector;
1962 	messageheader.msg_iovlen=1;
1963 
1964 	// use other parts of the msghdr structure to send the descriptor
1965 	#ifdef RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN
1966 
1967 		// new-style: the descriptor is passed in the msg_control...
1968 
1969 		// On OS X 10.7, CMSG_LEN ultimately makes a functon call, so
1970 		// this array must be dynamically allocated.
1971 		unsigned char	*control=new unsigned char[
1972 						CMSG_LEN(sizeof(int32_t))];
1973 		messageheader.msg_control=(caddr_t)control;
1974 		messageheader.msg_controllen=CMSG_LEN(sizeof(int32_t));
1975 
1976 		struct cmsghdr	*cmptr=CMSG_FIRSTHDR(&messageheader);
1977 		cmptr->cmsg_level=SOL_SOCKET;
1978 		cmptr->cmsg_type=SCM_RIGHTS;
1979 		cmptr->cmsg_len=CMSG_LEN(sizeof(int32_t));
1980 
1981 		bytestring::copy((int32_t *)CMSG_DATA(cmptr),
1982 						&fd,sizeof(int32_t));
1983 	#else
1984 		// old-style: the descriptor is passed in the accrights...
1985 		messageheader.msg_accrights=(caddr_t)&fd;
1986 		messageheader.msg_accrightslen=sizeof(int32_t);
1987 	#endif
1988 
1989 	// finally, send the msghdr
1990 	int32_t	result;
1991 	error::clearError();
1992 	do {
1993 		#if defined(RUDIMENTS_HAVE_SENDMSG) || \
1994 			defined(RUDIMENTS_HAVE_UNDEFINED_SENDMSG)
1995 			result=sendmsg(pvt->_fd,&messageheader,0);
1996 		#else
1997 			#error no sendmsg or anything like it
1998 		#endif
1999 	} while (result==-1 && error::getErrorNumber()==EINTR &&
2000 					pvt->_retryinterruptedwrites);
2001 
2002 	// clean up
2003 	#ifdef RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN
2004 		delete[] control;
2005 	#endif
2006 
2007 	return (result!=-1);
2008 
2009 #elif defined(RUDIMENTS_HAVE_DUPLICATEHANDLE)
2010 
2011 	// get a handle to this process
2012 	// Apparently we can't just use GetCurrentProcess() or
2013 	// we'll just get the pseudo-handle for our process.
2014 	HANDLE	localprocesshandle=OpenProcess(PROCESS_DUP_HANDLE,FALSE,
2015 						(DWORD)GetCurrentProcessId());
2016 	if (!localprocesshandle) {
2017 		return false;
2018 	}
2019 
2020 	// tell the other process to go
2021 	if (write(true)!=sizeof(bool)) {
2022 		return false;
2023 	}
2024 
2025 	// read the process id from the other side
2026 	uint32_t	otherpid;
2027 	if (read(&otherpid)!=sizeof(uint32_t)) {
2028 		return false;
2029 	}
2030 
2031 	// get a handle to that process
2032 	bool	success=true;
2033 	HANDLE	otherprocesshandle=OpenProcess(PROCESS_DUP_HANDLE,
2034 						FALSE,(DWORD)otherpid);
2035 	if (!otherprocesshandle) {
2036 		success=false;
2037 	}
2038 
2039 	// get the handle from the fd
2040 	HANDLE	localhandle=INVALID_HANDLE_VALUE;
2041 	if (success) {
2042 		localhandle=(HANDLE)getHandleFromFileDescriptor(fd);
2043 		success=(localhandle!=INVALID_HANDLE_VALUE);
2044 	}
2045 
2046 	// duplicate the handle
2047 	HANDLE	otherhandle=INVALID_HANDLE_VALUE;
2048 	if (success) {
2049 		success=(DuplicateHandle(localprocesshandle,
2050 						localhandle,
2051 						otherprocesshandle,
2052 						&otherhandle,
2053 						0,TRUE,
2054 						DUPLICATE_SAME_ACCESS)==TRUE);
2055 	}
2056 
2057 	// send otherhandle to other process
2058 	bool	retval=(write((uint64_t)otherhandle)==sizeof(uint64_t));
2059 
2060 	// close the other process handle
2061 	CloseHandle(otherprocesshandle);
2062 
2063 	// send done flag
2064 	return retval;
2065 #else
2066 	RUDIMENTS_SET_ENOSYS
2067 	return false;
2068 #endif
2069 }
2070 
receiveFileDescriptor(int32_t * fd)2071 bool filedescriptor::receiveFileDescriptor(int32_t *fd) {
2072 
2073 #if (defined(RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN) && \
2074 		defined(RUDIMENTS_HAVE_CMSGHDR)) || \
2075 		defined(RUDIMENTS_HAVE_MSGHDR_MSG_ACCRIGHTS)
2076 
2077 	// have to use recvmsg to receive a file descriptor.
2078 	// recvmsg can only send a msghdr
2079 	struct msghdr	messageheader;
2080 
2081 	// these must be null for stream sockets
2082 	messageheader.msg_name=NULL;
2083 	messageheader.msg_namelen=0;
2084 
2085 	#ifdef RUDIMENTS_HAVE_MSGHDR_MSG_FLAGS
2086 	// initialize flags to 0
2087 	messageheader.msg_flags=0;
2088 	#endif
2089 
2090 	// the process that's going to handoff it's socket will also
2091 	// send a single iovector with a single byte of data in it,
2092 	// so we'll receive that too
2093 	struct iovec	iovector[1];
2094 	char		ptr;
2095 	iovector[0].iov_base=(RUDIMENTS_IOV_BASE_TYPE)&ptr;
2096 	iovector[0].iov_len=sizeof(char);
2097 	messageheader.msg_iov=iovector;
2098 	messageheader.msg_iovlen=1;
2099 
2100 	#ifdef RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN
2101 		// new-style: the descriptor is passed in the msg_control...
2102 
2103 		// On OS X 10.7, CMSG_LEN ultimately makes a functon call, so
2104 		// this array must be dynamically allocated.
2105 		unsigned char	*control=new unsigned char[
2106 						CMSG_LEN(sizeof(int32_t))];
2107 		messageheader.msg_control=(caddr_t)control;
2108 		messageheader.msg_controllen=CMSG_LEN(sizeof(int32_t));
2109 	#else
2110 		// old-style: the descriptor is received in the accrights...
2111 		int32_t	newfd;
2112 		messageheader.msg_accrights=(caddr_t)&newfd;
2113 		messageheader.msg_accrightslen=sizeof(int32_t);
2114 	#endif
2115 
2116 	// receive the msghdr
2117 	int32_t	result;
2118 	error::clearError();
2119 	do {
2120 		// wait 120 seconds for data to come in
2121 		// FIXME: this should be configurable
2122 		bool	oldwaits=pvt->_retryinterruptedwaits;
2123 		pvt->_retryinterruptedwaits=pvt->_retryinterruptedreads;
2124 		result=waitForNonBlockingRead(120,0);
2125 		pvt->_retryinterruptedwaits=oldwaits;
2126 		if (result==RESULT_TIMEOUT) {
2127 			#ifdef RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN
2128 				delete[] control;
2129 			#endif
2130 			return false;
2131 		}
2132 		if (result>-1) {
2133 			#if defined(RUDIMENTS_HAVE_RECVMSG) || \
2134 				defined(RUDIMENTS_HAVE_UNDEFINED_RECVMSG)
2135 				result=recvmsg(pvt->_fd,&messageheader,0);
2136 			#else
2137 				#error no recvmsg or anything like it
2138 			#endif
2139 		}
2140 	} while (result==-1 && error::getErrorNumber()==EINTR &&
2141 					pvt->_retryinterruptedreads);
2142 	if (result==-1) {
2143 		#ifdef RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN
2144 			delete[] control;
2145 		#endif
2146 		return false;
2147 	}
2148 
2149 
2150 	// if we got valid data, set the passed-in descriptor to the
2151 	// descriptor we received and return success
2152 	#ifdef RUDIMENTS_HAVE_MSGHDR_MSG_CONTROLLEN
2153 
2154 		struct cmsghdr  *cmptr=CMSG_FIRSTHDR(&messageheader);
2155 		if (cmptr && cmptr->cmsg_len==CMSG_LEN(sizeof(int32_t)) &&
2156 				cmptr->cmsg_level==SOL_SOCKET &&
2157 				cmptr->cmsg_type==SCM_RIGHTS) {
2158 
2159 			bytestring::copy(fd,(int32_t *)CMSG_DATA(cmptr),
2160 							sizeof(int32_t));
2161 
2162 			delete[] control;
2163 			return true;
2164 		}
2165 		#ifdef DEBUG_PASSFD
2166 		else {
2167 
2168 			// if we got bad data, be specific about what was
2169 			// wrong, this will help debug problems with different
2170 			// platforms
2171 			if (!cmptr) {
2172 				debugPrintf("%d: ",
2173 						(int)process::getProcessId());
2174 				debugPrintf("null cmptr\n");
2175 			} else {
2176 				if (cmptr->cmsg_level!=SOL_SOCKET) {
2177 					debugPrintf("%d: ",
2178 						(int)process::getProcessId());
2179 					debugPrintf("got cmsg_level=%ld",
2180 						(long)(cmptr->cmsg_level));
2181 					debugPrintf(" instead of %ld",
2182 						(long)(SOL_SOCKET));
2183 					debugPrintf("\n");
2184 				}
2185 				if (cmptr->cmsg_type!=SCM_RIGHTS) {
2186 					debugPrintf("%d: ",
2187 						(int)process::getProcessId());
2188 					debugPrintf("got cmsg_type=%ld",
2189 						(long)(cmptr->cmsg_type));
2190 					debugPrintf(" instead of %ld",
2191 						(long)(SCM_RIGHTS));
2192 					debugPrintf("\n");
2193 				}
2194 			}
2195 		}
2196 		#endif
2197 
2198 		delete[] control;
2199 	#else
2200 		if (messageheader.msg_accrightslen==sizeof(int32_t)) {
2201 			*fd=newfd;
2202 			return true;
2203 		}
2204 	#endif
2205 
2206 	// if we're here then we must have received some bad data
2207 	return false;
2208 
2209 #elif defined(RUDIMENTS_HAVE_DUPLICATEHANDLE)
2210 
2211 	// wait for the other process to tell us to go
2212 	bool	go;
2213 	if (read(&go)!=sizeof(bool)) {
2214 		return false;
2215 	}
2216 
2217 	// send our process id
2218 	uint32_t	pid=process::getProcessId();
2219 	if (write(pid)!=sizeof(uint32_t)) {
2220 		return false;
2221 	}
2222 
2223 	// get the handle from the other process
2224 	uint64_t	handle;
2225 	if (read(&handle)!=sizeof(uint64_t)) {
2226 		return false;
2227 	}
2228 
2229 	// get file descriptor from handle
2230 	if ((HANDLE)handle!=INVALID_HANDLE_VALUE) {
2231 		*fd=_open_osfhandle((long)handle,0);
2232 		return true;
2233 	}
2234 	return false;
2235 #else
2236 	RUDIMENTS_SET_ENOSYS
2237 	return false;
2238 #endif
2239 }
2240 
passSocket(int32_t sock)2241 bool filedescriptor::passSocket(int32_t sock) {
2242 
2243 #if defined(RUDIMENTS_HAVE_WSADUPLICATESOCKET)
2244 
2245 	// tell the other process to go
2246 	if (write(true)!=sizeof(bool)) {
2247 		return false;
2248 	}
2249 
2250 	// read the process id from the other side
2251 	uint32_t	otherpid;
2252 	if (read(&otherpid)!=sizeof(uint32_t)) {
2253 		return false;
2254 	}
2255 
2256 	// duplicate the socket
2257 	WSAPROTOCOL_INFO	wpinfo;
2258 	if (WSADuplicateSocket((SOCKET)sock,otherpid,&wpinfo)) {
2259 		return false;
2260 	}
2261 
2262 	// write the wsaprotocol_info to the other side
2263 	if (write((void *)&wpinfo,sizeof(wpinfo))!=sizeof(wpinfo)) {
2264 		return false;
2265 	}
2266 
2267 	// get result from the other process
2268 	bool	result;
2269 	if (read(&result)!=sizeof(bool)) {
2270 		return false;
2271 	}
2272 	return result;
2273 #else
2274 	return passFileDescriptor(sock);
2275 #endif
2276 }
2277 
receiveSocket(int32_t * sock)2278 bool filedescriptor::receiveSocket(int32_t *sock) {
2279 
2280 #if defined(RUDIMENTS_HAVE_WSADUPLICATESOCKET)
2281 
2282 	// wait for the other process to tell us to go
2283 	bool	go;
2284 	if (read(&go)!=sizeof(bool)) {
2285 		return false;
2286 	}
2287 
2288 	// send our process id
2289 	uint32_t	pid=process::getProcessId();
2290 	if (write(pid)!=sizeof(uint32_t)) {
2291 		return false;
2292 	}
2293 
2294 	// read a wsaprotocol_info from the other side
2295 	WSAPROTOCOL_INFO	wpinfo;
2296 	if (read((void *)&wpinfo,sizeof(wpinfo))!=sizeof(wpinfo)) {
2297 		return false;
2298 	}
2299 
2300 	// create the socket
2301 	*sock=WSASocket(AF_INET,SOCK_STREAM,IPPROTO_TCP,
2302 					&wpinfo,0,WSA_FLAG_OVERLAPPED);
2303 	bool	result=(*sock!=INVALID_SOCKET);
2304 
2305 	// tell the other process how it went
2306 	if (write(result)!=sizeof(bool)) {
2307 		return false;
2308 	}
2309 	return result;
2310 #else
2311 	return receiveFileDescriptor(sock);
2312 #endif
2313 }
2314 
useNaglesAlgorithm()2315 bool filedescriptor::useNaglesAlgorithm() {
2316 	return setNoDelay(0);
2317 }
2318 
dontUseNaglesAlgorithm()2319 bool filedescriptor::dontUseNaglesAlgorithm() {
2320 	return setNoDelay(1);
2321 }
2322 
setNoDelay(int32_t onoff)2323 bool filedescriptor::setNoDelay(int32_t onoff) {
2324 #ifdef TCP_NODELAY
2325 	int32_t	value=onoff;
2326 	return !setSockOpt(IPPROTO_TCP,TCP_NODELAY,
2327 				(RUDIMENTS_SETSOCKOPT_OPTVAL_TYPE)&value,
2328 				(socklen_t)sizeof(int));
2329 #else
2330 	RUDIMENTS_SET_ENOSYS
2331 	return false;
2332 #endif
2333 }
2334 
getSocketWriteBufferSize(int32_t * size)2335 bool filedescriptor::getSocketWriteBufferSize(int32_t *size) {
2336 	socklen_t	intsize=sizeof(int);
2337 	return getSockOpt(SOL_SOCKET,SO_SNDBUF,
2338 				(RUDIMENTS_GETSOCKOPT_OPTVAL_TYPE)size,
2339 				&intsize)!=-1;
2340 }
2341 
setSocketWriteBufferSize(int32_t size)2342 bool filedescriptor::setSocketWriteBufferSize(int32_t size) {
2343 	return !setSockOpt(SOL_SOCKET,SO_SNDBUF,
2344 				(RUDIMENTS_SETSOCKOPT_OPTVAL_TYPE)&size,
2345 				(socklen_t)sizeof(int));
2346 }
2347 
getSocketReadBufferSize(int32_t * size)2348 bool filedescriptor::getSocketReadBufferSize(int32_t *size) {
2349 	socklen_t	intsize=sizeof(int);
2350 	return getSockOpt(SOL_SOCKET,SO_RCVBUF,
2351 				(RUDIMENTS_GETSOCKOPT_OPTVAL_TYPE)size,
2352 				&intsize)!=-1;
2353 }
2354 
setSocketReadBufferSize(int32_t size)2355 bool filedescriptor::setSocketReadBufferSize(int32_t size) {
2356 	return setSockOpt(SOL_SOCKET,SO_RCVBUF,
2357 				(RUDIMENTS_SETSOCKOPT_OPTVAL_TYPE)&size,
2358 				(socklen_t)sizeof(int))!=-1;
2359 }
2360 
disableIPv4()2361 bool filedescriptor::disableIPv4() {
2362 #ifdef IPV6_V6ONLY
2363 	int32_t	no=0;
2364 	return setSockOpt(IPPROTO_IPV6,IPV6_V6ONLY,
2365 				(void *)&no,
2366 				(socklen_t)sizeof(int32_t))!=-1;
2367 #else
2368 	RUDIMENTS_SET_ENOSYS
2369 	return false;
2370 #endif
2371 }
2372 
enableIPv4()2373 bool filedescriptor::enableIPv4() {
2374 #ifdef IPV6_V6ONLY
2375 	int32_t	yes=1;
2376 	return setSockOpt(IPPROTO_IPV6,IPV6_V6ONLY,
2377 				(void *)&yes,
2378 				(socklen_t)sizeof(int32_t))!=-1;
2379 #else
2380 	RUDIMENTS_SET_ENOSYS
2381 	return false;
2382 #endif
2383 }
2384 
getType() const2385 const char *filedescriptor::getType() const {
2386 	return pvt->_type;
2387 }
2388 
getPeerAddress() const2389 char *filedescriptor::getPeerAddress() const {
2390 
2391 	// initialize a socket address structure
2392 	struct sockaddr_in		clientsin;
2393 	RUDIMENTS_SOCKLEN_OR_SIZE_T	size=sizeof(clientsin);
2394 	bytestring::zero(&clientsin,sizeof(clientsin));
2395 
2396 	// get the peer address
2397 	int32_t	result;
2398 	error::clearError();
2399 	do {
2400 		#if defined(RUDIMENTS_HAVE_GETPEERNAME) || \
2401 			defined(RUDIMENTS_HAVE_UNDEFINED_GETPEERNAME)
2402 			result=getpeername(pvt->_fd,
2403 						(struct sockaddr *)&clientsin,
2404 						&size);
2405 		#else
2406 			#error no getpeername or anything like it
2407 		#endif
2408 	} while (result==-1 && error::getErrorNumber()==EINTR);
2409 
2410 	// if getpeername was successful and the peer was an inet socket,
2411 	// convert the address to a string and return a copy of it,
2412 	// otherwise return NULL
2413 	if (result!=-1 && ((struct sockaddr *)&clientsin)->sa_family==AF_INET) {
2414 		return charstring::duplicate(inet_ntoa(clientsin.sin_addr));
2415 	}
2416 	return NULL;
2417 }
2418 
getSockOpt(int32_t level,int32_t optname,void * optval,socklen_t * optlen)2419 int32_t filedescriptor::getSockOpt(int32_t level, int32_t optname,
2420 				void *optval, socklen_t *optlen) {
2421 	int32_t	result;
2422 	RUDIMENTS_SOCKLEN_OR_SIZE_T	tempoptlen;
2423 	if (optlen) {
2424 		tempoptlen=*optlen;
2425 	}
2426 	error::clearError();
2427 	do {
2428 		#if defined(RUDIMENTS_HAVE_GETSOCKOPT) || \
2429 			defined(RUDIMENTS_HAVE_UNDEFINED_GETSOCKOPT)
2430 			result=getsockopt(pvt->_fd,level,optname,
2431 				(RUDIMENTS_GETSOCKOPT_OPTVAL_TYPE)optval,
2432 				&tempoptlen);
2433 		#else
2434 			#error no getsockopt or anything like it
2435 		#endif
2436 	} while (result==-1 && error::getErrorNumber()==EINTR);
2437 	if (optlen) {
2438 		*optlen=tempoptlen;
2439 	}
2440 	return result;
2441 }
2442 
setSockOpt(int32_t level,int32_t optname,const void * optval,socklen_t optlen)2443 int32_t filedescriptor::setSockOpt(int32_t level, int32_t optname,
2444 				const void *optval, socklen_t optlen) {
2445 	int32_t	result;
2446 	error::clearError();
2447 	do {
2448 		#if defined(RUDIMENTS_HAVE_SETSOCKOPT) || \
2449 			defined(RUDIMENTS_HAVE_UNDEFINED_SETSOCKOPT)
2450 			result=setsockopt(pvt->_fd,level,optname,
2451 				(RUDIMENTS_SETSOCKOPT_OPTVAL_TYPE)optval,
2452 				optlen);
2453 		#else
2454 			#error no setsockopt or anything like it
2455 		#endif
2456 	} while (result==-1 && error::getErrorNumber()==EINTR);
2457 	return result;
2458 }
2459 
type() const2460 const char *filedescriptor::type() const {
2461 	return pvt->_type;
2462 }
2463 
type(const char * tp)2464 void filedescriptor::type(const char *tp) {
2465 	pvt->_type=tp;
2466 }
2467 
fd() const2468 int32_t filedescriptor::fd() const {
2469 	return pvt->_fd;
2470 }
2471 
fd(int32_t filedes)2472 void filedescriptor::fd(int32_t filedes) {
2473 	setFileDescriptor(filedes);
2474 }
2475 
secctx()2476 securitycontext *filedescriptor::secctx() {
2477 	return pvt->_secctx;
2478 }
2479 
closeOnExec()2480 bool filedescriptor::closeOnExec() {
2481 	#if defined(RUDIMENTS_HAVE_FD_CLOEXEC)
2482 		return !fCntl(F_SETFD,fCntl(F_GETFD,FD_CLOEXEC)|FD_CLOEXEC);
2483 	#elif defined(RUDIMENTS_HAVE_HANDLE_FLAG_INHERIT)
2484 		return SetHandleInformation(
2485 				(HANDLE)getHandleFromFileDescriptor(pvt->_fd),
2486 				HANDLE_FLAG_INHERIT,0)!=0;
2487 	#else
2488 		#error no FD_CLOEXEC or anything like it
2489 	#endif
2490 }
2491 
dontCloseOnExec()2492 bool filedescriptor::dontCloseOnExec() {
2493 	#if defined(RUDIMENTS_HAVE_FD_CLOEXEC)
2494 		return !fCntl(F_SETFD,fCntl(F_GETFD,FD_CLOEXEC)&(~FD_CLOEXEC));
2495 	#elif defined(RUDIMENTS_HAVE_HANDLE_FLAG_INHERIT)
2496 		return SetHandleInformation(
2497 				(HANDLE)getHandleFromFileDescriptor(pvt->_fd),
2498 				HANDLE_FLAG_INHERIT,
2499 				HANDLE_FLAG_INHERIT)!=0;
2500 	#else
2501 		#error no FD_CLOEXEC or anything like it
2502 	#endif
2503 }
2504 
getCloseOnExec()2505 bool filedescriptor::getCloseOnExec() {
2506 	#if defined(RUDIMENTS_HAVE_FD_CLOEXEC)
2507 		return fCntl(F_GETFD,FD_CLOEXEC);
2508 	#elif defined(RUDIMENTS_HAVE_HANDLE_FLAG_INHERIT)
2509 		DWORD	inherit;
2510 		if (GetHandleInformation(
2511 				(HANDLE)getHandleFromFileDescriptor(pvt->_fd),
2512 				&inherit)) {
2513 			return (bool)(inherit&HANDLE_FLAG_INHERIT);
2514 		}
2515 		return false;
2516 	#else
2517 		#error no FD_CLOEXEC or anything like it
2518 	#endif
2519 }
2520 
printf(const char * format,...)2521 size_t filedescriptor::printf(const char *format, ...) {
2522 	va_list	argp;
2523 	va_start(argp,format);
2524 	size_t	result=printf(format,&argp);
2525 	va_end(argp);
2526 	return result;
2527 }
2528 
printf(const char * format,va_list * argp)2529 size_t filedescriptor::printf(const char *format, va_list *argp) {
2530 
2531 	ssize_t	size=0;
2532 
2533 	// If we're not buffering writes...
2534 	if (!pvt->_writebuffer) {
2535 
2536 		#ifdef RUDIMENTS_HAVE_VDPRINTF
2537 
2538 			// use vdprintf if it's available
2539 			// (on some platforms (redhat 9), it tends to set
2540 			// errno=ESPIPE, even on success, so save/restore
2541 			// errno too)
2542 			int32_t	olderr=error::getErrorNumber();
2543 			int	result=vdprintf(pvt->_fd,format,*argp);
2544 			if (result>-1) {
2545 				error::setErrorNumber(olderr);
2546 			}
2547 			return result;
2548 
2549 		#else
2550 
2551 			// otherwise use vfprintf, if we can
2552 			FILE	*f=NULL;
2553 			if (pvt->_fd==0) {
2554 				f=stdin;
2555 			} else if (pvt->_fd==1) {
2556 				f=stdout;
2557 			} else if (pvt->_fd==2) {
2558 				f=stderr;
2559 			}
2560 
2561 			// Use fdopen if it's available.  Unfortunately we
2562 			// can't (reliably) on Windows because it won't work
2563 			// if the filedescriptor is a socket.
2564 			#if defined(RUDIMENTS_HAVE_FDOPEN) && \
2565 				defined(FD) && !defined(_WIN32)
2566 			else {
2567 				f=fdopen(pvt->_fd,"a");
2568 
2569 				// Some platforms (Unixware) don't like "a"
2570 				// with some types of file descriptors, so if
2571 				// "a" fails, then try "w".
2572 				if (!f) {
2573 					f=fdopen(pvt->_fd,"w");
2574 				}
2575 			}
2576 			#endif
2577 
2578 			if (f) {
2579 				size=vfprintf(f,format,*argp);
2580 				fflush(f);
2581 
2582 				#if defined(RUDIMENTS_HAVE_FDOPEN) && \
2583 					defined(FD) && !defined(_WIN32)
2584 				if (f!=stdin && f!=stdout && f!=stderr) {
2585 
2586 					// We need to free f but we don't want
2587 					// fclose() to close pvt->_fd.  There's
2588 					// no standard way of doing this though.
2589 					//
2590 					// Setting f's file descriptor member
2591 					// to -1 is generally reliable, though
2592 					// that's tricky too...
2593 
2594 					// The size and signedness of
2595 					// FD varies a bit.  This
2596 					// is the only way to handle
2597 					// all variations without the
2598 					// compiler throwing errors.
2599 					if (sizeof(FD)==1) {
2600 						int8_t	i8=-1;
2601 						bytestring::copy(&(FD),&i8,1);
2602 					} else if (sizeof(FD)==2) {
2603 						int16_t i16=-1;
2604 						bytestring::copy(&(FD),&i16,2);
2605 					} else if (sizeof(FD)==4) {
2606 						int32_t i32=-1;
2607 						bytestring::copy(&(FD),&i32,4);
2608 					} else if (sizeof(FD)==8) {
2609 						int64_t i64=-1;
2610 						bytestring::copy(&(FD),&i64,8);
2611 					}
2612 
2613 					// ok, now close f
2614 					fclose(f);
2615 				}
2616 				#endif
2617 
2618 				return size;
2619 			}
2620 		#endif
2621 	}
2622 
2623 	// If we are buffering writes though, don't use the above because it
2624 	// would bypass the buffer.
2625 
2626 	// write the formatted data to a buffer
2627 	char	*buffer=NULL;
2628 	#ifdef RUDIMENTS_HAVE_VASPRINTF
2629 		size=vasprintf(&buffer,format,*argp);
2630 	#else
2631 		size=charstring::printf(&buffer,format,argp);
2632 	#endif
2633 
2634 	// write the buffer to the file descriptor
2635 	write(buffer,size);
2636 
2637 	// clean up
2638 	#ifdef RUDIMENTS_HAVE_VASPRINTF
2639 		free(buffer);
2640 	#else
2641 		delete[] buffer;
2642 	#endif
2643 
2644 	return size;
2645 }
2646 
safePrint(char c)2647 void filedescriptor::safePrint(char c) {
2648 	safePrint((unsigned char)c);
2649 }
2650 
safePrint(const char * string,int32_t length)2651 void filedescriptor::safePrint(const char *string, int32_t length) {
2652 	safePrint((const unsigned char *)string,length);
2653 }
2654 
safePrint(const char * string)2655 void filedescriptor::safePrint(const char *string) {
2656 	safePrint((const unsigned char *)string);
2657 }
2658 
2659 static char hex[17]="0123456789ABCDEF";
2660 
safePrint(unsigned char c)2661 void filedescriptor::safePrint(unsigned char c) {
2662 	if (c=='\r') {
2663 		printf("\\r");
2664 	} else if (c=='\n') {
2665 		printf("\\n");
2666 	} else if (c=='	') {
2667 		printf("\\t");
2668 	} else if (c>=' ' && c<='~') {
2669 		printf("%c",c);
2670 	} else {
2671 		unsigned int	uintc=(unsigned char)c;
2672 		printf("(0x%c%c|%d)",hex[((c>>4)&0x0F)],hex[(c&0x0F)],uintc);
2673 	}
2674 }
2675 
safePrint(const unsigned char * string,int32_t length)2676 void filedescriptor::safePrint(const unsigned char *string, int32_t length) {
2677 	for (int32_t i=0; i<length; i++) {
2678 		safePrint(*string);
2679 		string++;
2680 	}
2681 }
2682 
safePrint(const unsigned char * string)2683 void filedescriptor::safePrint(const unsigned char *string) {
2684 	safePrint(string,charstring::length((const char *)string));
2685 }
2686 
printBits(unsigned char value)2687 void filedescriptor::printBits(unsigned char value) {
2688 	printBits((const unsigned char *)&value,sizeof(value));
2689 }
2690 
printBits(uint16_t value)2691 void filedescriptor::printBits(uint16_t value) {
2692 	printBits((const unsigned char *)&value,sizeof(value));
2693 }
2694 
printBits(uint32_t value)2695 void filedescriptor::printBits(uint32_t value) {
2696 	printBits((const unsigned char *)&value,sizeof(value));
2697 }
2698 
printBits(uint64_t value)2699 void filedescriptor::printBits(uint64_t value) {
2700 	printBits((const unsigned char *)&value,sizeof(value));
2701 }
2702 
printBits(char value)2703 void filedescriptor::printBits(char value) {
2704 	printBits((const unsigned char *)&value,sizeof(value));
2705 }
2706 
printBits(int16_t value)2707 void filedescriptor::printBits(int16_t value) {
2708 	printBits((const unsigned char *)&value,sizeof(value));
2709 }
2710 
printBits(int32_t value)2711 void filedescriptor::printBits(int32_t value) {
2712 	printBits((const unsigned char *)&value,sizeof(value));
2713 }
2714 
printBits(int64_t value)2715 void filedescriptor::printBits(int64_t value) {
2716 	printBits((const unsigned char *)&value,sizeof(value));
2717 }
2718 
printBits(const unsigned char * bits,uint64_t size)2719 void filedescriptor::printBits(const unsigned char *bits, uint64_t size) {
2720 	for (uint64_t i=0; i<size; i++) {
2721 		unsigned char byte=bits[i];
2722 		for (int8_t j=7; j>=0; j--) {
2723 			printf("%d",(byte>>j)&0x01);
2724 		}
2725 	}
2726 }
2727 
2728 #if defined(_WIN32) && defined(RUDIMENTS_HAVE_LONG_LONG)
invalidParameterHandler(const wchar_t * expression,const wchar_t * function,const wchar_t * file,unsigned int line,uintptr_t preserved)2729 static void invalidParameterHandler(const wchar_t *expression,
2730 					const wchar_t *function,
2731 					const wchar_t *file,
2732 					unsigned int line,
2733 					uintptr_t preserved) {
2734 	// don't do anything
2735 }
2736 #endif
2737 
getHandleFromFileDescriptor(int32_t fd)2738 void *filedescriptor::getHandleFromFileDescriptor(int32_t fd) {
2739 	#if defined(_WIN32)
2740 		#if defined(RUDIMENTS_HAVE_LONG_LONG)
2741 		if (fd<0) {
2742 			return INVALID_HANDLE_VALUE;
2743 		}
2744 		_invalid_parameter_handler	oldiph=
2745 			_set_invalid_parameter_handler(invalidParameterHandler);
2746 		intptr_t	handle=_get_osfhandle(fd);
2747 		_set_invalid_parameter_handler(oldiph);
2748 		return (void *)handle;
2749 		#else
2750 		// this is dangerous, and can crash if fd is invalid,
2751 		// but I'm not sure what else to do
2752 		return (void *)_get_osfhandle(fd);
2753 		#endif
2754 	#else
2755 		return NULL;
2756 	#endif
2757 }
2758