277 lines
6.4 KiB
C
Executable File
277 lines
6.4 KiB
C
Executable File
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
|
|
/* All Rights Reserved */
|
|
|
|
/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
|
|
/* The copyright notice above does not evidence any */
|
|
/* actual or intended publication of such source code. */
|
|
|
|
#ident "@(#)connect.c 1.16 94/04/08 SMI" /* SVr4.0 1.7 */
|
|
|
|
/*
|
|
* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
|
* PROPRIETARY NOTICE (Combined)
|
|
*
|
|
* This source code is unpublished proprietary information
|
|
* constituting, or derived under license from AT&T's UNIX(r) System V.
|
|
* In addition, portions of such source code were derived from Berkeley
|
|
* 4.3 BSD under license from the Regents of the University of
|
|
* California.
|
|
*
|
|
*
|
|
*
|
|
* Copyright Notice
|
|
*
|
|
* Notice of copyright on this source code product does not indicate
|
|
* publication.
|
|
*
|
|
* (c) 1986,1987,1988.1989 Sun Microsystems, Inc
|
|
* (c) 1983,1984,1985,1986,1987,1988,1989 AT&T.
|
|
* All rights reserved.
|
|
*
|
|
*/
|
|
|
|
#include "sockmt.h"
|
|
#include <sys/param.h>
|
|
#include <sys/ioctl.h>
|
|
#include <stropts.h>
|
|
#include <errno.h>
|
|
#include <tiuser.h>
|
|
#include <sys/socketvar.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/stream.h>
|
|
#include <sys/sockmod.h>
|
|
#include <fcntl.h>
|
|
#include <signal.h>
|
|
#include <netinet/in.h>
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include "sock.h"
|
|
|
|
static int __connect(struct _si_user *siptr, struct sockaddr *name,
|
|
int namelen, int nameflag, sigset_t *connmaskp);
|
|
|
|
#pragma weak connect = _connect
|
|
|
|
int
|
|
_connect(s, name, namelen)
|
|
register int s;
|
|
register struct sockaddr *name;
|
|
register int namelen;
|
|
{
|
|
struct _si_user *siptr;
|
|
sigset_t mask;
|
|
int retval;
|
|
|
|
if ((siptr = _s_checkfd(s)) == NULL)
|
|
return (-1);
|
|
|
|
MUTEX_LOCK_SIGMASK(&siptr->lock, mask);
|
|
retval = __connect(siptr, name, namelen, 1, &mask);
|
|
MUTEX_UNLOCK_SIGMASK(&siptr->lock, mask);
|
|
return (retval);
|
|
}
|
|
|
|
static int
|
|
__connect(siptr, name, namelen, nameflag, connmaskp)
|
|
struct _si_user *siptr;
|
|
register struct sockaddr *name;
|
|
register int namelen;
|
|
register int nameflag;
|
|
sigset_t *connmaskp;
|
|
{
|
|
struct t_call sndcall;
|
|
struct bind_ux bind_ux;
|
|
|
|
(void) memset((caddr_t)&sndcall, 0, sizeof (sndcall));
|
|
|
|
if (name && name->sa_family == AF_INET) {
|
|
struct sockaddr_in *saddr_in;
|
|
|
|
if (namelen < sizeof (*saddr_in)) {
|
|
errno = EINVAL;
|
|
return (-1);
|
|
}
|
|
saddr_in = (struct sockaddr_in *)name;
|
|
(void) memset(&saddr_in->sin_zero, 0, 8);
|
|
}
|
|
|
|
if (name && name->sa_family == AF_UNIX) {
|
|
struct stat rstat;
|
|
struct sockaddr_un *un;
|
|
int len;
|
|
|
|
if (siptr->udata.sockparams.sp_family != AF_UNIX) {
|
|
errno = EINVAL;
|
|
return (-1);
|
|
}
|
|
if (namelen > sizeof (name->sa_family)) {
|
|
un = (struct sockaddr_un *)name;
|
|
|
|
if (namelen > sizeof (*un) ||
|
|
(len = _s_uxpathlen(un)) ==
|
|
sizeof (un->sun_path)) {
|
|
errno = EMSGSIZE;
|
|
return (-1);
|
|
}
|
|
|
|
un->sun_path[len] = 0; /* Null terminate */
|
|
|
|
/*
|
|
* Stat the file.
|
|
*/
|
|
#if defined(i386)
|
|
if (_xstat(_STAT_VER, (caddr_t)un->sun_path,
|
|
&rstat) < 0)
|
|
#elif defined(sparc)
|
|
if (_stat((caddr_t) un->sun_path, &rstat) < 0)
|
|
#else
|
|
#error Unknown architecture!
|
|
#endif
|
|
return (-1);
|
|
|
|
if ((rstat.st_mode & S_IFMT) != S_IFIFO) {
|
|
errno = ENOTSOCK;
|
|
return (-1);
|
|
}
|
|
|
|
(void) memset((caddr_t)&bind_ux, 0, sizeof (bind_ux));
|
|
bind_ux.extdev = rstat.st_dev;
|
|
bind_ux.extino = rstat.st_ino;
|
|
bind_ux.extsize = sizeof (struct ux_dev);
|
|
if (nameflag == 0)
|
|
namelen = sizeof (name->sa_family);
|
|
(void) memcpy((caddr_t)&bind_ux.name,
|
|
(caddr_t)name, namelen);
|
|
|
|
sndcall.addr.buf = (caddr_t)&bind_ux;
|
|
sndcall.addr.len = sizeof (bind_ux);
|
|
} else {
|
|
sndcall.addr.buf = NULL;
|
|
sndcall.addr.len = 0;
|
|
}
|
|
} else {
|
|
sndcall.addr.buf = (caddr_t)name;
|
|
sndcall.addr.len = _s_min(namelen, siptr->udata.addrsize);
|
|
}
|
|
|
|
return (_connect2(siptr, &sndcall, connmaskp));
|
|
}
|
|
|
|
int
|
|
_connect2(siptr, sndcall, connmaskp)
|
|
register struct _si_user *siptr;
|
|
register struct t_call *sndcall;
|
|
sigset_t *connmaskp;
|
|
{
|
|
register int fctlflg;
|
|
sigset_t procmask;
|
|
struct strbuf ctlbuf;
|
|
int didalloc = 0;
|
|
|
|
fctlflg = s_getfflags(siptr);
|
|
|
|
if (fctlflg&(O_NDELAY|O_NONBLOCK) && siptr->udata.servtype != T_CLTS) {
|
|
/*
|
|
* Secretly tell sockmod not to pass
|
|
* up the T_CONN_CON, because we
|
|
* are not going to wait for it.
|
|
* (But dont tell anyone - especially
|
|
* the transport provider).
|
|
*/
|
|
sndcall->opt.len = (ulong)-1; /* secret sign */
|
|
}
|
|
|
|
/*
|
|
* must be bound for TLI except TCP.
|
|
*/
|
|
if ((siptr->udata.so_state & SS_ISBOUND) == 0) {
|
|
if (siptr->udata.sockparams.sp_family == AF_INET &&
|
|
siptr->udata.sockparams.sp_type == SOCK_STREAM) {
|
|
siptr->udata.so_state |= SS_ISBOUND;
|
|
} else if (__bind(siptr, NULL, 0, NULL, NULL) < 0)
|
|
return (-1);
|
|
}
|
|
/*
|
|
* Acquire ctlbuf for use in sending/receiving
|
|
*/
|
|
ctlbuf.len = 0;
|
|
if (siptr->ctlbuf) {
|
|
ctlbuf.buf = siptr->ctlbuf;
|
|
siptr->ctlbuf = NULL;
|
|
ctlbuf.maxlen = siptr->ctlsize;
|
|
} else {
|
|
/*
|
|
* siptr->ctlbuf is in use
|
|
* allocate and free after use.
|
|
*/
|
|
if ((ctlbuf.maxlen = _s_cbuf_alloc(siptr,
|
|
&ctlbuf.buf)) < 0)
|
|
return (-1);
|
|
didalloc = 1;
|
|
}
|
|
|
|
/*
|
|
* Block all signals till T_CONN_REQ req sent and
|
|
* acked with T_OK/ERROR_ACK
|
|
*/
|
|
_s_blockallsignals(&procmask);
|
|
if (_s_snd_conn_req(siptr, sndcall, &ctlbuf) < 0) {
|
|
_s_restoresigmask(&procmask);
|
|
goto err_out;
|
|
}
|
|
_s_restoresigmask(&procmask);
|
|
/*
|
|
* If no delay, return with error if not CLTS.
|
|
*/
|
|
if (fctlflg&(O_NDELAY|O_NONBLOCK) && siptr->udata.servtype != T_CLTS) {
|
|
errno = EINPROGRESS;
|
|
siptr->udata.so_state |= SS_ISCONNECTING;
|
|
goto err_out;
|
|
}
|
|
|
|
/*
|
|
* If CLTS, don't get the connection confirm.
|
|
*/
|
|
if (siptr->udata.servtype == T_CLTS) {
|
|
if (sndcall->addr.len == 0)
|
|
/*
|
|
* Connect to Null address, breaks
|
|
* the connection.
|
|
*/
|
|
siptr->udata.so_state &= ~SS_ISCONNECTED;
|
|
else siptr->udata.so_state |= SS_ISCONNECTED;
|
|
goto ok_out;
|
|
}
|
|
/*
|
|
* This is a potentially blocking call.
|
|
* In MT case, drop the lock and allow signals
|
|
* and then reacquire the lock later
|
|
*/
|
|
MUTEX_UNLOCK_SIGMASK(&siptr->lock, *connmaskp);
|
|
if (_s_rcv_conn_con(siptr, &ctlbuf) < 0) {
|
|
MUTEX_LOCK_SIGMASK(&siptr->lock, *connmaskp);
|
|
goto err_out;
|
|
}
|
|
MUTEX_LOCK_SIGMASK(&siptr->lock, *connmaskp);
|
|
|
|
siptr->udata.so_state |= SS_ISCONNECTED;
|
|
|
|
ok_out:
|
|
if (didalloc)
|
|
free(ctlbuf.buf);
|
|
else
|
|
siptr->ctlbuf = ctlbuf.buf;
|
|
|
|
return (0);
|
|
|
|
err_out:
|
|
if (didalloc)
|
|
free(ctlbuf.buf);
|
|
else
|
|
siptr->ctlbuf = ctlbuf.buf;
|
|
return (-1);
|
|
}
|