/*
 *
 * Copyright 1998-1999, University of Notre Dame.
 * Authors: Jeffrey M. Squyres, Kinis L. Meyer with M. D. McNally 
 *          and Andrew Lumsdaine
 *
 * This file is part of the Notre Dame LAM implementation of MPI.
 *
 * You should have received a copy of the License Agreement for the
 * Notre Dame LAM implementation of MPI along with the software; see
 * the file LICENSE.  If not, contact Office of Research, University
 * of Notre Dame, Notre Dame, IN 46556.
 *
 * Permission to modify the code and to distribute modified code is
 * granted, provided the text of this NOTICE is retained, a notice that
 * the code was modified is included with the above COPYRIGHT NOTICE and
 * with the COPYRIGHT NOTICE in the LICENSE file, and that the LICENSE
 * file is distributed with the modified code.
 *
 * LICENSOR MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED.
 * By way of example, but not limitation, Licensor MAKES NO
 * REPRESENTATIONS OR WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY
 * PARTICULAR PURPOSE OR THAT THE USE OF THE LICENSED SOFTWARE COMPONENTS
 * OR DOCUMENTATION WILL NOT INFRINGE ANY PATENTS, COPYRIGHTS, TRADEMARKS
 * OR OTHER RIGHTS.  
 *
 * Additional copyrights may follow.
 *
 *	Ohio Trollius
 *	Copyright 1998 The Ohio State University
 *	NJN
 *
 *	$Id: lfopenfd.c,v 6.3 1999/05/25 17:44:41 kmeyer1 Exp $
 *
 *	Function:	- pass stdio file descriptors to local filed
 *	Accepts:	- name to use for connection
 *	Returns:	- 0 or LAMERROR
 */

#include <lam_config.h>
#include <sfh.h>

#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#include <events.h>
#include <freq.h>
#include <ksignal.h>
#include <net.h>
#include <portable.h>
#include <typical.h>

/*
 * external functions
 */
extern int		mread();

/*
 * external variables
 */
extern struct fclient	_ufd[FUMAX];		/* client file desc. table */

int
lam_lfopenfd(server)

char			*server;

{
	struct nmsg	nhead;			/* network message desc. */
	struct freq	*request;		/* filed request */
	struct freply	*reply;			/* filed reply */
	int4		tfds[3];		/* LAM fds returned by filed */
	int		err = 0;		/* error code */
	int		mask;			/* signal mask */
	int		serv_fd;		/* server file desc. */
	int		pass_fd;		/* file desc. for passing fds */
	int		i;
/*
 * Open file descriptor passing server side.
 */
	if ((serv_fd = sfh_sock_open_srv_unix_stm(server)) < 0) {
		unlink(server);
		return(LAMERROR);
	}
/*
 * Send request to filed.
 */
	request = (struct freq *) nhead.nh_data;
	reply = (struct freply *) nhead.nh_data;

	request->fq_src_node = getnodeid();
	request->fq_src_event = -getpid();
	request->fq_req = FQOPENFD;

	nhead.nh_node = LOCAL;
	nhead.nh_event = EVFILED;
	nhead.nh_type = 0;
	nhead.nh_flags = 0;
	nhead.nh_msg = server;
	nhead.nh_length = strlen(server) + 1;

	if (nhead.nh_length > MAXNMSGLEN) {
		close(serv_fd);
		unlink(server);
		errno = ENAMETOOLONG;
		return(LAMERROR);
	}
/*
 * Don't block SIGUDIE since we may wish to kill a process hanging in
 * this protocol.  
 */
	mask = ksigblock(sigmask(SIGARREST));

	if (nsend(&nhead)) {
		close(serv_fd);
		unlink(server);
		ksigsetmask(mask);
		return(LAMERROR);
	}
/*
 * Accept connection from filed.
 */
	pass_fd = sfh_sock_accept_tmout(serv_fd, -1);

	close(serv_fd);
	unlink(server);

	if (pass_fd < 0) {
		return(LAMERROR);
	}
/*
 * Send file descriptors to filed.
 */
	if (sfh_send_fd(pass_fd, 0)
			|| sfh_send_fd(pass_fd, 1) || sfh_send_fd(pass_fd, 2)) {
		close(pass_fd);
		return(LAMERROR);
	}
/*
 * Receive LAM file descriptors from filed.
 */
	if (mread(pass_fd, (char *) tfds, sizeof(tfds)) != sizeof(tfds)) {
		err = errno;
	}
	close(pass_fd);
/*
 * Receive response from filed.
 */
	nhead.nh_event = -getpid();
	nhead.nh_length = 0;
	nhead.nh_msg = 0;

	if (nrecv(&nhead)) {
		ksigsetmask(mask);
		return(LAMERROR);
	}

	ksigsetmask(mask);

	if (err || reply->fr_errno) {
		errno = (reply->fr_errno) ? reply->fr_errno : err;
		return(LAMERROR);
	}
/*
 * Successfully received LAM file descriptors.  Fill in client fd table with
 * returned information.  If stdin is a tty leave it as the default.
 */
	if (!isatty(0)) {
		_ufd[0].fu_tflags = LAM_O_RDONLY | LAM_O_1WAY;
		_ufd[0].fu_node = nhead.nh_node;
		_ufd[0].fu_tfd = tfds[0];
	}

	for (i = 1; i < 3; i++) {
		_ufd[i].fu_tflags = LAM_O_WRONLY | LAM_O_1WAY;
		_ufd[i].fu_node = nhead.nh_node;
		_ufd[i].fu_tfd = tfds[i];
	}

	return(0);
}
