Multi-threaded signatures checking support, rename threads.
[novacoin.git] / src / qt / qtipcserver.cpp
1 // Copyright (c) 2009-2012 The Bitcoin developers
2 // Distributed under the MIT/X11 software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
5 #include <boost/version.hpp>
6 #if defined(WIN32) && BOOST_VERSION == 104900
7 #define BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME
8 #define BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME
9 #endif
10
11 #include "qtipcserver.h"
12 #include "guiconstants.h"
13 #include "ui_interface.h"
14 #include "util.h"
15
16 #include <boost/algorithm/string/predicate.hpp>
17 #include <boost/date_time/posix_time/posix_time.hpp>
18 #include <boost/interprocess/ipc/message_queue.hpp>
19 #include <boost/version.hpp>
20
21 #if defined(WIN32) && (!defined(BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME) || !defined(BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME) || BOOST_VERSION < 104900)
22 #warning Compiling without BOOST_INTERPROCESS_HAS_WINDOWS_KERNEL_BOOTTIME and BOOST_INTERPROCESS_HAS_KERNEL_BOOTTIME uncommented in boost/interprocess/detail/tmp_dir_helpers.hpp or using a boost version before 1.49 may have unintended results see svn.boost.org/trac/boost/ticket/5392
23 #endif
24
25 using namespace boost;
26 using namespace boost::interprocess;
27 using namespace boost::posix_time;
28
29 #if defined MAC_OSX || defined __FreeBSD__
30 // URI handling not implemented on OSX yet
31
32 void ipcScanRelay(int argc, char *argv[]) { }
33 void ipcInit(int argc, char *argv[]) { }
34
35 #else
36
37 static void ipcThread2(void* pArg);
38
39 static bool ipcScanCmd(int argc, char *argv[], bool fRelay)
40 {
41     // Check for URI in argv
42     bool fSent = false;
43     for (int i = 1; i < argc; i++)
44     {
45         if (boost::algorithm::istarts_with(argv[i], "novacoin:"))
46         {
47             const char *strURI = argv[i];
48             try {
49                 boost::interprocess::message_queue mq(boost::interprocess::open_only, BITCOINURI_QUEUE_NAME);
50                 if (mq.try_send(strURI, strlen(strURI), 0))
51                     fSent = true;
52                 else if (fRelay)
53                     break;
54             }
55             catch (boost::interprocess::interprocess_exception &ex) {
56                 // don't log the "file not found" exception, because that's normal for
57                 // the first start of the first instance
58                 if (ex.get_error_code() != boost::interprocess::not_found_error || !fRelay)
59                 {
60                     printf("main() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what());
61                     break;
62                 }
63             }
64         }
65     }
66     return fSent;
67 }
68
69 void ipcScanRelay(int argc, char *argv[])
70 {
71     if (ipcScanCmd(argc, argv, true))
72         exit(0);
73 }
74
75 static void ipcThread(void* pArg)
76 {
77     // Make this thread recognisable as the GUI-IPC thread
78     RenameThread("novacoin-gui-ipc");
79         
80     try
81     {
82         ipcThread2(pArg);
83     }
84     catch (std::exception& e) {
85         PrintExceptionContinue(&e, "ipcThread()");
86     } catch (...) {
87         PrintExceptionContinue(NULL, "ipcThread()");
88     }
89     printf("ipcThread exited\n");
90 }
91
92 static void ipcThread2(void* pArg)
93 {
94     printf("ipcThread started\n");
95
96     message_queue* mq = (message_queue*)pArg;
97     char buffer[MAX_URI_LENGTH + 1] = "";
98     size_t nSize = 0;
99     unsigned int nPriority = 0;
100
101     while (true)
102     {
103         ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(100);
104         if (mq->timed_receive(&buffer, sizeof(buffer), nSize, nPriority, d))
105         {
106             uiInterface.ThreadSafeHandleURI(std::string(buffer, nSize));
107             Sleep(1000);
108         }
109
110         if (fShutdown)
111             break;
112     }
113
114     // Remove message queue
115     message_queue::remove(BITCOINURI_QUEUE_NAME);
116     // Cleanup allocated memory
117     delete mq;
118 }
119
120 void ipcInit(int argc, char *argv[])
121 {
122     message_queue* mq = NULL;
123     char buffer[MAX_URI_LENGTH + 1] = "";
124     size_t nSize = 0;
125     unsigned int nPriority = 0;
126
127     try {
128         mq = new message_queue(open_or_create, BITCOINURI_QUEUE_NAME, 2, MAX_URI_LENGTH);
129
130         // Make sure we don't lose any bitcoin: URIs
131         for (int i = 0; i < 2; i++)
132         {
133             ptime d = boost::posix_time::microsec_clock::universal_time() + millisec(1);
134             if (mq->timed_receive(&buffer, sizeof(buffer), nSize, nPriority, d))
135             {
136                 uiInterface.ThreadSafeHandleURI(std::string(buffer, nSize));
137             }
138             else
139                 break;
140         }
141
142         // Make sure only one bitcoin instance is listening
143         message_queue::remove(BITCOINURI_QUEUE_NAME);
144         delete mq;
145
146         mq = new message_queue(open_or_create, BITCOINURI_QUEUE_NAME, 2, MAX_URI_LENGTH);
147     }
148     catch (interprocess_exception &ex) {
149         printf("ipcInit() - boost interprocess exception #%d: %s\n", ex.get_error_code(), ex.what());
150         return;
151     }
152
153     if (!NewThread(ipcThread, mq))
154     {
155         delete mq;
156         return;
157     }
158
159     ipcScanCmd(argc, argv, false);
160 }
161
162 #endif