• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Gallopsled / pwntools / a9bfe94a5c5087bad5a1d28eddc3071dea90ca3d

pending completion
a9bfe94a5c5087bad5a1d28eddc3071dea90ca3d

push

github-actions

GitHub
Merge branch 'dev' into rop_raw_list

3886 of 6368 branches covered (61.02%)

102 of 102 new or added lines in 15 files covered. (100.0%)

12212 of 16604 relevant lines covered (73.55%)

0.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.93
/pwnlib/tubes/tube.py
1
# -*- coding: utf-8 -*-
2
from __future__ import absolute_import
1✔
3
from __future__ import division
1✔
4

5
import abc
1✔
6
import logging
1✔
7
import re
1✔
8
import six
1✔
9
import string
1✔
10
import subprocess
1✔
11
import sys
1✔
12
import threading
1✔
13
import time
1✔
14

15
from six.moves import range
1✔
16

17
from pwnlib import atexit
1✔
18
from pwnlib import term
1✔
19
from pwnlib.context import context
1✔
20
from pwnlib.log import Logger
1✔
21
from pwnlib.timeout import Timeout
1✔
22
from pwnlib.tubes.buffer import Buffer
1✔
23
from pwnlib.util import misc
1✔
24
from pwnlib.util import packing
1✔
25

26

27
class tube(Timeout, Logger):
1✔
28
    """
29
    Container of all the tube functions common to sockets, TTYs and SSH connetions.
30
    """
31

32
    default = Timeout.default
1✔
33
    forever = Timeout.forever
1✔
34

35
    def __init__(self, timeout = default, level = None, *a, **kw):
1✔
36
        super(tube, self).__init__(timeout)
1✔
37

38
        Logger.__init__(self, None)
1✔
39
        if level is not None:
1✔
40
            self.setLevel(level)
1✔
41

42
        self.buffer = Buffer(*a, **kw)
1✔
43
        self._newline = None
1✔
44
        atexit.register(self.close)
1✔
45

46
    @property
1✔
47
    def newline(self):
48
        r'''Character sent with methods like sendline() or used for recvline().
49

50
            >>> t = tube()
51
            >>> t.newline = b'X'
52
            >>> t.unrecv(b'A\nB\nCX')
53
            >>> t.recvline()
54
            b'A\nB\nCX'
55

56
            >>> t = tube()
57
            >>> context.newline = b'\r\n'
58
            >>> t.newline
59
            b'\r\n'
60

61
            # Clean up
62
            >>> context.clear()
63
        '''
64
        if self._newline is not None:
1✔
65
            return self._newline
1✔
66
        return context.newline
1✔
67

68
    @newline.setter
1✔
69
    def newline(self, newline):
70
        self._newline = packing._need_bytes(newline)
1✔
71

72
    # Functions based on functions from subclasses
73
    def recv(self, numb = None, timeout = default):
1✔
74
        r"""recv(numb = 4096, timeout = default) -> bytes
75

76
        Receives up to `numb` bytes of data from the tube, and returns
77
        as soon as any quantity of data is available.
78

79
        If the request is not satisfied before ``timeout`` seconds pass,
80
        all data is buffered and an empty string (``''``) is returned.
81

82
        Raises:
83
            exceptions.EOFError: The connection is closed
84

85
        Returns:
86
            A bytes object containing bytes received from the socket,
87
            or ``''`` if a timeout occurred while waiting.
88

89
        Examples:
90

91
            >>> t = tube()
92
            >>> # Fake a data source
93
            >>> t.recv_raw = lambda n: b'Hello, world'
94
            >>> t.recv() == b'Hello, world'
95
            True
96
            >>> t.unrecv(b'Woohoo')
97
            >>> t.recv() == b'Woohoo'
98
            True
99
            >>> with context.local(log_level='debug'):
100
            ...    _ = t.recv() # doctest: +ELLIPSIS
101
            [...] Received 0xc bytes:
102
                b'Hello, world'
103
        """
104
        numb = self.buffer.get_fill_size(numb)
1✔
105
        return self._recv(numb, timeout) or b''
1✔
106

107
    def unrecv(self, data):
1✔
108
        """unrecv(data)
109

110
        Puts the specified data back at the beginning of the receive
111
        buffer.
112

113
        Examples:
114

115
            >>> t = tube()
116
            >>> t.recv_raw = lambda n: b'hello'
117
            >>> t.recv()
118
            b'hello'
119
            >>> t.recv()
120
            b'hello'
121
            >>> t.unrecv(b'world')
122
            >>> t.recv()
123
            b'world'
124
            >>> t.recv()
125
            b'hello'
126
        """
127
        data = packing._need_bytes(data)
1✔
128
        self.buffer.unget(data)
1✔
129

130
    def _fillbuffer(self, timeout = default):
1✔
131
        """_fillbuffer(timeout = default)
132

133
        Fills the internal buffer from the pipe, by calling
134
        :meth:`recv_raw` exactly once.
135

136
        Returns:
137

138
            The bytes of data received, or ``''`` if no data was received.
139

140
        Examples:
141

142
            >>> t = tube()
143
            >>> t.recv_raw = lambda *a: b'abc'
144
            >>> len(t.buffer)
145
            0
146
            >>> t._fillbuffer()
147
            b'abc'
148
            >>> len(t.buffer)
149
            3
150
        """
151
        data = b''
1✔
152

153
        with self.local(timeout):
1✔
154
            data = self.recv_raw(self.buffer.get_fill_size())
1✔
155

156
        if data and self.isEnabledFor(logging.DEBUG):
1✔
157
            self.debug('Received %#x bytes:' % len(data))
1✔
158
            self.maybe_hexdump(data, level=logging.DEBUG)
1✔
159
        if data:
1✔
160
            self.buffer.add(data)
1✔
161

162
        return data
1✔
163

164

165
    def _recv(self, numb = None, timeout = default):
1✔
166
        """_recv(numb = 4096, timeout = default) -> str
167

168
        Receives one chunk of from the internal buffer or from the OS if the
169
        buffer is empty.
170
        """
171
        numb = self.buffer.get_fill_size(numb)
1✔
172

173
        # No buffered data, could not put anything in the buffer
174
        # before timeout.
175
        if not self.buffer and not self._fillbuffer(timeout):
1✔
176
            return b''
1✔
177

178
        return self.buffer.get(numb)
1✔
179

180
    def recvpred(self, pred, timeout = default):
1✔
181
        """recvpred(pred, timeout = default) -> bytes
182

183
        Receives one byte at a time from the tube, until ``pred(all_bytes)``
184
        evaluates to True.
185

186
        If the request is not satisfied before ``timeout`` seconds pass,
187
        all data is buffered and an empty string (``''``) is returned.
188

189
        Arguments:
190
            pred(callable): Function to call, with the currently-accumulated data.
191
            timeout(int): Timeout for the operation
192

193
        Raises:
194
            exceptions.EOFError: The connection is closed
195

196
        Returns:
197
            A bytes object containing bytes received from the socket,
198
            or ``''`` if a timeout occurred while waiting.
199

200
        Examples:
201

202
            >>> t = tube()
203
            >>> t.recv_raw = lambda n: b'abbbaccc'
204
            >>> pred = lambda p: p.count(b'a') == 2
205
            >>> t.recvpred(pred)
206
            b'abbba'
207
            >>> pred = lambda p: p.count(b'd') > 0
208
            >>> t.recvpred(pred, timeout=0.05)
209
            b''
210
        """
211

212
        data = b''
1✔
213

214
        with self.countdown(timeout):
1✔
215
            while not pred(data):
1✔
216
                if not self.countdown_active():
1✔
217
                    self.unrecv(data)
1✔
218
                    return b''
1✔
219

220
                try:
1✔
221
                    res = self.recv(1, timeout=timeout)
1✔
222
                except Exception:
×
223
                    self.unrecv(data)
×
224
                    return b''
×
225

226
                if res:
1!
227
                    data += res
1✔
228
                else:
229
                    self.unrecv(data)
×
230
                    return b''
×
231

232
        return data
1✔
233

234
    def recvn(self, numb, timeout = default):
1✔
235
        """recvn(numb, timeout = default) -> bytes
236

237
        Receives exactly `n` bytes.
238

239
        If the request is not satisfied before ``timeout`` seconds pass,
240
        all data is buffered and an empty string (``''``) is returned.
241

242
        Raises:
243
            exceptions.EOFError: The connection closed before the request could be satisfied
244

245
        Returns:
246
            A string containing bytes received from the socket,
247
            or ``''`` if a timeout occurred while waiting.
248

249
        Examples:
250

251
            >>> t = tube()
252
            >>> data = b'hello world'
253
            >>> t.recv_raw = lambda *a: data
254
            >>> t.recvn(len(data)) == data
255
            True
256
            >>> t.recvn(len(data)+1) == data + data[:1]
257
            True
258
            >>> t.recv_raw = lambda *a: None
259
            >>> # The remaining data is buffered
260
            >>> t.recv() == data[1:]
261
            True
262
            >>> t.recv_raw = lambda *a: time.sleep(0.01) or b'a'
263
            >>> t.recvn(10, timeout=0.05)
264
            b''
265
            >>> t.recvn(10, timeout=0.06) # doctest: +ELLIPSIS
266
            b'aaaaaa...'
267
        """
268
        # Keep track of how much data has been received
269
        # It will be pasted together at the end if a
270
        # timeout does not occur, or put into the tube buffer.
271
        with self.countdown(timeout):
1✔
272
            while self.countdown_active() and len(self.buffer) < numb and self._fillbuffer(self.timeout):
1✔
273
                pass
1✔
274

275
        if len(self.buffer) < numb:
1✔
276
            return b''
1✔
277

278
        return self.buffer.get(numb)
1✔
279

280
    def recvuntil(self, delims, drop=False, timeout=default):
1✔
281
        """recvuntil(delims, drop=False, timeout=default) -> bytes
282

283
        Receive data until one of `delims` is encountered.
284

285
        If the request is not satisfied before ``timeout`` seconds pass,
286
        all data is buffered and an empty string (``''``) is returned.
287

288
        arguments:
289
            delims(bytes,tuple): Byte-string of delimiters characters, or list of delimiter byte-strings.
290
            drop(bool): Drop the ending.  If :const:`True` it is removed from the end of the return value.
291

292
        Raises:
293
            exceptions.EOFError: The connection closed before the request could be satisfied
294

295
        Returns:
296
            A string containing bytes received from the socket,
297
            or ``''`` if a timeout occurred while waiting.
298

299
        Examples:
300

301
            >>> t = tube()
302
            >>> t.recv_raw = lambda n: b"Hello World!"
303
            >>> t.recvuntil(b' ')
304
            b'Hello '
305
            >>> _=t.clean(0)
306
            >>> # Matches on 'o' in 'Hello'
307
            >>> t.recvuntil((b' ',b'W',b'o',b'r'))
308
            b'Hello'
309
            >>> _=t.clean(0)
310
            >>> # Matches expressly full string
311
            >>> t.recvuntil(b' Wor')
312
            b'Hello Wor'
313
            >>> _=t.clean(0)
314
            >>> # Matches on full string, drops match
315
            >>> t.recvuntil(b' Wor', drop=True)
316
            b'Hello'
317

318
            >>> # Try with regex special characters
319
            >>> t = tube()
320
            >>> t.recv_raw = lambda n: b"Hello|World"
321
            >>> t.recvuntil(b'|', drop=True)
322
            b'Hello'
323

324
        """
325
        # Convert string into singleton tupple
326
        if isinstance(delims, (bytes, bytearray, six.text_type)):
1✔
327
            delims = (delims,)
1✔
328
        delims = tuple(map(packing._need_bytes, delims))
1✔
329

330
        # Longest delimiter for tracking purposes
331
        longest = max(map(len, delims))
1✔
332

333
        # Cumulative data to search
334
        data = []
1✔
335
        top = b''
1✔
336

337
        with self.countdown(timeout):
1✔
338
            while self.countdown_active():
1✔
339
                try:
1✔
340
                    res = self.recv(timeout=self.timeout)
1✔
341
                except Exception:
×
342
                    self.unrecv(b''.join(data) + top)
×
343
                    raise
×
344

345
                if not res:
1✔
346
                    self.unrecv(b''.join(data) + top)
1✔
347
                    return b''
1✔
348

349
                top += res
1✔
350
                start = len(top)
1✔
351
                for d in delims:
1✔
352
                    j = top.find(d)
1✔
353
                    if start > j > -1:
1✔
354
                        start = j
1✔
355
                        end = j + len(d)
1✔
356
                if start < len(top):
1✔
357
                    self.unrecv(top[end:])
1✔
358
                    if drop:
1✔
359
                        top = top[:start]
1✔
360
                    else:
361
                        top = top[:end]
1✔
362
                    return b''.join(data) + top
1✔
363
                if len(top) > longest:
1✔
364
                    i = -longest - 1
1✔
365
                    data.append(top[:i])
1✔
366
                    top = top[i:]
1✔
367

368
        return b''
1✔
369

370
    def recvlines(self, numlines=2**20, keepends=False, timeout=default):
1✔
371
        r"""recvlines(numlines, keepends=False, timeout=default) -> list of bytes objects
372

373
        Receive up to ``numlines`` lines.
374

375
        A "line" is any sequence of bytes terminated by the byte sequence
376
        set by :attr:`newline`, which defaults to ``'\n'``.
377

378
        If the request is not satisfied before ``timeout`` seconds pass,
379
        all data is buffered and an empty string (``''``) is returned.
380

381
        Arguments:
382
            numlines(int): Maximum number of lines to receive
383
            keepends(bool): Keep newlines at the end of each line (:const:`False`).
384
            timeout(int): Maximum timeout
385

386
        Raises:
387
            exceptions.EOFError: The connection closed before the request could be satisfied
388

389
        Returns:
390
            A string containing bytes received from the socket,
391
            or ``''`` if a timeout occurred while waiting.
392

393
        Examples:
394

395
            >>> t = tube()
396
            >>> t.recv_raw = lambda n: b'\n'
397
            >>> t.recvlines(3)
398
            [b'', b'', b'']
399
            >>> t.recv_raw = lambda n: b'Foo\nBar\nBaz\n'
400
            >>> t.recvlines(3)
401
            [b'Foo', b'Bar', b'Baz']
402
            >>> t.recvlines(3, True)
403
            [b'Foo\n', b'Bar\n', b'Baz\n']
404
        """
405
        lines = []
1✔
406
        with self.countdown(timeout):
1✔
407
            for _ in range(numlines):
1✔
408
                try:
1✔
409
                    # We must set 'keepends' to True here so that we can
410
                    # restore the original, unmodified data to the buffer
411
                    # in the event of a timeout.
412
                    res = self.recvline(keepends=True, timeout=timeout)
1✔
413
                except Exception:
×
414
                    self.unrecv(b''.join(lines))
×
415
                    raise
×
416

417
                if res:
1!
418
                    lines.append(res)
1✔
419
                else:
420
                    break
×
421

422
        if not keepends:
1✔
423
            lines = [line.rstrip(self.newline) for line in lines]
1✔
424

425
        return lines
1✔
426

427
    def recvlinesS(self, numlines=2**20, keepends=False, timeout=default):
1✔
428
        r"""recvlinesS(numlines, keepends=False, timeout=default) -> str list
429

430
        This function is identical to :meth:`recvlines`, but decodes
431
        the received bytes into string using :func:`context.encoding`.
432
        You should use :meth:`recvlines` whenever possible for better performance.
433

434
        Examples:
435

436
            >>> t = tube()
437
            >>> t.recv_raw = lambda n: b'\n'
438
            >>> t.recvlinesS(3)
439
            ['', '', '']
440
            >>> t.recv_raw = lambda n: b'Foo\nBar\nBaz\n'
441
            >>> t.recvlinesS(3)
442
            ['Foo', 'Bar', 'Baz']
443
        """
444
        return [packing._decode(x) for x in self.recvlines(numlines, keepends, timeout)]
1✔
445

446
    def recvlinesb(self, numlines=2**20, keepends=False, timeout=default):
1✔
447
        r"""recvlinesb(numlines, keepends=False, timeout=default) -> bytearray list
448

449
        This function is identical to :meth:`recvlines`, but returns a bytearray.
450

451
        Examples:
452

453
            >>> t = tube()
454
            >>> t.recv_raw = lambda n: b'\n'
455
            >>> t.recvlinesb(3)
456
            [bytearray(b''), bytearray(b''), bytearray(b'')]
457
            >>> t.recv_raw = lambda n: b'Foo\nBar\nBaz\n'
458
            >>> t.recvlinesb(3)
459
            [bytearray(b'Foo'), bytearray(b'Bar'), bytearray(b'Baz')]
460
        """
461
        return [bytearray(x) for x in self.recvlines(numlines, keepends, timeout)]
1✔
462

463
    def recvline(self, keepends=True, timeout=default):
1✔
464
        r"""recvline(keepends=True, timeout=default) -> bytes
465

466
        Receive a single line from the tube.
467

468
        A "line" is any sequence of bytes terminated by the byte sequence
469
        set in :attr:`newline`, which defaults to ``'\n'``.
470

471
        If the request is not satisfied before ``timeout`` seconds pass,
472
        all data is buffered and an empty string (``''``) is returned.
473

474
        Arguments:
475
            keepends(bool): Keep the line ending (:const:`True`).
476
            timeout(int): Timeout
477

478
        Return:
479
            All bytes received over the tube until the first
480
            newline ``'\n'`` is received.  Optionally retains
481
            the ending.
482

483
        Examples:
484

485
            >>> t = tube()
486
            >>> t.recv_raw = lambda n: b'Foo\nBar\r\nBaz\n'
487
            >>> t.recvline()
488
            b'Foo\n'
489
            >>> t.recvline()
490
            b'Bar\r\n'
491
            >>> t.recvline(keepends = False)
492
            b'Baz'
493
            >>> t.newline = b'\r\n'
494
            >>> t.recvline(keepends = False)
495
            b'Foo\nBar'
496
        """
497
        return self.recvuntil(self.newline, drop = not keepends, timeout = timeout)
1✔
498

499
    def recvline_pred(self, pred, keepends=False, timeout=default):
1✔
500
        r"""recvline_pred(pred, keepends=False) -> bytes
501

502
        Receive data until ``pred(line)`` returns a truthy value.
503
        Drop all other data.
504

505
        If the request is not satisfied before ``timeout`` seconds pass,
506
        all data is buffered and an empty string (``''``) is returned.
507

508
        Arguments:
509
            pred(callable): Function to call.  Returns the line for which
510
                this function returns :const:`True`.
511

512
        Examples:
513

514
            >>> t = tube()
515
            >>> t.recv_raw = lambda n: b"Foo\nBar\nBaz\n"
516
            >>> t.recvline_pred(lambda line: line == b"Bar\n")
517
            b'Bar'
518
            >>> t.recvline_pred(lambda line: line == b"Bar\n", keepends=True)
519
            b'Bar\n'
520
            >>> t.recvline_pred(lambda line: line == b'Nope!', timeout=0.1)
521
            b''
522
        """
523

524
        tmpbuf = Buffer()
1✔
525
        line   = b''
1✔
526
        with self.countdown(timeout):
1✔
527
            while self.countdown_active():
1!
528
                try:
1✔
529
                    line = self.recvline(keepends=True)
1✔
530
                except Exception:
×
531
                    self.buffer.unget(tmpbuf)
×
532
                    raise
×
533

534
                if not line:
1✔
535
                    self.buffer.unget(tmpbuf)
1✔
536
                    return b''
1✔
537

538
                if pred(line):
1✔
539
                    if not keepends:
1✔
540
                        line = line[:-len(self.newline)]
1✔
541
                    return line
1✔
542
                else:
543
                    tmpbuf.add(line)
1✔
544

545
        return b''
×
546

547
    def recvline_contains(self, items, keepends = False, timeout = default):
1✔
548
        r"""
549
        Receive lines until one line is found which contains at least
550
        one of `items`.
551

552
        Arguments:
553
            items(str,tuple): List of strings to search for, or a single string.
554
            keepends(bool): Return lines with newlines if :const:`True`
555
            timeout(int): Timeout, in seconds
556

557
        Examples:
558

559
            >>> t = tube()
560
            >>> t.recv_raw = lambda n: b"Hello\nWorld\nXylophone\n"
561
            >>> t.recvline_contains(b'r')
562
            b'World'
563
            >>> f = lambda n: b"cat dog bird\napple pear orange\nbicycle car train\n"
564
            >>> t = tube()
565
            >>> t.recv_raw = f
566
            >>> t.recvline_contains(b'pear')
567
            b'apple pear orange'
568
            >>> t = tube()
569
            >>> t.recv_raw = f
570
            >>> t.recvline_contains((b'car', b'train'))
571
            b'bicycle car train'
572
        """
573
        if isinstance(items, (bytes, bytearray, six.text_type)):
1✔
574
            items = (items,)
1✔
575
        items = tuple(map(packing._need_bytes, items))
1✔
576

577
        def pred(line):
1✔
578
            return any(d in line for d in items)
1✔
579

580
        return self.recvline_pred(pred, keepends, timeout)
1✔
581

582
    def recvline_startswith(self, delims, keepends=False, timeout=default):
1✔
583
        r"""recvline_startswith(delims, keepends=False, timeout=default) -> bytes
584

585
        Keep receiving lines until one is found that starts with one of
586
        `delims`.  Returns the last line received.
587

588
        If the request is not satisfied before ``timeout`` seconds pass,
589
        all data is buffered and an empty string (``''``) is returned.
590

591
        Arguments:
592
            delims(str,tuple): List of strings to search for, or string of single characters
593
            keepends(bool): Return lines with newlines if :const:`True`
594
            timeout(int): Timeout, in seconds
595

596
        Returns:
597
            The first line received which starts with a delimiter in ``delims``.
598

599
        Examples:
600

601
            >>> t = tube()
602
            >>> t.recv_raw = lambda n: b"Hello\nWorld\nXylophone\n"
603
            >>> t.recvline_startswith((b'W',b'X',b'Y',b'Z'))
604
            b'World'
605
            >>> t.recvline_startswith((b'W',b'X',b'Y',b'Z'), True)
606
            b'Xylophone\n'
607
            >>> t.recvline_startswith(b'Wo')
608
            b'World'
609
        """
610
        # Convert string into singleton tupple
611
        if isinstance(delims, (bytes, bytearray, six.text_type)):
1✔
612
            delims = (delims,)
1✔
613
        delims = tuple(map(packing._need_bytes, delims))
1✔
614

615
        return self.recvline_pred(lambda line: any(map(line.startswith, delims)),
1✔
616
                                  keepends=keepends,
617
                                  timeout=timeout)
618

619
    def recvline_endswith(self, delims, keepends=False, timeout=default):
1✔
620
        r"""recvline_endswith(delims, keepends=False, timeout=default) -> bytes
621

622
        Keep receiving lines until one is found that ends with one of
623
        `delims`.  Returns the last line received.
624

625
        If the request is not satisfied before ``timeout`` seconds pass,
626
        all data is buffered and an empty string (``''``) is returned.
627

628
        See :meth:`recvline_startswith` for more details.
629

630
        Examples:
631

632
            >>> t = tube()
633
            >>> t.recv_raw = lambda n: b'Foo\nBar\nBaz\nKaboodle\n'
634
            >>> t.recvline_endswith(b'r')
635
            b'Bar'
636
            >>> t.recvline_endswith((b'a',b'b',b'c',b'd',b'e'), True)
637
            b'Kaboodle\n'
638
            >>> t.recvline_endswith(b'oodle')
639
            b'Kaboodle'
640
        """
641
        # Convert string into singleton tupple
642
        if isinstance(delims, (bytes, bytearray, six.text_type)):
1✔
643
            delims = (delims,)
1✔
644

645
        delims = tuple(packing._need_bytes(delim) + self.newline for delim in delims)
1✔
646

647
        return self.recvline_pred(lambda line: any(map(line.endswith, delims)),
1✔
648
                                  keepends=keepends,
649
                                  timeout=timeout)
650

651
    def recvregex(self, regex, exact=False, timeout=default, capture=False):
1✔
652
        r"""recvregex(regex, exact=False, timeout=default, capture=False) -> bytes
653

654
        Wrapper around :func:`recvpred`, which will return when a regex
655
        matches the string in the buffer.
656

657
        Returns all received data up until the regex matched. If `capture` is
658
        set to True, a :class:`re.Match` object is returned instead.
659

660
        By default :func:`re.RegexObject.search` is used, but if `exact` is
661
        set to True, then :func:`re.RegexObject.match` will be used instead.
662

663
        If the request is not satisfied before ``timeout`` seconds pass,
664
        all data is buffered and an empty string (``''``) is returned.
665

666
        Examples:
667

668
            >>> t = tube()
669
            >>> t.recv_raw = lambda n: b'The lucky number is 1337 as always\nBla blubb blargh\n'
670
            >>> m = t.recvregex(br'number is ([0-9]+) as always\n', capture=True)
671
            >>> m.group(1)
672
            b'1337'
673
            >>> t.recvregex(br'Bla .* blargh\n')
674
            b'Bla blubb blargh\n'
675
        """
676

677
        if isinstance(regex, (bytes, bytearray, six.text_type)):
1!
678
            regex = packing._need_bytes(regex)
1✔
679
            regex = re.compile(regex)
1✔
680

681
        if exact:
1!
682
            pred = regex.match
×
683
        else:
684
            pred = regex.search
1✔
685

686
        if capture:
1✔
687
            return pred(self.recvpred(pred, timeout = timeout))
1✔
688
        else:
689
            return self.recvpred(pred, timeout = timeout)
1✔
690

691
    def recvline_regex(self, regex, exact=False, keepends=False, timeout=default):
1✔
692
        """recvline_regex(regex, exact=False, keepends=False, timeout=default) -> bytes
693

694
        Wrapper around :func:`recvline_pred`, which will return when a regex
695
        matches a line.
696

697
        By default :func:`re.RegexObject.search` is used, but if `exact` is
698
        set to True, then :func:`re.RegexObject.match` will be used instead.
699

700
        If the request is not satisfied before ``timeout`` seconds pass,
701
        all data is buffered and an empty string (``''``) is returned.
702
        """
703

704
        if isinstance(regex, (bytes, bytearray, six.text_type)):
1!
705
            regex = packing._need_bytes(regex)
1✔
706
            regex = re.compile(regex)
1✔
707

708
        if exact:
1!
709
            pred = regex.match
×
710
        else:
711
            pred = regex.search
1✔
712

713
        return self.recvline_pred(pred, keepends = keepends, timeout = timeout)
1✔
714

715
    def recvrepeat(self, timeout=default):
1✔
716
        """recvrepeat(timeout=default) -> bytes
717

718
        Receives data until a timeout or EOF is reached.
719

720
        Examples:
721

722
            >>> data = [
723
            ... b'd',
724
            ... b'', # simulate timeout
725
            ... b'c',
726
            ... b'b',
727
            ... b'a',
728
            ... ]
729
            >>> def delayrecv(n, data=data):
730
            ...     return data.pop()
731
            >>> t = tube()
732
            >>> t.recv_raw = delayrecv
733
            >>> t.recvrepeat(0.2)
734
            b'abc'
735
            >>> t.recv()
736
            b'd'
737
        """
738

739
        try:
1✔
740
            while self._fillbuffer(timeout=timeout):
1✔
741
                pass
1✔
742
        except EOFError:
×
743
            pass
×
744

745
        return self.buffer.get()
1✔
746

747
    def recvall(self, timeout=Timeout.forever):
1✔
748
        """recvall() -> bytes
749

750
        Receives data until EOF is reached.
751
        """
752

753
        with self.waitfor('Receiving all data') as h:
1✔
754
            l = len(self.buffer)
1✔
755
            with self.local(timeout):
1✔
756
                try:
1✔
757
                    while True:
1✔
758
                        l = misc.size(len(self.buffer))
1✔
759
                        h.status(l)
1✔
760
                        if not self._fillbuffer():
1✔
761
                            break
1✔
762
                except EOFError:
1✔
763
                    pass
1✔
764
            h.success("Done (%s)" % l)
1✔
765
        self.close()
1✔
766

767
        return self.buffer.get()
1✔
768

769
    def send(self, data):
1✔
770
        """send(data)
771

772
        Sends data.
773

774
        If log level ``DEBUG`` is enabled, also prints out the data
775
        received.
776

777
        If it is not possible to send anymore because of a closed
778
        connection, it raises ``exceptions.EOFError``
779

780
        Examples:
781

782
            >>> def p(x): print(repr(x))
783
            >>> t = tube()
784
            >>> t.send_raw = p
785
            >>> t.send(b'hello')
786
            b'hello'
787
        """
788

789
        data = packing._need_bytes(data)
1✔
790

791
        if self.isEnabledFor(logging.DEBUG):
1!
792
            self.debug('Sent %#x bytes:' % len(data))
×
793
            self.maybe_hexdump(data, level=logging.DEBUG)
×
794

795
        self.send_raw(data)
1✔
796

797
    def sendline(self, line=b''):
1✔
798
        r"""sendline(data)
799

800
        Shorthand for ``t.send(data + t.newline)``.
801

802
        Examples:
803

804
            >>> def p(x): print(repr(x))
805
            >>> t = tube()
806
            >>> t.send_raw = p
807
            >>> t.sendline(b'hello')
808
            b'hello\n'
809
            >>> t.newline = b'\r\n'
810
            >>> t.sendline(b'hello')
811
            b'hello\r\n'
812
        """
813

814
        line = packing._need_bytes(line)
1✔
815

816
        self.send(line + self.newline)
1✔
817

818
    def sendlines(self, lines=[]):
1✔
819
        for line in lines:
×
820
            line = packing._need_bytes(line)
×
821
            self.sendline(line)
×
822

823
    def sendafter(self, delim, data, timeout = default):
1✔
824
        """sendafter(delim, data, timeout = default) -> str
825

826
        A combination of ``recvuntil(delim, timeout=timeout)`` and ``send(data)``.
827
        """
828

829
        data = packing._need_bytes(data)
×
830
        res = self.recvuntil(delim, timeout=timeout)
×
831
        self.send(data)
×
832
        return res
×
833

834
    def sendlineafter(self, delim, data, timeout = default):
1✔
835
        """sendlineafter(delim, data, timeout = default) -> str
836

837
        A combination of ``recvuntil(delim, timeout=timeout)`` and ``sendline(data)``."""
838

839
        data = packing._need_bytes(data)
×
840
        res = self.recvuntil(delim, timeout=timeout)
×
841
        self.sendline(data)
×
842
        return res
×
843

844
    def sendthen(self, delim, data, timeout = default):
1✔
845
        """sendthen(delim, data, timeout = default) -> str
846

847
        A combination of ``send(data)`` and ``recvuntil(delim, timeout=timeout)``."""
848

849
        data = packing._need_bytes(data)
×
850
        self.send(data)
×
851
        return self.recvuntil(delim, timeout=timeout)
×
852

853
    def sendlinethen(self, delim, data, timeout = default):
1✔
854
        """sendlinethen(delim, data, timeout = default) -> str
855

856
        A combination of ``sendline(data)`` and ``recvuntil(delim, timeout=timeout)``."""
857

858
        data = packing._need_bytes(data)
×
859
        self.sendline(data)
×
860
        return self.recvuntil(delim, timeout=timeout)
×
861

862
    def interactive(self, prompt = term.text.bold_red('$') + ' '):
1✔
863
        """interactive(prompt = pwnlib.term.text.bold_red('$') + ' ')
864

865
        Does simultaneous reading and writing to the tube. In principle this just
866
        connects the tube to standard in and standard out, but in practice this
867
        is much more usable, since we are using :mod:`pwnlib.term` to print a
868
        floating prompt.
869

870
        Thus it only works in while in :data:`pwnlib.term.term_mode`.
871
        """
872

873
        self.info('Switching to interactive mode')
1✔
874

875
        go = threading.Event()
1✔
876
        def recv_thread():
1✔
877
            while not go.isSet():
1!
878
                try:
×
879
                    cur = self.recv(timeout = 0.05)
×
880
                    cur = cur.replace(self.newline, b'\n')
×
881
                    if cur:
×
882
                        stdout = sys.stdout
×
883
                        if not term.term_mode:
×
884
                            stdout = getattr(stdout, 'buffer', stdout)
×
885
                        stdout.write(cur)
×
886
                        stdout.flush()
×
887
                except EOFError:
×
888
                    self.info('Got EOF while reading in interactive')
×
889
                    break
×
890

891
        t = context.Thread(target = recv_thread)
1✔
892
        t.daemon = True
1✔
893
        t.start()
1✔
894

895
        try:
1✔
896
            while not go.isSet():
1✔
897
                if term.term_mode:
1!
898
                    data = term.readline.readline(prompt = prompt, float = True)
×
899
                else:
900
                    stdin = getattr(sys.stdin, 'buffer', sys.stdin)
1✔
901
                    data = stdin.read(1)
1✔
902

903
                if data:
1!
904
                    try:
×
905
                        self.send(data)
×
906
                    except EOFError:
×
907
                        go.set()
×
908
                        self.info('Got EOF while sending in interactive')
×
909
                else:
910
                    go.set()
1✔
911
        except KeyboardInterrupt:
×
912
            self.info('Interrupted')
×
913
            go.set()
×
914

915
        while t.is_alive():
1✔
916
            t.join(timeout = 0.1)
1✔
917

918
    def stream(self, line_mode=True):
1✔
919
        """stream()
920

921
        Receive data until the tube exits, and print it to stdout.
922

923
        Similar to :func:`interactive`, except that no input is sent.
924

925
        Similar to ``print(tube.recvall())`` except that data is printed
926
        as it is received, rather than after all data is received.
927

928
        Arguments:
929
            line_mode(bool): Whether to receive line-by-line or raw data.
930

931
        Returns:
932
            All data printed.
933
        """
934
        buf = Buffer()
×
935
        function = self.recvline if line_mode else self.recv
×
936
        try:
×
937
            while True:
×
938
                buf.add(function())
×
939
                stdout = sys.stdout
×
940
                if not term.term_mode:
×
941
                    stdout = getattr(stdout, 'buffer', stdout)
×
942
                stdout.write(buf.data[-1])
×
943
        except KeyboardInterrupt:
×
944
            pass
×
945
        except EOFError:
×
946
            pass
×
947

948
        return buf.get()
×
949

950
    def clean(self, timeout = 0.05):
1✔
951
        """clean(timeout = 0.05)
952

953
        Removes all the buffered data from a tube by calling
954
        :meth:`pwnlib.tubes.tube.tube.recv` with a low timeout until it fails.
955

956
        If ``timeout`` is zero, only cached data will be cleared.
957

958
        Note: If timeout is set to zero, the underlying network is
959
        not actually polled; only the internal buffer is cleared.
960

961
        Returns:
962

963
            All data received
964

965
        Examples:
966

967
            >>> t = tube()
968
            >>> t.unrecv(b'clean me up')
969
            >>> t.clean(0)
970
            b'clean me up'
971
            >>> len(t.buffer)
972
            0
973
        """
974
        if timeout == 0:
1✔
975
            return self.buffer.get()
1✔
976

977
        return self.recvrepeat(timeout)
1✔
978

979
    def clean_and_log(self, timeout = 0.05):
1✔
980
        r"""clean_and_log(timeout = 0.05)
981

982
        Works exactly as :meth:`pwnlib.tubes.tube.tube.clean`, but logs received
983
        data with :meth:`pwnlib.self.info`.
984

985
        Returns:
986

987
            All data received
988

989
        Examples:
990

991
            >>> def recv(n, data=[b'', b'hooray_data']):
992
            ...     while data: return data.pop()
993
            >>> t = tube()
994
            >>> t.recv_raw      = recv
995
            >>> t.connected_raw = lambda d: True
996
            >>> t.fileno        = lambda: 1234
997
            >>> with context.local(log_level='info'):
998
            ...     data = t.clean_and_log() #doctest: +ELLIPSIS
999
            [DEBUG] Received 0xb bytes:
1000
                b'hooray_data'
1001
            >>> data
1002
            b'hooray_data'
1003
            >>> context.clear()
1004
        """
1005
        with context.local(log_level='debug'):
1✔
1006
            return self.clean(timeout)
1✔
1007

1008
    def connect_input(self, other):
1✔
1009
        """connect_input(other)
1010

1011
        Connects the input of this tube to the output of another tube object.
1012

1013

1014
        Examples:
1015

1016
            >>> def p(x): print(x.decode())
1017
            >>> def recvone(n, data=[b'data']):
1018
            ...     while data: return data.pop()
1019
            ...     raise EOFError
1020
            >>> a = tube()
1021
            >>> b = tube()
1022
            >>> a.recv_raw = recvone
1023
            >>> b.send_raw = p
1024
            >>> a.connected_raw = lambda d: True
1025
            >>> b.connected_raw = lambda d: True
1026
            >>> a.shutdown      = lambda d: True
1027
            >>> b.shutdown      = lambda d: True
1028
            >>> import time
1029
            >>> _=(b.connect_input(a), time.sleep(0.1))
1030
            data
1031
        """
1032

1033
        def pump():
1✔
1034
            import sys as _sys
1✔
1035
            while self.countdown_active():
1!
1036
                if not (self.connected('send') and other.connected('recv')):
1!
1037
                    break
×
1038

1039
                try:
1✔
1040
                    data = other.recv(timeout = 0.05)
1✔
1041
                except EOFError:
1✔
1042
                    break
1✔
1043

1044
                if not _sys:
1!
1045
                    return
×
1046

1047
                if not data:
1✔
1048
                    continue
1✔
1049

1050
                try:
1✔
1051
                    self.send(data)
1✔
1052
                except EOFError:
×
1053
                    break
×
1054

1055
                if not _sys:
1!
1056
                    return
×
1057

1058
            self.shutdown('send')
1✔
1059
            other.shutdown('recv')
1✔
1060

1061
        t = context.Thread(target = pump)
1✔
1062
        t.daemon = True
1✔
1063
        t.start()
1✔
1064

1065
    def connect_output(self, other):
1✔
1066
        """connect_output(other)
1067

1068
        Connects the output of this tube to the input of another tube object.
1069

1070
        Examples:
1071

1072
            >>> def p(x): print(repr(x))
1073
            >>> def recvone(n, data=[b'data']):
1074
            ...     while data: return data.pop()
1075
            ...     raise EOFError
1076
            >>> a = tube()
1077
            >>> b = tube()
1078
            >>> a.recv_raw = recvone
1079
            >>> b.send_raw = p
1080
            >>> a.connected_raw = lambda d: True
1081
            >>> b.connected_raw = lambda d: True
1082
            >>> a.shutdown      = lambda d: True
1083
            >>> b.shutdown      = lambda d: True
1084
            >>> _=(a.connect_output(b), time.sleep(0.1))
1085
            b'data'
1086
        """
1087

1088
        other.connect_input(self)
1✔
1089

1090
    def connect_both(self, other):
1✔
1091
        """connect_both(other)
1092

1093
        Connects the both ends of this tube object with another tube object."""
1094

1095
        self.connect_input(other)
1✔
1096
        self.connect_output(other)
1✔
1097

1098
    def spawn_process(self, *args, **kwargs):
1✔
1099
        """Spawns a new process having this tube as stdin, stdout and stderr.
1100

1101
        Takes the same arguments as :class:`subprocess.Popen`."""
1102

1103
        return subprocess.Popen(
1✔
1104
            *args,
1105
            stdin = self.fileno(),
1106
            stdout = self.fileno(),
1107
            stderr = self.fileno(),
1108
            **kwargs
1109
        )
1110

1111
    def __lshift__(self, other):
1✔
1112
        """
1113
        Shorthand for connecting multiple tubes.
1114

1115
        See :meth:`connect_input` for more information.
1116

1117
        Examples:
1118

1119
            The following are equivalent ::
1120

1121
                tube_a >> tube.b
1122
                tube_a.connect_input(tube_b)
1123

1124
            This is useful when chaining multiple tubes ::
1125

1126
                tube_a >> tube_b >> tube_a
1127
                tube_a.connect_input(tube_b)
1128
                tube_b.connect_input(tube_a)
1129
        """
1130
        self.connect_input(other)
×
1131
        return other
×
1132

1133
    def __rshift__(self, other):
1✔
1134
        """
1135
        Inverse of the ``<<`` operator.  See :meth:`__lshift__`.
1136

1137
        See :meth:`connect_input` for more information.
1138
        """
1139
        self.connect_output(other)
×
1140
        return other
×
1141

1142
    def __ne__(self, other):
1✔
1143
        """
1144
        Shorthand for connecting tubes to eachother.
1145

1146
        The following are equivalent ::
1147

1148
            a >> b >> a
1149
            a <> b
1150

1151
        See :meth:`connect_input` for more information.
1152
        """
1153
        self << other << self
×
1154

1155
    def wait_for_close(self, timeout=default):
1✔
1156
        """Waits until the tube is closed."""
1157

1158
        with self.countdown(timeout):
1✔
1159
            while self.countdown_active():
1!
1160
                if not self.connected():
1✔
1161
                    return
1✔
1162
                time.sleep(min(self.timeout, 0.05))
1✔
1163

1164
    wait = wait_for_close
1✔
1165

1166
    def can_recv(self, timeout = 0):
1✔
1167
        """can_recv(timeout = 0) -> bool
1168

1169
        Returns True, if there is data available within `timeout` seconds.
1170

1171
        Examples:
1172

1173
            >>> import time
1174
            >>> t = tube()
1175
            >>> t.can_recv_raw = lambda *a: False
1176
            >>> t.can_recv()
1177
            False
1178
            >>> _=t.unrecv(b'data')
1179
            >>> t.can_recv()
1180
            True
1181
            >>> _=t.recv()
1182
            >>> t.can_recv()
1183
            False
1184
        """
1185

1186
        return bool(self.buffer or self.can_recv_raw(timeout))
1✔
1187

1188
    def settimeout(self, timeout):
1✔
1189
        """settimeout(timeout)
1190

1191
        Set the timeout for receiving operations. If the string "default"
1192
        is given, then :data:`context.timeout` will be used. If None is given,
1193
        then there will be no timeout.
1194

1195
        Examples:
1196

1197
            >>> t = tube()
1198
            >>> t.settimeout_raw = lambda t: None
1199
            >>> t.settimeout(3)
1200
            >>> t.timeout == 3
1201
            True
1202
        """
1203

1204
        self.timeout = timeout
1✔
1205

1206

1207
    shutdown_directions = {
1✔
1208
        'in':    'recv',
1209
        'read':  'recv',
1210
        'recv':  'recv',
1211
        'out':   'send',
1212
        'write': 'send',
1213
        'send':  'send',
1214
    }
1215

1216
    connected_directions = shutdown_directions.copy()
1✔
1217
    connected_directions['any'] = 'any'
1✔
1218

1219
    def shutdown(self, direction = "send"):
1✔
1220
        """shutdown(direction = "send")
1221

1222
        Closes the tube for futher reading or writing depending on `direction`.
1223

1224
        Arguments:
1225
          direction(str): Which direction to close; "in", "read" or "recv"
1226
            closes the tube in the ingoing direction, "out", "write" or "send"
1227
            closes it in the outgoing direction.
1228

1229
        Returns:
1230
          :const:`None`
1231

1232
        Examples:
1233

1234
            >>> def p(x): print(x)
1235
            >>> t = tube()
1236
            >>> t.shutdown_raw = p
1237
            >>> _=list(map(t.shutdown, ('in', 'read', 'recv', 'out', 'write', 'send')))
1238
            recv
1239
            recv
1240
            recv
1241
            send
1242
            send
1243
            send
1244
            >>> t.shutdown('bad_value') #doctest: +ELLIPSIS
1245
            Traceback (most recent call last):
1246
            ...
1247
            KeyError: "direction must be in ['in', 'out', 'read', 'recv', 'send', 'write']"
1248
        """
1249
        try:
1✔
1250
            direction = self.shutdown_directions[direction]
1✔
1251
        except KeyError:
1✔
1252
            raise KeyError('direction must be in %r' % sorted(self.shutdown_directions))
1✔
1253
        else:
1254
            self.shutdown_raw(self.shutdown_directions[direction])
1✔
1255

1256
    def connected(self, direction = 'any'):
1✔
1257
        """connected(direction = 'any') -> bool
1258

1259
        Returns True if the tube is connected in the specified direction.
1260

1261
        Arguments:
1262
          direction(str): Can be the string 'any', 'in', 'read', 'recv',
1263
                          'out', 'write', 'send'.
1264

1265
        Doctest:
1266

1267
            >>> def p(x): print(x)
1268
            >>> t = tube()
1269
            >>> t.connected_raw = p
1270
            >>> _=list(map(t.connected, ('any', 'in', 'read', 'recv', 'out', 'write', 'send')))
1271
            any
1272
            recv
1273
            recv
1274
            recv
1275
            send
1276
            send
1277
            send
1278
            >>> t.connected('bad_value') #doctest: +ELLIPSIS
1279
            Traceback (most recent call last):
1280
            ...
1281
            KeyError: "direction must be in ['any', 'in', 'out', 'read', 'recv', 'send', 'write']"
1282
        """
1283
        try:
1✔
1284
            direction = self.connected_directions[direction]
1✔
1285
        except KeyError:
1✔
1286
            raise KeyError('direction must be in %r' % sorted(self.connected_directions))
1✔
1287
        else:
1288
            return self.connected_raw(direction)
1✔
1289

1290
    def __enter__(self):
1✔
1291
        """Permit use of 'with' to control scoping and closing sessions.
1292

1293
        Examples:
1294

1295
            >>> t = tube()
1296
            >>> def p(x): print(x)
1297
            >>> t.close = lambda: p("Closed!")
1298
            >>> with t: pass
1299
            Closed!
1300
        """
1301
        return self
1✔
1302

1303
    def __exit__(self, type, value, traceback):
1✔
1304
        """Handles closing for 'with' statement
1305

1306
        See :meth:`__enter__`
1307
        """
1308
        self.close()
1✔
1309

1310
    # The minimal interface to be implemented by a child
1311
    @abc.abstractmethod
1✔
1312
    def recv_raw(self, numb):
1313
        """recv_raw(numb) -> str
1314

1315
        Should not be called directly. Receives data without using the buffer
1316
        on the object.
1317

1318
        Unless there is a timeout or closed connection, this should always
1319
        return data. In case of a timeout, it should return None, in case
1320
        of a closed connection it should raise an ``exceptions.EOFError``.
1321
        """
1322

1323
        raise EOFError('Not implemented')
1✔
1324

1325
    @abc.abstractmethod
1✔
1326
    def send_raw(self, data):
1327
        """send_raw(data)
1328

1329
        Should not be called directly. Sends data to the tube.
1330

1331
        Should return ``exceptions.EOFError``, if it is unable to send any
1332
        more, because of a close tube.
1333
        """
1334

1335
        raise EOFError('Not implemented')
×
1336

1337
    def settimeout_raw(self, timeout):
1✔
1338
        """settimeout_raw(timeout)
1339

1340
        Should not be called directly. Sets the timeout for
1341
        the tube.
1342
        """
1343

1344
        raise NotImplementedError()
1✔
1345

1346
    def timeout_change(self):
1✔
1347
        """
1348
        Informs the raw layer of the tube that the timeout has changed.
1349

1350
        Should not be called directly.
1351

1352
        Inherited from :class:`Timeout`.
1353
        """
1354
        try:
1✔
1355
            self.settimeout_raw(self.timeout)
1✔
1356
        except NotImplementedError:
1✔
1357
            pass
1✔
1358

1359
    def can_recv_raw(self, timeout):
1✔
1360
        """can_recv_raw(timeout) -> bool
1361

1362
        Should not be called directly. Returns True, if
1363
        there is data available within the timeout, but
1364
        ignores the buffer on the object.
1365
        """
1366

1367
        raise NotImplementedError()
×
1368

1369
    def connected_raw(self, direction):
1✔
1370
        """connected(direction = 'any') -> bool
1371

1372
        Should not be called directly.  Returns True iff the
1373
        tube is connected in the given direction.
1374
        """
1375

1376
        raise NotImplementedError()
×
1377

1378
    def close(self):
1✔
1379
        """close()
1380

1381
        Closes the tube.
1382
        """
1383
        pass
×
1384
        # Ideally we could:
1385
        # raise NotImplementedError()
1386
        # But this causes issues with the unit tests.
1387

1388
    def fileno(self):
1✔
1389
        """fileno() -> int
1390

1391
        Returns the file number used for reading.
1392
        """
1393

1394
        raise NotImplementedError()
×
1395

1396
    def shutdown_raw(self, direction):
1✔
1397
        """shutdown_raw(direction)
1398

1399
        Should not be called directly.  Closes the tube for further reading or
1400
        writing.
1401
        """
1402

1403
        raise NotImplementedError()
×
1404

1405

1406
    def p64(self, *a, **kw):        return self.send(packing.p64(*a, **kw))
1!
1407
    def p32(self, *a, **kw):        return self.send(packing.p32(*a, **kw))
1!
1408
    def p16(self, *a, **kw):        return self.send(packing.p16(*a, **kw))
1!
1409
    def p8(self, *a, **kw):         return self.send(packing.p8(*a, **kw))
1!
1410
    def pack(self, *a, **kw):       return self.send(packing.pack(*a, **kw))
1✔
1411

1412
    def u64(self, *a, **kw):        return packing.u64(self.recvn(8), *a, **kw)
1!
1413
    def u32(self, *a, **kw):        return packing.u32(self.recvn(4), *a, **kw)
1!
1414
    def u16(self, *a, **kw):        return packing.u16(self.recvn(2), *a, **kw)
1!
1415
    def u8(self, *a, **kw):         return packing.u8(self.recvn(1), *a, **kw)
1!
1416
    def unpack(self, *a, **kw):     return packing.unpack(self.recvn(context.bytes), *a, **kw)
1✔
1417

1418
    def flat(self, *a, **kw):       return self.send(packing.flat(*a,**kw))
1!
1419
    def fit(self, *a, **kw):        return self.send(packing.fit(*a, **kw))
1!
1420

1421
    # Dynamic functions
1422

1423
    def make_wrapper(func):
1✔
1424
        def wrapperb(self, *a, **kw):
1✔
1425
            return bytearray(func(self, *a, **kw))
×
1426
        def wrapperS(self, *a, **kw):
1✔
1427
            return packing._decode(func(self, *a, **kw))
×
1428
        wrapperb.__doc__ = 'Same as :meth:`{func.__name__}`, but returns a bytearray'.format(func=func)
1✔
1429
        wrapperb.__name__ = func.__name__ + 'b'
1✔
1430
        wrapperS.__doc__ = 'Same as :meth:`{func.__name__}`, but returns a str, ' \
1✔
1431
                           'decoding the result using `context.encoding`. ' \
1432
                           '(note that the binary versions are way faster)'.format(func=func)
1433
        wrapperS.__name__ = func.__name__ + 'S'
1✔
1434
        return wrapperb, wrapperS
1✔
1435

1436
    for func in [recv,
1✔
1437
                 recvn,
1438
                 recvall,
1439
                 recvrepeat,
1440
                 recvuntil,
1441
                 recvpred,
1442
                 recvregex,
1443
                 recvline,
1444
                 recvline_contains,
1445
                 recvline_startswith,
1446
                 recvline_endswith,
1447
                 recvline_regex]:
1448
        for wrapper in make_wrapper(func):
1✔
1449
            locals()[wrapper.__name__] = wrapper
1✔
1450

1451
    def make_wrapper(func, alias):
1✔
1452
        def wrapper(self, *a, **kw):
1✔
1453
            return func(self, *a, **kw)
1✔
1454
        wrapper.__doc__ = 'Alias for :meth:`{func.__name__}`'.format(func=func)
1✔
1455
        wrapper.__name__ = alias
1✔
1456
        return wrapper
1✔
1457

1458
    for _name in list(locals()):
1✔
1459
        if 'recv' in _name:
1✔
1460
            _name2 = _name.replace('recv', 'read')
1✔
1461
        elif 'send' in _name:
1!
1462
            _name2 = _name.replace('send', 'write')
1✔
1463
        else:
1464
            continue
×
1465
        locals()[_name2] = make_wrapper(locals()[_name], _name2)
1✔
1466

1467
    # Clean up the scope
1468
    del wrapper, func, make_wrapper, _name, _name2
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc