This file is indexed.

/usr/share/pyshared/nanotubes.py is in python-fibranet 10-3.1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
#Copyright (c) 2006 Simon Wittber
#
#Permission is hereby granted, free of charge, to any person
#obtaining a copy of this software and associated documentation files
#(the "Software"), to deal in the Software without restriction,
#including without limitation the rights to use, copy, modify, merge,
#publish, distribute, sublicense, and/or sell copies of the Software,
#and to permit persons to whom the Software is furnished to do so,
#subject to the following conditions:
#
#The above copyright notice and this permission notice shall be
#included in all copies or substantial portions of the Software.
#
#THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
#EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
#MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
#NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
#BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
#ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
#CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
#SOFTWARE.

"""

The nanotubes module implements asynchronous socket handling, and provides
protocol classes which simplify event passing over sockets.

"""

__author__ = "simonwittber@gmail.com"

import socket
import select
import struct

import gherkin as encoder

from errno import EALREADY, EINPROGRESS, EWOULDBLOCK, ECONNRESET, ENOTCONN, ESHUTDOWN, EINTR, EISCONN

#---------------------------------------------------------------------#

class StringQueue(object):
    """
    A simple character buffer which is used for queing network bytes.
    """
    def __init__(self):
        self.l_buffer = []
        self.s_buffer = ""

    def write(self, data):
        """
        Append's data to the buffer.
        """
        self.l_buffer.append(data)

    def read(self, count=None):
        """
        Returns and removes a number of bytes from the buffer. If count is
        None, all bytes are returned.
        """
        result = self.peek(count)
        self.discard(count)
        return result
    
    def discard(self, count):
        """
        Removes a number of bytes from the buffer.
        """
        self.s_buffer = self.s_buffer[count:]
            
    def peek(self, count=None):
        """
        Returns a number of bytes from the buffer, but does not remove them.
        If count is None, all bytes are returned.
        """
        if count > len(self.s_buffer) or count==None:
            self._build_s_buffer()
        result = self.s_buffer[:count]
        return result

    def _build_s_buffer(self):
        new_string = "".join(self.l_buffer)
        self.s_buffer = "".join((self.s_buffer, new_string))
        self.l_buffer = []

    def __len__(self):
        self._build_s_buffer()
        return len(self.s_buffer)
        
#---------------------------------------------------------------------#

class SocketHandler(object):
    """
    The SocketHandler class registers all socket connections, and uses the
    select function to trigger read, write and close calls on Connection 
    objects.
    """
    sockets = []
    socket_objects = {}
    dead_sockets = []
    
    @classmethod
    def poll(cls):
        """
        The poll method removes dead sockets, and triggers method calls on 
        any Connection objects which are waiting for attention. This method
        needs to be called often.
        """
        for s in cls.dead_sockets:
            cls.sockets.remove(s)
            del cls.socket_objects[s]
        cls.dead_sockets[:] = []
        if cls.sockets:
            readable,writable,exceptional = select.select(cls.sockets,cls.sockets,cls.sockets,0)
            for s in readable:
                cls.socket_objects[s].handle_read()
            for s in writable:
                cls.socket_objects[s].handle_write()
            for s in exceptional:
                cls.socket_objects[s].handle_exception()
            
    @classmethod
    def nanothread(cls):
        """
        The nanothread method returns a generator which can be installed into
        the nanothread scheduler which will iterate the poll method.
        """
        while True:
            cls.poll()
            yield None
    
    @classmethod
    def remove(cls, s):
        """
        Schedules a socket for deletion.
        """
        cls.dead_sockets.append(s)
    
    @classmethod
    def add_socket(cls, s, s_o):
        """
        Adds a socket and socket_object to the handler. The socket_object 
        will have handler methods called when activity occurs on the socket.
        """
        cls.sockets.append(s)
        cls.socket_objects[s] = s_o


class Connection(object):
    def handle_close(self):
        pass
        
    def handle_read(self):
        pass

    def handle_write(self):
        pass
    
    def handle_exception(self):
        pass
        
    
class TCPConnection(Connection):
    def __init__(self, tcp_socket, protocol):
        self.protocol = protocol
        self.tcp_socket = tcp_socket
        self.tcp_socket.setblocking(0)
        SocketHandler.add_socket(self.tcp_socket, self)
        
    def channel(self, port):
        """
        Opens a UDP channel on a port.
        """
        udp_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        return UDPConnection(udp_socket, (self.host, port))
        
    def handle_read(self):
        try:
            data = self.tcp_socket.recv(4096)
        except socket.error:
            self.handle_exception()
        else:
            if len(data) == 0:
                self.handle_close()
            self.protocol.input_buffer.write(data)
            self.protocol.handle_read()

    def handle_write(self):
        data = self.protocol.output_buffer.peek(4096)
        if data:
            try:
                count = self.tcp_socket.send(data)
            except socket.error:
                self.handle_exception()
            else:
                self.protocol.output_buffer.discard(count)
    
    def handle_exception(self):
        self.protocol.handle_exception()
        

class UDPConnection(Connection):
    def __init__(self, udp_socket, (host, port)):
        self.udp_socket = udp_socket
        self.udp_socket.setblocking(0)
        self.host = host
        self.port = port
        self.transmissions = []
        SocketHandler.add_socket(self.udp_socket, self)
        
    def listen(self, receiver):
        """
        Listen on this channel for incoming traffic.
        receiver is a callback function which takes (address, data) as args.
        """
        self.receiver = receiver
        self.udp_socket.bind((self.host, self.port))
        self.handle_read = self._handle_read
    
    def handle_read(self):
        #Do nothing by default.
        pass
        
    def _handle_read(self):
        try:
            data, address = self.udp_socket.recvfrom(4096)
        except socket.error, e:
            self.handle_exception()
        else:
            self.receiver(address, data)
            
    def transmit(self, address, data):
        """
        Transmit data to address on this channel's port.
        """
        self.transmissions.append((address, data))
    
    def handle_write(self):
        try:
            address, data = self.transmissions.pop(-1)
        except IndexError:
            pass
        else:
            try:
                count = self.udp_socket.sendto(data, (address, self.port))
            except socket.error, e:
                self.handle_exception()
            
    def handle_exception(self):
        print 'UDP Exception.'
        pass


class Protocol(object):
    def __init__(self):
        self.input_buffer = StringQueue()
        self.output_buffer = StringQueue()
        
    def handle_close(self):
        pass
    
    def handle_read(self):
        pass
    
    def handle_exception(self):
        pass


class Listener(TCPConnection):
    """
    Opens a socket and starts listening for connections.
    """
    def __init__(self, (host, port), protocol_factory):
        TCPConnection.__init__(self, socket.socket(socket.AF_INET, socket.SOCK_STREAM), self)
        self.host = host
        self.port = port
        self.protocol_factory = protocol_factory
        self.tcp_socket.bind((host, port))
        self.tcp_socket.listen(5)
        
    def handle_new(self, tcp_connection):
        pass
        
    def handle_read(self):
        new_socket, address = self.tcp_socket.accept()
        c = TCPConnection(new_socket, self.protocol_factory())
        self.handle_new(c)


class Connector(TCPConnection):
    """
    Connects to a socket on a remote host.
    """
    def __init__(self, (host, port), protocol_factory):
        TCPConnection.__init__(self, socket.socket(socket.AF_INET, socket.SOCK_STREAM), protocol_factory())
        self.host = host
        self.port = port
        self.connect()
        
    def connect(self):
        err = self.tcp_socket.connect_ex((self.host, self.port))
        if err in (EINPROGRESS, EALREADY, EWOULDBLOCK):
            pass
        else:
            raise socket.error, err
    
#---------------------------------------------------------------------#

class MessageProtocol(Protocol):
    """
    The message protocol fires and forgets events over a connections.
    Events are (name, dict) pairs. Recieved events are queued up in the
    messages attribute.
    """
    def __init__(self):
        Protocol.__init__(self)
        self.unpacker = self._create_unpacker(self.input_buffer)
        self.messages = []
    
    def _create_unpacker(self, buffer):
        """
        This generator yields new messages from the incoming buffer.
        """
        while True:
            if len(buffer) >= 4:
                size = struct.unpack("!l", buffer.read(4))[0]
                while len(buffer) < size:
                    yield None
                message = buffer.read(size)
                yield message
            else:
                yield None

    def pack_message(self, name, kw):
        data = encoder.dumps((name, kw))
        size = struct.pack("!l", len(data))
        return "".join((size, data))
    
    def post(self, name, **kw):
        """
        Post an event over the connection. The name argument is the event
        name, kw arguments are the event attributes.
        """
        data = self.pack_message(name, kw)
        self.output_buffer.write(data)

    def handle_read(self):
        for message in self.unpacker:
            if message is not None:
                self.messages.append(encoder.loads(message))
            else: 
                break