?? sock.c
字號:
/*
* sock.c -- Posix Socket upper layer support module for general posix use
*
* Copyright (c) GoAhead Software Inc., 1995-2000. All Rights Reserved.
*
* $Id: sock.c,v 1.3 2002/10/24 14:44:50 bporter Exp $
*/
/******************************** Description *********************************/
/*
* Posix Socket Module. This supports blocking and non-blocking buffered
* socket I/O.
*/
/********************************** Includes **********************************/
#include <string.h>
#include <stdlib.h>
#ifdef UEMF
#include "uemf.h"
#else
#include <socket.h>
#include <types.h>
#include <unistd.h>
#include "emfInternal.h"
#endif
/************************************ Locals **********************************/
socket_t **socketList; /* List of open sockets */
int socketMax; /* Maximum size of socket */
int socketHighestFd = -1; /* Highest socket fd opened */
/***************************** Forward Declarations ***************************/
static int socketDoOutput(socket_t *sp, char *buf, int toWrite, int *errCode);
static int tryAlternateSendTo(int sock, char *buf, int toWrite, int i,
struct sockaddr *server);
/*********************************** Code *************************************/
/*
* 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.
*/
int socketWrite(int sid, char *buf, int bufsize)
{
socket_t *sp;
ringq_t *rq;
int len, bytesWritten, room;
a_assert(buf);
a_assert(bufsize >= 0);
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
/*
* Loop adding as much data to the output ringq as we can absorb. Initiate a
* flush when the ringq is too full and continue. Block in socketFlush if the
* socket is in blocking mode.
*/
rq = &sp->outBuf;
for (bytesWritten = 0; bufsize > 0; ) {
if ((room = ringqPutBlkMax(rq)) == 0) {
if (socketFlush(sid) < 0) {
return -1;
}
if ((room = ringqPutBlkMax(rq)) == 0) {
if (sp->flags & SOCKET_BLOCK) {
#if (defined (WIN) || defined (CE))
int errCode;
if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
&errCode)) {
return -1;
}
#endif
continue;
}
break;
}
continue;
}
len = min(room, bufsize);
ringqPutBlk(rq, (unsigned char *) buf, len);
bytesWritten += len;
bufsize -= len;
buf += len;
}
return bytesWritten;
}
/******************************************************************************/
/*
* Write a string to a socket
*/
int socketWriteString(int sid, char_t *buf)
{
#ifdef UNICODE
char *byteBuf;
int r, len;
len = gstrlen(buf);
byteBuf = ballocUniToAsc(buf, len);
r = socketWrite(sid, byteBuf, len);
bfreeSafe(B_L, byteBuf);
return r;
#else
return socketWrite(sid, buf, strlen(buf));
#endif /* UNICODE */
}
/******************************************************************************/
/*
* Read from a socket. Return the number of bytes read if successful. This
* may be less than the requested "bufsize" and may be zero. Return -1 for
* errors. Return 0 for EOF. Otherwise return the number of bytes read.
* If this routine returns zero it indicates an EOF condition.
* which can be verified with socketEof()
* Note: this ignores the line buffer, so a previous socketGets
* which read a partial line may cause a subsequent socketRead to miss some
* data. This routine may block if the socket is in blocking mode.
*
*/
int socketRead(int sid, char *buf, int bufsize)
{
socket_t *sp;
ringq_t *rq;
int len, room, errCode, bytesRead;
a_assert(buf);
a_assert(bufsize > 0);
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
if (sp->flags & SOCKET_EOF) {
return 0;
}
rq = &sp->inBuf;
for (bytesRead = 0; bufsize > 0; ) {
len = min(ringqLen(rq), bufsize);
if (len <= 0) {
/*
* if blocking mode and already have data, exit now or it may block
* forever.
*/
if ((sp->flags & SOCKET_BLOCK) &&
(bytesRead > 0)) {
break;
}
/*
* This flush is critical for readers of datagram packets. If the
* buffer is not big enough to read the whole datagram in one hit,
* the recvfrom call will fail.
*/
ringqFlush(rq);
room = ringqPutBlkMax(rq);
len = socketGetInput(sid, (char *) rq->endp, room, &errCode);
if (len < 0) {
if (errCode == EWOULDBLOCK) {
if ((sp->flags & SOCKET_BLOCK) &&
(bytesRead == 0)) {
continue;
}
if (bytesRead >= 0) {
return bytesRead;
}
}
return -1;
} else if (len == 0) {
/*
* If bytesRead is 0, this is EOF since socketRead should never
* be called unless there is data yet to be read. Set the flag.
* Then pass back the number of bytes read.
*/
if (bytesRead == 0) {
sp->flags |= SOCKET_EOF;
}
return bytesRead;
}
ringqPutBlkAdj(rq, len);
len = min(len, bufsize);
}
memcpy(&buf[bytesRead], rq->servp, len);
ringqGetBlkAdj(rq, len);
bufsize -= len;
bytesRead += len;
}
return bytesRead;
}
/******************************************************************************/
/*
* Get a string from a socket. This returns data in *buf in a malloced string
* after trimming the '\n'. If there is zero bytes returned, *buf will be set
* to NULL. If doing non-blocking I/O, it returns -1 for error, EOF or when
* no complete line yet read. If doing blocking I/O, it will block until an
* entire line is read. If a partial line is read socketInputBuffered or
* socketEof can be used to distinguish between EOF and partial line still
* buffered. This routine eats and ignores carriage returns.
*/
int socketGets(int sid, char_t **buf)
{
socket_t *sp;
ringq_t *lq;
char c;
int rc, len;
a_assert(buf);
*buf = NULL;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
lq = &sp->lineBuf;
while (1) {
if ((rc = socketRead(sid, &c, 1)) < 0) {
return rc;
}
if (rc == 0) {
/*
* If there is a partial line and we are at EOF, pretend we saw a '\n'
*/
if (ringqLen(lq) > 0 && (sp->flags & SOCKET_EOF)) {
c = '\n';
} else {
return -1;
}
}
/*
* If a newline is seen, return the data excluding the new line to the
* caller. If carriage return is seen, just eat it.
*/
if (c == '\n') {
len = ringqLen(lq);
if (len > 0) {
*buf = ballocAscToUni((char *)lq->servp, len);
} else {
*buf = NULL;
}
ringqFlush(lq);
return len;
} else if (c == '\r') {
continue;
}
ringqPutcA(lq, c);
}
return 0;
}
/******************************************************************************/
/*
* Flush the socket. Block if the socket is in blocking mode.
* This will return -1 on errors and 0 if successful.
*/
int socketFlush(int sid)
{
socket_t *sp;
ringq_t *rq;
int len, bytesWritten, errCode;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
rq = &sp->outBuf;
/*
* Set the background flushing flag which socketEventProc will check to
* continue the flush.
*/
if (! (sp->flags & SOCKET_BLOCK)) {
sp->flags |= SOCKET_FLUSHING;
}
/*
* Break from loop if not blocking after initiating output. If we are blocking
* we wait for a write event.
*/
while (ringqLen(rq) > 0) {
len = ringqGetBlkMax(&sp->outBuf);
bytesWritten = socketDoOutput(sp, (char*) rq->servp, len, &errCode);
if (bytesWritten < 0) {
if (errCode == EINTR) {
continue;
} else if (errCode == EWOULDBLOCK || errCode == EAGAIN) {
#if (defined (WIN) || defined (CE))
if (sp->flags & SOCKET_BLOCK) {
int errCode;
if (! socketWaitForEvent(sp, FD_WRITE | SOCKET_WRITABLE,
&errCode)) {
return -1;
}
continue;
}
#endif
/*
* Ensure we get a FD_WRITE message when the socket can absorb
* more data (non-blocking only.) Store the user's mask if we
* haven't done it already.
*/
if (sp->saveMask < 0 ) {
sp->saveMask = sp->handlerMask;
socketRegisterInterest(sp,
sp->handlerMask | SOCKET_WRITABLE);
}
return 0;
}
return -1;
}
ringqGetBlkAdj(rq, bytesWritten);
}
/*
* If the buffer is empty, reset the ringq pointers to point to the start
* of the buffer. This is essential to ensure that datagrams get written
* in one single I/O operation.
*/
if (ringqLen(rq) == 0) {
ringqFlush(rq);
}
/*
* Restore the users mask if it was saved by the non-blocking code above.
* Note: saveMask = -1 if empty. socketRegisterInterest will set handlerMask
*/
if (sp->saveMask >= 0) {
socketRegisterInterest(sp, sp->saveMask);
sp->saveMask = -1;
}
sp->flags &= ~SOCKET_FLUSHING;
return 0;
}
/******************************************************************************/
/*
* Return the count of input characters buffered. We look at both the line
* buffer and the input (raw) buffer. Return -1 on error or EOF.
*/
int socketInputBuffered(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
if (socketEof(sid)) {
return -1;
}
return ringqLen(&sp->lineBuf) + ringqLen(&sp->inBuf);
}
/******************************************************************************/
/*
* Return true if EOF
*/
int socketEof(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
return sp->flags & SOCKET_EOF;
}
/******************************************************************************/
/*
* Return the number of bytes the socket can absorb without blocking
*/
int socketCanWrite(int sid)
{
socket_t *sp;
if ((sp = socketPtr(sid)) == NULL) {
return -1;
}
return sp->outBuf.buflen - ringqLen(&sp->outBuf) - 1;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -