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
|
#!/usr/bin/python3
# Copyright 2020 Corey Minyard
#
# SPDX-License-Identifier: Apache-2.0
#
# A basic server that receives connections and handles certain strings
# when it sees them.
#
# This is the same as basic_server.c, written in python.
#
# To use this, run:
# basic_server telnet,tcp,3023
# then telnet to it.
#
# If you type in "hello" is reponds with "bonjour".
#
# If you type in "goodbye" it responds with "au revior" and closes
# the connection.
#
# If you type in "shutdown" it reponds with "adieu pour toujours" and
# shuts down the server.
import gensio
import sys
class Logger:
def gensio_log(self, level, log):
print("***%s log: %s" % (level, log))
gensio.gensio_set_log_mask(gensio.GENSIO_LOG_MASK_ALL);
o = gensio.alloc_gensio_selector(Logger())
class IOEvent:
def __init__(self, io, accev):
self.io = io
self.accev = accev
self.inbuf = ""
self.outbuf = "Ready\r\n"
self.in_close = False
io.set_cbs(self)
return
def handle_buf(self, buf):
if buf == "hello":
self.outbuf = self.outbuf + "bonjour\r\n"
elif buf == "goodbye":
self.outbuf = self.outbuf + "au revior\r\n"
self.in_close = True
elif buf == "shutdown":
self.outbuf = self.outbuf + "adieu pour toujours\r\n"
self.accev.shutdown(self)
self.in_close = True
else:
self.outbuf = self.outbuf + "Eh?\r\n"
def read_callback(self, io, err, data, auxdata):
if err:
if err != "Remote end closed connection":
print("read error: %s" % err)
io.close(self)
return 0
self.inbuf = self.inbuf + str(data, 'utf-8')
self.outbuf = self.outbuf + str(data, 'utf-8')
self.io.write_cb_enable(True)
npos = self.inbuf.find("\n")
if npos == -1:
npos = self.inbuf.find("\r")
if npos == -1:
return len(data)
self.outbuf = self.outbuf + "\n"
else:
self.outbuf = self.outbuf + "\r"
buf = self.inbuf[:npos]
self.inbuf = self.inbuf[npos + 1:]
self.handle_buf(buf)
return len(data)
def write_callback(self, io):
if len(self.outbuf) > 0:
try:
count = self.io.write(self.outbuf, None)
except Exception as E:
if str(e) != "Remote end closed connection":
print("write error: %s" % str(e))
self.io.close(self)
return
self.outbuf = self.outbuf[count:]
if len(self.outbuf) == 0:
self.io.write_cb_enable(False)
if self.in_close:
self.io.close(self)
return
def close_done(self, io):
self.accev.io_closed(self)
# Break loops
self.accev = None
self.io = None
return
class AccEvent:
def __init__(self):
self.ios = []
self.waiter = gensio.waiter(o)
self.in_shutdown = False
return
def log(self, acc, level, logval):
print("gensio acc %s err: %s" % (level, logval))
return
def new_connection(self, acc, io):
if self.in_shutdown:
# it will free automatically
return
ioev = IOEvent(io, self)
self.ios.append(ioev)
io.read_cb_enable(True)
io.write_cb_enable(True)
return
def check_finish(self):
if len(self.ios) == 0 and self.acc is None:
self.waiter.wake()
return
def io_closed(self, ioev):
i = self.ios.index(ioev)
del(self.ios[i])
self.check_finish()
return
def shutdown_done(self, acc):
self.acc = None
self.check_finish()
return
def shutdown(self, ioev):
if self.in_shutdown:
return
self.in_shutdown = True
self.acc.shutdown(self)
for i in self.ios:
if i != ioev:
# The caller will close itself, let it finish its write
i.io.close(i)
def wait(self):
self.waiter.wait(1)
if len(sys.argv) < 2:
print("No gensio supplied on commandline")
sys.exit(1)
accev = AccEvent()
accev.acc = gensio.gensio_accepter(o, sys.argv[1], accev)
accev.acc.startup()
accev.wait()
|