📄 cfsocket.cpp
字号:
/////////////////////////////////////////////////////////////////////////////// Name: src/mac/carbon/cfsocket.cpp// Purpose: Socket handler classes// Authors: Guilhem Lavaux, Guillermo Rodriguez Garcia// Created: April 1997// Copyright: (C) 1999-1997, Guilhem Lavaux// (C) 2000-1999, Guillermo Rodriguez Garcia// RCS_ID: $Id: cfsocket.cpp,v 1.16 2006/08/31 19:30:43 ABX Exp $// License: see wxWindows licence/////////////////////////////////////////////////////////////////////////////#include "wx/wxprec.h"#ifdef __BORLANDC__ #pragma hdrstop#endif#if wxUSE_SOCKETS#include "wx/socket.h"#ifndef WX_PRECOMP #include "wx/object.h" #include "wx/string.h" #include "wx/intl.h" #include "wx/log.h" #include "wx/event.h" #include "wx/app.h" #include "wx/utils.h" #include "wx/timer.h" #include "wx/module.h"#endif#include "wx/apptrait.h"#include "wx/sckaddr.h"#include "wx/mac/carbon/private.h"#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#define HAVE_INET_ATON// DLL options compatibility check:#include "wx/build.h"WX_CHECK_BUILD_OPTIONS("wxNet")// discard buffer#define MAX_DISCARD_SIZE (10 * 1024)#ifndef INVALID_SOCKET#define INVALID_SOCKET -1#endif// what to do within waits: we have 2 cases: from the main thread itself we// have to call wxYield() to let the events (including the GUI events and the// low-level (not wxWidgets) events from GSocket) be processed. From another// thread it is enough to just call wxThread::Yield() which will give away the// rest of our time slice: the explanation is that the events will be processed// by the main thread anyhow, without calling wxYield(), but we don't want to// eat the CPU time uselessly while sitting in the loop waiting for the data#if wxUSE_THREADS #define PROCESS_EVENTS() \ { \ if ( wxThread::IsMain() ) \ wxYield(); \ else \ wxThread::Yield(); \ }#else // !wxUSE_THREADS #define PROCESS_EVENTS() wxYield()#endif // wxUSE_THREADS/!wxUSE_THREADS#define wxTRACE_Socket _T("wxSocket")IMPLEMENT_CLASS(wxSocketBase, wxObject)IMPLEMENT_CLASS(wxSocketServer, wxSocketBase)IMPLEMENT_CLASS(wxSocketClient, wxSocketBase)IMPLEMENT_CLASS(wxDatagramSocket, wxSocketBase)IMPLEMENT_DYNAMIC_CLASS(wxSocketEvent, wxEvent)// --------------------------------------------------------------------------// private classes// --------------------------------------------------------------------------class wxSocketState : public wxObject{public: wxSocketFlags m_flags; wxSocketEventFlags m_eventmask; bool m_notify; void *m_clientData;public: wxSocketState() : wxObject() {} DECLARE_NO_COPY_CLASS(wxSocketState)};struct _GSocket{ CFSocketNativeHandle m_fd; GAddress *m_local; GAddress *m_peer; GSocketError m_error; int m_non_blocking; int m_server; int m_stream; int m_oriented; int m_establishing; unsigned long m_timeout; // Callbacks GSocketEventFlags m_detected; GSocketCallback m_cbacks[GSOCK_MAX_EVENT]; char *m_data[GSOCK_MAX_EVENT]; CFSocketRef m_cfSocket; CFRunLoopSourceRef m_runLoopSource; CFReadStreamRef m_readStream ; CFWriteStreamRef m_writeStream ;};struct _GAddress{ struct sockaddr *m_addr; size_t m_len; GAddressType m_family; int m_realfamily; GSocketError m_error; int somethingElse ;};void wxMacCFSocketCallback(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void* data, void* info) ;void _GSocket_Enable(GSocket *socket, GSocketEvent event) ;void _GSocket_Disable(GSocket *socket, GSocketEvent event) ;// ==========================================================================// wxSocketBase// ==========================================================================// --------------------------------------------------------------------------// Initialization and shutdown// --------------------------------------------------------------------------// FIXME-MT: all this is MT-unsafe, of course, we should protect all accesses// to m_countInit with a crit sectionsize_t wxSocketBase::m_countInit = 0;bool wxSocketBase::IsInitialized(){ return m_countInit > 0;}bool wxSocketBase::Initialize(){ if ( !m_countInit++ ) {#if 0 wxAppTraits *traits = wxAppConsole::GetInstance() ? wxAppConsole::GetInstance()->GetTraits() : NULL; GSocketGUIFunctionsTable *functions = traits ? traits->GetSocketGUIFunctionsTable() : NULL; GSocket_SetGUIFunctions(functions); if ( !GSocket_Init() ) { m_countInit--; return false; }#endif } return true;}void wxSocketBase::Shutdown(){ // we should be initialized wxASSERT_MSG( m_countInit, wxT("extra call to Shutdown()") ); if ( !--m_countInit ) {#if 0 GSocket_Cleanup();#endif }}// --------------------------------------------------------------------------// Ctor and dtor// --------------------------------------------------------------------------void wxSocketBase::Init(){ m_socket = NULL; m_type = wxSOCKET_UNINIT; // state m_flags = 0; m_connected = m_establishing = m_reading = m_writing = m_error = false; m_lcount = 0; m_timeout = 600; m_beingDeleted = false; // pushback buffer m_unread = NULL; m_unrd_size = 0; m_unrd_cur = 0; // events m_id = -1; m_handler = NULL; m_clientData = NULL; m_notify = false; m_eventmask = 0; if ( !IsInitialized() ) { // this Initialize() will be undone by wxSocketModule::OnExit(), all the // other calls to it should be matched by a call to Shutdown() Initialize(); }}wxSocketBase::wxSocketBase(){ Init();}wxSocketBase::wxSocketBase( wxSocketFlags flags, wxSocketType type){ Init(); m_flags = flags; m_type = type;}wxSocketBase::~wxSocketBase(){ // Just in case the app called Destroy() *and* then deleted // the socket immediately: don't leave dangling pointers. wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; if ( traits ) traits->RemoveFromPendingDelete(this); // Shutdown and close the socket if (!m_beingDeleted) Close(); // Destroy the GSocket object if (m_socket) { GSocket_destroy(m_socket); } // Free the pushback buffer if (m_unread) free(m_unread);}bool wxSocketBase::Destroy(){ // Delayed destruction: the socket will be deleted during the next // idle loop iteration. This ensures that all pending events have // been processed. m_beingDeleted = true; // Shutdown and close the socket Close(); // Supress events from now on Notify(false); // schedule this object for deletion wxAppTraits *traits = wxTheApp ? wxTheApp->GetTraits() : NULL; if ( traits ) { // let the traits object decide what to do with us traits->ScheduleForDestroy(this); } else // no app or no traits { // in wxBase we might have no app object at all, don't leak memory delete this; } return true;}// --------------------------------------------------------------------------// Basic IO calls// --------------------------------------------------------------------------// The following IO operations update m_error and m_lcount:// {Read, Write, ReadMsg, WriteMsg, Peek, Unread, Discard}//// TODO: Should Connect, Accept and AcceptWith update m_error?bool wxSocketBase::Close(){ // Interrupt pending waits InterruptWait(); if (m_socket) GSocket_Shutdown(m_socket); m_connected = false; m_establishing = false; return true;}wxSocketBase& wxSocketBase::Read(void* buffer, wxUint32 nbytes){ // Mask read events m_reading = true; m_lcount = _Read(buffer, nbytes); // If in wxSOCKET_WAITALL mode, all bytes should have been read. if (m_flags & wxSOCKET_WAITALL) m_error = (m_lcount != nbytes); else m_error = (m_lcount == 0); // Allow read events from now on m_reading = false; return *this;}wxUint32 wxSocketBase::_Read(void* buffer, wxUint32 nbytes){ int total = 0; // Try the pushback buffer first total = GetPushback(buffer, nbytes, false); nbytes -= total; buffer = (char *)buffer + total; // Return now in one of the following cases: // - the socket is invalid, // - we got all the data, // - we got *some* data and we are not using wxSOCKET_WAITALL. if ( !m_socket || !nbytes || ((total != 0) && !(m_flags & wxSOCKET_WAITALL)) ) return total; // Possible combinations (they are checked in this order) // wxSOCKET_NOWAIT // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK) // wxSOCKET_BLOCK // wxSOCKET_NONE // int ret; if (m_flags & wxSOCKET_NOWAIT) { GSocket_SetNonBlocking(m_socket, 1); ret = GSocket_Read(m_socket, (char *)buffer, nbytes); GSocket_SetNonBlocking(m_socket, 0); if (ret > 0) total += ret; } else { bool more = true; while (more) { if ( !(m_flags & wxSOCKET_BLOCK) && !WaitForRead() ) break; ret = GSocket_Read(m_socket, (char *)buffer, nbytes); if (ret > 0) { total += ret; nbytes -= ret; buffer = (char *)buffer + ret; } // If we got here and wxSOCKET_WAITALL is not set, we can leave // now. Otherwise, wait until we recv all the data or until there // is an error. // more = (ret > 0 && nbytes > 0 && (m_flags & wxSOCKET_WAITALL)); } } return total;}wxSocketBase& wxSocketBase::ReadMsg(void* buffer, wxUint32 nbytes){ wxUint32 len, len2, sig, total; bool error; int old_flags; struct { unsigned char sig[4]; unsigned char len[4]; } msg; // Mask read events m_reading = true; total = 0; error = true; old_flags = m_flags; SetFlags((m_flags & wxSOCKET_BLOCK) | wxSOCKET_WAITALL); if (_Read(&msg, sizeof(msg)) != sizeof(msg)) goto exit; sig = (wxUint32)msg.sig[0]; sig |= (wxUint32)(msg.sig[1] << 8); sig |= (wxUint32)(msg.sig[2] << 16); sig |= (wxUint32)(msg.sig[3] << 24); if (sig != 0xfeeddead) { wxLogWarning( wxT("wxSocket: invalid signature in ReadMsg.") ); goto exit; } len = (wxUint32)msg.len[0]; len |= (wxUint32)(msg.len[1] << 8); len |= (wxUint32)(msg.len[2] << 16); len |= (wxUint32)(msg.len[3] << 24); if (len > nbytes) { len2 = len - nbytes; len = nbytes; } else len2 = 0; // Don't attemp to read if the msg was zero bytes long. if (len) { total = _Read(buffer, len); if (total != len) goto exit; } if (len2) { char *discard_buffer = new char[MAX_DISCARD_SIZE]; long discard_len; // NOTE: discarded bytes don't add to m_lcount. do { discard_len = ((len2 > MAX_DISCARD_SIZE)? MAX_DISCARD_SIZE : len2); discard_len = _Read(discard_buffer, (wxUint32)discard_len); len2 -= (wxUint32)discard_len; } while ((discard_len > 0) && len2); delete [] discard_buffer; if (len2 != 0) goto exit; } if (_Read(&msg, sizeof(msg)) != sizeof(msg)) goto exit; sig = (wxUint32)msg.sig[0]; sig |= (wxUint32)(msg.sig[1] << 8); sig |= (wxUint32)(msg.sig[2] << 16); sig |= (wxUint32)(msg.sig[3] << 24); if (sig != 0xdeadfeed) { wxLogWarning( wxT("wxSocket: invalid signature in ReadMsg.") ); goto exit; } // everything was OK error = false;exit: m_error = error; m_lcount = total; m_reading = false; SetFlags(old_flags); return *this;}wxSocketBase& wxSocketBase::Peek(void* buffer, wxUint32 nbytes){ // Mask read events m_reading = true; m_lcount = _Read(buffer, nbytes); Pushback(buffer, m_lcount); // If in wxSOCKET_WAITALL mode, all bytes should have been read. if (m_flags & wxSOCKET_WAITALL) m_error = (m_lcount != nbytes); else m_error = (m_lcount == 0); // Allow read events again m_reading = false; return *this;}wxSocketBase& wxSocketBase::Write(const void *buffer, wxUint32 nbytes){ // Mask write events m_writing = true; m_lcount = _Write(buffer, nbytes); // If in wxSOCKET_WAITALL mode, all bytes should have been written. if (m_flags & wxSOCKET_WAITALL) m_error = (m_lcount != nbytes); else m_error = (m_lcount == 0); // Allow write events again m_writing = false; return *this;}wxUint32 wxSocketBase::_Write(const void *buffer, wxUint32 nbytes){ wxUint32 total = 0; // If the socket is invalid or parameters are ill, return immediately if (!m_socket || !buffer || !nbytes) return 0; // Possible combinations (they are checked in this order) // wxSOCKET_NOWAIT // wxSOCKET_WAITALL (with or without wxSOCKET_BLOCK) // wxSOCKET_BLOCK // wxSOCKET_NONE // int ret; if (m_flags & wxSOCKET_NOWAIT) { GSocket_SetNonBlocking(m_socket, 1); ret = GSocket_Write(m_socket, (const char *)buffer, nbytes); GSocket_SetNonBlocking(m_socket, 0); if (ret > 0) total = ret; } else { bool more = true; while (more)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -