示例#1
0
/*
    Write to a socket. Absorb as much data as the socket can buffer. Block if the socket is in blocking mode. Returns -1
    on error, otherwise the number of bytes written.
 */
PUBLIC ssize socketWrite(int sid, void *buf, ssize bufsize)
{
    WebsSocket    *sp;
    ssize       len, written, sofar;
    int         errCode;

    if (buf == 0 || (sp = socketPtr(sid)) == NULL) {
        return -1;
    }
    if (sp->flags & SOCKET_EOF) {
        return -1;
    }
    len = bufsize;
    sofar = 0;
    while (len > 0) {
        if ((written = send(sp->sock, (char*) buf + sofar, (int) len, 0)) < 0) {
            errCode = socketGetError();
            if (errCode == EINTR) {
                continue;
            } else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
                return sofar;
            }
            return -errCode;
        }
        len -= written;
        sofar += written;
    }
    return sofar;
}
示例#2
0
/*
    Read from a socket. Return the number of bytes read if successful. This may be less than the requested "bufsize" and
    may be zero. This routine may block if the socket is in blocking mode.
    Return -1 for errors or EOF. Distinguish between error and EOF via socketEof().
 */
PUBLIC ssize socketRead(int sid, void *buf, ssize bufsize)
{
    WebsSocket    *sp;
    ssize       bytes;
    int         errCode;

    assert(buf);
    assert(bufsize > 0);

    if ((sp = socketPtr(sid)) == NULL) {
        return -1;
    }
    if (sp->flags & SOCKET_EOF) {
        return -1;
    }
    if ((bytes = recv(sp->sock, buf, (int) bufsize, 0)) < 0) {
        errCode = socketGetError();
        if (errCode == EAGAIN || errCode == EWOULDBLOCK) {
            bytes = 0;
        } else {
            /* Conn reset or Some other error */
            sp->flags |= SOCKET_EOF;
            bytes = -errCode;
        }

    } else if (bytes == 0) {
        sp->flags |= SOCKET_EOF;
        bytes = -1;
    }
    return bytes;
}
示例#3
0
size_t WebWrite(SOCKET sockfd, char * buf, size_t bufsize)
{
    size_t       len, written, sofar;
    int         errCode;

    len = bufsize;
    sofar = 0;
    while (len > 0)
    {
        written = send(sockfd, (char*) buf + sofar, (int) len, 0);
        if (written < (size_t)0 || written > len)
        {
            errCode = socketGetError();
            if (errCode == EINTR)
            {
                WEBLOG_ERROR("<%s> EINTR, %s.\n", __FUNCTION__,  strerror(errCode));
                continue;
            }
            else if (errCode == EWOULDBLOCK || errCode == EAGAIN)
            {
                return sofar;
            }
            return -errCode;
        }
        WEBLOG_ERROR("<%s> "sizett"/"sizett"\n", __FUNCTION__, written, len);
        len -= written;
        sofar += written;
    }
    return sofar;
}
示例#4
0
int socketGetInput(int sid, char *buf, int toRead, int *errCode)
{
	struct sockaddr_in 	server;
	socket_t			*sp;
	int 				len, bytesRead;

	a_assert(buf);
	a_assert(errCode);

	*errCode = 0;

	if ((sp = socketPtr(sid)) == NULL) {
		return -1;
	}

/*
 *	If we have previously seen an EOF condition, then just return
 */
	if (sp->flags & SOCKET_EOF) {
		return 0;
	}
#if ((defined (WIN) || defined (CE)) && (!defined (LITTLEFOOT) && !defined  (WEBS)))
	if ( !(sp->flags & SOCKET_BLOCK)
			&& ! socketWaitForEvent(sp,  FD_CONNECT, errCode)) {
		return -1;
	}
#endif

/*
 *	Read the data
 */
	if (sp->flags & SOCKET_DATAGRAM) {
		len = sizeof(server);
		bytesRead = recvfrom(sp->sock, buf, toRead, 0,
			(struct sockaddr *) &server, &len);
	} else {
		bytesRead = recv(sp->sock, buf, toRead, 0);
	}

   /*
    * BUG 01865 -- CPU utilization hangs on Windows. The original code used 
    * the 'errno' global variable, which is not set by the winsock functions
    * as it is under *nix platforms. We use the platform independent
    * socketGetError() function instead, which does handle Windows correctly. 
    * Other, *nix compatible platforms should work as well, since on those
    * platforms, socketGetError() just returns the value of errno.
    * Thanks to Jonathan Burgoyne for the fix.
    */
   if (bytesRead < 0) 
   {
      *errCode = socketGetError();
      if (*errCode == ECONNRESET) 
      {
         sp->flags |= SOCKET_CONNRESET;
         return 0;
      }
      return -1;
   }
	return bytesRead;
}
示例#5
0
static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode)
{
	struct sockaddr_in	server;
	int					bytes;

	a_assert(sp);
	a_assert(buf);
	a_assert(toWrite > 0);
	a_assert(errCode);

	*errCode = 0;

#if (defined (WIN) || defined (CE))
	if ((sp->flags & SOCKET_ASYNC)
			&& ! socketWaitForEvent(sp,  FD_CONNECT, errCode)) {
		return -1;
	}
#endif

/*
 *	Write the data
 */
	if (sp->flags & SOCKET_BROADCAST) {
		server.sin_family = AF_INET;
		server.sin_addr.s_addr = INADDR_BROADCAST;
		server.sin_port = htons((short)(sp->port & 0xFFFF));
		if ((bytes = sendto(sp->sock, buf, toWrite, 0,
			(struct sockaddr *) &server, sizeof(server))) < 0) {
			bytes = tryAlternateSendTo(sp->sock, buf, toWrite, 0,
			(struct sockaddr *) &server);
		}
	} else if (sp->flags & SOCKET_DATAGRAM) {
		server.sin_family = AF_INET;
		server.sin_addr.s_addr = inet_addr(sp->host);
		server.sin_port = htons((short)(sp->port & 0xFFFF));
		bytes = sendto(sp->sock, buf, toWrite, 0,
			(struct sockaddr *) &server, sizeof(server));

	} else {
		bytes = send(sp->sock, buf, toWrite, 0);
	}

	if (bytes < 0) {
		*errCode = socketGetError();
#if (defined (WIN) || defined (CE))
		sp->currentEvents &= ~FD_WRITE;
#endif

		return -1;

	} else if (bytes == 0 && bytes != toWrite) {
		*errCode = EWOULDBLOCK;
#if (defined (WIN) || defined (CE))
		sp->currentEvents &= ~FD_WRITE;
#endif
		return -1;
	}

	return bytes;
}
示例#6
0
文件: socket.c 项目: EMali2HF/goahead
/*
    Write to a socket. Absorb as much data as the socket can buffer. Block if the socket is in blocking mode. Returns -1
    on error, otherwise the number of bytes written.
 */
PUBLIC ssize socketWrite(int sid, void *buf, ssize bufsize)
{
    WebsSocket    *sp;
    ssize       len, written, sofar;
    int         errCode;

    if (buf == 0 || (sp = socketPtr(sid)) == NULL) {
        return -1;
    }
    if (sp->flags & SOCKET_EOF) {
        return -1;
    }
    len = bufsize;
    sofar = 0;
    while (len > 0) {
        if ((written = send(sp->sock, (char*) buf + sofar, (int) len, 0)) < 0) {
            errCode = socketGetError();
            if (errCode == EINTR) {
                continue;
            } else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
                if (sofar) {
                    /*
                        If some data was written, we mask the EAGAIN for this time. Caller should recall and then
                        will get a negative return code with EAGAIN.
                     */
                    return sofar;
                }
            }
            return -errCode;
        }
        len -= written;
        sofar += written;
    }
    return sofar;
}
示例#7
0
PUBLIC int socketConnect(char *ip, int port, int flags)
{
    WebsSocket                *sp;
    struct sockaddr_storage addr;
    socklen_t               addrlen;
    int                     family, protocol, sid, rc;

    if (port > SOCKET_PORT_MAX) {
        return -1;
    }
    if ((sid = socketAlloc(ip, port, NULL, flags)) < 0) {
        return -1;
    }
    sp = socketList[sid];
    assert(sp);

    if (socketInfo(ip, port, &family, &protocol, &addr, &addrlen) < 0) {
        return -1;       
    }
    if ((sp->sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
        socketFree(sid);
        return -1;
    }
    socketHighestFd = max(socketHighestFd, sp->sock);

#if ME_COMPILER_HAS_FCNTL
    fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
#endif

    /*
        Connect to the remote server in blocking mode, then go into non-blocking mode if desired.
     */
    if (!(sp->flags & SOCKET_BLOCK)) {
#if ME_WIN_LIKE
        /*
            Set to non-blocking for an async connect
         */
        int flag = 1;
        if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) {
            socketFree(sid);
            return -1;
        }
        sp->flags |= SOCKET_ASYNC;
#else
        socketSetBlock(sid, 1);
#endif
    }
    if ((rc = connect(sp->sock, (struct sockaddr*) &addr, sizeof(addr))) < 0 && 
        (rc = tryAlternateConnect(sp->sock, (struct sockaddr*) &addr)) < 0) {
#if ME_WIN_LIKE
        if (socketGetError() != EWOULDBLOCK) {
            socketFree(sid);
            return -1;
        }
#else
        socketFree(sid);
        return -1;

#endif
    }
    socketSetBlock(sid, (flags & SOCKET_BLOCK));
    return sid;
}
/*
	sslWrite encodes 'data' as a single SSL record.

	Return codes:
	-1	Internal failure. caller should free sess and close socket
	0	WOULDBLOCK. caller should call back with same input later
	> 0	success status.  number of plaintext bytes encoded and sent

	In order for non-blocking sockets to work transparently to the upper
	layers in webs, we manage the buffering of outgoing data and fudge the
	number of bytes sent until the entire SSL record is sent.

	This is because the encoded SSL record will be longer than 'len' with the
	SSL header prepended and the MAC and padding appended. There is no easy way
	to indicate to the caller if only a partial record was sent via the webs
	socket API.

	For example, if the caller specifies one byte of 'data' ('len' == 1),
	the SSL record could be 33 bytes long. If the socket send is able to write
	10 bytes of data, how would we indicate this to the caller, which expects
	only 1 byte, 0 bytes or a negative error code as a result of this call?

	The solution here is to always return 0 from this function, until we have
	flushed out all the bytes in the SSL record (33 in this example), and when
	the record has all been sent, return the originally requested length, which
	is 1 in this example.

	This assumes that on a 0 return, the caller will wait for a writable event
	on the socket and re-call this api with the same 'data' and 'len' as
	previously sent. Essentially a 0 return means "retry the same sslWrite call
	later".
*/
int sslWrite(sslConn_t *cp, char *data, int len)
{
    unsigned char	*buf;
    int				rc, transferred, ctLen;
    /*
    	If sendBlocked is set, then the previous time into sslWrite with this cp
    	could not send all the requested data, and zero was returned to the caller.
    	In this case, the data has already been encoded into the SSL outdata buffer,
    	and we don't need to re-encode it here.
    	This assumes that the caller is sending the same 'len' and contents of
    	'data' as they did last time.
     */
    if (!cp->sendBlocked) {
        if (matrixSslGetWritebuf(cp->ssl, &buf, len) < len) {
            /* SSL buffer must hold requested plaintext + SSL overhead */
            return -1;
        }
        memcpy((char *)buf, data, len);
        if (matrixSslEncodeWritebuf(cp->ssl, len) < 0) {
            return -1;
        }
    } else {
        /*
        		Not all previously encoded data could be sent without blocking and
        		0 bytes was previously returned to caller as sent. Ensure caller is
        		retrying with same len (and presumably the same data).
         */
        if (len != cp->ptReqBytes) {
            a_assert(len != cp->ptReqBytes);
            return -1;
        }
    }
WRITE_MORE:
    /*
    	There is a small chance that we are here with sendBlocked set, and yet
    	there is no buffered outdata to send. This happens because a send can
    	also happen in sslRead, and that could have flushed the outgoing buffer
    	in addition to a handshake message reply.
     */
    ctLen = matrixSslGetOutdata(cp->ssl, &buf);
    if (ctLen > 0) {
        transferred = send(cp->fd, buf, ctLen, MSG_NOSIGNAL);
        if (transferred <= 0) {
#ifdef USE_NONBLOCKING_SSL_SOCKETS
            if (socketGetError() != EWOULDBLOCK) {
                return -1;
            }
            if (!cp->sendBlocked) {
                cp->sendBlocked = 1;
                cp->ptReqBytes = len;
            } else {
            }
            return 0;
#else
            return -1;
#endif
        }
        /* Update the SSL buffer that we've written > 0 bytes of data */
        if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) {
            return -1;
        }
        /* There is more data in the SSL buffer to send */
        if (rc == MATRIXSSL_REQUEST_SEND) {
            goto WRITE_MORE;
        }
    }
    cp->sendBlocked = 0;
    cp->ptReqBytes = 0;
    return len;
}
/*
	Primary MatrixSSL read function that transparently handles SSL handshakes
	and the subsequent incoming application data records.

	A NULL inbuf parameter is an indication that this is a call to perform a
	new SSL handshake with an incoming client and no out data is expected

	Params:
	inbuf	allocated storage for plaintext data to be copied to
	inlen	length of inbuf

	Return codes:
	-1	EOF or internal failure.  caller should free sess and close socket
	0	success status.  no data is being returned to the caller
	>0	success status.  number of plaintext bytes written to inbuf

	Note that unlike a standard "socket read", a read of an SSL record can
	produce data that must be written, for example, a response to a handshake
	message that must be sent before any more data is read. Also, data can
	be read from the network such as an SSL alert, that produces no data to
	pass back to caller.

	Because webs doesn't have the concept of a read forcing a write, we
	do the write here, inline. If we are non-blocking, this presents an issue
	because we can't block indefinitely on a send, and we also can't indicate
	that the send be done later. The workaround below uses select() to
	implement a "timed send", which will fail and indicate the connection be
	closed if not complete within a time threshold.

	This situation is extremely unlikely in normal operation, since the only
	records that must be sent as a result of a recv are handshake messages,
	and TCP buffers would not typically be full enough at that point to
	result in an EWOULDBLOCK on send. Conceivably, it could occur on a client
	initiated SSl re-handshake that is sent by a slow-reading client to a
	server with full TCP buffers. A non-malicious client in this situation
	would read immediately after a re-handshake request and fail anyway
	because a buffered appdata record would be read.
*/
int	sslRead(sslConn_t *cp, char *inbuf, int inlen)
{
    unsigned char	*buf;
    int				rc, len, transferred;

    /*
    	Always first look to see if any plaintext application data is waiting
    	We have two levels of buffer here, one for decoded data and one for
    	partial, still encoded SSL records. The partial SSL records are stored
    	transparently in MatrixSSL, but the plaintext is stored in 'cp'.
     */
    if (inbuf != NULL && inlen > 0 && cp->ptBytes > 0 && cp->pt) {
        if (cp->ptBytes < inlen) {
            inlen = cp->ptBytes;
        }
        memcpy(inbuf, cp->currPt, inlen);
        cp->currPt += inlen;
        cp->ptBytes -= inlen;
        /* Free buffer as we go if empty */
        if (cp->ptBytes == 0) {
            bfree(B_L, cp->pt);
            cp->pt = cp->currPt = NULL;
        }
        return inlen;
    }
    /*
    	If there is outgoing data buffered, just try to write it here before
    	doing our read on the socket. Because the read could produce data to
    	be written, this will ensure we have as much room as possible in that
    	case for the written record. Note that there may be data here to send
    	because of a previous sslWrite that got EWOULDBLOCK.
    */
WRITE_MORE:
    if ((len = matrixSslGetOutdata(cp->ssl, &buf)) > 0) {
        transferred = send(cp->fd, buf, len, MSG_NOSIGNAL);
        if (transferred <= 0) {
            if (socketGetError() != EWOULDBLOCK) {
                return -1;
            }
            if (waitForWriteEvent(cp->fd, MAX_WRITE_MSEC) == 0) {
                goto WRITE_MORE;
            }
            return -1;
        } else {
            /* Indicate that we've written > 0 bytes of data */
            if ((rc = matrixSslSentData(cp->ssl, transferred)) < 0) {
                return -1;
            }
            if (rc == MATRIXSSL_REQUEST_CLOSE) {
                return -1;
            } else if (rc == MATRIXSSL_HANDSHAKE_COMPLETE) {
                /* If called via sslAccept (NULL buf), then we can just leave */
                return 0;
            }
            /* Try to send again if more data to send */
            if (rc == MATRIXSSL_REQUEST_SEND || transferred < len) {
                goto WRITE_MORE;
            }
        }
    } else if (len < 0) {
        return -1;
    }

READ_MORE:
    /* Get the ssl buffer and how much data it can accept */
    /* Note 0 is a return failure, unlike with matrixSslGetOutdata */
    if ((len = matrixSslGetReadbuf(cp->ssl, &buf)) <= 0) {
        return -1;
    }
    if ((transferred = recv(cp->fd, buf, len, MSG_NOSIGNAL)) < 0) {
        /* Support non-blocking sockets if turned on */
        if (socketGetError() == EWOULDBLOCK) {
            return 0;
        }
        trace(1, T("RECV error: %d\n"), socketGetError());
        return -1;
    }
    if (transferred == 0) {
        /* If EOF, remote socket closed. This is semi-normal closure. */
        trace(4, T("Closing connection %d on EOF\n"), cp->fd);
        return -1;
    }
    /*
    	Notify SSL state machine that we've received more data into the
    	ssl buffer retreived with matrixSslGetReadbuf.
     */
    if ((rc = matrixSslReceivedData(cp->ssl, transferred, &buf,
                                    (uint32*)&len)) < 0) {
        return -1;
    }

PROCESS_MORE:
    switch (rc) {
    case MATRIXSSL_REQUEST_SEND:
        /* There is a handshake response we must send */
        goto WRITE_MORE;
    case MATRIXSSL_REQUEST_RECV:
        goto READ_MORE;
    case MATRIXSSL_HANDSHAKE_COMPLETE:
        /* Session resumption handshake */
        goto READ_MORE;
    case MATRIXSSL_RECEIVED_ALERT:
        /* Any fatal alert will simply cause a read error and exit */
        if (*buf == SSL_ALERT_LEVEL_FATAL) {
            trace(1, T("Fatal alert: %d, closing connection.\n"),
                  *(buf + 1));
            return -1;
        }
        /* Closure alert is normal (and best) way to close */
        if (*(buf + 1) == SSL_ALERT_CLOSE_NOTIFY) {
            return -1;
        }
        /* Eating warning alerts */
        trace(4, T("Warning alert: %d\n"), *(buf + 1));
        if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len))
            == 0) {
            /* Possible there was plaintext before the alert */
            if (inbuf != NULL && inlen > 0 && cp->ptBytes > 0 && cp->pt) {
                if (cp->ptBytes < inlen) {
                    inlen = cp->ptBytes;
                }
                memcpy(inbuf, cp->currPt, inlen);
                cp->currPt += inlen;
                cp->ptBytes -= inlen;
                /* Free buffer as we go if empty */
                if (cp->ptBytes == 0) {
                    bfree(B_L, cp->pt);
                    cp->pt = cp->currPt = NULL;
                }
                return inlen;
            } else {
                return 0;
            }
        }
        goto PROCESS_MORE;

    case MATRIXSSL_APP_DATA:
        if (cp->ptBytes == 0) {
            /*
            				Catching here means this is new app data just grabbed off the
            				wire.
            */
            cp->ptBytes = len;
            cp->pt = balloc(B_L, len);
            memcpy(cp->pt, buf, len);
            cp->currPt = cp->pt;
        } else {
            /*
            				Multi-record.  This case should only ever be possible if no
            				data has already been read out of the 'pt' cache so it is
            				fine to assume an unprocessed buffer.
            */
            psAssert(cp->pt == cp->currPt);
            cp->pt = brealloc(B_L, cp->pt, cp->ptBytes + len);
            memcpy(cp->pt + cp->ptBytes, buf, len);
            cp->currPt = cp->pt;
            cp->ptBytes += len;
        }
        if ((rc = matrixSslProcessedData(cp->ssl, &buf, (uint32*)&len))
            < 0) {
            return -1;
        }
        /* Check for multi-record app data*/
        if (rc > 0) {
            goto PROCESS_MORE;
        }
        /*
        			Otherwise pass back how much the caller wants to read (if any)
        */
        if (inbuf != 0 && inlen > 0) {
            if (cp->ptBytes < inlen) {
                inlen = cp->ptBytes;
            }
            memcpy(inbuf, cp->currPt, inlen);
            cp->currPt += inlen;
            cp->ptBytes -= inlen;
            return inlen; /* Just a breakpoint holder */
        }
        return 0; /* Have it stored, but caller didn't want any data */
    default:
        return -1;
    }

    return 0; /* really can never hit this */
}
示例#10
0
文件: sock.c 项目: sd-eblana/bawx
static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode)
{
	struct sockaddr_in	server;
	int					bytes;

	a_assert(sp);
	a_assert(buf);
	a_assert(toWrite > 0);
	a_assert(errCode);

	*errCode = 0;

#if (defined (WIN) || defined (CE))
	if ((sp->flags & SOCKET_ASYNC)
			&& ! socketWaitForEvent(sp,  FD_CONNECT, errCode)) {
		return -1;
	}
#endif

/*
 *	Write the data
 */
	if (sp->flags & SOCKET_BROADCAST) {
		server.sin_family = AF_INET;
#if (defined (UEMF) || defined (LITTLEFOOT))
		server.sin_addr.s_addr = INADDR_BROADCAST;
#else
		server.sin_addr.s_addr = inet_addr(basicGetBroadcastAddress());
#endif
		server.sin_port = htons((short)(sp->port & 0xFFFF));
		if ((bytes = sendto(sp->sock, buf, toWrite, 0,
			(struct sockaddr *) &server, sizeof(server))) < 0) {
			bytes = tryAlternateSendTo(sp->sock, buf, toWrite, 0,
			(struct sockaddr *) &server);
		}
	} else if (sp->flags & SOCKET_DATAGRAM) {
		server.sin_family = AF_INET;
		server.sin_addr.s_addr = inet_addr(sp->host);
		server.sin_port = htons((short)(sp->port & 0xFFFF));
		bytes = sendto(sp->sock, buf, toWrite, 0,
			(struct sockaddr *) &server, sizeof(server));

	} else {
		bytes = send(sp->sock, buf, toWrite, 0);
	}

	if (bytes < 0) {
		*errCode = socketGetError();
#if (defined (WIN) || defined (CE))
		sp->currentEvents &= ~FD_WRITE;
#endif

		return -1;

	} else if (bytes == 0 && bytes != toWrite) {
		*errCode = EWOULDBLOCK;
#if (defined (WIN) || defined (CE))
		sp->currentEvents &= ~FD_WRITE;
#endif
		return -1;
	}

/*
 *	Ensure we get to write some more data real soon if the socket can absorb
 *	more data
 */
#ifndef UEMF
#ifdef WIN 
	if (sp->interestEvents & FD_WRITE) {
		emfTime_t blockTime = { 0, 0 };
		emfSetMaxBlockTime(&blockTime);
	}
#endif /* WIN */
#endif
	return bytes;
}
示例#11
0
int handle_http_get(http_req * req, http_rsp * rsp)
{
    int ret           = OK;
    HashElement * e     = NULL;
    /* ------------------------------------ */
    FILE * fp           = NULL;
    char * timebuf      = NULL;
    /* ------------------------------------ */
    size_t total_length = 0;    /* total length of the file. */
    size_t task_length  = 0;    /* requested length. */
    char   strbuf[64]   = {0};
    size_t from         = -1;
    size_t to           = -1;
    char   path[256]    = {0};
    char * vpath        = path;
    struct stat buf;

    WEBLOG_API();

#ifdef WEBCFG_SUPPORT_AUTH
    /* Authentication has a very high priority. */
    if (OK != CheckAuthorization(req, rsp))
    {
        return handle_http_error(401, req, rsp);
    }
#endif

    vpath = req->uri;
    ASSERT(vpath && vpath[0]);
    ASSERT(rsp->headOptions != NULL_HANDLE);

    if(0 == strlen(vpath))
    {
        strcat(vpath, "/");
        WEBLOG_VERBOSE("<%s> redirect to root path. [%s].\n", __FUNCTION__, vpath);
    }

    /* Make sure the requesting URI is authorized. */
    if(strstr(vpath, "..") || strstr(vpath, "./"))
        return handle_http_error(403, req, rsp);

    /* Check if the requesting URI is a directory. */
    WEBLOG_INFO("<%s> stat the file \"%s\".\n", __FUNCTION__, vpath);
    ret = web_stat(vpath, &buf);

    /* Check if statistics are valid: */
    if(ret != 0)
    {
        WEBLOG_ERROR("<%s> fail to stat the file \"%s\".\n", __FUNCTION__, vpath);
        switch (errno)
        {
            case ENOENT:
                WEBLOG_ERROR("<%s> File %s not found.\n", __FUNCTION__, vpath);
                return handle_http_error(404, req, rsp);

            case EINVAL: /* no break */
            default:
                /* Should never be reached. */
                WEBLOG_ERROR("<%s> Unexpected error in _stat.\n", __FUNCTION__);
                return handle_http_error(500, req, rsp);
        }
    }
    else
    {
        WEBLOG_INFO("<%s> File size     : "sizett"\n", __FUNCTION__, buf.st_size );
        //WEBLOG_INFO("<%s> Drive         : %c:\n", __FUNCTION__, buf.st_dev + 'A' );
        timebuf = ctime(&buf.st_mtime);
        WEBLOG_INFO("<%s> Time modified : %s", __FUNCTION__, timebuf);

        if(S_IFDIR & buf.st_mode)
        {
#if 1 //#ifdef WEBCFG_SUPPORT_WEBDAV
            CacheHandle cache = CacheCreate();
            if (NULL_HANDLE == cache)
                return handle_http_error(500, req, rsp);
            rsp->code = 200;

            web_lsdir(cache, vpath);
            http_add_rspoption(rsp, "Content-Type", "text/html; charset=\"utf-8\"");
            CacheGetData(cache, &rsp->body);
            http_send_response(rsp);
            if (cache != NULL_HANDLE) CacheDestroy(cache);
            return OK;

#else
            WEBLOG_INFO("<%s> client requesting a directory!\n", __FUNCTION__);
            return handle_http_error(403, req, rsp);
#endif
        }
    }

#ifdef WEBCFG_SUPPORT_HTTPTIME
    /* RFC2616, 14.25. If-Modified-Since */
    e = HashLookup(req->headOptions, "If-Modified-Since");
    if(e)
    {
        time_t reqtime, acctime;
        ASSERT(e->value.type == eHashString);
        reqtime = get_http_time(e->value.data.string);
        acctime = get_http_time(timebuf);

        //WEBLOG_INFO("<%s> reqtime=[%u] vs [%u]=acctime\n", __FUNCTION__, reqtime, acctime);
        if(reqtime >= acctime)
        {
            rsp->code = 304;
            rsp->body = using_customized_body; // 304 has no body.
            http_add_rspoption(rsp, "Content-Length", "0");
            return http_send_response(rsp);
        }
    }
#endif

    fp = web_fopen(vpath,"rb");
    WEBLOG_INFO("<%s> fopen(%s) == %p \n", __FUNCTION__, vpath, fp);
    if(!fp)
    {
        WEBLOG_ERROR("<%s> failed to open file \"%s\" %s \n",
                     __FUNCTION__, vpath, strerror(errno));
        return handle_http_error(500, req, rsp);
    }
    ASSERT(fp); /* check if fp is NULL. */

    fseek(fp, 0, SEEK_END);
    total_length = ftell(fp);
    fseek(fp, 0, SEEK_SET);

#ifdef WEBCFG_SUPPORT_HTTPRANGE
    /* handle range request */
    e = HashLookup(req->headOptions, "Range");
    if(e)
    {
        char * p = e->value.data.string;
        ASSERT(e->value.type == eHashString);
        WEBLOG_INFO("<%s> client range request: %s\n", __FUNCTION__, p);

        /* figure out FROM-TO */
        if(0 == strncmp(p, " bytes=-", 8))
        {
            sscanf(p," bytes=-"sizett"", &task_length);
            from = total_length-task_length;
            to = total_length-1;
        }
        else
        {
            sscanf(p," bytes="sizett"-"sizett"", &from, &to);
            if(to < 0)
            {
                task_length = total_length - from;
                to = total_length-1;
            }
            else
            {
                task_length = to - from + 1;
            }
        }


        WEBLOG_INFO("<%s> request "sizett"-"sizett", total "sizett", we have "sizett".\n",
                    __FUNCTION__, from, to, task_length, total_length);

        if(from < 0 || to < 0 || to >= total_length || from >= total_length || from > to)
        {
            http_add_rspoption(rsp, "Accept-Ranges", "bytes");
            //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri));
            http_add_rspoption(rsp, "Content-Range", "*/*");
            return handle_http_error(416, req, rsp);
        }
        else
        {
            rsp->code = 206;
            rsp->body = using_customized_body;
            http_add_rspoption(rsp, "Accept-Ranges", "bytes");
            //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri));
            sprintf(strbuf, "bytes "sizett"-"sizett"/"sizett"", from, to, total_length);
            http_add_rspoption(rsp, "Content-Range", strbuf);
            sprintf(strbuf, sizett, task_length);
            http_add_rspoption(rsp, "Content-Length", strbuf);

            http_send_response(rsp);
        }
    }
    else
#endif /* WEBCFG_SUPPORT_HTTPRANGE */
    {
        from = 0;
        task_length = total_length;
        to = total_length-1;
        sprintf(strbuf, sizett, task_length);

        rsp->code = 200;
        rsp->body = using_customized_body;
#ifdef WEBCFG_SUPPORT_HTTPRANGE
        http_add_rspoption(rsp, "Accept-Ranges", "bytes");
#endif
        //http_add_rspoption(rsp, "Content-Type", mimetype(req->uri));
        http_add_rspoption(rsp, "Content-Length", strbuf);
        http_send_response(rsp);
    }

    ret = OK;

    /* Respond with data. For HEAD request, skip this. */
    if(HTTP_GET == req->method)
    {
        size_t  i           = 0;
        size_t  buflen      = 1024*1024;
        size_t  readsize    = 0;
        size_t  counter     = 0;
        char  * buffer      = NULL;

#define SPEED_REPORT
#ifdef SPEED_REPORT
        /* speed test */
        //size_t  data_1 = 0, data_2 = 0;
        time_t  time_1 = time(NULL), time_2;
#endif
        do
        {
            buflen /= 2;
            buffer = (char *)webmalloc(buflen);
        }
        while(!buffer);

        fseek(fp, from, SEEK_SET);
        while(1)
        {
            memset(buffer, 0, buflen);
            if(task_length-counter > buflen)
                readsize=fread(buffer, 1, buflen, fp);
            else
                readsize=fread(buffer, 1, task_length-counter, fp);

            if(readsize <= 0)
            {
                WEBLOG_ERROR("<%s> fread fail "sizett". %s.\n", __FUNCTION__, readsize, strerror(socketGetError()));
                ret = NG;
                break;
            }
            WEBLOG_VERBOSE("<%s> read "sizett" from %s, sent "sizett" to socket.\n ", __FUNCTION__, readsize, vpath, i);
            i = WebWrite(req->sock, buffer, readsize);
            if(i != readsize)
            {
                WEBLOG_ERROR("<%s> WebWrite fail "sizett". %s.\n", __FUNCTION__, i, strerror(socketGetError()));
                ret = NG;
                break;
            }
            //ASSERT(i==readsize);
            counter += readsize;
#ifdef SPEED_REPORT
            time_2 = time(NULL);
            if (time_2 - time_1 > 1)
                WEBLOG_VERBOSE("<%s> "sizett"KB/s\n", __FUNCTION__, counter/1024/(time_2-time_1));
#endif
            WEBLOG_VERBOSE("<%s> "sizett"/"sizett"\n", __FUNCTION__, counter, task_length);
            if(counter >= task_length)
                break;
        }

        webfree(buffer);
    }

    if(fp) fclose(fp);
    return ret;
}
示例#12
0
int socketOpenConnection(char *host, int port, socketAccept_t accept, int flags)
{
#if (!defined (NO_GETHOSTBYNAME) && !defined (VXWORKS))
	struct hostent		*hostent;					/* Host database entry */
#endif /* ! (NO_GETHOSTBYNAME || VXWORKS) */
	socket_t			*sp;
	struct sockaddr_in	sockaddr;
	int					sid, bcast, dgram, rc;
#ifdef WF_USE_IPV6
	int					gaierr;
	char				portstr[10];
	struct addrinfo		hints;
	struct addrinfo		*ai, *ai2, *aiv6 = NULL;
	struct sockaddr_in6	sockaddr6;
#endif

	if (port > SOCKET_PORT_MAX) {
		return -1;
	}
/*
 *	Allocate a socket structure
 */
	if ((sid = socketAlloc(host, port, accept, flags)) < 0) {
		return -1;
	}
	sp = socketList[sid];
	a_assert(sp);

/*
 *	Create the socket address structure
 */
#ifdef WF_USE_IPV6
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_flags = AI_PASSIVE;
	hints.ai_socktype = SOCK_STREAM;

	snprintf(portstr, sizeof(portstr), "%d", port);
	if ((gaierr = getaddrinfo(host, portstr, &hints, &ai)) != 0) {
		fprintf(stderr, "goahead: getaddrinfo - %s\n", gai_strerror(gaierr));
		socketFree(sid);
		return -1;
	}
	aiv6 = NULL;
	for (ai2 = ai; ai2 != (struct addrinfo*)0; ai2 = ai2->ai_next) {
		switch (ai2->ai_family) {
			case AF_INET6:
				if (aiv6 == NULL)
					aiv6 = ai2;
				break;
		}
	}
	if (aiv6 == NULL) {
		fprintf(stderr, "goahead: cannot find IPv6 addrinfo\n");
		socketFree(sid);
		return -1;
	}
	memcpy(&sockaddr6, aiv6->ai_addr, aiv6->ai_addrlen);
	freeaddrinfo(ai);
#else /* WF_USE_IPV6 */
	memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in));
	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port = htons((short) (port & 0xFFFF));

	if (host == NULL) {
		sockaddr.sin_addr.s_addr = INADDR_ANY;
	} else {
		sockaddr.sin_addr.s_addr = inet_addr(host);
		if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
/*
 *			If the OS does not support gethostbyname functionality, the macro:
 *			NO_GETHOSTBYNAME should be defined to skip the use of gethostbyname.
 *			Unfortunatly there is no easy way to recover, the following code
 *			simply uses the basicGetHost IP for the sockaddr.
 */

#ifdef NO_GETHOSTBYNAME
			if (strcmp(host, basicGetHost()) == 0) {
				sockaddr.sin_addr.s_addr = inet_addr(basicGetAddress());
			}
			if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
				socketFree(sid);
				return -1;
			}
#elif (defined (VXWORKS))
			sockaddr.sin_addr.s_addr = (unsigned long) hostGetByName(host);
			if (sockaddr.sin_addr.s_addr == NULL) {
				errno = ENXIO;
				socketFree(sid);
				return -1;
			}
#else
			hostent = gethostbyname(host);
			if (hostent != NULL) {
				memcpy((char *) &sockaddr.sin_addr, 
					(char *) hostent->h_addr_list[0],
					(size_t) hostent->h_length);
			} else {
				char	*asciiAddress;
				char_t	*address;

				address = basicGetAddress();
				asciiAddress = ballocUniToAsc(address, gstrlen(address));
				sockaddr.sin_addr.s_addr = inet_addr(asciiAddress);
				bfree(B_L, asciiAddress);
				if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
					errno = ENXIO;
					socketFree(sid);
					return -1;
				}
			}
#endif /* (NO_GETHOSTBYNAME || VXWORKS) */
		}
	}
#endif /* WF_USE_IPV6 */

	bcast = sp->flags & SOCKET_BROADCAST;
	if (bcast) {
		sp->flags |= SOCKET_DATAGRAM;
	}
	dgram = sp->flags & SOCKET_DATAGRAM;

/*
 *	Create the socket. Support for datagram sockets. Set the close on
 *	exec flag so children don't inherit the socket.
 */
#ifdef WF_USE_IPV6
	sp->sock = socket(AF_INET6, SOCK_STREAM, 0);
#else
	sp->sock = socket(AF_INET, dgram ? SOCK_DGRAM: SOCK_STREAM, 0);
#endif
	if (sp->sock < 0) {
		socketFree(sid);
		return -1;
	}
#ifndef __NO_FCNTL
	fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
#endif
	socketHighestFd = max(socketHighestFd, sp->sock);

/*
 *	If broadcast, we need to turn on broadcast capability.
 */
	if (bcast) {
		int broadcastFlag = 1;
		if (setsockopt(sp->sock, SOL_SOCKET, SO_BROADCAST,
				(char *) &broadcastFlag, sizeof(broadcastFlag)) < 0) {
			socketFree(sid);
			return -1;
		}
	}

/*
 *	Host is set if we are the client
 */
	if (host) {
/*
 *		Connect to the remote server in blocking mode, then go into 
 *		non-blocking mode if desired.
 */
		if (!dgram) {
			if (! (sp->flags & SOCKET_BLOCK)) {
/*
 *				sockGen.c is only used for Windows products when blocking
 *				connects are expected.  This applies to FieldUpgrader
 *				agents and open source webserver connectws.  Therefore the
 *				asynchronous connect code here is not compiled.
 */
#if (defined (WIN) || defined (CE)) && (!defined (LITTLEFOOT) && !defined (WEBS))
				int flag;

				sp->flags |= SOCKET_ASYNC;
/*
 *				Set to non-blocking for an async connect
 */
				flag = 1;
				if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) {
					socketFree(sid);
					return -1;
				}
#else
				socketSetBlock(sid, 1);
#endif /* #if (WIN || CE) && !(LITTLEFOOT || WEBS) */

			}
			if ((rc = connect(sp->sock, (struct sockaddr *) &sockaddr,
				sizeof(sockaddr))) < 0 && 
				(rc = tryAlternateConnect(sp->sock,
				(struct sockaddr *) &sockaddr)) < 0) {
#if (defined (WIN) || defined (CE))
				if (socketGetError() != EWOULDBLOCK) {
					socketFree(sid);
					return -1;
				}
#else
				socketFree(sid);
				return -1;

#endif /* WIN || CE */

			}
		}
	} else {
/*
 *		Bind to the socket endpoint and the call listen() to start listening
 */
		rc = 1;
		setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
#ifdef WF_USE_IPV6
		if (bind(sp->sock, (struct sockaddr *) &sockaddr6,
				sizeof(sockaddr6)) < 0) {
#else
		if (bind(sp->sock, (struct sockaddr *) &sockaddr, 
				sizeof(sockaddr)) < 0) {
#endif
			socketFree(sid);
			return -1;
		}

		if (! dgram) {
			if (listen(sp->sock, SOMAXCONN) < 0) {
				socketFree(sid);
				return -1;
			}
			sp->flags |= SOCKET_LISTENING;
		}
		sp->handlerMask |= SOCKET_READABLE;
	}

/*
 *	Set the blocking mode
 */

	if (flags & SOCKET_BLOCK) {
		socketSetBlock(sid, 1);
	} else {
		socketSetBlock(sid, 0);
	}
	return sid;
}


/******************************************************************************/
/*
 *	If the connection failed, swap the first two bytes in the 
 *	sockaddr structure.  This is a kludge due to a change in
 *	VxWorks between versions 5.3 and 5.4, but we want the 
 *	product to run on either.
 */

static int tryAlternateConnect(int sock, struct sockaddr *sockaddr)
{
#ifdef VXWORKS
	char *ptr;

	ptr = (char *)sockaddr;
	*ptr = *(ptr+1);
	*(ptr+1) = 0;
	return connect(sock, sockaddr, sizeof(struct sockaddr));
#else
	return -1;
#endif /* VXWORKS */
}
示例#13
0
int socketOpenConnection(char *host, int port, socketAccept_t accept, int flags)
{
#if (!defined (NO_GETHOSTBYNAME) && !defined (VXWORKS))
	struct hostent		*hostent;					/* Host database entry */
#endif /* ! (NO_GETHOSTBYNAME || VXWORKS) */
	socket_t			*sp;
	struct sockaddr_in	sockaddr;
	int					sid, bcast, dgram, rc;

	if (port > SOCKET_PORT_MAX) {
		return -1;
	}
/*
 *	Allocate a socket structure
 */
	if ((sid = socketAlloc(host, port, accept, flags)) < 0) {
		return -1;
	}
	sp = socketList[sid];
	a_assert(sp);

/*
 *	Create the socket address structure
 */
	memset((char *) &sockaddr, '\0', sizeof(struct sockaddr_in));
	sockaddr.sin_family = AF_INET;
	sockaddr.sin_port = htons((short) (port & 0xFFFF));

	if (host == NULL) {
		sockaddr.sin_addr.s_addr = INADDR_ANY;
	} else {
		sockaddr.sin_addr.s_addr = inet_addr(host);
		if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
/*
 *			If the OS does not support gethostbyname functionality, the macro:
 *			NO_GETHOSTBYNAME should be defined to skip the use of gethostbyname.
 *			Unfortunatly there is no easy way to recover, the following code
 *			simply uses the basicGetHost IP for the sockaddr.
 */

#ifdef NO_GETHOSTBYNAME
			if (strcmp(host, basicGetHost()) == 0) {
				sockaddr.sin_addr.s_addr = inet_addr(basicGetAddress());
			}
			if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
				socketFree(sid);
				return -1;
			}
#elif (defined (VXWORKS))
			sockaddr.sin_addr.s_addr = (unsigned long) hostGetByName(host);
			if (sockaddr.sin_addr.s_addr == NULL) {
				errno = ENXIO;
				socketFree(sid);
				return -1;
			}
#else
			hostent = gethostbyname(host);
			if (hostent != NULL) {
				memcpy((char *) &sockaddr.sin_addr, 
					(char *) hostent->h_addr_list[0],
					(size_t) hostent->h_length);
			} else {
				char	*asciiAddress;
				char	*address;

				address = basicGetAddress();
				asciiAddress = ballocUniToAsc(address, gstrlen(address));
				sockaddr.sin_addr.s_addr = inet_addr(asciiAddress);
				bfree(B_L, asciiAddress);
				if (sockaddr.sin_addr.s_addr == INADDR_NONE) {
					errno = ENXIO;
					socketFree(sid);
					return -1;
				}
			}
#endif /* (NO_GETHOSTBYNAME || VXWORKS) */
		}
	}

	bcast = sp->flags & SOCKET_BROADCAST;
	if (bcast) {
		sp->flags |= SOCKET_DATAGRAM;
	}
	dgram = sp->flags & SOCKET_DATAGRAM;

/*
 *	Create the socket. Support for datagram sockets. Set the close on
 *	exec flag so children don't inherit the socket.
 */
	sp->sock = socket(AF_INET, dgram ? SOCK_DGRAM: SOCK_STREAM, 0);
	if (sp->sock < 0) {
		socketFree(sid);
		return -1;
	}
#ifndef __NO_FCNTL
	fcntl(sp->sock, F_SETFD, FD_CLOEXEC);
#endif
	socketHighestFd = max(socketHighestFd, sp->sock);

/*
 *	If broadcast, we need to turn on broadcast capability.
 */
	if (bcast) {
		int broadcastFlag = 1;
		if (setsockopt(sp->sock, SOL_SOCKET, SO_BROADCAST,
				(char *) &broadcastFlag, sizeof(broadcastFlag)) < 0) {
			socketFree(sid);
			return -1;
		}
	}

/*
 *	Host is set if we are the client
 */
	if (host) {
/*
 *		Connect to the remote server in blocking mode, then go into 
 *		non-blocking mode if desired.
 */
		if (!dgram) {
			if (! (sp->flags & SOCKET_BLOCK)) {
/*
 *				sockGen.c is only used for Windows products when blocking
 *				connects are expected.  This applies to FieldUpgrader
 *				agents and open source webserver connectws.  Therefore the
 *				asynchronous connect code here is not compiled.
 */
#if (defined (WIN) || defined (CE)) && (!defined (LITTLEFOOT) && !defined (WEBS))
				int flag;

				sp->flags |= SOCKET_ASYNC;
/*
 *				Set to non-blocking for an async connect
 */
				flag = 1;
				if (ioctlsocket(sp->sock, FIONBIO, &flag) == SOCKET_ERROR) {
					socketFree(sid);
					return -1;
				}
#else
				socketSetBlock(sid, 1);
#endif /* #if (WIN || CE) && !(LITTLEFOOT || WEBS) */

			}
			if ((rc = connect(sp->sock, (struct sockaddr *) &sockaddr,
				sizeof(sockaddr))) < 0 && 
				(rc = tryAlternateConnect(sp->sock,
				(struct sockaddr *) &sockaddr)) < 0) {
#if (defined (WIN) || defined (CE))
				if (socketGetError() != EWOULDBLOCK) {
					socketFree(sid);
					return -1;
				}
#else
				socketFree(sid);
				return -1;

#endif /* WIN || CE */

			}
		}
	} else {
/*
 *		Bind to the socket endpoint and the call listen() to start listening
 */
		rc = 1;
		setsockopt(sp->sock, SOL_SOCKET, SO_REUSEADDR, (char *)&rc, sizeof(rc));
		if (bind(sp->sock, (struct sockaddr *) &sockaddr, 
				sizeof(sockaddr)) < 0) {
			socketFree(sid);
			return -1;
		}

		if (! dgram) {
			if (listen(sp->sock, SOMAXCONN) < 0) {
				socketFree(sid);
				return -1;
			}
#ifndef UEMF
			sp->fileHandle = emfCreateFileHandler(sp->sock, SOCKET_READABLE,
				(emfFileProc *) socketAccept, (void *) sp);
#else
			sp->flags |= SOCKET_LISTENING;
#endif
		}
		sp->handlerMask |= SOCKET_READABLE;
	}

/*
 *	Set the blocking mode
 */

	if (flags & SOCKET_BLOCK) {
		socketSetBlock(sid, 1);
	} else {
		socketSetBlock(sid, 0);
	}
	return sid;
}