summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux/linux_socket.c
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2005-03-07 07:26:42 +0000
committersobomax <sobomax@FreeBSD.org>2005-03-07 07:26:42 +0000
commita5d845fec654f4b43610ba376ae17fa9309853b0 (patch)
tree0b22e0cd71756d80eb0006639568691eaa0e3623 /sys/compat/linux/linux_socket.c
parent7d3d18d907337f6f78e665a6e87ad183892db3c8 (diff)
downloadFreeBSD-src-a5d845fec654f4b43610ba376ae17fa9309853b0.zip
FreeBSD-src-a5d845fec654f4b43610ba376ae17fa9309853b0.tar.gz
Handle MSG_NOSIGNAL flag in linux_send() by setting SO_NOSIGPIPE on socket
for the duration of the send() call. Such approach may be less than ideal in threading environment, when several threads share the same socket and it might happen that several of them are calling linux_send() at the same time with and without SO_NOSIGPIPE set. However, such race condition is very unlikely in practice, therefore this change provides practical improvement compared to the previous behaviour. PR: kern/76426 Submitted by: Steven Hartland <killing@multiplay.co.uk> MFC after: 3 days
Diffstat (limited to 'sys/compat/linux/linux_socket.c')
-rw-r--r--sys/compat/linux/linux_socket.c27
1 files changed, 25 insertions, 2 deletions
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c
index dd358ce..6f6f501 100644
--- a/sys/compat/linux/linux_socket.c
+++ b/sys/compat/linux/linux_socket.c
@@ -816,18 +816,41 @@ linux_send(struct thread *td, struct linux_send_args *args)
caddr_t to;
int tolen;
} */ bsd_args;
- int error;
+ int error, nosigpipe, onosigpipe;
+ socklen_t valsize;
if ((error = copyin(args, &linux_args, sizeof(linux_args))))
return (error);
+ if (linux_args.flags & LINUX_MSG_NOSIGNAL) {
+ valsize = sizeof(onosigpipe);
+ error = kern_getsockopt(td, linux_args.s, SOL_SOCKET,
+ SO_NOSIGPIPE, &onosigpipe, UIO_SYSSPACE,
+ &valsize);
+ if (error != 0)
+ return error;
+ if (onosigpipe == 0) {
+ nosigpipe = 1;
+ error = kern_setsockopt(td, linux_args.s, SOL_SOCKET,
+ SO_NOSIGPIPE, &nosigpipe, UIO_SYSSPACE,
+ sizeof(nosigpipe));
+ if (error != 0)
+ return error;
+ }
+ }
bsd_args.s = linux_args.s;
bsd_args.buf = (caddr_t)PTRIN(linux_args.msg);
bsd_args.len = linux_args.len;
bsd_args.flags = linux_args.flags;
bsd_args.to = NULL;
bsd_args.tolen = 0;
- return (sendto(td, &bsd_args));
+ error = sendto(td, &bsd_args);
+ if ((linux_args.flags & LINUX_MSG_NOSIGNAL) && (onosigpipe == 0)) {
+ kern_setsockopt(td, linux_args.s, SOL_SOCKET,
+ SO_NOSIGPIPE, &onosigpipe, UIO_SYSSPACE,
+ sizeof(onosigpipe));
+ }
+ return error;
}
struct linux_recv_args {
OpenPOWER on IntegriCloud