diff options
author | bptato <nincsnevem662@gmail.com> | 2025-01-09 20:46:50 +0100 |
---|---|---|
committer | bptato <nincsnevem662@gmail.com> | 2025-01-09 20:48:20 +0100 |
commit | 8c769fc302a04737f1060fdcc0fab16a733d94c9 (patch) | |
tree | 174bd70c150b298a65ce7cecb48406caf4adf155 /src/local | |
parent | 73f8c04970cbd0bc5a5923272ef21bf39d5c9293 (diff) | |
download | chawan-8c769fc302a04737f1060fdcc0fab16a733d94c9.tar.gz |
buffer: remove server socket
Now we just pass through a socket created in pager. This removes the need for a socket directory, and strengthens the buffer sandbox slightly. I've kept the ServerSocket code, because I want to add some form of RPC and communication between separate instances in the future. However, I don't expect this to be handled outside the main process, so I've removed the Capsicum-specific connectat/bindat code.
Diffstat (limited to 'src/local')
-rw-r--r-- | src/local/client.nim | 4 | ||||
-rw-r--r-- | src/local/container.nim | 38 | ||||
-rw-r--r-- | src/local/pager.nim | 167 |
3 files changed, 81 insertions, 128 deletions
diff --git a/src/local/client.nim b/src/local/client.nim index 7f30e587..87d15cc6 100644 --- a/src/local/client.nim +++ b/src/local/client.nim @@ -163,9 +163,7 @@ proc newClient*(config: Config; forkserver: ForkServer; loaderPid: int; loaderStream: SocketStream): Client = let jsrt = JS_GetRuntime(jsctx) let clientPid = getCurrentProcessId() - let sockDirFd = openSockDir(config.external.sockdir) - let loader = newFileLoader(loaderPid, clientPid, config.external.sockdir, - sockDirFd, loaderStream) + let loader = newFileLoader(loaderPid, clientPid, loaderStream) let client = Client( jsrt: jsrt, jsctx: jsctx, diff --git a/src/local/container.nim b/src/local/container.nim index dba32473..abd9bbf0 100644 --- a/src/local/container.nim +++ b/src/local/container.nim @@ -227,11 +227,8 @@ proc newContainer*(config: BufferConfig; loaderConfig: LoaderClientConfig; lastPeek: HoverType.high ) -proc c_rename(oldname, newname: cstring): cint {.importc: "rename", - header: "<stdio.h>".} - proc clone*(container: Container; newurl: URL; loader: FileLoader): - Promise[Container] = + Promise[tuple[c: Container; fd: cint]] = if container.iface == nil: return nil let url = if newurl != nil: @@ -239,20 +236,15 @@ proc clone*(container: Container; newurl: URL; loader: FileLoader): else: container.url let p = container.iface.clone(url) - # create a server socket, pass it on to the buffer, then move it to - # the expected path after the buffer forked itself - #TODO this is very ugly - let ssock = newServerSocket(loader.sockDir, loader.sockDirFd, - loader.clientPid) - SocketStream(container.iface.stream.source).sendFd(ssock.fd) - ssock.close() - return p.then(proc(pid: int): Container = + var sv {.noinit.}: array[2, cint] + if socketpair(AF_UNIX, SOCK_STREAM, IPPROTO_IP, sv) != 0: + return nil + SocketStream(container.iface.stream.source).sendFd(sv[1]) + discard close(sv[1]) + return p.then(proc(pid: int): tuple[c: Container; fd: cint] = if pid == -1: - return nil - let newPath = getSocketPath(loader.sockDir, pid) - let oldPath = getSocketPath(loader.sockDir, loader.clientPid) - if c_rename(cstring(oldPath), cstring(newPath)) == -1: - return nil + discard close(sv[0]) + return (nil, -1) let nc = Container() nc[] = container[] nc.url = url @@ -263,7 +255,7 @@ proc clone*(container: Container; newurl: URL; loader: FileLoader): nc.parent = nil nc.children = @[] nc.cachedImages = @[] - return nc + return (nc, sv[0]) ) func lineLoaded(container: Container; y: int): bool = @@ -1713,16 +1705,14 @@ proc startLoad(container: Container) = container.triggerEvent(cetTitle) ) -proc setStream*(container: Container; stream: SocketStream; - registerFun: proc(fd: int)) = +proc setStream*(container: Container; stream: BufStream) = assert cfCloned notin container.flags - container.iface = newBufferInterface(stream, registerFun) + container.iface = newBufferInterface(stream) container.startLoad() -proc setCloneStream*(container: Container; stream: SocketStream; - registerFun: proc(fd: int)) = +proc setCloneStream*(container: Container; stream: BufStream) = assert cfCloned in container.flags - container.iface = cloneInterface(stream, registerFun) + container.iface = cloneInterface(stream) # Maybe we have to resume loading. Let's try. container.startLoad() diff --git a/src/local/pager.nim b/src/local/pager.nim index 792f7fa4..5dc6bad9 100644 --- a/src/local/pager.nim +++ b/src/local/pager.nim @@ -76,13 +76,6 @@ type lmAlert = "Alert: " lmMailcap = "Mailcap: " - ProcMapItem = object - container*: Container - ostream*: PosixStream - istreamOutputId*: int - ostreamOutputId*: int - redirected*: bool - PagerAlertState = enum pasNormal, pasAlertOn, pasLoadInfo @@ -170,7 +163,6 @@ type pollData*: PollData precnum*: int32 # current number prefix (when vi-numeric-prefix is true) pressed: tuple[col, row: int] - procmap*: seq[ProcMapItem] refreshAllowed: HashSet[string] regex: Opt[Regex] reverseSearch: bool @@ -205,6 +197,9 @@ proc askMailcap(pager: Pager; container: Container; ostream: PosixStream; contentType: string; i: int; response: Response; sx: int) proc connected2(pager: Pager; container: Container; res: MailcapResult; response: Response) +proc connected3(pager: Pager; container: Container; stream: SocketStream; + ostream: PosixStream; istreamOutputId, ostreamOutputId: int; + redirected: bool) proc draw(pager: Pager) proc dumpBuffers(pager: Pager) proc evalJS(pager: Pager; src, filename: string; module = false): JSValue @@ -1361,27 +1356,17 @@ func findConnectingContainer(pager: Pager; container: Container): return item return nil -func findProcMapItem(pager: Pager; pid: int): int = - for i, item in pager.procmap.mypairs: - if item.container.process == pid: - return i - -1 - proc dupeBuffer(pager: Pager; container: Container; url: URL) = let p = container.clone(url, pager.loader) if p == nil: pager.alert("Failed to duplicate buffer.") else: - p.then(proc(container: Container): Container = - if container == nil: + p.then(proc(res: tuple[c: Container; fd: cint]): Container = + if res.c == nil: pager.alert("Failed to duplicate buffer.") else: - pager.addContainer(container) - pager.procmap.add(ProcMapItem( - container: container, - istreamOutputId: -1, - ostreamOutputId: -1 - )) + pager.addContainer(res.c) + pager.connected3(res.c, newSocketStream(res.fd), nil, -1, -1, false) ) proc dupeBuffer(pager: Pager) {.jsfunc.} = @@ -2444,7 +2429,7 @@ proc runMailcapReadFile(pager: Pager; stream: PosixStream; quit(1) stream.sclose() let ret = execCmd(cmd) - discard tryRemoveFile(outpath) + discard unlink(cstring(outpath)) quit(ret) else: # parent pouts.sclose() @@ -2461,7 +2446,7 @@ proc runMailcapWriteFile(pager: Pager; stream: PosixStream; pager.alert("Error: failed to write file for mailcap process") else: discard execCmd(cmd) - discard tryRemoveFile(outpath) + discard unlink(cstring(outpath)) pager.term.restart() else: # don't block @@ -2475,7 +2460,7 @@ proc runMailcapWriteFile(pager: Pager; stream: PosixStream; quit(1) stream.sclose() let ret = execCmd(cmd) - discard tryRemoveFile(outpath) + discard unlink(cstring(outpath)) quit(ret) # parent stream.sclose() @@ -2658,28 +2643,75 @@ proc connected2(pager: Pager; container: Container; res: MailcapResult; url = newURL(url) url.username = "" url.password = "" - container.process = pager.forkserver.forkBuffer( + let (pid, fd) = pager.forkserver.forkBuffer( container.config, url, attrs, cmfHTML in res.flags, container.charsetStack ) - pager.procmap.add(ProcMapItem( - container: container, - ostream: res.ostream, - redirected: cmfRedirected in res.flags, - ostreamOutputId: res.ostreamOutputId, - istreamOutputId: response.outputId - )) + container.process = pid if container.replace != nil: pager.deleteContainer(container.replace, container.find(ndAny)) container.replace = nil + pager.connected3(container, newSocketStream(fd), res.ostream, + response.outputId, res.ostreamOutputId, cmfRedirected in res.flags) else: dec pager.numload pager.deleteContainer(container, container.find(ndAny)) pager.refreshStatusMsg() +proc connected3(pager: Pager; container: Container; stream: SocketStream; + ostream: PosixStream; istreamOutputId, ostreamOutputId: int; + redirected: bool) = + let loader = pager.loader + let cstream = loader.addClient(container.process, container.loaderConfig, + container.clonedFrom) + let bufStream = newBufStream(stream, proc(fd: int) = + pager.pollData.unregister(fd) + pager.pollData.register(fd, POLLIN or POLLOUT)) + if istreamOutputId != -1: # new buffer + if container.cacheId == -1: + container.cacheId = loader.addCacheFile(istreamOutputId, loader.clientPid) + if container.request.url.scheme == "cache": + # loading from cache; now both the buffer and us hold a new reference + # to the cached item, but it's only shared with the buffer. add a + # pager ref too. + loader.shareCachedItem(container.cacheId, loader.clientPid) + let pid = container.process + var outCacheId = container.cacheId + if not redirected: + loader.shareCachedItem(container.cacheId, pid) + loader.resume(istreamOutputId) + else: + outCacheId = loader.addCacheFile(ostreamOutputId, pid) + loader.resume([istreamOutputId, ostreamOutputId]) + stream.withPacketWriter w: + w.swrite(outCacheId) + w.sendAux.add(cstream.fd) + # pass down ostream + # must come after the previous block so the first packet is flushed + stream.sendFd(ostream.fd) + ostream.sclose() + container.setStream(bufStream) + else: # cloned buffer + stream.withPacketWriter w: + w.sendAux.add(cstream.fd) + # buffer is cloned, just share the parent's cached source + loader.shareCachedItem(container.cacheId, container.process) + # also add a reference here; it will be removed when the container is + # deleted + loader.shareCachedItem(container.cacheId, loader.clientPid) + container.setCloneStream(bufStream) + cstream.sclose() + loader.put(ContainerData(stream: stream, container: container)) + pager.pollData.register(stream.fd, POLLIN) + # clear replacement references, because we can't fail to load this + # buffer anymore + container.replaceRef = nil + container.replace = nil + container.replaceBackup = nil + proc saveEntry(pager: Pager; entry: MailcapEntry) = if not pager.config.external.auto_mailcap.saveEntry(entry): pager.alert("Could not write to " & pager.config.external.auto_mailcap.path) @@ -3065,79 +3097,12 @@ proc acceptBuffers(pager: Pager) = pager.pollData.unregister(fd) pager.loader.unset(fd) stream.sclose() - elif container.process != -1: # connecting to buffer process - let i = pager.findProcMapItem(container.process) - if i != -1: - pager.procmap.del(i) elif (let item = pager.findConnectingContainer(container); item != nil): # connecting to URL let stream = item.stream pager.pollData.unregister(int(stream.fd)) stream.sclose() pager.loader.unset(item) - let registerFun = proc(fd: int) = - pager.pollData.unregister(fd) - pager.pollData.register(fd, POLLIN or POLLOUT) - for item in pager.procmap: - let container = item.container - # unlink here; on Linux we can't unlink from the buffer :/ - #TODO replace this with a socketpair - # (also, it seems better to just do this from connect2...) - let stream = connectSocketStream(pager.config.external.sockdir, - pager.loader.sockDirFd, container.process) - discard tryRemoveFile(getSocketPath(pager.config.external.sockdir, - container.process)) - if stream == nil: - pager.alert("Error: failed to set up buffer") - continue - let loader = pager.loader - let cstream = pager.loader.addClient(container.process, - container.loaderConfig, container.clonedFrom) - if item.istreamOutputId != -1: # new buffer - if container.cacheId == -1: - container.cacheId = loader.addCacheFile(item.istreamOutputId, - loader.clientPid) - if container.request.url.scheme == "cache": - # loading from cache; now both the buffer and us hold a new reference - # to the cached item, but it's only shared with the buffer. add a - # pager ref too. - loader.shareCachedItem(container.cacheId, loader.clientPid) - let pid = container.process - var outCacheId = container.cacheId - if not item.redirected: - loader.shareCachedItem(container.cacheId, pid) - loader.resume(item.istreamOutputId) - else: - outCacheId = loader.addCacheFile(item.ostreamOutputId, pid) - loader.resume([item.istreamOutputId, item.ostreamOutputId]) - stream.withPacketWriter w: - w.swrite(outCacheId) - w.sendAux.add(cstream.fd) - # pass down ostream - # must come after the previous block so the first packet is flushed - stream.sendFd(item.ostream.fd) - item.ostream.sclose() - container.setStream(stream, registerFun) - else: # cloned buffer - stream.withPacketWriter w: - w.sendAux.add(cstream.fd) - # buffer is cloned, just share the parent's cached source - loader.shareCachedItem(container.cacheId, container.process) - # also add a reference here; it will be removed when the container is - # deleted - loader.shareCachedItem(container.cacheId, loader.clientPid) - container.setCloneStream(stream, registerFun) - cstream.sclose() - let fd = int(stream.fd) - pager.loader.put(ContainerData(stream: stream, container: container)) - pager.pollData.register(fd, POLLIN) - # clear replacement references, because we can't fail to load this - # buffer anymore - container.replaceRef = nil - container.replace = nil - container.replaceBackup = nil - pager.handleEvents(container) - pager.procmap.setLen(0) proc handleStderr(pager: Pager) = const BufferSize = 4096 @@ -3301,7 +3266,7 @@ proc inputLoop(pager: Pager) = func hasSelectFds(pager: Pager): bool = return not pager.timeouts.empty or pager.numload > 0 or - pager.loader.mapFds > 0 or pager.procmap.len > 0 + pager.loader.mapFds > 0 proc headlessLoop(pager: Pager) = while pager.hasSelectFds(): |