~brian-sidebotham/wxwidgets-cmake/wxpython-2.9.4

« back to all changes in this revision

Viewing changes to src/common/sckipc.cpp

  • Committer: Brian Sidebotham
  • Date: 2013-08-03 14:30:08 UTC
  • Revision ID: brian.sidebotham@gmail.com-20130803143008-c7806tkych1tp6fc
Initial import into Bazaar

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        src/common/sckipc.cpp
 
3
// Purpose:     Interprocess communication implementation (wxSocket version)
 
4
// Author:      Julian Smart
 
5
// Modified by: Guilhem Lavaux (big rewrite) May 1997, 1998
 
6
//              Guillermo Rodriguez (updated for wxSocket v2) Jan 2000
 
7
//                                  (callbacks deprecated)    Mar 2000
 
8
//              Vadim Zeitlin (added support for Unix sockets) Apr 2002
 
9
//                            (use buffering, many fixes/cleanup) Oct 2008
 
10
// Created:     1993
 
11
// RCS-ID:      $Id: sckipc.cpp 71624 2012-06-01 11:01:18Z VZ $
 
12
// Copyright:   (c) Julian Smart 1993
 
13
//              (c) Guilhem Lavaux 1997, 1998
 
14
//              (c) 2000 Guillermo Rodriguez <guille@iies.es>
 
15
// Licence:     wxWindows licence
 
16
/////////////////////////////////////////////////////////////////////////////
 
17
 
 
18
// ==========================================================================
 
19
// declarations
 
20
// ==========================================================================
 
21
 
 
22
// --------------------------------------------------------------------------
 
23
// headers
 
24
// --------------------------------------------------------------------------
 
25
 
 
26
// For compilers that support precompilation, includes "wx.h".
 
27
#include "wx/wxprec.h"
 
28
 
 
29
#ifdef __BORLANDC__
 
30
    #pragma hdrstop
 
31
#endif
 
32
 
 
33
#if wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS
 
34
 
 
35
#include "wx/sckipc.h"
 
36
 
 
37
#ifndef WX_PRECOMP
 
38
    #include "wx/log.h"
 
39
    #include "wx/event.h"
 
40
    #include "wx/module.h"
 
41
#endif
 
42
 
 
43
#include <stdlib.h>
 
44
#include <stdio.h>
 
45
#include <errno.h>
 
46
 
 
47
#include "wx/socket.h"
 
48
 
 
49
// --------------------------------------------------------------------------
 
50
// macros and constants
 
51
// --------------------------------------------------------------------------
 
52
 
 
53
namespace
 
54
{
 
55
 
 
56
// Message codes (don't change them to avoid breaking the existing code using
 
57
// wxIPC protocol!)
 
58
enum IPCCode
 
59
{
 
60
    IPC_EXECUTE         = 1,
 
61
    IPC_REQUEST         = 2,
 
62
    IPC_POKE            = 3,
 
63
    IPC_ADVISE_START    = 4,
 
64
    IPC_ADVISE_REQUEST  = 5,
 
65
    IPC_ADVISE          = 6,
 
66
    IPC_ADVISE_STOP     = 7,
 
67
    IPC_REQUEST_REPLY   = 8,
 
68
    IPC_FAIL            = 9,
 
69
    IPC_CONNECT         = 10,
 
70
    IPC_DISCONNECT      = 11,
 
71
    IPC_MAX
 
72
};
 
73
 
 
74
} // anonymous namespace
 
75
 
 
76
// headers needed for umask()
 
77
#ifdef __UNIX_LIKE__
 
78
    #include <sys/types.h>
 
79
    #include <sys/stat.h>
 
80
#endif // __UNIX_LIKE__
 
81
 
 
82
// ----------------------------------------------------------------------------
 
83
// private functions
 
84
// ----------------------------------------------------------------------------
 
85
 
 
86
// get the address object for the given server name, the caller must delete it
 
87
static wxSockAddress *
 
88
GetAddressFromName(const wxString& serverName,
 
89
                   const wxString& host = wxEmptyString)
 
90
{
 
91
    // we always use INET sockets under non-Unix systems
 
92
#if defined(__UNIX__) && !defined(__WINDOWS__) && !defined(__WINE__)
 
93
    // under Unix, if the server name looks like a path, create a AF_UNIX
 
94
    // socket instead of AF_INET one
 
95
    if ( serverName.Find(wxT('/')) != wxNOT_FOUND )
 
96
    {
 
97
        wxUNIXaddress *addr = new wxUNIXaddress;
 
98
        addr->Filename(serverName);
 
99
 
 
100
        return addr;
 
101
    }
 
102
#endif // Unix/!Unix
 
103
    {
 
104
        wxIPV4address *addr = new wxIPV4address;
 
105
        addr->Service(serverName);
 
106
        if ( !host.empty() )
 
107
        {
 
108
            addr->Hostname(host);
 
109
        }
 
110
 
 
111
        return addr;
 
112
    }
 
113
}
 
114
 
 
115
// --------------------------------------------------------------------------
 
116
// wxTCPEventHandler stuff (private class)
 
117
// --------------------------------------------------------------------------
 
118
 
 
119
class wxTCPEventHandler : public wxEvtHandler
 
120
{
 
121
public:
 
122
    wxTCPEventHandler() : wxEvtHandler() { }
 
123
 
 
124
    void Client_OnRequest(wxSocketEvent& event);
 
125
    void Server_OnRequest(wxSocketEvent& event);
 
126
 
 
127
private:
 
128
    void HandleDisconnect(wxTCPConnection *connection);
 
129
 
 
130
    DECLARE_EVENT_TABLE()
 
131
    wxDECLARE_NO_COPY_CLASS(wxTCPEventHandler);
 
132
};
 
133
 
 
134
enum
 
135
{
 
136
    _CLIENT_ONREQUEST_ID = 1000,
 
137
    _SERVER_ONREQUEST_ID
 
138
};
 
139
 
 
140
// --------------------------------------------------------------------------
 
141
// wxTCPEventHandlerModule (private class)
 
142
// --------------------------------------------------------------------------
 
143
 
 
144
class wxTCPEventHandlerModule : public wxModule
 
145
{
 
146
public:
 
147
    wxTCPEventHandlerModule() : wxModule() { }
 
148
 
 
149
    // get the global wxTCPEventHandler creating it if necessary
 
150
    static wxTCPEventHandler& GetHandler()
 
151
    {
 
152
        if ( !ms_handler )
 
153
            ms_handler = new wxTCPEventHandler;
 
154
 
 
155
        return *ms_handler;
 
156
    }
 
157
 
 
158
    // as ms_handler is initialized on demand, don't do anything in OnInit()
 
159
    virtual bool OnInit() { return true; }
 
160
    virtual void OnExit() { wxDELETE(ms_handler); }
 
161
 
 
162
private:
 
163
    static wxTCPEventHandler *ms_handler;
 
164
 
 
165
    DECLARE_DYNAMIC_CLASS(wxTCPEventHandlerModule)
 
166
    wxDECLARE_NO_COPY_CLASS(wxTCPEventHandlerModule);
 
167
};
 
168
 
 
169
IMPLEMENT_DYNAMIC_CLASS(wxTCPEventHandlerModule, wxModule)
 
170
 
 
171
wxTCPEventHandler *wxTCPEventHandlerModule::ms_handler = NULL;
 
172
 
 
173
// --------------------------------------------------------------------------
 
174
// wxIPCSocketStreams
 
175
// --------------------------------------------------------------------------
 
176
 
 
177
#define USE_BUFFER
 
178
 
 
179
// this class contains the various (related) streams used by wxTCPConnection
 
180
// and also provides a way to read from the socket stream directly
 
181
//
 
182
// for writing to the stream use the IPCOutput class below
 
183
class wxIPCSocketStreams
 
184
{
 
185
public:
 
186
    // ctor initializes all the streams on top of the given socket
 
187
    //
 
188
    // note that we use a bigger than default buffer size which matches the
 
189
    // typical Ethernet MTU (minus TCP header overhead)
 
190
    wxIPCSocketStreams(wxSocketBase& sock)
 
191
        : m_socketStream(sock),
 
192
#ifdef USE_BUFFER
 
193
          m_bufferedOut(m_socketStream, 1448),
 
194
#else
 
195
          m_bufferedOut(m_socketStream),
 
196
#endif
 
197
          m_dataIn(m_socketStream),
 
198
          m_dataOut(m_bufferedOut)
 
199
    {
 
200
    }
 
201
 
 
202
    // expose the IO methods needed by IPC code (notice that writing is only
 
203
    // done via IPCOutput)
 
204
 
 
205
    // flush output
 
206
    void Flush()
 
207
    {
 
208
#ifdef USE_BUFFER
 
209
        m_bufferedOut.Sync();
 
210
#endif
 
211
    }
 
212
 
 
213
    // simple wrappers around the functions with the same name in
 
214
    // wxDataInputStream
 
215
    wxUint8 Read8()
 
216
    {
 
217
        Flush();
 
218
        return m_dataIn.Read8();
 
219
    }
 
220
 
 
221
    wxUint32 Read32()
 
222
    {
 
223
        Flush();
 
224
        return m_dataIn.Read32();
 
225
    }
 
226
 
 
227
    wxString ReadString()
 
228
    {
 
229
        Flush();
 
230
        return m_dataIn.ReadString();
 
231
    }
 
232
 
 
233
    // read arbitrary (size-prepended) data
 
234
    //
 
235
    // connection parameter is needed to call its GetBufferAtLeast() method
 
236
    void *ReadData(wxConnectionBase *conn, size_t *size)
 
237
    {
 
238
        Flush();
 
239
 
 
240
        wxCHECK_MSG( conn, NULL, "NULL connection parameter" );
 
241
        wxCHECK_MSG( size, NULL, "NULL size parameter" );
 
242
 
 
243
        *size = Read32();
 
244
 
 
245
        void * const data = conn->GetBufferAtLeast(*size);
 
246
        wxCHECK_MSG( data, NULL, "IPC buffer allocation failed" );
 
247
 
 
248
        m_socketStream.Read(data, *size);
 
249
 
 
250
        return data;
 
251
    }
 
252
 
 
253
    // same as above but for data preceded by the format
 
254
    void *
 
255
    ReadFormatData(wxConnectionBase *conn, wxIPCFormat *format, size_t *size)
 
256
    {
 
257
        wxCHECK_MSG( format, NULL, "NULL format parameter" );
 
258
 
 
259
        *format = static_cast<wxIPCFormat>(Read8());
 
260
 
 
261
        return ReadData(conn, size);
 
262
    }
 
263
 
 
264
 
 
265
    // these methods are only used by IPCOutput and not directly
 
266
    wxDataOutputStream& GetDataOut() { return m_dataOut; }
 
267
    wxOutputStream& GetUnformattedOut() { return m_bufferedOut; }
 
268
 
 
269
private:
 
270
    // this is the low-level underlying stream using the connection socket
 
271
    wxSocketStream m_socketStream;
 
272
 
 
273
    // the buffered stream is used to avoid writing all pieces of an IPC
 
274
    // request to the socket one by one but to instead do it all at once when
 
275
    // we're done with it
 
276
#ifdef USE_BUFFER
 
277
    wxBufferedOutputStream m_bufferedOut;
 
278
#else
 
279
    wxOutputStream& m_bufferedOut;
 
280
#endif
 
281
 
 
282
    // finally the data streams are used to be able to write typed data into
 
283
    // the above streams easily
 
284
    wxDataInputStream  m_dataIn;
 
285
    wxDataOutputStream m_dataOut;
 
286
 
 
287
    wxDECLARE_NO_COPY_CLASS(wxIPCSocketStreams);
 
288
};
 
289
 
 
290
namespace
 
291
{
 
292
 
 
293
// an object of this class should be instantiated on the stack to write to the
 
294
// underlying socket stream
 
295
//
 
296
// this class is intentionally separated from wxIPCSocketStreams to ensure that
 
297
// Flush() is always called
 
298
class IPCOutput
 
299
{
 
300
public:
 
301
    // construct an object associated with the given streams (which must have
 
302
    // life time greater than ours as we keep a reference to it)
 
303
    IPCOutput(wxIPCSocketStreams *streams)
 
304
        : m_streams(*streams)
 
305
    {
 
306
        wxASSERT_MSG( streams, "NULL streams pointer" );
 
307
    }
 
308
 
 
309
    // dtor calls Flush() really sending the IPC data to the network
 
310
    ~IPCOutput() { m_streams.Flush(); }
 
311
 
 
312
 
 
313
    // write a byte
 
314
    void Write8(wxUint8 i)
 
315
    {
 
316
        m_streams.GetDataOut().Write8(i);
 
317
    }
 
318
 
 
319
    // write the reply code and a string
 
320
    void Write(IPCCode code, const wxString& str)
 
321
    {
 
322
        Write8(code);
 
323
        m_streams.GetDataOut().WriteString(str);
 
324
    }
 
325
 
 
326
    // write the reply code, a string and a format in this order
 
327
    void Write(IPCCode code, const wxString& str, wxIPCFormat format)
 
328
    {
 
329
        Write(code, str);
 
330
        Write8(format);
 
331
    }
 
332
 
 
333
    // write arbitrary data
 
334
    void WriteData(const void *data, size_t size)
 
335
    {
 
336
        m_streams.GetDataOut().Write32(size);
 
337
        m_streams.GetUnformattedOut().Write(data, size);
 
338
    }
 
339
 
 
340
 
 
341
private:
 
342
    wxIPCSocketStreams& m_streams;
 
343
 
 
344
    wxDECLARE_NO_COPY_CLASS(IPCOutput);
 
345
};
 
346
 
 
347
} // anonymous namespace
 
348
 
 
349
// ==========================================================================
 
350
// implementation
 
351
// ==========================================================================
 
352
 
 
353
IMPLEMENT_DYNAMIC_CLASS(wxTCPServer, wxServerBase)
 
354
IMPLEMENT_DYNAMIC_CLASS(wxTCPClient, wxClientBase)
 
355
IMPLEMENT_CLASS(wxTCPConnection, wxConnectionBase)
 
356
 
 
357
// --------------------------------------------------------------------------
 
358
// wxTCPClient
 
359
// --------------------------------------------------------------------------
 
360
 
 
361
wxTCPClient::wxTCPClient()
 
362
           : wxClientBase()
 
363
{
 
364
}
 
365
 
 
366
bool wxTCPClient::ValidHost(const wxString& host)
 
367
{
 
368
    wxIPV4address addr;
 
369
 
 
370
    return addr.Hostname(host);
 
371
}
 
372
 
 
373
wxConnectionBase *wxTCPClient::MakeConnection(const wxString& host,
 
374
                                              const wxString& serverName,
 
375
                                              const wxString& topic)
 
376
{
 
377
    wxSockAddress *addr = GetAddressFromName(serverName, host);
 
378
    if ( !addr )
 
379
        return NULL;
 
380
 
 
381
    wxSocketClient * const client = new wxSocketClient(wxSOCKET_WAITALL);
 
382
    wxIPCSocketStreams * const streams = new wxIPCSocketStreams(*client);
 
383
 
 
384
    bool ok = client->Connect(*addr);
 
385
    delete addr;
 
386
 
 
387
    if ( ok )
 
388
    {
 
389
        // Send topic name, and enquire whether this has succeeded
 
390
        IPCOutput(streams).Write(IPC_CONNECT, topic);
 
391
 
 
392
        unsigned char msg = streams->Read8();
 
393
 
 
394
        // OK! Confirmation.
 
395
        if (msg == IPC_CONNECT)
 
396
        {
 
397
            wxTCPConnection *
 
398
                connection = (wxTCPConnection *)OnMakeConnection ();
 
399
 
 
400
            if (connection)
 
401
            {
 
402
                if (wxDynamicCast(connection, wxTCPConnection))
 
403
                {
 
404
                    connection->m_topic = topic;
 
405
                    connection->m_sock  = client;
 
406
                    connection->m_streams = streams;
 
407
                    client->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
 
408
                                            _CLIENT_ONREQUEST_ID);
 
409
                    client->SetClientData(connection);
 
410
                    client->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
 
411
                    client->Notify(true);
 
412
                    return connection;
 
413
                }
 
414
                else
 
415
                {
 
416
                    delete connection;
 
417
                    // and fall through to delete everything else
 
418
                }
 
419
            }
 
420
        }
 
421
    }
 
422
 
 
423
    // Something went wrong, delete everything
 
424
    delete streams;
 
425
    client->Destroy();
 
426
 
 
427
    return NULL;
 
428
}
 
429
 
 
430
wxConnectionBase *wxTCPClient::OnMakeConnection()
 
431
{
 
432
    return new wxTCPConnection();
 
433
}
 
434
 
 
435
// --------------------------------------------------------------------------
 
436
// wxTCPServer
 
437
// --------------------------------------------------------------------------
 
438
 
 
439
wxTCPServer::wxTCPServer()
 
440
           : wxServerBase()
 
441
{
 
442
    m_server = NULL;
 
443
}
 
444
 
 
445
bool wxTCPServer::Create(const wxString& serverName)
 
446
{
 
447
    // Destroy previous server, if any
 
448
    if (m_server)
 
449
    {
 
450
        m_server->SetClientData(NULL);
 
451
        m_server->Destroy();
 
452
        m_server = NULL;
 
453
    }
 
454
 
 
455
    wxSockAddress *addr = GetAddressFromName(serverName);
 
456
    if ( !addr )
 
457
        return false;
 
458
 
 
459
#ifdef __UNIX_LIKE__
 
460
    mode_t umaskOld;
 
461
    if ( addr->Type() == wxSockAddress::UNIX )
 
462
    {
 
463
        // ensure that the file doesn't exist as otherwise calling socket()
 
464
        // would fail
 
465
        int rc = remove(serverName.fn_str());
 
466
        if ( rc < 0 && errno != ENOENT )
 
467
        {
 
468
            delete addr;
 
469
 
 
470
            return false;
 
471
        }
 
472
 
 
473
        // also set the umask to prevent the others from reading our file
 
474
        umaskOld = umask(077);
 
475
    }
 
476
    else
 
477
    {
 
478
        // unused anyhow but shut down the compiler warnings
 
479
        umaskOld = 0;
 
480
    }
 
481
#endif // __UNIX_LIKE__
 
482
 
 
483
    // Create a socket listening on the specified port (reusing it to allow
 
484
    // restarting the server listening on the same port as was used by the
 
485
    // previous instance of this server)
 
486
    m_server = new wxSocketServer(*addr, wxSOCKET_WAITALL | wxSOCKET_REUSEADDR);
 
487
 
 
488
#ifdef __UNIX_LIKE__
 
489
    if ( addr->Type() == wxSockAddress::UNIX )
 
490
    {
 
491
        // restore the umask
 
492
        umask(umaskOld);
 
493
 
 
494
        // save the file name to remove it later
 
495
        m_filename = serverName;
 
496
    }
 
497
#endif // __UNIX_LIKE__
 
498
 
 
499
    delete addr;
 
500
 
 
501
    if (!m_server->IsOk())
 
502
    {
 
503
        m_server->Destroy();
 
504
        m_server = NULL;
 
505
 
 
506
        return false;
 
507
    }
 
508
 
 
509
    m_server->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
 
510
                              _SERVER_ONREQUEST_ID);
 
511
    m_server->SetClientData(this);
 
512
    m_server->SetNotify(wxSOCKET_CONNECTION_FLAG);
 
513
    m_server->Notify(true);
 
514
 
 
515
    return true;
 
516
}
 
517
 
 
518
wxTCPServer::~wxTCPServer()
 
519
{
 
520
    if ( m_server )
 
521
    {
 
522
        m_server->SetClientData(NULL);
 
523
        m_server->Destroy();
 
524
    }
 
525
 
 
526
#ifdef __UNIX_LIKE__
 
527
    if ( !m_filename.empty() )
 
528
    {
 
529
        if ( remove(m_filename.fn_str()) != 0 )
 
530
        {
 
531
            wxLogDebug(wxT("Stale AF_UNIX file '%s' left."), m_filename.c_str());
 
532
        }
 
533
    }
 
534
#endif // __UNIX_LIKE__
 
535
}
 
536
 
 
537
wxConnectionBase *
 
538
wxTCPServer::OnAcceptConnection(const wxString& WXUNUSED(topic))
 
539
{
 
540
    return new wxTCPConnection();
 
541
}
 
542
 
 
543
// --------------------------------------------------------------------------
 
544
// wxTCPConnection
 
545
// --------------------------------------------------------------------------
 
546
 
 
547
void wxTCPConnection::Init()
 
548
{
 
549
    m_sock = NULL;
 
550
    m_streams = NULL;
 
551
}
 
552
 
 
553
wxTCPConnection::~wxTCPConnection()
 
554
{
 
555
    Disconnect();
 
556
 
 
557
    if ( m_sock )
 
558
    {
 
559
        m_sock->SetClientData(NULL);
 
560
        m_sock->Destroy();
 
561
    }
 
562
 
 
563
    delete m_streams;
 
564
}
 
565
 
 
566
void wxTCPConnection::Compress(bool WXUNUSED(on))
 
567
{
 
568
    // TODO
 
569
}
 
570
 
 
571
// Calls that CLIENT can make.
 
572
bool wxTCPConnection::Disconnect()
 
573
{
 
574
    if ( !GetConnected() )
 
575
        return true;
 
576
 
 
577
    // Send the disconnect message to the peer.
 
578
    IPCOutput(m_streams).Write8(IPC_DISCONNECT);
 
579
 
 
580
    if ( m_sock )
 
581
    {
 
582
        m_sock->Notify(false);
 
583
        m_sock->Close();
 
584
    }
 
585
 
 
586
    SetConnected(false);
 
587
 
 
588
    return true;
 
589
}
 
590
 
 
591
bool wxTCPConnection::DoExecute(const void *data,
 
592
                                size_t size,
 
593
                                wxIPCFormat format)
 
594
{
 
595
    if ( !m_sock->IsConnected() )
 
596
        return false;
 
597
 
 
598
    // Prepare EXECUTE message
 
599
    IPCOutput out(m_streams);
 
600
    out.Write8(IPC_EXECUTE);
 
601
    out.Write8(format);
 
602
 
 
603
    out.WriteData(data, size);
 
604
 
 
605
    return true;
 
606
}
 
607
 
 
608
const void *wxTCPConnection::Request(const wxString& item,
 
609
                                     size_t *size,
 
610
                                     wxIPCFormat format)
 
611
{
 
612
    if ( !m_sock->IsConnected() )
 
613
        return NULL;
 
614
 
 
615
    IPCOutput(m_streams).Write(IPC_REQUEST, item, format);
 
616
 
 
617
    const int ret = m_streams->Read8();
 
618
    if ( ret != IPC_REQUEST_REPLY )
 
619
        return NULL;
 
620
 
 
621
    // ReadData() needs a non-NULL size pointer but the client code can call us
 
622
    // with NULL pointer (this makes sense if it knows that it always works
 
623
    // with NUL-terminated strings)
 
624
    size_t sizeFallback;
 
625
    return m_streams->ReadData(this, size ? size : &sizeFallback);
 
626
}
 
627
 
 
628
bool wxTCPConnection::DoPoke(const wxString& item,
 
629
                             const void *data,
 
630
                             size_t size,
 
631
                             wxIPCFormat format)
 
632
{
 
633
    if ( !m_sock->IsConnected() )
 
634
        return false;
 
635
 
 
636
    IPCOutput out(m_streams);
 
637
    out.Write(IPC_POKE, item, format);
 
638
    out.WriteData(data, size);
 
639
 
 
640
    return true;
 
641
}
 
642
 
 
643
bool wxTCPConnection::StartAdvise(const wxString& item)
 
644
{
 
645
    if ( !m_sock->IsConnected() )
 
646
        return false;
 
647
 
 
648
    IPCOutput(m_streams).Write(IPC_ADVISE_START, item);
 
649
 
 
650
    const int ret = m_streams->Read8();
 
651
 
 
652
    return ret == IPC_ADVISE_START;
 
653
}
 
654
 
 
655
bool wxTCPConnection::StopAdvise (const wxString& item)
 
656
{
 
657
    if ( !m_sock->IsConnected() )
 
658
        return false;
 
659
 
 
660
    IPCOutput(m_streams).Write(IPC_ADVISE_STOP, item);
 
661
 
 
662
    const int ret = m_streams->Read8();
 
663
 
 
664
    return ret == IPC_ADVISE_STOP;
 
665
}
 
666
 
 
667
// Calls that SERVER can make
 
668
bool wxTCPConnection::DoAdvise(const wxString& item,
 
669
                               const void *data,
 
670
                               size_t size,
 
671
                               wxIPCFormat format)
 
672
{
 
673
    if ( !m_sock->IsConnected() )
 
674
        return false;
 
675
 
 
676
    IPCOutput out(m_streams);
 
677
    out.Write(IPC_ADVISE, item, format);
 
678
    out.WriteData(data, size);
 
679
 
 
680
    return true;
 
681
}
 
682
 
 
683
// --------------------------------------------------------------------------
 
684
// wxTCPEventHandler (private class)
 
685
// --------------------------------------------------------------------------
 
686
 
 
687
BEGIN_EVENT_TABLE(wxTCPEventHandler, wxEvtHandler)
 
688
    EVT_SOCKET(_CLIENT_ONREQUEST_ID, wxTCPEventHandler::Client_OnRequest)
 
689
    EVT_SOCKET(_SERVER_ONREQUEST_ID, wxTCPEventHandler::Server_OnRequest)
 
690
END_EVENT_TABLE()
 
691
 
 
692
void wxTCPEventHandler::HandleDisconnect(wxTCPConnection *connection)
 
693
{
 
694
    // connection was closed (either gracefully or not): destroy everything
 
695
    connection->m_sock->Notify(false);
 
696
    connection->m_sock->Close();
 
697
 
 
698
    // don't leave references to this soon-to-be-dangling connection in the
 
699
    // socket as it won't be destroyed immediately as its destruction will be
 
700
    // delayed in case there are more events pending for it
 
701
    connection->m_sock->SetClientData(NULL);
 
702
 
 
703
    connection->SetConnected(false);
 
704
    connection->OnDisconnect();
 
705
}
 
706
 
 
707
void wxTCPEventHandler::Client_OnRequest(wxSocketEvent &event)
 
708
{
 
709
    wxSocketBase *sock = event.GetSocket();
 
710
    if (!sock)
 
711
        return;
 
712
 
 
713
    wxSocketNotify evt = event.GetSocketEvent();
 
714
    wxTCPConnection * const
 
715
        connection = static_cast<wxTCPConnection *>(sock->GetClientData());
 
716
 
 
717
    // This socket is being deleted; skip this event
 
718
    if (!connection)
 
719
        return;
 
720
 
 
721
    if ( evt == wxSOCKET_LOST )
 
722
    {
 
723
        HandleDisconnect(connection);
 
724
        return;
 
725
    }
 
726
 
 
727
    // Receive message number.
 
728
    wxIPCSocketStreams * const streams = connection->m_streams;
 
729
 
 
730
    const wxString topic = connection->m_topic;
 
731
    wxString item;
 
732
 
 
733
    bool error = false;
 
734
 
 
735
    const int msg = streams->Read8();
 
736
    switch ( msg )
 
737
    {
 
738
        case IPC_EXECUTE:
 
739
            {
 
740
                wxIPCFormat format;
 
741
                size_t size wxDUMMY_INITIALIZE(0);
 
742
                void * const
 
743
                    data = streams->ReadFormatData(connection, &format, &size);
 
744
                if ( data )
 
745
                    connection->OnExecute(topic, data, size, format);
 
746
                else
 
747
                    error = true;
 
748
            }
 
749
            break;
 
750
 
 
751
        case IPC_ADVISE:
 
752
            {
 
753
                item = streams->ReadString();
 
754
 
 
755
                wxIPCFormat format;
 
756
                size_t size wxDUMMY_INITIALIZE(0);
 
757
                void * const
 
758
                    data = streams->ReadFormatData(connection, &format, &size);
 
759
 
 
760
                if ( data )
 
761
                    connection->OnAdvise(topic, item, data, size, format);
 
762
                else
 
763
                    error = true;
 
764
            }
 
765
            break;
 
766
 
 
767
        case IPC_ADVISE_START:
 
768
            {
 
769
                item = streams->ReadString();
 
770
 
 
771
                IPCOutput(streams).Write8(connection->OnStartAdvise(topic, item)
 
772
                                            ? IPC_ADVISE_START
 
773
                                            : IPC_FAIL);
 
774
            }
 
775
            break;
 
776
 
 
777
        case IPC_ADVISE_STOP:
 
778
            {
 
779
                item = streams->ReadString();
 
780
 
 
781
                IPCOutput(streams).Write8(connection->OnStopAdvise(topic, item)
 
782
                                             ? IPC_ADVISE_STOP
 
783
                                             : IPC_FAIL);
 
784
            }
 
785
            break;
 
786
 
 
787
        case IPC_POKE:
 
788
            {
 
789
                item = streams->ReadString();
 
790
                wxIPCFormat format = (wxIPCFormat)streams->Read8();
 
791
 
 
792
                size_t size wxDUMMY_INITIALIZE(0);
 
793
                void * const data = streams->ReadData(connection, &size);
 
794
 
 
795
                if ( data )
 
796
                    connection->OnPoke(topic, item, data, size, format);
 
797
                else
 
798
                    error = true;
 
799
            }
 
800
            break;
 
801
 
 
802
        case IPC_REQUEST:
 
803
            {
 
804
                item = streams->ReadString();
 
805
 
 
806
                wxIPCFormat format = (wxIPCFormat)streams->Read8();
 
807
 
 
808
                size_t user_size = wxNO_LEN;
 
809
                const void *user_data = connection->OnRequest(topic,
 
810
                                                              item,
 
811
                                                              &user_size,
 
812
                                                              format);
 
813
 
 
814
                if ( !user_data )
 
815
                {
 
816
                    IPCOutput(streams).Write8(IPC_FAIL);
 
817
                    break;
 
818
                }
 
819
 
 
820
                IPCOutput out(streams);
 
821
                out.Write8(IPC_REQUEST_REPLY);
 
822
 
 
823
                if ( user_size == wxNO_LEN )
 
824
                {
 
825
                    switch ( format )
 
826
                    {
 
827
                        case wxIPC_TEXT:
 
828
                        case wxIPC_UTF8TEXT:
 
829
                            user_size = strlen((const char *)user_data) + 1;  // includes final NUL
 
830
                            break;
 
831
                        case wxIPC_UNICODETEXT:
 
832
                            user_size = (wcslen((const wchar_t *)user_data) + 1) * sizeof(wchar_t);  // includes final NUL
 
833
                            break;
 
834
                        default:
 
835
                            user_size = 0;
 
836
                    }
 
837
                }
 
838
 
 
839
                out.WriteData(user_data, user_size);
 
840
            }
 
841
            break;
 
842
 
 
843
        case IPC_DISCONNECT:
 
844
            HandleDisconnect(connection);
 
845
            break;
 
846
 
 
847
        case IPC_FAIL:
 
848
            wxLogDebug("Unexpected IPC_FAIL received");
 
849
            error = true;
 
850
            break;
 
851
 
 
852
        default:
 
853
            wxLogDebug("Unknown message code %d received.", msg);
 
854
            error = true;
 
855
            break;
 
856
    }
 
857
 
 
858
    if ( error )
 
859
        IPCOutput(streams).Write8(IPC_FAIL);
 
860
}
 
861
 
 
862
void wxTCPEventHandler::Server_OnRequest(wxSocketEvent &event)
 
863
{
 
864
    wxSocketServer *server = (wxSocketServer *) event.GetSocket();
 
865
    if (!server)
 
866
        return;
 
867
    wxTCPServer *ipcserv = (wxTCPServer *) server->GetClientData();
 
868
 
 
869
    // This socket is being deleted; skip this event
 
870
    if (!ipcserv)
 
871
        return;
 
872
 
 
873
    if (event.GetSocketEvent() != wxSOCKET_CONNECTION)
 
874
        return;
 
875
 
 
876
    // Accept the connection, getting a new socket
 
877
    wxSocketBase *sock = server->Accept();
 
878
    if (!sock)
 
879
        return;
 
880
    if (!sock->IsOk())
 
881
    {
 
882
        sock->Destroy();
 
883
        return;
 
884
    }
 
885
 
 
886
    wxIPCSocketStreams *streams = new wxIPCSocketStreams(*sock);
 
887
 
 
888
    {
 
889
        IPCOutput out(streams);
 
890
 
 
891
        const int msg = streams->Read8();
 
892
        if ( msg == IPC_CONNECT )
 
893
        {
 
894
            const wxString topic = streams->ReadString();
 
895
 
 
896
            wxTCPConnection *new_connection =
 
897
                (wxTCPConnection *)ipcserv->OnAcceptConnection (topic);
 
898
 
 
899
            if (new_connection)
 
900
            {
 
901
                if (wxDynamicCast(new_connection, wxTCPConnection))
 
902
                {
 
903
                    // Acknowledge success
 
904
                    out.Write8(IPC_CONNECT);
 
905
 
 
906
                    new_connection->m_sock = sock;
 
907
                    new_connection->m_streams = streams;
 
908
                    new_connection->m_topic = topic;
 
909
                    sock->SetEventHandler(wxTCPEventHandlerModule::GetHandler(),
 
910
                                          _CLIENT_ONREQUEST_ID);
 
911
                    sock->SetClientData(new_connection);
 
912
                    sock->SetNotify(wxSOCKET_INPUT_FLAG | wxSOCKET_LOST_FLAG);
 
913
                    sock->Notify(true);
 
914
                    return;
 
915
                }
 
916
                else
 
917
                {
 
918
                    delete new_connection;
 
919
                    // and fall through to delete everything else
 
920
                }
 
921
            }
 
922
        }
 
923
 
 
924
        // Something went wrong, send failure message and delete everything
 
925
        out.Write8(IPC_FAIL);
 
926
    } // IPCOutput object is destroyed here, before destroying stream
 
927
 
 
928
    delete streams;
 
929
    sock->Destroy();
 
930
}
 
931
 
 
932
#endif // wxUSE_SOCKETS && wxUSE_IPC && wxUSE_STREAMS