diff --git a/onionr/communicator2.py b/onionr/communicator2.py
index c0fbb698..01af7270 100755
--- a/onionr/communicator2.py
+++ b/onionr/communicator2.py
@@ -466,8 +466,12 @@ class OnionrCommunicatorDaemon:
self.blockToUpload = cmd[1]
threading.Thread(target=self.uploadBlock).start()
elif cmd[0] == 'startSocket':
- # Create a socket or connect to one
- self.onionrsockets.append(onionrsockets.OnionrSockets(self._core, startData))
+ # Create a socket or connect to one.
+ # The socket handler (such as the plugin or app using it) is specified in startData['reason]
+ startData = json.loads(cmd[1])
+ rCallback = onionrsockets.getSocketCallbackRecieveHandler(self._core, startData['reason'], startData['create'])
+ sCallback = onionrsockets.getSocketCallbackSendHandler(self._core, startData['reason'], startData['create'])
+ self.onionrsockets.append(onionrsockets.OnionrSockets(self._core, startData, recieveCallback=rCallback, sendCallback=sCallback))
else:
logger.info('Recieved daemonQueue command:' + cmd[0])
diff --git a/onionr/core.py b/onionr/core.py
index 3ce4bbfd..54219390 100644
--- a/onionr/core.py
+++ b/onionr/core.py
@@ -21,7 +21,7 @@ import sqlite3, os, sys, time, math, base64, tarfile, getpass, simplecrypt, hash
from onionrblockapi import Block
import onionrutils, onionrcrypto, onionrproofs, onionrevents as events, onionrexceptions, onionrvalues
-import onionrblacklist
+import onionrblacklist, onionrchat
import dbcreator
if sys.version_info < (3, 6):
try:
@@ -79,6 +79,7 @@ class Core:
# Initialize the crypto object
self._crypto = onionrcrypto.OnionrCrypto(self)
self._blacklist = onionrblacklist.OnionrBlackList(self)
+ self.chatInst = onionrchat.OnionrChat(self)
except Exception as error:
logger.error('Failed to initialize core Onionr library.', error=error)
diff --git a/onionr/netcontroller.py b/onionr/netcontroller.py
index b3691956..56b12573 100644
--- a/onionr/netcontroller.py
+++ b/onionr/netcontroller.py
@@ -68,6 +68,7 @@ class NetController:
# Set the Tor control password. Meant to make it harder to manipulate our Tor instance
plaintext = base64.b64encode(os.urandom(50)).decode()
config.set('tor.controlpassword', plaintext, savefile=True)
+ config.set('tor.socksport', self.socksPort, savefile=True)
controlPort = random.randint(1025, 65535)
diff --git a/onionr/onionrchat.py b/onionr/onionrchat.py
new file mode 100644
index 00000000..a4051828
--- /dev/null
+++ b/onionr/onionrchat.py
@@ -0,0 +1,30 @@
+'''
+ Onionr - P2P Anonymous Storage Network
+
+ Onionr Chat Messages
+'''
+'''
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see .
+'''
+import logger
+class OnionrChat:
+ def __init__(self, coreInst):
+ return
+
+ def recieveMessage(self, socketInst, data):
+ logger.info('Got %s' % (data,))
+ return ''
+
+ def sendMessage(self, socketInst, data):
+ return "Hello"
\ No newline at end of file
diff --git a/onionr/onionrsockets.py b/onionr/onionrsockets.py
index 8111f039..2a63613c 100644
--- a/onionr/onionrsockets.py
+++ b/onionr/onionrsockets.py
@@ -18,13 +18,25 @@
along with this program. If not, see .
'''
import stem.control
-import socket, selectors
-import onionrexceptions, time
+import socket, selectors, socks, config
+import onionrexceptions, time, onionrchat
from dependencies import secrets
sel = selectors.DefaultSelector()
+def getSocketCallbackRecieveHandler(coreInst, reason, create):
+ '''Return the recieve handler function for a given socket reason'''
+ retData = ''
+ if startData == 'chat':
+ retData = coreInst.chatInst.recieveMessage
+
+def getSocketCallbackSendHandler(coreInst, reason, create):
+ '''Return the send handler function for a given socket reason'''
+ retData = ''
+ if startData == 'chat':
+ retData = coreInst.chatInst.sendMessage
+
class OnionrSockets:
- def __init__(self, coreInst, socketInfo):
+ def __init__(self, coreInst, socketInfo, recieveCallback=None, sendCallback=None):
'''Create a new Socket object. This interface is named a bit misleadingly
and does not actually forward network requests.
@@ -36,6 +48,12 @@ class OnionrSockets:
self.socketID = secrets.token_hex(32) # Generate an ID for this socket
self._core = coreInst
self.socketInfo = socketInfo
+
+ if not callable(sendCallback) or not callable(recieveCallback)
+ raise ValueError("callback must be a function")
+
+ self.sendCallback = sendCallback
+ self.recieveCallback = recieveCallback
# Make sure socketInfo provides all necessary values
for i in ('peer', 'address', 'create', 'port'):
@@ -50,11 +68,11 @@ class OnionrSockets:
self.socketPort = socketInfo['port']
self.serverAddress = socketInfo['address']
self.connected = False
- self.segment = 0
- self.connData = {}
if self.isServer:
self.createServer()
+ else:
+ self.connectServer()
def createServer(self):
# Create our HS and advertise it via a block
@@ -87,34 +105,31 @@ class OnionrSockets:
callback(key.fileobj, mask)
return
-
- def connectServer(self):
- return
def _accept(self, sock, mask):
# Just accept the connection and pass it to our handler
conn, addr = sock.accept()
conn.setblocking(False)
sel.register(conn, selectors.EVENT_READ, self._read)
+ self.connected = True
def _read(self, conn, mask):
- data = conn.recv(1000).decode()
+ data = conn.recv(1024)
if data:
- self.segment += 1
- self.connData[self.segment] = data
- conn.send(data)
+ data = data.decode()
+ self.callback(self, data)
else:
sel.unregister(conn)
conn.close()
-
- def readConnection(self):
- if not self.connected:
- raise Exception("Connection closed")
- count = 0
- while self.connected:
- try:
- yield self.connData[count]
- count += 1
- except KeyError:
- pass
- time.sleep(0.01)
+
+ def connectServer(self):
+ # Set the Tor proxy
+ socks.setdefaultproxy(socks.PROXY_TYPE_SOCKS5, '127.0.0.1', config.get('tor.socksport'), rdns=True)
+ socket.socket = socks.socksocket
+ remoteSocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+
+ with remoteSocket as s:
+ s.connect((self.serverAddress, self.port))
+ data = s.recv(1024)
+ data.send(self.sendCallback(self, data.decode()))
+ return
\ No newline at end of file
diff --git a/onionr/static-data/default-plugins/metadataprocessor/main.py b/onionr/static-data/default-plugins/metadataprocessor/main.py
index 3b0191ae..940dc424 100644
--- a/onionr/static-data/default-plugins/metadataprocessor/main.py
+++ b/onionr/static-data/default-plugins/metadataprocessor/main.py
@@ -85,8 +85,12 @@ def on_processBlocks(api):
port = api.data['port']
except KeyError:
raise ValueError("Missing port for new socket")
+ try:
+ reason = api.data['reason']
+ except KeyError:
+ raise ValueError("Missing socket reason")
- socketInfo = json.dumps({'peer': api.data['signer'], 'address': address, 'port': port, create = False})
+ socketInfo = json.dumps({'peer': api.data['signer'], 'address': address, 'port': port, 'create' = False, 'reason': reason})
api.get_core().daemonQueueAdd('startSocket', socketInfo)
def on_init(api, data = None):