Beispiel #1
0
/*
**      Opens a local file usien whatever means are available on the current
**      platform. If we have unix file descriptors then use that as we can use
**      select on them. Otherwise use ANSI C file descriptors.
**
**      returns         HT_ERROR        Error has occured or interrupted
**                      HT_OK           if connected
**                      HT_WOULD_BLOCK  if operation would have blocked
*/
PUBLIC int HTFileOpen (HTNet * net, char * local, HTLocalMode mode)
{
    HTRequest * request = HTNet_request(net);
    HTHost * host = HTNet_host(net);
#ifdef NO_UNIX_IO
    FILE * fp = NULL;
#else
    SOCKET sockfd = INVSOC;
#endif /* NO_UNIX_IO */

#ifndef NO_UNIX_IO
    int status = -1;    /* JTD:5/30/96 - must init status to -1 */
    if ((sockfd = open(local, mode)) == -1) {
	HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "open");
	return HT_ERROR;
    }

    /* If non-blocking protocol then change socket status
    ** I use fcntl() so that I can ask the status before I set it.
    ** See W. Richard Stevens (Advan. Prog. in UNIX env, p.364)
    ** Be CAREFULL with the old `O_NDELAY' - it wont work as read()
    ** returns 0 when blocking and NOT -1. FNDELAY is ONLY for BSD
    ** and does NOT work on SVR4 systems. O_NONBLOCK is POSIX.
    */
    if (!HTNet_preemptive(net)) {
#ifdef HAVE_FCNTL
	if ((status = fcntl(sockfd, F_GETFL, 0)) != -1) {
#ifdef O_NONBLOCK
	    status |= O_NONBLOCK;/* POSIX */
#else
#ifdef F_NDELAY
	    status |= F_NDELAY; /* BSD */
#endif /* F_NDELAY */
#endif /* O_NONBLOCK */
	    status = fcntl(sockfd, F_SETFL, status);
	}
#endif /* HAVE_FCNTL */
	HTTRACE(PROT_TRACE, "HTFileOpen.. `%s\' opened %d as %sblocking socket\n" _ 
		local _ sockfd _ status == -1 ? "" : "NON-");
    }
    /* #endif - HAVE_FCNTL <- wrong location, moved up JTD:5/30/96 */
#else /* !NO_UNIX_IO */
#ifdef VMS
    if ((fp = fopen(local, mode,"shr=put","shr=upd")) == NULL) {
	HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
	return HT_ERROR;
    }
#else
    if ((fp = fopen(local, mode)) == NULL) {
        HTRequest_addSystemError(request, ERR_FATAL, errno, NO, "fopen");
        return HT_ERROR;
    }
#endif /* VMS */
    HTTRACE(PROT_TRACE, "HTDoOpen.... `%s\' opened using FILE %p\n" _ local _ fp);
#endif /* !NO_UNIX_IO */

    /*
    **  Associate the channel with the host and create
    **  an input and and output stream 
    */
#ifdef NO_UNIX_IO
    HTHost_setChannel(host, HTChannel_new(INVSOC, fp, YES));
#else
    HTHost_setChannel(host, HTChannel_new(sockfd, NULL, YES));
#endif /* NO_UNIX_IO */

    HTHost_getInput(host, HTNet_transport(net), NULL, 0);
    HTHost_getOutput(host, HTNet_transport(net), NULL, 0);
    return HT_OK;
}
Beispiel #2
0
/*	HTFile_readDir
**	--------------
**	Reads the directory "path"
**	Returns:
**		HT_ERROR	Error
**		HT_FORBIDDEN	Directory reading not allowed
**		HT_LOADED	Successfully read the directory
*/
PRIVATE int HTFile_readDir (HTRequest * request, file_info *file)
{
#ifdef HAVE_READDIR
    DIR * dp;
    struct stat file_info;
    HTParentAnchor * anchor = HTRequest_anchor(request);
    char *url = HTAnchor_physical(anchor);
    char fullname[HT_MAX_PATH+1];
    char *name;
    HTTRACE(PROT_TRACE, "Reading..... directory\n");
    if (dir_access == HT_DIR_FORBID) {
	HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
		   NULL, 0, "HTFile_readDir");
	return HT_FORBIDDEN;
    }
    
    /* Initialize path name for stat() */
    if (*(name = (url+strlen(url)-1)) != '/') {
	char *newurl = NULL;
	StrAllocCopy(newurl, url);
	StrAllocCat(newurl, "/");
	HT_FREE(file->local);
	file->local = HTWWWToLocal(newurl, "", HTRequest_userProfile(request));
	HT_FREE(newurl);
    }
    strcpy(fullname, file->local);
    name = fullname+strlen(fullname);		 /* Point to end of fullname */

    /* Check if access is enabled */
    if (dir_access == HT_DIR_SELECTIVE) {
	strcpy(name, DEFAULT_DIR_FILE);
	if (HT_STAT(fullname, &file_info)) {
	    HTTRACE(PROT_TRACE, "Read dir.... `%s\' not found\n" _ DEFAULT_DIR_FILE);
	    HTRequest_addError(request, ERR_FATAL, NO, HTERR_FORBIDDEN,
		       NULL, 0, "HTFile_readDir");
	    return HT_FORBIDDEN;
	}
    }

    if ((dp = opendir(file->local))) {
	struct dirent * dirbuf;
	HTDir *dir = HTDir_new(request, dir_show, dir_key);
	char datestr[20];
	char sizestr[10];
	HTFileMode mode;
#ifdef HT_REENTRANT
	struct dirent result;				    /* For readdir_r */
#endif

#ifdef HAVE_READDIR_R_2
        while ((dirbuf = (struct dirent *) readdir_r(dp, &result)))
#elif defined(HAVE_READDIR_R_3)
        while (readdir_r(dp, &result, &dirbuf) == 0)
#else
	while ((dirbuf = readdir(dp)))
#endif /* HAVE_READDIR_R_2 */
	{
	    /* Current and parent directories are never shown in list */
#ifdef HAVE_DIRENT_INO
	    if (!dirbuf->d_ino ||
		!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
#else
	    if (!strcmp(dirbuf->d_name, ".") || !strcmp(dirbuf->d_name, ".."))
#endif
		continue;

	    /* Make a lstat on the file */
	    strcpy(name, dirbuf->d_name);
	    if (HT_LSTAT(fullname, &file_info)) {
		HTTRACE(PROT_TRACE, "Read dir.... lstat failed: %s\n" _ fullname);
		continue;
	    }

	    /* Convert stat info to fit our setup */
	    if (((mode_t) file_info.st_mode & S_IFMT) == S_IFDIR) {
#ifdef VMS
		char *dot = strstr(name, ".DIR");      /* strip .DIR part... */
		if (dot) *dot = '\0';
#endif /* VMS */
		mode = HT_IS_DIR;
		if (dir_show & HT_DS_SIZE) strcpy(sizestr, "-");
	    } else {
		mode = HT_IS_FILE;
		if (dir_show & HT_DS_SIZE)
		    HTNumToStr(file_info.st_size, sizestr, 10);
	    }
	    if (dir_show & HT_DS_DATE)
		HTDateDirStr(&file_info.st_mtime, datestr, 20);

	    /* Add to the list */
	    if (HTDir_addElement(dir, name, datestr, sizestr, mode) != YES)
		break;
	}
	closedir(dp);
	HTDir_free(dir);
	return HT_LOADED;
    } else {
	HTRequest_addSystemError(request,  ERR_FATAL, errno, NO, "opendir");
	return HT_ERROR;
    }
#else
    return HT_ERROR;	/* needed for WWW_MSWINDOWS */
#endif /* HAVE_READDIR */
}
Beispiel #3
0
/*	Write to the socket
**
** According to Solaris 2.3 man on write:
**
**    o	If O_NONBLOCK and O_NDELAY are clear, write() blocks
**	until the data can be accepted.
**
**    o	If O_NONBLOCK or O_NDELAY is set, write()  does  not
**	block  the  process.   If  some  data  can be written
**	without blocking the process, write() writes what  it
**	can  and returns the number of bytes written.  Other-
**	wise, if O_NONBLOCK is set, it returns - 1  and  sets
**	errno to EAGAIN or if O_NDELAY is set, it returns 0.
**
** According to SunOS 4.1.1 man on write:
**
**   +	If the descriptor is  marked  for  non-blocking  I/O
**	using  fcntl()  to  set  the FNONBLOCK or O_NONBLOCK
**	flag (defined in  <sys/fcntl.h>),  write()  requests
**	for  {PIPE_BUF}  (see  pathconf(2V))  or fewer bytes
**	either  succeed  completely  and  return  nbyte,  or
**	return -1 and set errno to EAGAIN. A write() request
**	for greater than {PIPE_BUF} bytes  either  transfers
**	what it can and returns the number of bytes written,
**	or transfers no data and returns -1 and  sets  errno
**	to  EAGAIN.  If  a  write()  request is greater than
**	{PIPE_BUF} bytes and all data previously written  to
**	the  pipe  has been read, write() transfers at least
**	{PIPE_BUF} bytes.
*/
PRIVATE int HTWriter_write (HTOutputStream * me, const char * buf, int len)
{
    HTHost * host = me->host;
    SOCKET soc = HTChannel_socket(HTHost_channel(host));
    HTNet * net = HTHost_getWriteNet(host);
    int b_write;
    char * wrtp;
    const char *limit = buf+len;

    /* If we don't have a Net object then return right away */
    if (!net) {
        HTTRACE(STREAM_TRACE, "Write Socket No Net object %d (offset %d)\n" _ soc _ me->offset);
        return HT_ERROR;
    }

#ifdef NOT_ASCII
    if (len && !me->ascbuf) {			      /* Generate new buffer */
        const char *orig = buf;
        char *dest;
        int cnt;
        if ((me->ascbuf = (char  *) HT_MALLOC(len)) == NULL)
            HT_OUTOFMEM("HTWriter_write");
        dest = me->ascbuf;
        for (cnt=0; cnt<len; cnt++) {
            *dest = TOASCII(*orig);
            dest++, orig++;
        }
        wrtp = me->ascbuf;
        limit = me->ascbuf+len;
    }
#else
    if (!me->offset)
        wrtp = (char *) buf;
    else {
        wrtp = (char *) buf + me->offset;
        len -= me->offset;
        me->offset = 0;
    }
#endif

    /* Write data to the network */
    while (wrtp < limit) {
        if ((b_write = NETWRITE(soc, wrtp, len)) < 0) {
#ifdef EAGAIN
            if (socerrno == EAGAIN || socerrno == EWOULDBLOCK)/* POSIX, SVR4 */
#else
            if (socerrno == EWOULDBLOCK)			      /* BSD */
#endif
            {
                HTHost_register(host, net, HTEvent_WRITE);
                me->offset = wrtp - buf;
                HTTRACE(STREAM_TRACE, "Write Socket WOULD BLOCK %d (offset %d)\n" _ soc _ me->offset);
                return HT_WOULD_BLOCK;
#ifdef EINTR
            } else if (socerrno == EINTR) {
                /*
                **	EINTR	A signal was caught during the  write  opera-
                **		tion and no data was transferred.
                */
                HTTRACE(STREAM_TRACE, "Write Socket call interrupted - try again\n");
                continue;
#endif
            } else {
                host->broken_pipe = YES;
#ifdef EPIPE
                if (socerrno == EPIPE) {
                    /* JK: an experimental bug solution proposed by
                               Olga and Mikhael */
                    HTTRACE(STREAM_TRACE, "Write Socket got EPIPE\n");
                    HTHost_unregister(host, net, HTEvent_WRITE);
                    HTHost_register(host, net, HTEvent_CLOSE);
                    /* @@ JK: seems that some functions check the errors
                       as part of the flow control */
                    HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
                                             "NETWRITE");
                    return HT_CLOSED;
                }
#endif /* EPIPE */
                /* all errors that aren't EPIPE */
                HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO,
                                         "NETWRITE");
                return HT_ERROR;
            }
        }

        /* We do this unconditionally, should we check to see if we ever blocked? */
        HTTRACEDATA(wrtp, b_write, "Writing to socket %d" _ soc);
        HTNet_addBytesWritten(net, b_write);
        wrtp += b_write;
        len -= b_write;
        HTTRACE(STREAM_TRACE, "Write Socket %d bytes written to %d\n" _ b_write _ soc);
        {
            HTAlertCallback *cbf = HTAlert_find(HT_PROG_WRITE);
            if (cbf) {
                int tw = HTNet_bytesWritten(net);
                (*cbf)(net->request, HT_PROG_WRITE,
                       HT_MSG_NULL, NULL, &tw, NULL);
            }
        }
    }
#ifdef NOT_ASCII
    HT_FREE(me->ascbuf);
#endif
    return HT_OK;
}
Beispiel #4
0
/*	HTGetHostByName
**	---------------
**	Resolve the host name using internal DNS cache. As we want to refer   
**	a specific host when timing the connection the weight function must
**	use the 'current' value as returned.
**      Returns:
**	       	>0	Number of homes
**		-1	Error
*/
PUBLIC int HTGetHostByName (HTHost * host, char *hostname, HTRequest* request)
{
    SockA *sin = HTHost_getSockAddr(host);
    int homes = -1;
    HTList *list;				    /* Current list in cache */
    HTdns *pres = NULL;
    if (!host || !hostname) {
	HTTRACE(PROT_TRACE, "HostByName.. Bad argument\n");
	return -1;
    }
    HTHost_setHome(host, 0);
    
    /* Find a hash for this host */
    {
	int hash = 0;
	char *ptr;
	for(ptr=hostname; *ptr; ptr++)
	    hash = (int) ((hash * 3 + (*(unsigned char *) ptr)) % HT_M_HASH_SIZE);
	if (!CacheTable) {
	    if ((CacheTable = (HTList* *) HT_CALLOC(HT_M_HASH_SIZE, sizeof(HTList *))) == NULL)
	        HT_OUTOFMEM("HTDNS_init");
	}
	if (!CacheTable[hash]) CacheTable[hash] = HTList_new();
	list = CacheTable[hash];
    }

    /* Search the cache */
    {
	HTList *cur = list;
	while ((pres = (HTdns *) HTList_nextObject(cur))) {
	    if (!strcmp(pres->hostname, hostname)) {
		if (time(NULL) > pres->ntime + DNSTimeout) {
		    HTTRACE(PROT_TRACE, "HostByName.. Refreshing cache\n");
		    delete_object(list, pres);
		    pres = NULL;
		}
		break;
	    }
	}
    }
    if (pres) {
	/*
	** Find the best home. We still want to do this as we use it as a
	** fall back for persistent connections
	*/
	homes = pres->homes;
	if (pres->homes > 1) {
	    int cnt = 0;
	    double best_weight = 1e30;			      /* Pretty bad */
	    while (cnt < pres->homes) {
		if (*(pres->weight+cnt) < best_weight) {
		    best_weight = *(pres->weight+cnt);
		    HTHost_setHome(host, cnt);
		}
		cnt++;
	    }
	}
	host->dns = pres;
	memcpy((void *) &sin->sin_addr, *(pres->addrlist+HTHost_home(host)),
	       pres->addrlength);
    } else {
	struct hostent *hostelement;			      /* see netdb.h */
	HTAlertCallback *cbf = HTAlert_find(HT_PROG_DNS);
#ifdef HT_REENTRANT
	int thd_errno;
	char buffer[HOSTENT_MAX];
	struct hostent result;			      /* For gethostbyname_r */
#endif
#ifdef HAVE_GETHOSTBYNAME_R_3
        struct hostent_data hdata;
#endif

	if (cbf) (*cbf)(request, HT_PROG_DNS, HT_MSG_NULL,NULL,hostname,NULL);
#ifdef HAVE_GETHOSTBYNAME_R_5
	hostelement = gethostbyname_r(hostname, &result, buffer,
				      HOSTENT_MAX, &thd_errno);
#elif defined(HAVE_GETHOSTBYNAME_R_6)
	gethostbyname_r(hostname, &result, buffer,
		        HOSTENT_MAX, &hostelement, &thd_errno);

#elif defined(HAVE_GETHOSTBYNAME_R_3)
        if (gethostbyname_r(hostname, &result, &hdata) == 0) {
	    hostelement = &result;
	}
	else {
	    hostelement = NULL;
	}
#else
	if (cbf) (*cbf)(request, HT_PROG_DNS, HT_MSG_NULL,NULL,hostname,NULL);
	hostelement = gethostbyname(hostname);
#endif
	if (!hostelement) {
            HTRequest_addSystemError(request, ERR_FATAL, socerrno, NO,
   			             "gethostbyname");
	    return -1;
	}	
	host->dns = HTDNS_add(list, hostelement, hostname, &homes);
	memcpy((void *) &sin->sin_addr, *hostelement->h_addr_list,
	       hostelement->h_length);
    }
    return homes;
}
Beispiel #5
0
PRIVATE int HTSSLReader_read (HTInputStream * me)
{
    HTHost * host = me->host;
    SOCKET soc = HTChannel_socket(me->ch);
    HTNet * net = HTHost_getReadNet(host);
    HTRequest * request = HTNet_request(net);
    int status;
    if (!net->readStream) {
	HTTRACE(STREAM_TRACE, "HTSSLReader. No read stream for net object %p\n" _ net);
        return HT_ERROR;
    }
        
    /* Setting SSL */
    if (!me->htssl) {
	if ((me->htssl = HTSSL_new(soc)) == NULL) {
	    HTRequest_addSystemError(net->request, ERR_FATAL, socerrno, NO, "SSLREAD");
	    return HT_ERROR;
	}
    }

    /* Read from socket if we got rid of all the data previously read */
    do {

	/* Don't read if we have to push unwritten data from last call */
        if (me->write >= me->read) {
            me->b_read = 0;
            me->data[0] ='\0';
 	    me->b_read = HTSSL_read(me->htssl, soc, me->data, INPUT_BUFFER_SIZE);     
	    status = HTSSL_getError(me->htssl, me->b_read);
	    HTTRACE(STREAM_TRACE, "HTSSLReader. SSL returned %d\n" _ status);

	    /* Check what we got done */
	    switch (status) {

	    case SSL_ERROR_NONE:

		HTTRACEDATA(me->data, me->b_read, "Reading from socket %d" _ soc);
		me->write = me->data;
		me->read = me->data + me->b_read;
		HTTRACE(STREAM_TRACE, "HTSSLReader. %d bytes read from socket %d\n" _ 
			me->b_read _ soc);

		/* Make progress notification */
		if (request) {
		    HTAlertCallback * cbf = HTAlert_find(HT_PROG_READ);
		    if (HTNet_rawBytesCount(net))
			HTNet_addBytesRead(net, me->b_read);
		    if (cbf) {
			int tr = HTNet_bytesRead(net);
			(*cbf)(request, HT_PROG_READ, HT_MSG_NULL, NULL, &tr, NULL);
		    }
		}
		break;

	    case SSL_ERROR_WANT_READ:
		HTTRACE(STREAM_TRACE, "HTSSLReader. WOULD BLOCK fd %d\n" _ soc);
		HTHost_register(host, net, HTEvent_READ);

		/*
		**  There seems to be a bug as even though it says "read finished"
		**  it doesn't say that it wants to write. We therefore have to make
		**  an explicit flush to make sure that we don't block forever.
		*/
		HTHost_forceFlush(host);

		return HT_WOULD_BLOCK;

	    case SSL_ERROR_WANT_WRITE:
		return HTHost_forceFlush(host);

	    case SSL_ERROR_WANT_X509_LOOKUP:
		/* @@@ what to do here? @@@ */
		return HT_OK;

	    case SSL_ERROR_ZERO_RETURN:
	    case SSL_ERROR_SSL:
	    case SSL_ERROR_SYSCALL:
		HTTRACE(PROT_TRACE, "HTSSLReader. FIN received on socket %d\n" _ soc);
                HTHost_unregister(host, net, HTEvent_READ);
                HTHost_register(host, net, HTEvent_CLOSE);

                HTSSL_close(me->htssl);    
                HTSSL_free(me->htssl);
                me->htssl = NULL;

                return HT_CLOSED;
	    }
	}

#ifdef FIND_SIGNATURES
	{
	    char * ptr = me->data;
	    int len = me->b_read;
	    while ((ptr = strnstr(ptr, &len, "HTTP/1.1 200 OK")) != NULL) {
		HTTRACE(STREAM_TRACE, "HTSSLReader. Signature found at 0x%x of 0x%x.\n" _ ptr - me->data _ me->b_read);
		ptr++;
		len--;
	    }
	}
#endif /* FIND_SIGNATURES */
 #ifdef NOT_ASCII
	{
	    char *p = me->data;
	    while (p < me->read) {
		*p = FROMASCII(*p);
		p++;
	    }
	}
#endif /* NOT_ASCII */
	
	/* Now push the data down the stream */
	if ((status = (*net->readStream->isa->put_block)
	     (net->readStream, me->write, me->b_read)) != HT_OK) {
	    if (status == HT_WOULD_BLOCK) {
		HTTRACE(STREAM_TRACE, "HTSSLReader. Target WOULD BLOCK\n");
		HTHost_unregister(host, net, HTEvent_READ);
		return HT_WOULD_BLOCK;
	    } else if (status == HT_PAUSE) {
		HTTRACE(STREAM_TRACE, "HTSSLReader. Target PAUSED\n");
		HTHost_unregister(host, net, HTEvent_READ);
		return HT_PAUSE;
	    /* CONTINUE code or stream code means data was consumed */
	    } else if (status == HT_CONTINUE || status > 0) {
		if (status == HT_CONTINUE) {
		    HTTRACE(STREAM_TRACE, "HTSSLReader. CONTINUE\n");
		} else
		    HTTRACE(STREAM_TRACE, "HTSSLReader. Target returns %d\n" _ status);
/*		me->write = me->read; */
		return status;
	    } else {				     /* We have a real error */
		HTTRACE(STREAM_TRACE, "HTSSLReader. Target ERROR %d\n" _ status);
		return status;
	    }
	}
	me->write = me->read;
	{
	    int remaining = HTHost_remainingRead(host);
	    if (remaining > 0) {
		HTTRACE(STREAM_TRACE, "HTSSLReader. DIDN'T CONSUME %d BYTES: `%s\'\n" _ 
			    remaining _ me->read);
		HTHost_setConsumed(host, remaining);
	    }
	}
    } while (net->preemptive);
    HTHost_register(host, net, HTEvent_READ);
    return HT_WOULD_BLOCK;
}