📄 cfsocket.cpp
字号:
{
if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForWrite() )
break;
ret = GSocket_Write(m_socket, (const char *)buffer, nbytes);
if (ret > 0)
{
total += ret;
nbytes -= ret;
buffer = (const char *)buffer + ret;
}
// If we got here and wxSOCKET_WAITALL is not set, we can leave
// now. Otherwise, wait until we send all the data or until there
// is an error.
//
more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL));
}
}
return total;
}
wxSocketBase& wxSocketBase::WriteMsg(const void *buffer, wxUint32 nbytes)
{
wxUint32 total;
bool error;
struct
{
unsigned char sig[4];
unsigned char len[4];
}
msg;
// Mask write events
m_writing = true;
error = true;
total = 0;
SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL);
msg.sig[0] = (unsigned char) 0xad;
msg.sig[1] = (unsigned char) 0xde;
msg.sig[2] = (unsigned char) 0xed;
msg.sig[3] = (unsigned char) 0xfe;
msg.len[0] = (unsigned char) (nbytes & 0xff);
msg.len[1] = (unsigned char) ((nbytes >> 8) & 0xff);
msg.len[2] = (unsigned char) ((nbytes >> 16) & 0xff);
msg.len[3] = (unsigned char) ((nbytes >> 24) & 0xff);
if (_Write(&msg, sizeof(msg)) < sizeof(msg))
goto exit;
total = _Write(buffer, nbytes);
if (total < nbytes)
goto exit;
msg.sig[0] = (unsigned char) 0xed;
msg.sig[1] = (unsigned char) 0xfe;
msg.sig[2] = (unsigned char) 0xad;
msg.sig[3] = (unsigned char) 0xde;
msg.len[0] = msg.len[1] = msg.len[2] = msg.len[3] = (char) 0;
if ((_Write(&msg, sizeof(msg))) < sizeof(msg))
goto exit;
// everything was OK
error = false;
exit:
m_error = error;
m_lcount = total;
m_writing = false;
return *this;
}
wxSocketBase& wxSocketBase::Unread(const void *buffer, wxUint32 nbytes)
{
if (nbytes != 0)
Pushback(buffer, nbytes);
m_error = false;
m_lcount = nbytes;
return *this;
}
wxSocketBase& wxSocketBase::Discard()
{
char *buffer = new char[MAX_DISCARD_SIZE];
wxUint32 ret;
wxUint32 total = 0;
// Mask read events
m_reading = true;
SetFlags(wxSOCKET_NOWAIT);
do
{
ret = _Read(buffer, MAX_DISCARD_SIZE);
total += ret;
}
while (ret == MAX_DISCARD_SIZE);
delete[] buffer;
m_lcount = total;
m_error = false;
// Allow read events again
m_reading = false;
return *this;
}
// --------------------------------------------------------------------------
// Wait functions
// --------------------------------------------------------------------------
// All Wait functions poll the socket using GSocket_Select() to
// check for the specified combination of conditions, until one
// of these conditions become true, an error occurs, or the
// timeout elapses. The polling loop calls PROCESS_EVENTS(), so
// this won't block the GUI.
bool wxSocketBase::_Wait(long seconds,
long milliseconds,
wxSocketEventFlags flags)
{
GSocketEventFlags result;
long timeout;
// Set this to true to interrupt ongoing waits
m_interrupt = false;
// Check for valid socket
if (!m_socket)
return false;
// Check for valid timeout value.
if (seconds != -1)
timeout = seconds * 1000 + milliseconds;
else
timeout = m_timeout * 1000;
#if !defined(wxUSE_GUI) || !wxUSE_GUI
GSocket_SetTimeout(m_socket, timeout);
#endif
// Wait in an active polling loop.
//
// NOTE: We duplicate some of the code in OnRequest, but this doesn't
// hurt. It has to be here because the (GSocket) event might arrive
// a bit delayed, and it has to be in OnRequest as well because we
// don't know whether the Wait functions are being used.
//
// Do this at least once (important if timeout == 0, when
// we are just polling). Also, if just polling, do not yield.
wxStopWatch chrono;
bool done = false;
while (!done)
{
result = GSocket_Select(m_socket, flags | GSOCK_LOST_FLAG);
// Incoming connection (server) or connection established (client)
if (result & GSOCK_CONNECTION_FLAG)
{
m_connected = true;
m_establishing = false;
return true;
}
// Data available or output buffer ready
if ((result & GSOCK_INPUT_FLAG) || (result & GSOCK_OUTPUT_FLAG))
{
return true;
}
// Connection lost
if (result & GSOCK_LOST_FLAG)
{
m_connected = false;
m_establishing = false;
return (flags & GSOCK_LOST_FLAG) != 0;
}
// Wait more?
if ((!timeout) || (chrono.Time() > timeout) || (m_interrupt))
done = true;
else
PROCESS_EVENTS();
}
return false;
}
bool wxSocketBase::Wait(long seconds, long milliseconds)
{
return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG |
GSOCK_OUTPUT_FLAG |
GSOCK_CONNECTION_FLAG |
GSOCK_LOST_FLAG);
}
bool wxSocketBase::WaitForRead(long seconds, long milliseconds)
{
// Check pushback buffer before entering _Wait
if (m_unread)
return true;
// Note that GSOCK_INPUT_LOST has to be explicitly passed to
// _Wait becuase of the semantics of WaitForRead: a return
// value of true means that a GSocket_Read call will return
// immediately, not that there is actually data to read.
return _Wait(seconds, milliseconds, GSOCK_INPUT_FLAG | GSOCK_LOST_FLAG);
}
bool wxSocketBase::WaitForWrite(long seconds, long milliseconds)
{
return _Wait(seconds, milliseconds, GSOCK_OUTPUT_FLAG);
}
bool wxSocketBase::WaitForLost(long seconds, long milliseconds)
{
return _Wait(seconds, milliseconds, GSOCK_LOST_FLAG);
}
// --------------------------------------------------------------------------
// Miscellaneous
// --------------------------------------------------------------------------
//
// Get local or peer address
//
bool wxSocketBase::GetPeer(wxSockAddress& addr_man) const
{
GAddress *peer;
if (!m_socket)
return false;
peer = GSocket_GetPeer(m_socket);
// copying a null address would just trigger an assert anyway
if (!peer)
return false;
addr_man.SetAddress(peer);
GAddress_destroy(peer);
return true;
}
bool wxSocketBase::GetLocal(wxSockAddress& addr_man) const
{
#if 0
GAddress *local;
if (!m_socket)
return false;
local = GSocket_GetLocal(m_socket);
addr_man.SetAddress(local);
GAddress_destroy(local);
#endif
return true;
}
//
// Save and restore socket state
//
void wxSocketBase::SaveState()
{
wxSocketState *state;
state = new wxSocketState();
state->m_flags = m_flags;
state->m_notify = m_notify;
state->m_eventmask = m_eventmask;
state->m_clientData = m_clientData;
m_states.Append(state);
}
void wxSocketBase::RestoreState()
{
wxList::compatibility_iterator node;
wxSocketState *state;
node = m_states.GetLast();
if (!node)
return;
state = (wxSocketState *)node->GetData();
m_flags = state->m_flags;
m_notify = state->m_notify;
m_eventmask = state->m_eventmask;
m_clientData = state->m_clientData;
m_states.Erase(node);
delete state;
}
//
// Timeout and flags
//
void wxSocketBase::SetTimeout(long seconds)
{
m_timeout = seconds;
#if 0
if (m_socket)
GSocket_SetTimeout(m_socket, m_timeout * 1000);
#endif
}
void wxSocketBase::SetFlags(wxSocketFlags flags)
{
m_flags = flags;
}
// --------------------------------------------------------------------------
// Event handling
// --------------------------------------------------------------------------
// A note on how events are processed, which is probably the most
// difficult thing to get working right while keeping the same API
// and functionality for all platforms.
//
// When GSocket detects an event, it calls wx_socket_callback, which in
// turn just calls wxSocketBase::OnRequest in the corresponding wxSocket
// object. OnRequest does some housekeeping, and if the event is to be
// propagated to the user, it creates a new wxSocketEvent object and
// posts it. The event is not processed immediately, but delayed with
// AddPendingEvent instead. This is necessary in order to decouple the
// event processing from wx_socket_callback; otherwise, subsequent IO
// calls made from the user event handler would fail, as gtk callbacks
// are not reentrant.
//
// Note that, unlike events, user callbacks (now deprecated) are _not_
// decoupled from wx_socket_callback and thus they suffer from a variety
// of problems. Avoid them where possible and use events instead.
extern "C"
void LINKAGEMODE wx_socket_callback(GSocket * WXUNUSED(socket),
GSocketEvent notification,
char *cdata)
{
wxSocketBase *sckobj = (wxSocketBase *)cdata;
sckobj->OnRequest((wxSocketNotify) notification);
}
void wxSocketBase::OnRequest(wxSocketNotify notification)
{
// NOTE: We duplicate some of the code in _Wait, but this doesn't
// hurt. It has to be here because the (GSocket) event might arrive
// a bit delayed, and it has to be in _Wait as well because we don't
// know whether the Wait functions are being used.
switch (notification)
{
case wxSOCKET_CONNECTION:
m_establishing = false;
m_connected = true;
break;
// If we are in the middle of a R/W operation, do not
// propagate events to users. Also, filter 'late' events
// which are no longer valid.
case wxSOCKET_INPUT:
if (m_reading || !GSocket_Select(m_socket, GSOCK_INPUT_FLAG))
return;
break;
case wxSOCKET_OUTPUT:
if (m_writing || !GSocket_Select(m_socket, GSOCK_OUTPUT_FLAG))
return;
break;
case wxSOCKET_LOST:
m_connected = false;
m_establishing = false;
break;
default:
break;
}
// Schedule the event
wxSocketEventFlags flag = 0;
wxUnusedVar(flag);
switch (notification)
{
case GSOCK_INPUT:
flag = GSOCK_INPUT_FLAG;
break;
case GSOCK_OUTPUT:
flag = GSOCK_OUTPUT_FLAG;
break;
case GSOCK_CONNECTION:
flag = GSOCK_CONNECTION_FLAG;
break;
case GSOCK_LOST:
flag = GSOCK_LOST_FLAG;
break;
default:
wxLogWarning( wxT("wxSocket: unknown event!") );
return;
}
if (((m_eventmask & flag) == flag) && m_notify)
{
if (m_handler)
{
wxSocketEvent event(m_id);
event.m_event = notification;
event.m_clientData = m_clientData;
event.SetEventObject(this);
m_handler->AddPendingEvent(event);
}
}
}
void wxSocketBase::Notify(bool notify)
{
m_notify = notify;
}
void wxSocketBase::SetNotify(wxSocketEventFlags flags)
{
m_eventmask = flags;
}
void wxSocketBase::SetEventHandler(wxEvtHandler& handler, int id)
{
m_handler = &handler;
m_id = id;
}
// --------------------------------------------------------------------------
// Pushback buffer
// --------------------------------------------------------------------------
void wxSocketBase::Pushback(const void *buffer, wxUint32 size)
{
if (!size)
return;
if (m_unread == NULL)
m_unread = malloc(size);
else
{
void *tmp;
tmp = malloc(m_unrd_size + size);
memcpy((char *)tmp + size, m_unread, m_unrd_size);
free(m_unread);
m_unread = tmp;
}
m_unrd_size += size;
memcpy(m_unread, buffer, size);
}
wxUint32 wxSocketBase::GetPushback(void *buffer, wxUint32 size, bool peek)
{
if (!m_unrd_size)
return 0;
if (size > (m_unrd_size-m_unrd_cur))
size = m_unrd_size-m_unrd_cur;
memcpy(buffer, (char *)m_unread + m_unrd_cur, size);
if (!peek)
{
m_unrd_cur += size;
if (m_unrd_size == m_unrd_cur)
{
free(m_unread);
m_unread = NULL;
m_unrd_size = 0;
m_unrd_cur = 0;
}
}
return size;
}
// ==========================================================================
// wxSocketServer
// ==========================================================================
// --------------------------------------------------------------------------
// Ctor
// --------------------------------------------------------------------------
wxSocketServer::wxSocketServer(wxSockAddress& addr_man,
wxSocketFlags flags)
: wxSocketBase(flags, wxSOCKET_SERVER)
{
wxLogTrace( wxTRACE_Socket, wxT("Opening wxSocketServer") );
m_socket = GSocket_new();
if (!m_socket)
{
wxLogTrace( wxTRACE_Socket, wxT("*** GSocket_new failed") );
return;
}
// Setup the socket as server
#if 0
GSocket_SetLocal(m_socket, addr_man.GetAddress());
if (GSocket_SetServer(m_socket) != GSOCK_NOERROR)
{
GSocket_destroy(m_socket);
m_socket = NULL;
wxLogTrace( wxTRACE_Socket, wxT("*** GSocket_SetServer failed") );
return;
}
GSocket_SetTimeout(m_socket, m_timeout * 1000);
GSocket_SetCallback(m_socket, GSOCK_INPUT_FLAG | GSOCK_OUTPUT_FLAG |
GSOCK_LOST_FLAG | GSOCK_CONNECTION_FLAG,
wx_socket_callback, (char *)this);
#endif
}
// --------------------------------------------------------------------------
// Accept
// --------------------------------------------------------------------------
bool wxSocketServer::AcceptWith(wxSocketBase& sock, bool wait)
{
GSocket *child_socket;
if (!m_socket)
return false;
// If wait == false, then the call should be nonblocking.
// When we are finished, we put the socket to blocking mode
// again.
#if 0
if (!wait)
GSocket_SetNonBlocking(m_socket, 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -