#ifndef LINT
static char *rcsid="$Id: clnt_unix.c,v 1.16 2001/07/20 07:35:54 crosser Exp $";
#endif

/*
	$Log: clnt_unix.c,v $
	Revision 1.16  2001/07/20 07:35:54  crosser
	more tuning of AF_UNIX address size, now works on FreeBSD
	
	Revision 1.15  2001/07/20 05:48:59  crosser
	address bug with AF_UNIX address size
	fix permissions of unix datagram socket (on Linux, honors umask)
	
	Revision 1.14  1999/10/06 15:54:03  crosser
	fix for kluge about initializing private fields
	Initialization for global parameters
	
	Revision 1.13  1999/10/03 21:18:03  crosser
	First (probably) working version with new run time config parser.
	Also added listenq parameter (backlog size for listen()) and
	renamed wtest to whoson (and with man page).  Release 2.00beta1.
	
	Revision 1.12  1999/08/19 17:22:14  crosser
	Move to new config scheme (does not work yet)
	
	Revision 1.11  1999/07/27 17:30:05  crosser
	fix names
	
	Revision 1.10  1999/06/02 22:10:36  crosser
	deal with UNIX_PATH_MAX in a better way

	Revision 1.9  1999/01/30 14:41:05  crosser
	fix use of saved errno

	Revision 1.8  1998/07/26 14:06:40  crosser
	fix for multiline responces

	Revision 1.7  1998/07/12 16:43:57  crosser
	Change protocol: responce now is terminated with empty line

	Revision 1.6  1998/07/05 00:26:18  crosser
	Change copyright

	Revision 1.5  1998/07/03 11:10:39  crosser
	setup for _REENTRANT mode

	Revision 1.4  1998/07/03 09:32:48  crosser
	make persistant connections work

	Revision 1.3  1998/07/02 18:01:15  crosser
	change error reporting to syslog

	Revision 1.2  1998/07/02 15:37:07  crosser
	make right return if req invalid or disallowed

	Revision 1.1  1998/07/01 21:55:16  crosser
	Initial revision

*/

/*
	WHAT IS IT:
		Implementation of experimental "whoson" protocol
	AUTHOR:
		Eugene G. Crosser <crosser@average.org>
	COPYRIGHT:
		Public domain
*/

#include "config.h"

#include <sys/types.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/un.h>
#include <netdb.h>
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#include "whoson.h"
#include "rtconfig.h"
#include "clnt_common.h"
#include "report.h"

#include "rtc_begin.h"
#include "clnt_unix_cfg.h"
#include "rtc_middle.h"
#include "clnt_unix_cfg.h"
#include "rtc_end.h"

#define MAXTRIES 3
#define MAXREQL 1024

int wso_unix_clnt_connect(void *priv,char *buf)
{
	wso_clnt_unix_cfg *rec=(wso_clnt_unix_cfg *)(priv);
	struct sockaddr_un server;
	int len,off,left,crcount,lfcount,saveerr;
	char *p;
	int tries=0;
	RETSIGTYPE (*savepipe)(int);
#ifdef _REENTRANT
	int fd=-1;
#define FD fd
#else
#define FD rec->fd
#endif

	DPRINT(("unix_connect at entry fd=%d\n",FD))
	if (FD >= 0) goto session;
reconnect:
	memset((char *)&server,0,sizeof(server));
	server.sun_family = AF_UNIX;
	strncpy(server.sun_path,rec->port,sizeof(server.sun_path)-1);
	server.sun_path[sizeof(server.sun_path)-1]='\0';
	if ((FD=socket(AF_UNIX,SOCK_STREAM,0)) < 0) {
		ERRLOG((LOG_ERR,"[WHOSON] server socket: %m"))
		return -1;
	}
	if (connect(FD,(struct sockaddr *)&server,
		sizeof(server)-sizeof(server.sun_path)+
					strlen(server.sun_path)+1) < 0) {
		ERRLOG((LOG_ERR,"[WHOSON] connect server: %m"))
		close(FD);
		FD=-1;
		return -1;
	}
session:
	savepipe=signal(SIGPIPE,SIG_IGN);
	len=write(FD,buf,strlen(buf));
	saveerr=errno;
	(void)signal(SIGPIPE,savepipe);
	errno=saveerr;
	if (len != strlen(buf)) {
		if ((errno == EPIPE) && (++tries < MAXTRIES)) {
			DPRINT(("server gone (write), reconnecting %d\n",tries))
			close(FD);
			goto reconnect;
		}
		ERRLOG((LOG_ERR,"[WHOSON] write to server: %m"))
		close(FD);
		FD=-1;
		return -1;
	}
	off=0;
	left=MAXREQL-1;
	crcount=0;
	lfcount=0;
	while (left) {
		if ((len=read(FD,buf+off,left)) < 0) {
			if ((errno == EPIPE) && (++tries < MAXTRIES)) {
				DPRINT(("server gone (read), reconnect %d\n",
					tries))
				close(FD);
				goto reconnect;
			}
			ERRLOG((LOG_ERR,"[WHOSON] read from server: %m"))
			close(FD);
			FD=-1;
			return -1;
		}
		if (len == 0) break;
		for (p=buf+off;
		     (p<buf+MAXREQL) && (crcount<2) && (lfcount<2);
		     p++)
		switch (*p) {
		case '\r':      crcount++;
				break;
		case '\n':      lfcount++;
				break;
		default:        crcount=0; lfcount=0;
				break;
		}
		off+=len;
		left-=len;
		if ((crcount > 1) || (lfcount > 1)) break;
	}
	buf[off]='\0';

#ifdef _REENTRANT
	close(FD);
	FD=-1;
#endif

	return 0;
}


syntax highlighted by Code2HTML, v. 0.9.1