about summary refs log tree commit diff stats
Commit message (Expand)AuthorAgeFilesLines
...
* implemented NET_ACTIVE_WINDOW supportAnselm R.Garbe2006-08-084-1/+20
* fixed typoAnselm R.Garbe2006-08-081-1/+1
* it always takes a while until one sticks to a colorscheme, but this one feels...Anselm R.Garbe2006-08-081-1/+1
* default colors are bestAnselm R.Garbe2006-08-081-3/+3
* without borders it looks cleanerAnselm R.Garbe2006-08-081-2/+2
* red is easier to my eyes with ffffaa bgAnselm R.Garbe2006-08-081-2/+2
* using a better colorscheme (ffffaa is the best background for black)Anselm R.Garbe2006-08-081-2/+2
* applied Sanders tiny patchesAnselm R.Garbe2006-08-084-7/+8
* removed some "arg@10ksloc.org2006-08-071-4/+4
* I really only need 3 tagsarg@10ksloc.org2006-08-071-17/+11
* added a trailing '.' to shortcut descriptions in dwm(1)arg@10ksloc.org2006-08-071-15/+15
* changed signature of drawtextarg@10ksloc.org2006-08-071-12/+10
* applied grabbing-- and shell_minimalarg@10ksloc.org2006-08-072-9/+1
* updated screenshot sectionarg@10ksloc.org2006-08-071-1/+2
* changed font size, I'm not blind...arg@10ksloc.org2006-08-071-2/+2
* small fix of a commentarg@10ksloc.org2006-08-071-1/+1
* typo fixarg@10ksloc.org2006-08-071-1/+1
* applied Sanders man page/Makefile patcharg@10ksloc.org2006-08-072-2/+2
* settle with greyarg@10ksloc.org2006-08-071-2/+2
* next version is 0.8arg@10ksloc.org2006-08-071-1/+1
* made my colors tasting better with the backgroundarg@10ksloc.org2006-08-071-3/+3
* status box should have a border in my eyesarg@10ksloc.org2006-08-072-2/+2
* next attempt for w on black switcharg@10ksloc.org2006-08-071-4/+4
* Added tag 0.7 for changeset 3fb41412e2492f66476d92ce8f007a8b48fb1d2aarg@10ksloc.org2006-08-071-0/+1
* prepared dwm.html 0.7arg@10ksloc.org2006-08-071-3/+6
* added stripping to dwm target in Makefilearg@10ksloc.org2006-08-071-0/+1
* changed getproto, maybe that might fix the killclient issue reported on the listarg@10ksloc.org2006-08-071-2/+3
* applied endless loop prevention on zoom()arg@10ksloc.org2006-08-071-1/+3
* updated man pagearg@10ksloc.org2006-08-071-0/+2
* small fix of the last commitarg@10ksloc.org2006-08-051-1/+1
* using -Os again, zoom is ignored in floating mode or on floating clientsarg@10ksloc.org2006-08-052-2/+2
* mouse grab needs also to grab for combinations of numlock/lockmaskarg@10ksloc.org2006-08-051-0/+20
* slight fixarg@10ksloc.org2006-08-051-3/+2
* small performance tweak ;)arg@10ksloc.org2006-08-041-2/+4
* fixed xterm font change (all other related apps should work fine with this fi...arg@10ksloc.org2006-08-041-14/+12
* fixed view-change bug reported on the listarg@10ksloc.org2006-08-041-14/+10
* no need for -g anymore, regexp matching works nowarg@10ksloc.org2006-08-041-4/+4
* fixed dmenu link (thx to deifl)arg@10ksloc.org2006-08-041-1/+1
* switched to regexp matching for Rulesarg@10ksloc.org2006-08-046-31/+65
* fixed a bug in dmenu callarg@10ksloc.org2006-08-042-6/+3
* using execl now, argv changed, using cmd and const char defs directly in the ...arg@10ksloc.org2006-08-044-18/+18
* added dmenu to dwm.htmlarg@10ksloc.org2006-08-041-0/+4
* small stylistic fixarg@10ksloc.org2006-08-041-1/+2
* removed CONFIGarg@10ksloc.org2006-08-031-3/+2
* make config.h not a time dependencearg@10ksloc.org2006-08-031-1/+1
* removed rm config.h from cleanarg@10ksloc.org2006-08-031-1/+1
* added gmake compliancearg@10ksloc.org2006-08-031-2/+2
* s/tag2/two/garg@10ksloc.org2006-08-032 ## var server = newAsyncSocket() ## server.bindAddr(TPort(12345)) ## server.listen() ## ## while true: ## let client = await server.accept() ## clients.add client ## ## processClient(client) ## ## serve() ## runForever() ## ## ## **Note:** This module is still largely experimental. import asyncdispatch import rawsockets import net when defined(ssl): import openssl type # TODO: I would prefer to just do: # PAsyncSocket* {.borrow: `.`.} = distinct PSocket. But that doesn't work. TAsyncSocket {.borrow: `.`.} = distinct TSocketImpl PAsyncSocket* = ref TAsyncSocket # TODO: Save AF, domain etc info and reuse it in procs which need it like connect. proc newSocket(fd: TAsyncFD, isBuff: bool): PAsyncSocket = assert fd != osInvalidSocket.TAsyncFD new(result.PSocket) result.fd = fd.TSocketHandle result.isBuffered = isBuff if isBuff: result.currPos = 0 proc newAsyncSocket*(domain: TDomain = AF_INET, typ: TType = SOCK_STREAM, protocol: TProtocol = IPPROTO_TCP, buffered = true): PAsyncSocket = ## Creates a new asynchronous socket. result = newSocket(newAsyncRawSocket(domain, typ, protocol), buffered) proc connect*(socket: PAsyncSocket, address: string, port: TPort, af = AF_INET): PFuture[void] = ## Connects ``socket`` to server at ``address:port``. ## ## Returns a ``PFuture`` which will complete when the connection succeeds ## or an error occurs. result = connect(socket.fd.TAsyncFD, address, port, af) proc readIntoBuf(socket: PAsyncSocket, flags: set[TSocketFlags]): PFuture[int] {.async.} = var data = await recv(socket.fd.TAsyncFD, BufferSize, flags) if data.len != 0: copyMem(addr socket.buffer[0], addr data[0], data.len) socket.bufLen = data.len socket.currPos = 0 result = data.len proc recv*(socket: PAsyncSocket, size: int, flags = {TSocketFlags.SafeDisconn}): PFuture[string] {.async.} = ## Reads ``size`` bytes from ``socket``. Returned future will complete once ## all of the requested data is read. If socket is disconnected during the ## recv operation then the future may complete with only a part of the ## requested data read. If socket is disconnected and no data is available ## to be read then the future will complete with a value of ``""``. if socket.isBuffered: result = newString(size) let originalBufPos = socket.currPos if socket.bufLen == 0: let res = await socket.readIntoBuf(flags - {TSocketFlags.Peek}) if res == 0: result.setLen(0) return var read = 0 while read < size: if socket.currPos >= socket.bufLen: if TSocketFlags.Peek in flags: # We don't want to get another buffer if we're peeking. break let res = await socket.readIntoBuf(flags - {TSocketFlags.Peek}) if res == 0: break let chunk = min(socket.bufLen-socket.currPos, size-read) copyMem(addr(result[read]), addr(socket.buffer[socket.currPos]), chunk) read.inc(chunk) socket.currPos.inc(chunk) if TSocketFlags.Peek in flags: # Restore old buffer cursor position. socket.currPos = originalBufPos result.setLen(read) else: result = await recv(socket.fd.TAsyncFD, size, flags) proc send*(socket: PAsyncSocket, data: string, flags = {TSocketFlags.SafeDisconn}): PFuture[void] = ## Sends ``data`` to ``socket``. The returned future will complete once all ## data has been sent. assert socket != nil result = send(socket.fd.TAsyncFD, data, flags) proc acceptAddr*(socket: PAsyncSocket): PFuture[tuple[address: string, client: PAsyncSocket]] = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection and the remote address of the client. ## The future will complete when the connection is successfully accepted. var retFuture = newFuture[tuple[address: string, client: PAsyncSocket]]() var fut = acceptAddr(socket.fd.TAsyncFD) fut.callback = proc (future: PFuture[tuple[address: string, client: TAsyncFD]]) = assert future.finished if future.failed: retFuture.fail(future.readError) else: let resultTup = (future.read.address, newSocket(future.read.client, socket.isBuffered)) retFuture.complete(resultTup) return retFuture proc accept*(socket: PAsyncSocket): PFuture[PAsyncSocket] = ## Accepts a new connection. Returns a future containing the client socket ## corresponding to that connection. ## The future will complete when the connection is successfully accepted. var retFut = newFuture[PAsyncSocket]() var fut = acceptAddr(socket) fut.callback = proc (future: PFuture[tuple[address: string, client: PAsyncSocket]]) = assert future.finished if future.failed: retFut.fail(future.readError) else: retFut.complete(future.read.client) return retFut proc recvLine*(socket: PAsyncSocket, flags = {TSocketFlags.SafeDisconn}): PFuture[string] {.async.} = ## Reads a line of data from ``socket``. Returned future will complete once ## a full line is read or an error occurs. ## ## If a full line is read ``\r\L`` is not ## added to ``line``, however if solely ``\r\L`` is read then ``line`` ## will be set to it. ## ## If the socket is disconnected, ``line`` will be set to ``""``. ## ## If the socket is disconnected in the middle of a line (before ``\r\L`` ## is read) then line will be set to ``""``. ## The partial line **will be lost**. ## ## **Warning**: The ``Peek`` flag is not yet implemented. template addNLIfEmpty(): stmt = if result.len == 0: result.add("\c\L") assert TSocketFlags.Peek notin flags ## TODO: if socket.isBuffered: result = "" if socket.bufLen == 0: let res = await socket.readIntoBuf(flags) if res == 0: return var lastR = false while true: if socket.currPos >= socket.bufLen: let res = await socket.readIntoBuf(flags) if res == 0: result = "" break case socket.buffer[socket.currPos] of '\r': lastR = true addNLIfEmpty() of '\L': addNLIfEmpty() socket.currPos.inc() return else: if lastR: socket.currPos.inc() return else: result.add socket.buffer[socket.currPos] socket.currPos.inc() else: result = "" var c = "" while true: c = await recv(socket, 1, flags) if c.len == 0: return "" if c == "\r": c = await recv(socket, 1, flags + {TSocketFlags.Peek}) if c.len > 0 and c == "\L": let dummy = await recv(socket, 1, flags) assert dummy == "\L" addNLIfEmpty() return elif c == "\L": addNLIfEmpty() return add(result.string, c) proc bindAddr*(socket: PAsyncSocket, port = TPort(0), address = "") = ## Binds ``address``:``port`` to the socket. ## ## If ``address`` is "" then ADDR_ANY will be bound. socket.PSocket.bindAddr(port, address) proc listen*(socket: PAsyncSocket, backlog = SOMAXCONN) = ## Marks ``socket`` as accepting connections. ## ``Backlog`` specifies the maximum length of the ## queue of pending connections. ## ## Raises an EOS error upon failure. socket.PSocket.listen(backlog) proc close*(socket: PAsyncSocket) = ## Closes the socket. socket.fd.TAsyncFD.closeSocket() # TODO SSL when isMainModule: type TestCases = enum HighClient, LowClient, LowServer const test = HighClient when test == HighClient: proc main() {.async.} = var sock = newAsyncSocket() await sock.connect("irc.freenode.net", TPort(6667)) while true: let line = await sock.recvLine() if line == "": echo("Disconnected") break else: echo("Got line: ", line) asyncCheck main() elif test == LowClient: var sock = newAsyncSocket() var f = connect(sock, "irc.freenode.net", TPort(6667)) f.callback = proc (future: PFuture[void]) = echo("Connected in future!") for i in 0 .. 50: var recvF = recv(sock, 10) recvF.callback = proc (future: PFuture[string]) = echo("Read ", future.read.len, ": ", future.read.repr) elif test == LowServer: var sock = newAsyncSocket() sock.bindAddr(TPort(6667)) sock.listen() proc onAccept(future: PFuture[PAsyncSocket]) = let client = future.read echo "Accepted ", client.fd.cint var t = send(client, "test\c\L") t.callback = proc (future: PFuture[void]) = echo("Send") client.close() var f = accept(sock) f.callback = onAccept var f = accept(sock) f.callback = onAccept runForever()