modpython socket creation does not persist #993

Closed
opened 2026-10-05 04:57:30 +02:00 by adam · 5 comments
Owner

I am attempting to open a telnet socket using the example socket code from https://wiki.znc.in/Modpython - the socket creates and connects ok, but immediately disconnects and shuts down without ever triggering OnReadLine(). OnReadData triggers, despite EnableReadLine() having been used prior. If I put Write() statements immediately after Connect() the data is transmitted (and received) but the connection then closes. OnSockError() sees nothing (assuming this is exposed in modpython).

How do I get the socket to persist?

I am attempting to open a telnet socket using the example socket code from https://wiki.znc.in/Modpython - the socket creates and connects ok, but immediately disconnects and shuts down without ever triggering OnReadLine(). OnReadData triggers, despite EnableReadLine() having been used prior. If I put Write() statements immediately after Connect() the data is transmitted (and received) but the connection then closes. OnSockError() sees nothing (assuming this is exposed in modpython). How do I get the socket to persist? <!-- github-sync-id:954501290 -->
adam closed this issue 2026-10-05 04:57:30 +02:00
Author
Owner

Sorry, should have included the code. The host in question is an eggdrop bot, FYI.

# telnettest.py
import znc
    
class telnettest(znc.Module):
    description = "Telnet Test Module"
    
    def OnRaw(self, rawline):
        self.PutStatus(rawline.s)
        return znc.CONTINUE
    
    def OnModCommand(self, cmd):
        #any command to start the test
        self.sock = self.CreateSocket(telconn, "localhost", 30200)
        return znc.CONTINUE
        

class telconn(znc.Socket):
    def Init(self, host, port):
        self.Connect(host,port,timeout=60)
        self.EnableReadLine()
        return znc.CONTINUE
        
    def OnReadLine(self, line):
        self.GetModule().PutStatus("OnReadLine: {0}".format(line))
        return znc.CONTINUE
    
    def OnConnected(self):
        self.GetModule().PutStatus("connected")
        self.GetModule().PutStatus(self.GetRemoteIP())
        return znc.CONTINUE
    
    def OnReadData(self, data):
        #self.GetModule().PutStatus("OnReadData: {0}".format(data))
        self.GetModule().PutStatus("OnReadData: {0}".format("".join(map(chr, data))))
        return znc.CONTINUE
    
    def OnDisconnected(self):
        self.GetModule().PutStatus("disconnected")
        return znc.CONTINUE

Output to *status is:

<*status> connected
<*status> 127.0.0.1
<*status> OnReadData: ÿû
<*status> Botname  (Eggdrop v1.8.4 (C) 1997 Robey Pointer (C) 2010-2018 Eggheads)
<*status> Please enter your nickname.
<*status> disconnected
Sorry, should have included the code. The host in question is an eggdrop bot, FYI. ``` # telnettest.py import znc class telnettest(znc.Module): description = "Telnet Test Module" def OnRaw(self, rawline): self.PutStatus(rawline.s) return znc.CONTINUE def OnModCommand(self, cmd): #any command to start the test self.sock = self.CreateSocket(telconn, "localhost", 30200) return znc.CONTINUE class telconn(znc.Socket): def Init(self, host, port): self.Connect(host,port,timeout=60) self.EnableReadLine() return znc.CONTINUE def OnReadLine(self, line): self.GetModule().PutStatus("OnReadLine: {0}".format(line)) return znc.CONTINUE def OnConnected(self): self.GetModule().PutStatus("connected") self.GetModule().PutStatus(self.GetRemoteIP()) return znc.CONTINUE def OnReadData(self, data): #self.GetModule().PutStatus("OnReadData: {0}".format(data)) self.GetModule().PutStatus("OnReadData: {0}".format("".join(map(chr, data)))) return znc.CONTINUE def OnDisconnected(self): self.GetModule().PutStatus("disconnected") return znc.CONTINUE ``` Output to *status is: ``` <*status> connected <*status> 127.0.0.1 <*status> OnReadData: ÿû <*status> Botname  (Eggdrop v1.8.4 (C) 1997 Robey Pointer (C) 2010-2018 Eggheads) <*status> Please enter your nickname. <*status> disconnected ``` <!-- github-comment-id:888171491 -->
Author
Owner

Can you check znc -D?

ÿû� looks concerning. Does the module stay loaded after the disconnect?

My suspicion is that it can't parse the line as UTF-8 (the default encoding), and reports the error via closing it.

OnReadData triggers, despite EnableReadLine() having been used prior

Correct. OnReadData triggers for all data. OnReadLine is triggered for lines only, after parsing them from raw bytes with the specified encoding.

Can you check `znc -D`? `ÿû�` looks concerning. Does the module stay loaded after the disconnect? My suspicion is that it can't parse the line as UTF-8 (the default encoding), and reports the error via closing it. > OnReadData triggers, despite EnableReadLine() having been used prior Correct. OnReadData triggers for all data. OnReadLine is triggered for lines only, after parsing them from raw bytes with the specified encoding. <!-- github-comment-id:888178434 -->
Author
Owner

Can you check znc -D?

I think you're onto something - znc -D shows:

[2021-07-28 22:06:31.886761] python socket failed in OnReadLine: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte\x0A

ÿû� looks concerning. Does the module stay loaded after the disconnect?

Yes, the module stays loaded.

Correct. OnReadData triggers for all data. OnReadLine is triggered for lines only, after parsing them from raw bytes with the specified encoding.

So possibly I'm never getting to that point as it's erroring and closing the socket when the decode fails.

> Can you check `znc -D`? I think you're onto something - znc -D shows: ``` [2021-07-28 22:06:31.886761] python socket failed in OnReadLine: UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte\x0A ``` > `ÿû�` looks concerning. Does the module stay loaded after the disconnect? Yes, the module stays loaded. > Correct. OnReadData triggers for all data. OnReadLine is triggered for lines only, after parsing them from raw bytes with the specified encoding. So possibly I'm never getting to that point as it's erroring and closing the socket when the decode fails. <!-- github-comment-id:888186305 -->
Author
Owner

Either don't use EnableReadLine(), so that it doesn't try to decode the bytes at all, or specify the encoding via SetEncoding(), which supports some fallback options between UTF-8 and something else (which I should document somewhere...)

Either don't use `EnableReadLine()`, so that it doesn't try to decode the bytes at all, or specify the encoding via `SetEncoding()`, which supports some fallback options between UTF-8 and something else (which I should document somewhere...) <!-- github-comment-id:888188576 -->
Author
Owner

Either don't use EnableReadLine(), so that it doesn't try to decode the bytes at all, or specify the encoding via SetEncoding(), which supports some fallback options between UTF-8 and something else (which I should document somewhere...)

Awesome, thanks. Using SetEncoding('utf8') gets me past that point - will soldier on - thanks a lot!

> Either don't use `EnableReadLine()`, so that it doesn't try to decode the bytes at all, or specify the encoding via `SetEncoding()`, which supports some fallback options between UTF-8 and something else (which I should document somewhere...) Awesome, thanks. Using `SetEncoding('utf8')` gets me past that point - will soldier on - thanks a lot! <!-- github-comment-id:888204225 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/znc#993