socket: implement SOCK_CLOEXEC and SOCK_NONBLOCK
Change-Id: I3fa36fa999c82a192d402cb4d913bd397e106e53
This commit is contained in:
		
							parent
							
								
									fd610ba1b0
								
							
						
					
					
						commit
						fa78dc389f
					
				| @ -18,12 +18,17 @@ __weak_alias(socket, _socket) | |||||||
| 
 | 
 | ||||||
| #define DEBUG 0 | #define DEBUG 0 | ||||||
| 
 | 
 | ||||||
| static int _tcp_socket(int protocol); | static int _tcp_socket(int type, int protocol); | ||||||
| static int _udp_socket(int protocol); | static int _udp_socket(int type, int protocol); | ||||||
| static int _uds_socket(int type, int protocol); | static int _uds_socket(int type, int protocol); | ||||||
|  | static void _socket_flags(int type, int *result); | ||||||
| 
 | 
 | ||||||
| int socket(int domain, int type, int protocol) | int socket(int domain, int type, int protocol) | ||||||
| { | { | ||||||
|  | 	int sock_type; | ||||||
|  | 
 | ||||||
|  | 	sock_type = type & ~SOCK_FLAGS_MASK; | ||||||
|  | 
 | ||||||
| #if DEBUG | #if DEBUG | ||||||
| 	fprintf(stderr, "socket: domain %d, type %d, protocol %d\n", | 	fprintf(stderr, "socket: domain %d, type %d, protocol %d\n", | ||||||
| 		domain, type, protocol); | 		domain, type, protocol); | ||||||
| @ -37,15 +42,16 @@ int socket(int domain, int type, int protocol) | |||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if (domain == AF_UNIX && (type == SOCK_STREAM || | 	if (domain == AF_UNIX && (sock_type == SOCK_STREAM || | ||||||
| 				type == SOCK_DGRAM || type == SOCK_SEQPACKET)) | 				  sock_type == SOCK_DGRAM || | ||||||
|  | 				  sock_type == SOCK_SEQPACKET)) | ||||||
| 		return _uds_socket(type, protocol); | 		return _uds_socket(type, protocol); | ||||||
| 
 | 
 | ||||||
| 	if (domain == AF_INET && type == SOCK_STREAM) | 	if (domain == AF_INET && sock_type == SOCK_STREAM) | ||||||
| 		return _tcp_socket(protocol); | 		return _tcp_socket(type, protocol); | ||||||
| 
 | 
 | ||||||
| 	if (domain == AF_INET && type == SOCK_DGRAM) | 	if (domain == AF_INET && sock_type == SOCK_DGRAM) | ||||||
| 		return _udp_socket(protocol); | 		return _udp_socket(type, protocol); | ||||||
| 
 | 
 | ||||||
| #if DEBUG | #if DEBUG | ||||||
| 	fprintf(stderr, "socket: nothing for domain %d, type %d, protocol %d\n", | 	fprintf(stderr, "socket: nothing for domain %d, type %d, protocol %d\n", | ||||||
| @ -55,9 +61,25 @@ int socket(int domain, int type, int protocol) | |||||||
| 	return -1; | 	return -1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int _tcp_socket(int protocol) | static void | ||||||
|  | _socket_flags(int type, int *result) | ||||||
| { | { | ||||||
| 	int fd; | 	/* Process socket flags */ | ||||||
|  | 	if (type & SOCK_CLOEXEC) { | ||||||
|  | 		*result |= O_CLOEXEC; | ||||||
|  | 	} | ||||||
|  | 	if (type & SOCK_NONBLOCK) { | ||||||
|  | 		*result |= O_NONBLOCK; | ||||||
|  | 	} | ||||||
|  | 	if (type & SOCK_NOSIGPIPE) { | ||||||
|  | 		*result |= O_NOSIGPIPE; | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static int _tcp_socket(int type, int protocol) | ||||||
|  | { | ||||||
|  | 	int flags = O_RDWR; | ||||||
|  | 
 | ||||||
| 	if (protocol != 0 && protocol != IPPROTO_TCP) | 	if (protocol != 0 && protocol != IPPROTO_TCP) | ||||||
| 	{ | 	{ | ||||||
| #if DEBUG | #if DEBUG | ||||||
| @ -66,13 +88,15 @@ static int _tcp_socket(int protocol) | |||||||
| 		errno= EPROTONOSUPPORT; | 		errno= EPROTONOSUPPORT; | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 	fd= open(TCP_DEVICE, O_RDWR); | 
 | ||||||
| 	return fd; | 	_socket_flags(type, &flags); | ||||||
|  | 
 | ||||||
|  | 	return open(TCP_DEVICE, flags); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static int _udp_socket(int protocol) | static int _udp_socket(int type, int protocol) | ||||||
| { | { | ||||||
| 	int r, fd, t_errno; | 	int r, fd, t_errno, flags = O_RDWR; | ||||||
| 	struct sockaddr_in sin; | 	struct sockaddr_in sin; | ||||||
| 
 | 
 | ||||||
| 	if (protocol != 0 && protocol != IPPROTO_UDP) | 	if (protocol != 0 && protocol != IPPROTO_UDP) | ||||||
| @ -83,7 +107,8 @@ static int _udp_socket(int protocol) | |||||||
| 		errno= EPROTONOSUPPORT; | 		errno= EPROTONOSUPPORT; | ||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 	fd= open(UDP_DEVICE, O_RDWR); | 	_socket_flags(type, &flags); | ||||||
|  | 	fd= open(UDP_DEVICE, flags); | ||||||
| 	if (fd == -1) | 	if (fd == -1) | ||||||
| 		return fd; | 		return fd; | ||||||
| 
 | 
 | ||||||
| @ -104,7 +129,7 @@ static int _udp_socket(int protocol) | |||||||
| 
 | 
 | ||||||
| static int _uds_socket(int type, int protocol) | static int _uds_socket(int type, int protocol) | ||||||
| { | { | ||||||
| 	int fd, r; | 	int fd, r, flags = O_RDWR, sock_type; | ||||||
| 	if (protocol != 0) | 	if (protocol != 0) | ||||||
| 	{ | 	{ | ||||||
| #if DEBUG | #if DEBUG | ||||||
| @ -114,7 +139,8 @@ static int _uds_socket(int type, int protocol) | |||||||
| 		return -1; | 		return -1; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fd= open(UDS_DEVICE, O_RDWR); | 	_socket_flags(type, &flags); | ||||||
|  | 	fd= open(UDS_DEVICE, flags); | ||||||
| 	if (fd == -1) { | 	if (fd == -1) { | ||||||
| 		return fd; | 		return fd; | ||||||
| 	} | 	} | ||||||
| @ -122,7 +148,8 @@ static int _uds_socket(int type, int protocol) | |||||||
| 	/* set the type for the socket via ioctl (SOCK_DGRAM, 
 | 	/* set the type for the socket via ioctl (SOCK_DGRAM, 
 | ||||||
| 	 * SOCK_STREAM, SOCK_SEQPACKET, etc) | 	 * SOCK_STREAM, SOCK_SEQPACKET, etc) | ||||||
| 	 */ | 	 */ | ||||||
| 	r= ioctl(fd, NWIOSUDSTYPE, &type); | 	sock_type = type & ~SOCK_FLAGS_MASK; | ||||||
|  | 	r= ioctl(fd, NWIOSUDSTYPE, &sock_type); | ||||||
| 	if (r == -1) { | 	if (r == -1) { | ||||||
| 		int ioctl_errno; | 		int ioctl_errno; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -286,7 +286,16 @@ int do_fcntl() | |||||||
| 
 | 
 | ||||||
| 	break; | 	break; | ||||||
|      } |      } | ||||||
| 
 |     case F_GETNOSIGPIPE: | ||||||
|  | 	/* POSIX: return value other than -1 is flag is set, else -1 */ | ||||||
|  | 	r = -1; | ||||||
|  | 	if (f->filp_flags & O_NOSIGPIPE) | ||||||
|  | 		r = 0; | ||||||
|  | 	break; | ||||||
|  |     case F_SETNOSIGPIPE: | ||||||
|  | 	fl = (O_NOSIGPIPE); | ||||||
|  | 	f->filp_flags = (f->filp_flags & ~fl) | (fcntl_argx & fl); | ||||||
|  | 	break; | ||||||
|     default: |     default: | ||||||
| 	r = EINVAL; | 	r = EINVAL; | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -174,7 +174,7 @@ endpoint_t map_to_fs_e; | |||||||
|  *				pipe_check				     * |  *				pipe_check				     * | ||||||
|  *===========================================================================*/ |  *===========================================================================*/ | ||||||
| int pipe_check( | int pipe_check( | ||||||
| struct vnode *vp,	/* the inode of the pipe */ | struct filp *filp,	/* the filp of the pipe */ | ||||||
| int rw_flag,		/* READING or WRITING */ | int rw_flag,		/* READING or WRITING */ | ||||||
| int oflags,		/* flags set by open or fcntl */ | int oflags,		/* flags set by open or fcntl */ | ||||||
| int bytes,		/* bytes to be read or written (all chunks) */ | int bytes,		/* bytes to be read or written (all chunks) */ | ||||||
| @ -186,9 +186,12 @@ int notouch		/* check only */ | |||||||
|  * and there is no writer, return 0 bytes.  If a process is writing to a |  * and there is no writer, return 0 bytes.  If a process is writing to a | ||||||
|  * pipe and no one is reading from it, give a broken pipe error. |  * pipe and no one is reading from it, give a broken pipe error. | ||||||
|  */ |  */ | ||||||
|  |   struct vnode *vp; | ||||||
|   off_t pos; |   off_t pos; | ||||||
|   int r = OK; |   int r = OK; | ||||||
| 
 | 
 | ||||||
|  |   vp = filp->filp_vno; | ||||||
|  | 
 | ||||||
|   /* Reads start at the beginning; writes append to pipes */ |   /* Reads start at the beginning; writes append to pipes */ | ||||||
|   if (notouch) /* In this case we don't actually care whether data transfer
 |   if (notouch) /* In this case we don't actually care whether data transfer
 | ||||||
| 		* would succeed. See POSIX 1003.1-2008 */ | 		* would succeed. See POSIX 1003.1-2008 */ | ||||||
| @ -221,10 +224,6 @@ int notouch		/* check only */ | |||||||
| 
 | 
 | ||||||
|   /* Process is writing to a pipe. */ |   /* Process is writing to a pipe. */ | ||||||
|   if (find_filp(vp, R_BIT) == NULL) { |   if (find_filp(vp, R_BIT) == NULL) { | ||||||
| 	/* Process is writing, but there is no reader. Tell kernel to generate
 |  | ||||||
| 	 * a SIGPIPE signal. */ |  | ||||||
| 	if (!notouch) sys_kill(fp->fp_endpoint, SIGPIPE); |  | ||||||
| 
 |  | ||||||
| 	return(EPIPE); | 	return(EPIPE); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -186,7 +186,7 @@ int do_check_perms(void); | |||||||
| int do_pipe(void); | int do_pipe(void); | ||||||
| int map_vnode(struct vnode *vp, endpoint_t fs_e); | int map_vnode(struct vnode *vp, endpoint_t fs_e); | ||||||
| void unpause(endpoint_t proc_e); | void unpause(endpoint_t proc_e); | ||||||
| int pipe_check(struct vnode *vp, int rw_flag, int oflags, int bytes, | int pipe_check(struct filp *filp, int rw_flag, int oflags, int bytes, | ||||||
| 	int notouch); | 	int notouch); | ||||||
| void release(struct vnode *vp, int op, int count); | void release(struct vnode *vp, int op, int count); | ||||||
| void revive(endpoint_t proc_e, int returned); | void revive(endpoint_t proc_e, int returned); | ||||||
|  | |||||||
| @ -124,27 +124,23 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, | |||||||
|   register struct vnode *vp; |   register struct vnode *vp; | ||||||
|   u64_t position, res_pos, new_pos; |   u64_t position, res_pos, new_pos; | ||||||
|   unsigned int cum_io, cum_io_incr, res_cum_io; |   unsigned int cum_io, cum_io_incr, res_cum_io; | ||||||
|   int op, oflags, r; |   int op, r; | ||||||
| 
 | 
 | ||||||
|   position = f->filp_pos; |   position = f->filp_pos; | ||||||
|   oflags = f->filp_flags; |  | ||||||
|   vp = f->filp_vno; |   vp = f->filp_vno; | ||||||
|   r = OK; |   r = OK; | ||||||
|   cum_io = 0; |   cum_io = 0; | ||||||
| 
 | 
 | ||||||
|   if (size > SSIZE_MAX) return(EINVAL); |   if (size > SSIZE_MAX) return(EINVAL); | ||||||
| 
 | 
 | ||||||
|   if (S_ISFIFO(vp->v_mode)) { |   op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); | ||||||
|  | 
 | ||||||
|  |   if (S_ISFIFO(vp->v_mode)) {		/* Pipes */ | ||||||
| 	if (fp->fp_cum_io_partial != 0) { | 	if (fp->fp_cum_io_partial != 0) { | ||||||
| 		panic("VFS: read_write: fp_cum_io_partial not clear"); | 		panic("VFS: read_write: fp_cum_io_partial not clear"); | ||||||
| 	} | 	} | ||||||
| 	r = rw_pipe(rw_flag, for_e, f, buf, size); | 	r = rw_pipe(rw_flag, for_e, f, buf, size); | ||||||
| 	return(r); |   } else if (S_ISCHR(vp->v_mode)) {	/* Character special files. */ | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   op = (rw_flag == READING ? VFS_DEV_READ : VFS_DEV_WRITE); |  | ||||||
| 
 |  | ||||||
|   if (S_ISCHR(vp->v_mode)) {	/* Character special files. */ |  | ||||||
| 	dev_t dev; | 	dev_t dev; | ||||||
| 	int suspend_reopen; | 	int suspend_reopen; | ||||||
| 
 | 
 | ||||||
| @ -154,7 +150,7 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, | |||||||
| 	suspend_reopen = (f->filp_state & FS_NEEDS_REOPEN); | 	suspend_reopen = (f->filp_state & FS_NEEDS_REOPEN); | ||||||
| 	dev = (dev_t) vp->v_sdev; | 	dev = (dev_t) vp->v_sdev; | ||||||
| 
 | 
 | ||||||
| 	r = dev_io(op, dev, for_e, buf, position, size, oflags, | 	r = dev_io(op, dev, for_e, buf, position, size, f->filp_flags, | ||||||
| 		   suspend_reopen); | 		   suspend_reopen); | ||||||
| 	if (r >= 0) { | 	if (r >= 0) { | ||||||
| 		cum_io = r; | 		cum_io = r; | ||||||
| @ -178,7 +174,7 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, | |||||||
|   } else {				/* Regular files */ |   } else {				/* Regular files */ | ||||||
| 	if (rw_flag == WRITING) { | 	if (rw_flag == WRITING) { | ||||||
| 		/* Check for O_APPEND flag. */ | 		/* Check for O_APPEND flag. */ | ||||||
| 		if (oflags & O_APPEND) position = cvul64(vp->v_size); | 		if (f->filp_flags & O_APPEND) position = cvul64(vp->v_size); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/* Issue request */ | 	/* Issue request */ | ||||||
| @ -208,7 +204,18 @@ int read_write(int rw_flag, struct filp *f, char *buf, size_t size, | |||||||
| 
 | 
 | ||||||
|   f->filp_pos = position; |   f->filp_pos = position; | ||||||
| 
 | 
 | ||||||
|   if (r == OK) return(cum_io); |   if (r == EPIPE && rw_flag == WRITING) { | ||||||
|  | 	/* Process is writing, but there is no reader. Tell the kernel to
 | ||||||
|  | 	 * generate s SIGPIPE signal. | ||||||
|  | 	 */ | ||||||
|  | 	if (!(f->filp_flags & O_NOSIGPIPE)) { | ||||||
|  | 		sys_kill(fp->fp_endpoint, SIGPIPE); | ||||||
|  | 	} | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   if (r == OK) { | ||||||
|  | 	return(cum_io); | ||||||
|  |   } | ||||||
|   return(r); |   return(r); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -277,7 +284,7 @@ size_t req_size; | |||||||
|   /* fp->fp_cum_io_partial is only nonzero when doing partial writes */ |   /* fp->fp_cum_io_partial is only nonzero when doing partial writes */ | ||||||
|   cum_io = fp->fp_cum_io_partial; |   cum_io = fp->fp_cum_io_partial; | ||||||
| 
 | 
 | ||||||
|   r = pipe_check(vp, rw_flag, oflags, req_size, 0); |   r = pipe_check(f, rw_flag, oflags, req_size, 0); | ||||||
|   if (r <= 0) { |   if (r <= 0) { | ||||||
| 	if (r == SUSPEND) pipe_suspend(f, buf, req_size); | 	if (r == SUSPEND) pipe_suspend(f, buf, req_size); | ||||||
| 	return(r); | 	return(r); | ||||||
|  | |||||||
| @ -453,7 +453,7 @@ static int select_request_pipe(struct filp *f, int *ops, int block) | |||||||
| 
 | 
 | ||||||
|   if ((*ops & (SEL_RD|SEL_ERR))) { |   if ((*ops & (SEL_RD|SEL_ERR))) { | ||||||
| 	/* Check if we can read 1 byte */ | 	/* Check if we can read 1 byte */ | ||||||
| 	err = pipe_check(f->filp_vno, READING, f->filp_flags & ~O_NONBLOCK, 1, | 	err = pipe_check(f, READING, f->filp_flags & ~O_NONBLOCK, 1, | ||||||
| 			 1 /* Check only */); | 			 1 /* Check only */); | ||||||
| 
 | 
 | ||||||
| 	if (err != SUSPEND) | 	if (err != SUSPEND) | ||||||
| @ -470,7 +470,7 @@ static int select_request_pipe(struct filp *f, int *ops, int block) | |||||||
| 
 | 
 | ||||||
|   if ((*ops & (SEL_WR|SEL_ERR))) { |   if ((*ops & (SEL_WR|SEL_ERR))) { | ||||||
| 	/* Check if we can write 1 byte */ | 	/* Check if we can write 1 byte */ | ||||||
| 	err = pipe_check(f->filp_vno, WRITING, f->filp_flags & ~O_NONBLOCK, 1, | 	err = pipe_check(f, WRITING, f->filp_flags & ~O_NONBLOCK, 1, | ||||||
| 			 1 /* Check only */); | 			 1 /* Check only */); | ||||||
| 
 | 
 | ||||||
| 	if (err != SUSPEND) | 	if (err != SUSPEND) | ||||||
|  | |||||||
| @ -73,7 +73,9 @@ | |||||||
| 				 * restart | 				 * restart | ||||||
| 				 */ | 				 */ | ||||||
| #define O_CLOEXEC     020000	/* close on exec */ | #define O_CLOEXEC     020000	/* close on exec */ | ||||||
| 
 | #if defined(_NETBSD_SOURCE) | ||||||
|  | #define O_NOSIGPIPE   040000	/* don't deliver sigpipe */ | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| #ifndef __minix  /* NOT SUPPORTED! */ | #ifndef __minix  /* NOT SUPPORTED! */ | ||||||
| #if defined(_NETBSD_SOURCE) | #if defined(_NETBSD_SOURCE) | ||||||
| @ -126,6 +128,10 @@ | |||||||
| #define F_SETLK            6	/* set record locking information */ | #define F_SETLK            6	/* set record locking information */ | ||||||
| #define F_SETLKW           7	/* set record locking info; wait if blocked */ | #define F_SETLKW           7	/* set record locking info; wait if blocked */ | ||||||
| #define F_FREESP           8	/* free a section of a regular file */ | #define F_FREESP           8	/* free a section of a regular file */ | ||||||
|  | #if defined(_NETBSD_SOURCE) | ||||||
|  | #define F_GETNOSIGPIPE     9 | ||||||
|  | #define F_SETNOSIGPIPE    10 | ||||||
|  | #endif | ||||||
| 
 | 
 | ||||||
| /* File descriptor flags used for fcntl().  POSIX Table 6-2. */ | /* File descriptor flags used for fcntl().  POSIX Table 6-2. */ | ||||||
| #define FD_CLOEXEC         1	/* close on exec flag for third arg of fcntl */ | #define FD_CLOEXEC         1	/* close on exec flag for third arg of fcntl */ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 Thomas Veerman
						Thomas Veerman