Beispiel #1
0
/* Return a pair of mutually connected sockets in sv[0] and sv[1] */
int
socketpair(
int af,
int type,
int protocol,
int sv[]
){
	struct usock *up0, *up1;
	if(sv == NULL){
		errno = EFAULT;
		return -1;
	}
	if(af != AF_LOCAL){
		errno = EAFNOSUPPORT;
		return -1;
	}
	if(type != SOCK_STREAM && type != SOCK_DGRAM){
		errno = ESOCKTNOSUPPORT;
		return -1;
	}
	if((sv[0] = socket(af,type,protocol)) == -1)
		return -1;
	if((sv[1] = socket(af,type,protocol)) == -1){
		close_s(sv[0]);
		return -1;
	}
	up0 = itop(sv[0]);
	up1 = itop(sv[1]);
	up0->cb.local->peer = up1;
	up1->cb.local->peer = up0;
	return sv[1];
}
Beispiel #2
0
/* Wait for a connection. Valid only for connection-oriented sockets. */
int
accept(
int s,			/* Socket index */
struct sockaddr *peername,		/* Peer name */
int *peernamelen	/* Length of peer name */
){
	int i;
	register struct usock *up;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(up->cb.p == NULL){
		errno = EOPNOTSUPP;
		return -1;
	}
	sp = up->sp;
	/* Fail if accept flag isn't set */
	if(sp->accept == FALSE){
		errno = EOPNOTSUPP;
		return -1;
	}
	/* Wait for the state-change upcall routine to signal us */
	while(up->cb.p != NULL && up->rdysock == -1){
		if(up->noblock){
			errno = EWOULDBLOCK;
			return -1;
		} else if((errno = kwait(up)) != 0){
			return -1;
		}
	}
	if(up->cb.p == NULL){
		/* Blown away */
		errno = EBADF;
		return -1;
	}
	i = up->rdysock;
	up->rdysock = -1;

	up = itop(i);
	if(peername != NULL && peernamelen != NULL){
		*peernamelen = min(up->peernamelen,*peernamelen);
		memcpy(peername,up->peername,*peernamelen);
	}
	return i;
}
Beispiel #3
0
/* Return local name passed in an earlier bind() call */
int
getsockname(
int s,		/* Socket index */
struct sockaddr *name,	/* Place to stash name */
int *namelen	/* Length of same */
){
	register struct usock *up;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(name == NULL || namelen == (int *)NULL){
		errno = EFAULT;
		return -1;
	}
	if(up->name == NULL){
		/* Not bound yet */
		*namelen = 0;
		return 0;
	}
	if(up->name != NULL){
		*namelen = min(*namelen,up->namelen);
		memcpy(name,up->name,*namelen);
	}
	return 0;
}
Beispiel #4
0
/* Close down a socket three ways. Type 0 means "no more receives"; this
 * replaces the incoming data upcall with a routine that discards further
 * data. Type 1 means "no more sends", and obviously corresponds to sending
 * a TCP FIN. Type 2 means "no more receives or sends". This I interpret
 * as "abort the connection".
 */
int
shutdown(
int s,		/* Socket index */
int how		/* (see above) */
){
	register struct usock *up;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(up->cb.p == NULL){
		errno = ENOTCONN;
		return -1;
	}
	sp = up->sp;
	/* Just close the socket if special shutdown routine not present */
	if(sp->shut == NULL){
		close_s(s);
	} else if((*sp->shut)(up,how) == -1){
		return -1;
	}
	ksignal(up,0);
	return 0;
}
Beispiel #5
0
/* Close a socket, freeing it for reuse. Try to do a graceful close on a
 * TCP socket, if possible
 */
int
close_s(
int s		/* Socket index */
){
	register struct usock *up;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(--up->refcnt > 0)
		return 0;	/* Others are still using it */
	/* Call proto-specific close routine if there is one */
	if((sp = up->sp) != NULL && sp->close != NULL)
		(*sp->close)(up);

	free(up->name);
	free(up->peername);

	ksignal(up,0);	/* Wake up anybody doing an accept() or recv() */
	Usock[_fd_seq(up->index)] = NULL;
	free(up);
	return 0;
}
Beispiel #6
0
/* TCP transmit upcall routine */
static void
s_ttcall(struct tcb *tcb,int32 cnt)
{
	/* Wake up anybody waiting to send data, and let them run */
	ksignal(itop(tcb->user),1);
	kwait(NULL);
}
Beispiel #7
0
/* Return length of protocol queue, either send or receive. */
int
socklen(
int s,		/* Socket index */
int rtx		/* 0 = receive queue, 1 = transmit queue */
){
	register struct usock *up;
	struct socklink *sp;
	int len = -1;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(up->cb.p == NULL){
		errno = ENOTCONN;
		return -1;
	}
	if(rtx < 0 || rtx > 1){
		errno = EINVAL;
		return -1;
	}
	sp = up->sp;
	/* Fail if qlen routine isn't present */
	if(sp->qlen == NULL || (len = (*sp->qlen)(up,rtx)) == -1){
		errno = EOPNOTSUPP;
		return -1;
	}
	return len;
}
Beispiel #8
0
Datei: use.c Projekt: 8l/myrddin
static void fixtypemappings(Stab *st)
{
    size_t i;
    Type *t, *old;


    /*
     * merge duplicate definitions.
     * This allows us to compare named types by id, instead
     * of doing a deep walk through the type. This ability is
     * depended on when we do type inference.
     */
    for (i = 0; i < ntypefixdest; i++) {
        t = htget(tidmap, itop(typefixid[i]));
        if (!t)
            die("Unable to find type for id %zd\n", typefixid[i]);
        *typefixdest[i] = t;
    }
    for (i = 0; i < ntypefixdest; i++) {
        old = *typefixdest[i];
        if (old->type == Tyname || old->type == Tygeneric) {
            t = htget(tydedup, old);
            if (!t) {
                t = old;
                htput(tydedup, old, old);
            }
            *typefixdest[i] = t;
        }
    }

    /* check for duplicate type definitions */
    for (i = 0; i < ntypefixdest; i++) {
        t = htget(tidmap, itop(typefixid[i]));
        if ((t->type != Tyname && t->type != Tygeneric) || t->issynth)
            continue;
        old = htget(tydedup, t);
        if (old && !tyeq(t, old) && !isspecialization(t, old))
            lfatal(t->loc, "Duplicate definition of type %s on %s:%d", tystr(old), file->file.files[old->loc.file], old->loc.line);
    }
    for (i = 0; i < ntypefixdest; i++) 
    lfree(&typefixdest, &ntypefixdest);
    lfree(&typefixid, &ntypefixid);
}
Beispiel #9
0
/* Return end-of-line convention for socket */
char *
eolseq(int s)
{
	struct usock *up;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return NULL;
	}
	return up->sp->eol;
}
Beispiel #10
0
/* Set Internet type-of-service to be used */
int
settos(int s, int tos)
{
	struct usock *up;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	up->tos = tos;
	return 0;
}
Beispiel #11
0
Datei: use.c Projekt: 8l/myrddin
static void rdtype(FILE *fd, Type **dest)
{
    uintptr_t tid;

    tid = rdint(fd);
    if (tid & Builtinmask) {
        *dest = mktype(Zloc, tid & ~Builtinmask);
    } else {
        lappend(&typefixdest, &ntypefixdest, dest);
        lappend(&typefixid, &ntypefixid, itop(tid));
    }
}
Beispiel #12
0
/* Increment reference count for specified socket */
int
usesock(int s)
{
	struct usock *up;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	up->refcnt++;
	return 0;
}
Beispiel #13
0
void MinMax (IMAGE a, IMAGE b, int *rmax, 
	     int *cmax, int *rmin, int *cmin)
{
	int x=0, y=0;

/* (0,0) index is which pixel? */
	y = jtop (a, 0);
	x = jtop (b, 0);
	if (x < y) *cmin = x; else *cmin = y;

	y = itop (a, 0);
	x = itop (b, 0);
	if (x < y) *rmin = x; else *rmin = y;

/* Now max indices */
	x = itop (a, a->info->nr);
	y = itop (b, b->info->nr);
	if (x > y) *rmax = x; else *rmax = y;

	x = jtop (a, a->info->nc);
	y = jtop (b, b->info->nc);
	if (x>y) *cmax = x; else *cmax = y;
}
Beispiel #14
0
Datei: use.c Projekt: 8l/myrddin
static void rdtrait(FILE *fd, Trait **dest, Type *ty)
{
    uintptr_t tid;

    tid = rdint(fd);
    if (tid & Builtinmask) {
        if (dest)
            *dest = traittab[tid & ~Builtinmask];
        if (ty)
            settrait(ty, traittab[tid & ~Builtinmask]);
    } else {
        lappend(&traitfixdest, &ntraitfixdest, dest);
        lappend(&traitfixtype, &ntraitfixtype, ty);
        lappend(&traitfixid, &ntraitfixid, itop(tid));
    }
}
Beispiel #15
0
/* Change owner of socket, return previous owner */
struct proc *
sockowner(
int s,			/* Socket index */
struct proc *newowner	/* Process table address of new owner */
){
	register struct usock *up;
	struct proc *pp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return NULL;
	}
	pp = up->owner;
	if(newowner != NULL)
		up->owner = newowner;
	return pp;
}
Beispiel #16
0
Datei: use.c Projekt: 8l/myrddin
Trait *traitunpickle(FILE *fd)
{
    Trait *tr;
    size_t i, n;
    intptr_t uid;

    /* create an empty trait */
    tr = mktrait(Zloc, NULL, NULL, NULL, 0, NULL, 0, 0);
    uid = rdint(fd);
    tr->ishidden = rdbool(fd);
    tr->name = unpickle(fd);
    tr->param = tyunpickle(fd);
    n = rdint(fd);
    for (i = 0; i < n; i++)
        lappend(&tr->memb, &tr->nmemb, rdsym(fd, tr));
    n = rdint(fd);
    for (i = 0; i < n; i++)
        lappend(&tr->funcs, &tr->nfuncs, rdsym(fd, tr));
    htput(trmap, itop(uid), tr);
    return tr;
}
Beispiel #17
0
/* Force retransmission. Valid only for connection-oriented sockets. */
int
sockkick(
int s	/* Socket index */
){
	register struct usock *up;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	sp = up->sp;
	/* Fail if kick routine isn't present */
	if(sp->kick == NULL){
		errno = EOPNOTSUPP;
		return -1;
	}
 	if((*sp->kick)(up) == -1)
		return -1;
	return 0;
}
Beispiel #18
0
/* Attach a local address/port to a socket. If not issued before a connect
 * or listen, will be issued automatically
 */
int
bind(
int s,			/* Socket index */
struct sockaddr *name,	/* Local name */
int namelen		/* Length of name */
){
	register struct usock *up;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(name == NULL){
		errno = EFAULT;
		return -1;
	}
	if(up->name != NULL){
		/* Bind has already been issued */
		errno = EINVAL;
		return -1;
	}
	sp = up->sp;
	if(sp->check != NULL && (*sp->check)(name,namelen) == -1){
		/* Incorrect length or family for chosen protocol */
		errno = EAFNOSUPPORT;
		return -1;	
	}
	/* Stash name in an allocated block */
	up->namelen = namelen;
	up->name = mallocw(namelen);
	memcpy(up->name,name,namelen);

	/* a bind routine is optional - don't fail if it isn't present */
	if(sp->bind != NULL && (*sp->bind)(up) == -1){
		errno = EOPNOTSUPP;
		return -1;
	}
	return 0;
}
Beispiel #19
0
/* Low level send routine; user supplies mbuf for transmission. More
 * efficient than send() or sendto(), the higher level interfaces.
 * The "to" and "tolen" parameters are ignored on connection-oriented
 * sockets.
 *
 * In case of error, bp is freed so the caller doesn't have to worry about it.
 */
int
send_mbuf(
int s,			/* Socket index */
struct mbuf **bpp,	/* Buffer to send */
int flags,		/* not currently used */
struct sockaddr *to,		/* Destination, only for datagrams */
int tolen		/* Length of destination */
){
	register struct usock *up;
	int cnt;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		free_p(bpp);
		errno = EBADF;
		return -1;
	}
	sp = up->sp;
	/* Fail if send routine isn't present (shouldn't happen) */
	if(sp->send == NULL){
		free_p(bpp);
		return -1;
	}
	/* If remote address is supplied, check it */
	if(to != NULL && (sp->check != NULL)
	 && (*sp->check)(to,tolen) == -1){
		free_p(bpp);
		errno = EAFNOSUPPORT;
		return -1;
	}
	/* The proto send routine is expected to free the buffer
	 * we pass it even if the send fails
	 */
	if((cnt = (*sp->send)(up,bpp,to)) == -1){
		errno = EOPNOTSUPP;
		return -1;
	}
	return cnt;
}
Beispiel #20
0
/* Low-level receive routine. Passes mbuf back to user; more efficient than
 * higher-level functions recv() and recvfrom(). Datagram sockets ignore
 * the len parameter.
 */
int
recv_mbuf(
int s,			/* Socket index */
struct mbuf **bpp,	/* Place to stash receive buffer */
int flags,		/* Unused; will control out-of-band data, etc */
struct sockaddr *from,		/* Peer address (only for datagrams) */
int *fromlen		/* Length of peer address */
){
	register struct usock *up;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	sp = up->sp;
	/* Fail if recv routine isn't present */
	if(sp->recv == NULL){
		errno = EOPNOTSUPP;
		return -1;
	}
	return (*sp->recv)(up,bpp,from,fromlen);
}
Beispiel #21
0
/* Initiate active open. For datagram sockets, merely bind the remote address. */
int
connect(
int s,			/* Socket index */
struct sockaddr *peername,		/* Peer name */
int peernamelen		/* Length of peer name */
){
	register struct usock *up;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(peername == NULL){
		/* Connect must specify a remote address */
		errno = EFAULT;
		return -1;
	}
	sp = up->sp;
	/* Check name format, if checking routine is available */
	if(sp->check != NULL && (*sp->check)(peername,peernamelen) == -1){
		errno = EAFNOSUPPORT;
		return -1;
	}
	if(up->peername != NULL)
		free(up->peername);
	up->peername = mallocw(peernamelen);
	memcpy(up->peername,peername,peernamelen);
	up->peernamelen = peernamelen;

	/* a connect routine is optional - don't fail if it isn't present */
	if(sp->connect != NULL && (*sp->connect)(up) == -1){
		return -1;
	}
	return 0;
}
Beispiel #22
0
/* Get remote name, returning result of earlier connect() call. */
int
getpeername(
int s,			/* Socket index */
struct sockaddr *peername,		/* Place to stash name */
int *peernamelen	/* Length of same */
){
	register struct usock *up;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(up->peername == NULL){
		errno = ENOTCONN;
		return -1;
	}
	if(peername == NULL || peernamelen == (int *)NULL){
		errno = EFAULT;
		return -1;
	}
	*peernamelen = min(*peernamelen,up->peernamelen);
	memcpy(peername,up->peername,*peernamelen);
	return 0;
}
Beispiel #23
0
Datei: use.c Projekt: 8l/myrddin
static void fixtraitmappings(Stab *st)
{
    size_t i;
    Trait *t;

    /*
     * merge duplicate definitions.
     * This allows us to compare named types by id, instead
     * of doing a deep walk through the type. This ability is
     * depended on when we do type inference.
     */
    for (i = 0; i < ntraitfixdest; i++) {
        t = htget(trmap, itop(traitfixid[i]));
        if (!t)
            die("Unable to find trait for id %zd\n", traitfixid[i]);
        if (traitfixdest[i])
            *traitfixdest[i] = t;
        if (traitfixtype[i])
            settrait(traitfixtype[i], t);
    }

    lfree(&traitfixdest, &ntraitfixdest);
    lfree(&traitfixid, &ntraitfixid);
}
Beispiel #24
0
/* Post a listen on a socket */
int
listen(
int s,		/* Socket index */
int backlog	/* 0 for a single connection, !=0 for multiple connections */
){
	register struct usock *up;
	struct socklink *sp;

	if((up = itop(s)) == NULL){
		errno = EBADF;
		return -1;
	}
	if(up->cb.p != NULL){
		errno = EISCONN;
		return -1;
	}
	sp = up->sp;
	/* Fail if listen routine isn't present */
	if(sp->listen == NULL || (*sp->listen)(up,backlog) == -1){
		errno = EOPNOTSUPP;
		return -1;
	}
	return 0;
}
Beispiel #25
0
s_ttcall(struct tcb *tcb,int32 cnt)
{
	/* Wake up anybody waiting to send data, and let them run */
	ksignal(itop(tcb->user),1);
	kwait(NULL);
}
/* TCP state change upcall routine */
static void
s_tscall(struct tcb *tcb,int old,int new)
{
	int s,ns;
	struct usock *up,*nup,*oup;
	union sp sp;

	s = tcb->user;
	oup = up = itop(s);

	switch(new){
	case TCP_CLOSED:
		/* Clean up. If the user has already closed the socket,
		 * then up will be null (s was set to -1 by the close routine).
		 * If not, then this is an abnormal close (e.g., a reset)
		 * and clearing out the pointer in the socket structure will
		 * prevent any further operations on what will be a freed
		 * control block. Also wake up anybody waiting on events
		 * related to this tcb so they will notice it disappearing.
		 */
		if(up != NULL){
			up->cb.tcb = NULL;
			up->errcodes[0] = tcb->reason;
			up->errcodes[1] = tcb->type;
Beispiel #26
0
Datei: use.c Projekt: 8l/myrddin
/* Usefile format:
 *     U<pkgname>
 *     T<pickled-type>
 *     R<picled-trait>
 *     I<pickled-impl>
 *     D<picled-decl>
 *     G<pickled-decl><pickled-initializer>
 */
int loaduse(char *path, FILE *f, Stab *st, Vis vis)
{
    intptr_t tid;
    size_t i;
    int v;
    char *pkg;
    Node *dcl, *impl, *init;
    Stab *s;
    Type *ty;
    Trait *tr;
    char *lib;
    int c;

    pushstab(file->file.globls);
    if (!tydedup)
        tydedup = mkht(tyhash, tyeq);
    if (fgetc(f) != 'U')
        return 0;
    v = rdint(f);
    if (v != Abiversion) {
        fprintf(stderr, "%s: abi version %d, expected %d\n", path, v, Abiversion);
        return 0;
    }
    pkg = rdstr(f);
    /* if the package names match up, or the usefile has no declared
     * package, then we simply add to the current stab. Otherwise,
     * we add a new stab under the current one */
    if (st->name) {
        if (pkg && !strcmp(pkg, st->name)) {
            s = st;
        } else {
            s = findstab(st, pkg);
        }
    } else {
        if (pkg) {
            s = findstab(st, pkg);
        } else {
            s = st;
        }
    }
    if (!streq(st->name, pkg))
        vis = Visintern;
    if (!s) {
        printf("could not find matching package for merge: %s in %s\n", st->name, path);
        exit(1);
    }
    tidmap = mkht(ptrhash, ptreq);
    trmap = mkht(ptrhash, ptreq);
    if (!initmap)
        initmap = mkht(namehash, nameeq);
    /* builtin traits */
    for (i = 0; i < Ntraits; i++)
        htput(trmap, itop(i), traittab[i]);
    while ((c = fgetc(f)) != EOF) {
        switch(c) {
            case 'L':
                lib = rdstr(f);
                for (i = 0; i < file->file.nlibdeps; i++)
                    if (!strcmp(file->file.libdeps[i], lib))
                        /* break out of both loop and switch */
                        goto foundlib;
                lappend(&file->file.libdeps, &file->file.nlibdeps, lib);
foundlib:
                break;
            case 'X':
                lib = rdstr(f);
                for (i = 0; i < file->file.nextlibs; i++)
                    if (!strcmp(file->file.extlibs[i], lib))
                        /* break out of both loop and switch */
                        goto foundextlib;
                lappend(&file->file.extlibs, &file->file.nextlibs, lib);
foundextlib:
                break;
            case 'F':
                lappend(&file->file.files, &file->file.nfiles, rdstr(f));
                break;
            case 'G':
            case 'D':
                dcl = rdsym(f, NULL);
                dcl->decl.vis = vis;
                dcl->decl.isglobl = 1;
                putdcl(s, dcl);
                break;
            case 'S':
                init = unpickle(f);
                if (!hthas(initmap, init)) {
                    htput(initmap, init, init);
                    lappend(&file->file.init, &file->file.ninit, init);
                }
                break;
            case 'R':
                tr = traitunpickle(f);
                tr->vis = vis;
                puttrait(s, tr->name, tr);
                for (i = 0; i < tr->nfuncs; i++)
                    putdcl(s, tr->funcs[i]);
                break;
            case 'T':
                tid = rdint(f);
                ty = tyunpickle(f);
                if(!ty->ishidden)
                    ty->vis = vis;
                htput(tidmap, itop(tid), ty);
                /* fix up types */
                if (ty->type == Tyname || ty->type == Tygeneric) {
                    if (ty->issynth)
                        break;
                    if (!streq(s->name, ty->name->name.ns))
                        ty->ishidden = 1;
                    if (!gettype(s, ty->name) && !ty->ishidden)
                        puttype(s, ty->name, ty);
                } else if (ty->type == Tyunion)  {
                    for (i = 0; i < ty->nmemb; i++)
                        if (!getucon(s, ty->udecls[i]->name) && !ty->udecls[i]->synth)
                            putucon(s, ty->udecls[i]);
                }
                break;
            case 'I':
                impl = unpickle(f);
                putimpl(s, impl);
                /* specialized declarations always go into the global stab */
                for (i = 0; i < impl->impl.ndecls; i++)
                    putdcl(file->file.globls, impl->impl.decls[i]);
                break;
            case EOF:
                break;
        }
    }
    fixtypemappings(s);
    fixtraitmappings(s);
    htfree(tidmap);
    popstab();
    return 1;
}
Beispiel #27
0
SEXP RS_connect(SEXP sHost, SEXP sPort, SEXP useTLS, SEXP sProxyTarget, SEXP sProxyWait) {
    int port = asInteger(sPort), use_tls = (asInteger(useTLS) == 1), px_get_slot = (asInteger(sProxyWait) == 0);
    const char *host;
    char idstr[32];
    rsconn_t *c;
    SEXP res, caps = R_NilValue;

    if (port < 0 || port > 65534)
	Rf_error("Invalid port number");
#ifdef WIN32
    if (!port)
	Rf_error("unix sockets are not supported in Windows");
#endif
#ifndef USE_TLS
    if (use_tls)
	Rf_error("TLS is not supported in this build - recompile with OpenSSL");
#endif
    if (sHost == R_NilValue && !port)
	Rf_error("socket name must be specified in socket mode");
    if (sHost == R_NilValue)
	host = "127.0.0.1";
    else {
	if (TYPEOF(sHost) != STRSXP || LENGTH(sHost) != 1)
	    Rf_error("host must be a character vector of length one");
	host = R2UTF8(sHost);
    }
    c = rsc_connect(host, port);
    if (!c)
	Rf_error("cannot connect to %s:%d", host, port);
#ifdef USE_TLS
    if (use_tls && tls_upgrade(c) != 1) {
	rsc_close(c);
	Rf_error("TLS handshake failed");
    }
#endif	
    if (rsc_read(c, idstr, 32) != 32) {
	rsc_close(c);
	Rf_error("Handshake failed - ID string not received");
    }
    if (!memcmp(idstr, "RSpx", 4) && !memcmp(idstr + 8, "QAP1", 4)) { /* RSpx proxy protocol */
	const char *proxy_target;
	struct phdr hdr;
	if (TYPEOF(sProxyTarget) != STRSXP || LENGTH(sProxyTarget) < 1) {
	    rsc_close(c);
	    Rf_error("Connected to a non-transparent proxy, but no proxy target was specified");
	}
	/* send CMD_PROXY_TARGET and re-fetch ID string */
	proxy_target = CHAR(STRING_ELT(sProxyTarget, 0));
	hdr.cmd = itop(CMD_PROXY_TARGET);
	hdr.len = itop(strlen(proxy_target) + 1);
	hdr.dof = 0;
	hdr.res = 0;
	rsc_write(c, &hdr, sizeof(hdr));
	rsc_write(c, proxy_target, strlen(proxy_target) + 1);
	if (px_get_slot) { /* send CMD_PROXY_GET_SLOT as well if requested */
	    hdr.cmd = itop(CMD_PROXY_GET_SLOT);
	    hdr.len = 0;
	    rsc_write(c, &hdr, sizeof(hdr));
	}
	rsc_flush(c);
	if (rsc_read(c, idstr, 32) != 32) {
	    rsc_close(c);
	    Rf_error("Handshake failed - ID string not received (after CMD_PROXY_TARGET)");
	}
    }
    /* OC mode */
    if (((const int*)idstr)[0] == itop(CMD_OCinit)) {
	int sb_len;
	struct phdr *hdr = (struct phdr *) idstr;
	hdr->len = itop(hdr->len);
	if (hdr->res || hdr->dof || hdr->len > sizeof(slurp_buffer) || hdr->len < 16) {
	    rsc_close(c);
	    Rf_error("Handshake failed - invalid RsOC OCinit message");
	}
	sb_len = 32 - sizeof(struct phdr);
	memcpy(slurp_buffer, idstr + sizeof(struct phdr), sb_len);
	if (rsc_read(c, slurp_buffer + sb_len, hdr->len - sb_len) != hdr->len - sb_len) {
	    rsc_close(c);
	    Rf_error("Handshake failed - truncated RsOC OCinit message");
	} else {
	    unsigned int *ibuf = (unsigned int*) slurp_buffer;
	    int par_type = PAR_TYPE(*ibuf);
	    int is_large = (par_type & DT_LARGE) ? 1 : 0;
	    if (is_large) par_type ^= DT_LARGE;
	    if (par_type != DT_SEXP) {
		rsc_close(c);
		Rf_error("Handshake failed - invalid payload in OCinit message");
	    }
	    ibuf += is_large + 1;
	    caps = QAP_decode(&ibuf);
	    if (caps != R_NilValue)
		PROTECT(caps);
	}
    } else {
	if (memcmp(idstr, "Rsrv", 4) || memcmp(idstr + 8, "QAP1", 4)) {
	    rsc_close(c);
	    Rf_error("Handshake failed - unknown protocol");
	}

	/* supported range 0100 .. 0103 */
	if (memcmp(idstr + 4, "0100", 4) < 0 || memcmp(idstr + 4, "0103", 4) > 0) {
	    rsc_close(c);
	    Rf_error("Handshake failed - server protocol version too high");
	}
    }

    res = PROTECT(R_MakeExternalPtr(c, R_NilValue, R_NilValue));
    setAttrib(res, R_ClassSymbol, mkString("RserveConnection"));
    R_RegisterCFinalizer(res, rsconn_fin);
    if (caps != R_NilValue) {
	setAttrib(res, install("capabilities"), caps);
	UNPROTECT(1);
    }	  
    UNPROTECT(1);
    return res;
}