diff options
author | msmith <msmith@FreeBSD.org> | 1998-02-07 02:13:27 +0000 |
---|---|---|
committer | msmith <msmith@FreeBSD.org> | 1998-02-07 02:13:27 +0000 |
commit | d3baeeda1e135d3e3e0d724edeea82b87846ed9e (patch) | |
tree | 5c69b73294099a3ac2ac1bbc5c6b20df7706c1d1 /sys/compat/linux | |
parent | 0511880d25a97d12093ac2652b29266fa6f86f9e (diff) | |
download | FreeBSD-src-d3baeeda1e135d3e3e0d724edeea82b87846ed9e.zip FreeBSD-src-d3baeeda1e135d3e3e0d724edeea82b87846ed9e.tar.gz |
In the words of the submitter:
----
I've worked to enhance the connect() patches.
I've just tested this with the Linux JDK appletviewer on an applet
that does a lot of connects, and it works as well as during my
previous tests.
The connect() patch is now a merge between my older patch and the
OpenBSD stuff. It ensures that any async error is returned by
connect() instead of getsockopt(SOL_SOCKET, SO_ERROR) as reasonnable
systems do.
There are also minor patches to implement IPPROTO_TCP for
get/setsocktopt(). These are also tested (with Linux Apache).
----
I would appreciate any feedback regarding these changes, as they'd
be very useful in 2.2.6.
Submitted by: pb@fasterix.freenix.org (Pierre Beyssac)
Diffstat (limited to 'sys/compat/linux')
-rw-r--r-- | sys/compat/linux/linux_socket.c | 64 |
1 files changed, 62 insertions, 2 deletions
diff --git a/sys/compat/linux/linux_socket.c b/sys/compat/linux/linux_socket.c index dc89319..aac40a0 100644 --- a/sys/compat/linux/linux_socket.c +++ b/sys/compat/linux/linux_socket.c @@ -25,7 +25,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $Id: linux_socket.c,v 1.10 1997/12/14 03:17:54 msmith Exp $ + * $Id: linux_socket.c,v 1.11 1997/12/16 17:40:11 eivind Exp $ */ /* XXX we use functions that might not exist. */ @@ -39,6 +39,7 @@ #include <sys/proc.h> #include <sys/systm.h> #include <sys/sysproto.h> +#include <sys/fcntl.h> #include <sys/socket.h> #include <netinet/in.h> @@ -348,7 +349,58 @@ linux_connect(struct proc *p, struct linux_connect_args *args) bsd_args.s = linux_args.s; bsd_args.name = (caddr_t)linux_args.name; bsd_args.namelen = linux_args.namelen; - return connect(p, &bsd_args); + error = connect(p, &bsd_args); + if (error == EISCONN) { + /* + * Linux doesn't return EISCONN the first time it occurs, + * when on a non-blocking socket. Instead it returns the + * error getsockopt(SOL_SOCKET, SO_ERROR) would return on BSD. + */ + struct fcntl_args /* { + int fd; + int cmd; + int arg; + } */ bsd_fcntl_args; + struct getsockopt_args /* { + int s; + int level; + int name; + caddr_t val; + int *avalsize; + } */ bsd_getsockopt_args; + void *status, *statusl; + int stat, statl = sizeof stat; + caddr_t sg; + + /* Check for non-blocking */ + bsd_fcntl_args.fd = linux_args.s; + bsd_fcntl_args.cmd = F_GETFL; + bsd_fcntl_args.arg = 0; + error = fcntl(p, &bsd_fcntl_args); + if (error == 0 && (p->p_retval[0] & O_NONBLOCK)) { + sg = stackgap_init(); + status = stackgap_alloc(&sg, sizeof stat); + statusl = stackgap_alloc(&sg, sizeof statusl); + + if ((error = copyout(&statl, statusl, sizeof statl))) + return error; + + bsd_getsockopt_args.s = linux_args.s; + bsd_getsockopt_args.level = SOL_SOCKET; + bsd_getsockopt_args.name = SO_ERROR; + bsd_getsockopt_args.val = status; + bsd_getsockopt_args.avalsize = statusl; + + error = getsockopt(p, &bsd_getsockopt_args); + if (error) + return error; + if ((error = copyin(status, &stat, sizeof stat))) + return error; + p->p_retval[0] = stat; + return 0; + } + } + return error; } struct linux_listen_args { @@ -661,6 +713,10 @@ linux_setsockopt(struct proc *p, struct linux_setsockopt_args *args) case IPPROTO_IP: name = linux_to_bsd_ip_sockopt(linux_args.optname); break; + case IPPROTO_TCP: + /* Linux TCP option values match BSD's */ + name = linux_args.optname; + break; default: return EINVAL; } @@ -704,6 +760,10 @@ linux_getsockopt(struct proc *p, struct linux_getsockopt_args *args) case IPPROTO_IP: name = linux_to_bsd_ip_sockopt(linux_args.optname); break; + case IPPROTO_TCP: + /* Linux TCP option values match BSD's */ + name = linux_args.optname; + break; default: return EINVAL; } |