Exemplo n.º 1
0
PRIVATE int HTANSIReader_read (HTInputStream * me)
{
    FILE * fp = HTChannel_file(me->ch);
    HTNet * net = HTHost_getReadNet(me->host);
    int status;

    /* Read the file desriptor */
    while (fp) {
	if ((me->b_read = fread(me->data, 1, FILE_BUFFER_SIZE, fp)) == 0){
	    if (ferror(fp)) {
		HTTRACE(PROT_TRACE, "ANSI read... READ ERROR\n");
	    } else {
		HTAlertCallback *cbf = HTAlert_find(HT_PROG_DONE);
		HTTRACE(PROT_TRACE, "ANSI read... Finished loading file %p\n" _ fp);
		if (cbf) (*cbf)(net->request, HT_PROG_DONE, HT_MSG_NULL,NULL,NULL,NULL);
		return HT_CLOSED;
	    }
	}

	/* Remember how much we have read from the input socket */
	HTTRACEDATA(me->data, me->b_read, "HTANSIReader_read me->data:");
	me->write = me->data;
	me->read = me->data + me->b_read;

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

	/* Now push the data down the stream */
	if ((status = (*net->readStream->isa->put_block)
	     (net->readStream, me->data, me->b_read)) != HT_OK) {
	    if (status == HT_WOULD_BLOCK) {
		HTTRACE(PROT_TRACE, "ANSI read... Target WOULD BLOCK\n");
		return HT_WOULD_BLOCK;
	    } else if (status == HT_PAUSE) {
		HTTRACE(PROT_TRACE, "ANSI read... Target PAUSED\n");
		return HT_PAUSE;
	    } else if (status > 0) {	      /* Stream specific return code */
		HTTRACE(PROT_TRACE, "ANSI read... Target returns %d\n" _ status);
		me->write = me->data + me->b_read;
		return status;
	    } else {				     /* We have a real error */
		HTTRACE(PROT_TRACE, "ANSI read... Target ERROR\n");
		return status;
	    }
	}
	me->write = me->data + me->b_read;
    }
    HTTRACE(PROT_TRACE, "ANSI read... File descriptor is NULL...\n");
    return HT_ERROR;
}
Exemplo n.º 2
0
/*
**  For a given socket, reqister a request structure, a set of operations, 
**  a HTEventCallback function, and a priority. For this implementation, 
**  we allow only a single HTEventCallback function for all operations.
**  and the priority field is ignored.
*/
PUBLIC int HTEventList_register (SOCKET s, HTEventType type, HTEvent * event)
{
    int newset = 0;
    SockEvents * sockp;
    HTTRACE(THD_TRACE, "Event....... Register socket %d, request %p handler %p type %s at priority %d\n" _ 
		s _ (void *) event->request _ 
		(void *) event->cbf _ HTEvent_type2str(type) _ 
		(unsigned) event->priority);
    if (s==INVSOC || HTEvent_INDEX(type) >= HTEvent_TYPES)
	return 0;

    /*
    ** Insert socket into appropriate file descriptor set. We also make sure
    ** that it is registered in the global set.
    */
    HTTRACE(THD_TRACE, "Event....... Registering socket for %s\n" _ HTEvent_type2str(type));
    sockp = SockEvents_get(s, SockEvents_mayCreate);
    sockp->s = s;
    sockp->events[HTEvent_INDEX(type)] = event;
    newset = EventList_remaining(sockp);
#ifdef WWW_WIN_ASYNC
    if (WSAAsyncSelect(s, HTSocketWin, HTwinMsg, HTEvent_BITS(newset)) < 0) {
        HTTRACE(THD_TRACE, "Event....... WSAAsyncSelect returned `%s'!" _ HTErrnoString(socerrno));
	return HT_ERROR;
    }
#else /* WWW_WIN_ASYNC */
    FD_SET(s, FdArray+HTEvent_INDEX(type));

    HTTRACEDATA((char *) FdArray+HTEvent_INDEX(type), 8, "HTEventList_register: (s:%d)" _ s);

    if (s > MaxSock) {
	MaxSock = s ;
	HTTRACE(THD_TRACE, "Event....... New value for MaxSock is %d\n" _ MaxSock);
    }
#endif /* !WWW_WIN_ASYNC */

    /*
    **  If the timeout has been set (relative in millis) then we register 
    **  a new timeout for this event unless we already have a timer.
    */
    if (event->millis >= 0) {
	sockp->timeouts[HTEvent_INDEX(type)] =
	    HTTimer_new(sockp->timeouts[HTEvent_INDEX(type)],
			EventListTimerHandler, sockp, event->millis, YES, YES);
    }

    return HT_OK;
}
Exemplo n.º 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;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
/*
** Remove the registered information for the specified socket for the actions 
** specified in ops. if no actions remain after the unregister, the registered
** info is deleted, and, if the socket has been registered for notification, 
** the HTEventCallback will be invoked.
*/
PUBLIC int HTEventList_unregister (SOCKET s, HTEventType type) 
{
    long 		v = HASH(s);
    HTList * 		cur = HashTable[v];
    HTList * 		last = cur;
    SockEvents *	pres;
    int			ret = HT_ERROR;

    /* if the socket doesn't exists, don't do anything */
    if (s == INVSOC)
      return HT_OK;

    while (cur && (pres = (SockEvents *) HTList_nextObject(cur))) {
        if (pres->s == s) {
	    int	remaining = 0;

	    /*
	    **  Unregister the event from this action
	    */
	    pres->events[HTEvent_INDEX(type)] = NULL;
            remaining = EventList_remaining(pres);

	    /*
	    **  Check to see of there was a timeout connected with the event.
	    **  If so then delete the timeout as well.
	    */
	    {
		HTTimer * timer = pres->timeouts[HTEvent_INDEX(type)];
                if (timer) HTTimer_delete(timer);
                pres->timeouts[HTEvent_INDEX(type)] = NULL;
	    }
	    
#ifdef WWW_WIN_ASYNC
	    if (WSAAsyncSelect(s, HTSocketWin, HTwinMsg, remaining) < 0)
		ret = HT_ERROR;
#else /* WWW_WIN_ASYNC */
	    FD_CLR(s, FdArray+HTEvent_INDEX(type));

	    HTTRACEDATA((char*)FdArray+HTEvent_INDEX(type), 8, "HTEventList_unregister: (s:%d)" _ s);

#endif /* !WWW_WIN_ASYNC */

	    /*
	    **  Check to see if we can delete the action completely. We do this
	    **  if there are no more events registered.
	    */
	    if (remaining == 0) {
		HTList * doomed = cur;
		HTTRACE(THD_TRACE, "Event....... No more events registered for socket %d\n" _ s);

#ifndef WWW_WIN_ASYNC
		/* Check to see if we have to update MaxSock */
		if (pres->s >= MaxSock) __ResetMaxSock();
#endif /* !WWW_WIN_ASYNC */

		HT_FREE(pres);
		pres = (SockEvents *) HTList_nextObject(cur);
		HTList_quickRemoveElement(doomed, last);
	    }
	    ret = HT_OK;

      	    HTTRACE(THD_TRACE, "Event....... Socket %d unregistered for %s\n" _ s _ 
				   HTEvent_type2str(type));

	    /* We found the socket and can break */
	    break;
	}
	last = cur;
    }
    if (THD_TRACE) {
	if (ret == HT_ERROR)
	    HTTRACE(THD_TRACE, "Event....... Couldn't find socket %d. Can't unregister type %s\n" _
		    s _ HTEvent_type2str(type));
    }
    return ret;
}