parsav  Check-in [f8816b0ab5]

Overview
Comment:enable remote control of running instances
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: f8816b0ab5148803709d93515359d37691d7dbdd695b0c6b0b8ac8cea5a62dbf
User & Date: lexi on 2020-12-29 15:48:34
Other Links: manifest | tags
Context
2020-12-30
00:43
continued iteration check-in: 0324d62546 user: lexi tags: trunk
2020-12-29
15:48
enable remote control of running instances check-in: f8816b0ab5 user: lexi tags: trunk
14:35
check in missing file check-in: 5a4f99fb55 user: lexi tags: trunk
Changes

Modified ipc.t from [5ea8386d8f] to [ff639e2a51].

195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
246
247
248
249
250
251
252

253
254
255
256
257
258
259
...
264
265
266
267
268
269
270

271
272
273
274
275
276
277

	cmd.cmd = m.cmd.none
end

terra m.emperor:mallack() return lib.mem.heapa(m.ack, self:countpeers()) end
terra m.emperor.methods.decree :: {
	&m.emperor, uint64, rawstring, m.cmd.t, uint64, &m.ack
} -> {}
terra m.emperor:decree(
	tgtclid: uint64, tgtname: rawstring,
	cmd: m.cmd.t, operand: uint64,
	result: &m.ack
): {}
	if self.client then lib.bail('client attempted to issue IPC decree') end
	var dem = m.demand {
		cmd = cmd;
		operand = operand;
		empq = self.msqid; -- register to receive replies
	}
	var npeers = self:countpeers()
	if npeers == 0 then lib.bail('no processes connected to control bus') end
	if tgtclid == 0 and tgtname == nil then
		lib.dbg('sending to all instances, waiting for edict to become writable')
		self.edict:sem(0) -- wait for all locks on edict to resolve
		lib.dbg('locking edict')
		self.edict:sem(npeers) -- place a read lock for each peer
		self.edict.demand = dem
		lib.dbg('sending edict')
................................................................................
				found = true
				tgt = acks(i).cliq
			end
		end
		acks:free()
		if not found then
			lib.warn('no such instance is currently online and responding to IPC calls')

		else
			lib.dbg('located instance, sending command')
			if mq.msgsnd(tgt, &dem, sizeof(m.demand), 0) == -1 then
				lib.bail('could not send command to target process')
			end
			while true do
				var ack: m.ack
................................................................................
					lib.dbg('got response, writing out and returning')
					@result = ack
					break
				else lib.warn('got spurious response, ignoring') end
			end
		end
	end

end

terra m.demand:ack(emp: &m.emperor, a: &m.ack)
	a.clid = emp.clid
	a.cliq = emp.msqid
	mq.msgsnd(self.empq, a, sizeof(m.ack), 0)
end







|




|







|







 







>







 







>







195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
...
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
...
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279

	cmd.cmd = m.cmd.none
end

terra m.emperor:mallack() return lib.mem.heapa(m.ack, self:countpeers()) end
terra m.emperor.methods.decree :: {
	&m.emperor, uint64, rawstring, m.cmd.t, uint64, &m.ack
} -> bool
terra m.emperor:decree(
	tgtclid: uint64, tgtname: rawstring,
	cmd: m.cmd.t, operand: uint64,
	result: &m.ack
): bool
	if self.client then lib.bail('client attempted to issue IPC decree') end
	var dem = m.demand {
		cmd = cmd;
		operand = operand;
		empq = self.msqid; -- register to receive replies
	}
	var npeers = self:countpeers()
	if npeers == 0 then lib.warn('no processes connected to control bus') return false end
	if tgtclid == 0 and tgtname == nil then
		lib.dbg('sending to all instances, waiting for edict to become writable')
		self.edict:sem(0) -- wait for all locks on edict to resolve
		lib.dbg('locking edict')
		self.edict:sem(npeers) -- place a read lock for each peer
		self.edict.demand = dem
		lib.dbg('sending edict')
................................................................................
				found = true
				tgt = acks(i).cliq
			end
		end
		acks:free()
		if not found then
			lib.warn('no such instance is currently online and responding to IPC calls')
			return false
		else
			lib.dbg('located instance, sending command')
			if mq.msgsnd(tgt, &dem, sizeof(m.demand), 0) == -1 then
				lib.bail('could not send command to target process')
			end
			while true do
				var ack: m.ack
................................................................................
					lib.dbg('got response, writing out and returning')
					@result = ack
					break
				else lib.warn('got spurious response, ignoring') end
			end
		end
	end
	return true
end

terra m.demand:ack(emp: &m.emperor, a: &m.ack)
	a.clid = emp.clid
	a.cliq = emp.msqid
	mq.msgsnd(self.empq, a, sizeof(m.ack), 0)
end

Modified mem.t from [a177326f1c] to [1f9397ac82].

60
61
62
63
64
65
66

67
68
69
70
71
72
73
		t.methods = {
			free = terra(self: &t): bool
				[recurse and quote
					self.ptr:free()
				end or {}]
				if self.ct > 0 then
					m.heapf(self.ptr)

					self.ct = 0
					return true
				end
				return false
			end;
			init = terra(self: &t, newct: intptr): bool
				if newct == 0 then self.ct = 0 self.ptr = nil return false end







>







60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
		t.methods = {
			free = terra(self: &t): bool
				[recurse and quote
					self.ptr:free()
				end or {}]
				if self.ct > 0 then
					m.heapf(self.ptr)
					self.ptr = nil
					self.ct = 0
					return true
				end
				return false
			end;
			init = terra(self: &t, newct: intptr): bool
				if newct == 0 then self.ct = 0 self.ptr = nil return false end

Modified mgtool.t from [c954b701da] to [c623f2c8c5].

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
..
45
46
47
48
49
50
51


52
53
54



55
56
57
58
59
60
61
..
67
68
69
70
71
72
73


















74
75
76
77
78
79
80
..
92
93
94
95
96
97
98












99
100
101
102
103
104
105
106
107
108



109
110
111
112
113
114
115
...
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
...
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180









181
182

183
184
185
186
187
188
189
local ctloptions = lib.cmdparse({
	version = {'V', 'display information about the binary build and exit'};
	verbose = {'v', 'increase logging verbosity', inc=1};
	quiet = {'q', 'do not print to standard out'};
	help = {'h', 'display this list'};
	backend_file = {'B', 'init from specified backend file', consume=1};
	backend = {'b', 'operate on only the selected backend'};
	instance = {'i', 'specify the instance to control by name', consume=1};

	all = {'A', 'affect all running instances'};
}, { subcmd = 1 })

local pbasic = lib.cmdparse {
	help = {'h', 'display this list'}
}
local subcmds = {
}

local ctlcmds = {
	{ 'start', 'start a new instance of the server' };
	{ 'stop', 'stop a running instance' };

	{ 'attach', 'capture log output from a running instance' };
	{ 'db', 'set up and manage the database' };
	{ 'user', 'manage users, privileges, and credentials'};
	{ 'mkroot <handle>', 'establish a new root user with the given handle' };
	{ 'actor <xid> purge-all', 'remove all traces of a user from the database (except local user credentials -- use \27[1mauth all purge\27[m to prevent a user from accessing the instance)' };
	{ 'actor <xid> create', 'instantiate a new actor' };
	{ 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' };
................................................................................
			v[2]
		)
	end
	return str
end

local struct idelegate {


	all: bool
	src: &lib.store.source
	srv: &lib.srv.overlord



}
idelegate.metamethods.__methodmissing = macro(function(meth, self, ...)
	local expr = {...}
	local rt
	for _,f in pairs(lib.store.backend.entries) do
		local fn = f.field or f[1]
		local ft = f.type or f[2]
................................................................................
		if self.all
			then r=self.srv:[meth]([expr])
			elseif self.src ~= nil then r=self.src:[meth]([expr])
			else lib.bail('no data source specified')
		end
	in r end
end)



















local terra gensec(sdest: rawstring)
	var dest = [&uint8](sdest)
	lib.crypt.spray(dest,64)
	for i=0,64 do dest[i] = dest[i] % (0x7e - 0x20) + 0x20 end
	dest[64] = 0
end
................................................................................
		else tmppw[i] = tmppw[i] + 0x30 end
	end
	lib.dbg('assigning temporary password')
	dlg:auth_create_pw(uid, reset, pstr {
		ptr = [rawstring](tmppw), ct = 32
	})
end













local emp = lib.ipc.global_emperor
local terra entry_mgtool(argc: int, argv: &rawstring): int
	if argc < 1 then lib.bail('bad invocation!') end

	lib.noise.init(2)
	[lib.init]

	var srv: lib.srv.overlord
	var dlg = idelegate { srv = &srv, src = nil }




	var mode: ctloptions
	mode:parse(argc,argv) defer mode:free()
	if mode.version then version() return 0 end
	if mode.help then
		[ lib.emit(false, 1, 'usage: ', `argv[0], ' ', ctloptions.helptxt.flags, ' <cmd> [<args>…]', ctloptions.helptxt.opts, cmdhelp(ctlcmds)) ]
		return 0
................................................................................
	var cnf: rawstring
	if mode.backend_file ~= nil
		then cnf = @mode.backend_file
		else cnf = lib.proc.getenv('parsav_backend_file')
	end
	if cnf == nil then cnf = [config.prefix_conf .. "/backend.conf"] end
	if mode.all then dlg.all = true else
		-- iterate through and pick the right backend










	end

	if mode.arglist.ct == 0 then lib.bail('no command') return 1 end

	if lib.str.cmp(mode.arglist(0),'start') ~= 0 then
	-- hack to save us some pain around forking
		emp = lib.ipc.emperor.mk(false)
	end
	defer emp:release()

	if lib.str.cmp(mode.arglist(0),'attach') == 0 then
	elseif lib.str.cmp(mode.arglist(0),'start') == 0 then
		mode.arglist(0) = "-";






		var chargv = mode.arglist.ptr




		var lsr = lib.ipc.listener.mk()
		var chpid = lib.proc.fork()
		if chpid == 0 then
			lsr:release()
			--lib.proc.daemonize(1,0)






			lib.io.close(0) lib.io.close(1) lib.io.close(2)

			lib.proc.exec([config.prefix_bin .. '/parsavd'], chargv)
			lib.proc.execp([config.prefix_bin .. '/parsavd'], chargv)
			lib.ipc.notify_parent(lib.ipc.signals.state_fail_find)
			lib.bail('cannot find parsav program')

		else
			lib.report('starting parsav daemon')
			while true do
				var sig = lsr:block()
				if sig.system then lib.dbg('got system signal') end
				if sig.from == chpid then
					if sig.system and sig.sig == lib.ipc.signals.sys_child then 
................................................................................
					else lib.warn('got unrecognized signal, ignoring')
					end
				end
			end
			lsr:release() -- just because i feel distinctly uncomfortable leaving it out
		end
	elseif lib.str.cmp(mode.arglist(0),'stop') == 0 then
		var acks = emp:mallack()
		emp:decree(0,nil, lib.ipc.cmd.stop, 0, &acks(0)) -- TODO targeting
		for i=0,acks.ct do
			if acks(i).success then
				lib.io.fmt('instance %llu successfully stepped down\n', acks(i).clid)
			else
				lib.io.fmt('instance %llu reports failure to halt\n', acks(i).clid)
			end









		end
		acks:free()

	else
		if lib.str.cmp(mode.arglist(0),'db') == 0 then
			var dbmode: pbasic dbmode:parse(mode.arglist.ct, &mode.arglist(0))
			if dbmode.help then
				[ lib.emit(false, 1, 'usage: ', `argv[0], ' db ', dbmode.type.helptxt.flags, ' <cmd> [<args>…]', dbmode.type.helptxt.opts, cmdhelp {
					{ 'db init <domain>', 'initialize backend databases (or a single specified database) with the necessary schema and structures for the given FQDN' };
					{ 'db vacuum', 'delete old remote content from the database' };







|
>
|











>







 







>
>



>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>









|
>
>
>







 







|
>
>
>
>
>
>
>
>
>
>












|
>
>
>
>
>
>
|
>
>
>
>




|
>
>
>
>
>
>
|
>
|
|


>







 







|
|
|
|
|
<
<
|
>
>
>
>
>
>
>
>
>
|
|
>







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
..
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
..
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
...
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
...
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
...
234
235
236
237
238
239
240
241
242
243
244
245


246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
local ctloptions = lib.cmdparse({
	version = {'V', 'display information about the binary build and exit'};
	verbose = {'v', 'increase logging verbosity', inc=1};
	quiet = {'q', 'do not print to standard out'};
	help = {'h', 'display this list'};
	backend_file = {'B', 'init from specified backend file', consume=1};
	backend = {'b', 'operate on only the selected backend'};
	instance_id = {'i', 'specify the instance to control by name', consume=1};
	instance_serial = {'I', 'specify the instance to control by serial', consume=1};
	all = {'A', 'affect all running instances/backends'};
}, { subcmd = 1 })

local pbasic = lib.cmdparse {
	help = {'h', 'display this list'}
}
local subcmds = {
}

local ctlcmds = {
	{ 'start', 'start a new instance of the server' };
	{ 'stop', 'stop a running instance' };
	{ 'ls', 'list all running instances' };
	{ 'attach', 'capture log output from a running instance' };
	{ 'db', 'set up and manage the database' };
	{ 'user', 'manage users, privileges, and credentials'};
	{ 'mkroot <handle>', 'establish a new root user with the given handle' };
	{ 'actor <xid> purge-all', 'remove all traces of a user from the database (except local user credentials -- use \27[1mauth all purge\27[m to prevent a user from accessing the instance)' };
	{ 'actor <xid> create', 'instantiate a new actor' };
	{ 'actor <xid> bestow <epithet>', 'bestow an epithet upon an actor' };
................................................................................
			v[2]
		)
	end
	return str
end

local struct idelegate {
	emperor: &lib.ipc.emperor

	all: bool
	src: &lib.store.source
	srv: &lib.srv.overlord

	sid: uint64
	iname: rawstring
}
idelegate.metamethods.__methodmissing = macro(function(meth, self, ...)
	local expr = {...}
	local rt
	for _,f in pairs(lib.store.backend.entries) do
		local fn = f.field or f[1]
		local ft = f.type or f[2]
................................................................................
		if self.all
			then r=self.srv:[meth]([expr])
			elseif self.src ~= nil then r=self.src:[meth]([expr])
			else lib.bail('no data source specified')
		end
	in r end
end)

terra idelegate:ipc_send(cmd: lib.ipc.cmd.t, operand: uint64)
	var emp = self.emperor
	var acks: lib.mem.ptr(lib.ipc.ack)
	if self.sid == 0 and self.iname == nil then
		if not self.all and emp:countpeers() > 1 then
			lib.bail('either specify the instance to control or pass --all to control all instances')
		end
		acks = emp:mallack()
		emp:decree(0,nil, cmd, operand, &acks(0)) -- TODO targeting
	else
		acks = lib.mem.heapa(lib.ipc.ack, 1)
		if not emp:decree(self.sid, self.iname, cmd, operand, &acks(0)) then
			acks:free()
		end
	end
	return acks
end

local terra gensec(sdest: rawstring)
	var dest = [&uint8](sdest)
	lib.crypt.spray(dest,64)
	for i=0,64 do dest[i] = dest[i] % (0x7e - 0x20) + 0x20 end
	dest[64] = 0
end
................................................................................
		else tmppw[i] = tmppw[i] + 0x30 end
	end
	lib.dbg('assigning temporary password')
	dlg:auth_create_pw(uid, reset, pstr {
		ptr = [rawstring](tmppw), ct = 32
	})
end

local terra ipc_report(acks: lib.mem.ptr(lib.ipc.ack), rep: rawstring)
	var decbuf: int8[21]
	for i=0,acks.ct do
		var num = lib.math.decstr(acks(i).clid, &decbuf[20])
		if acks(i).success then
			lib.report('instance #',num,' reports successful ',rep)
		else
			lib.report('instance #',num,' reports failed ',rep)
		end
	end
end

local emp = lib.ipc.global_emperor
local terra entry_mgtool(argc: int, argv: &rawstring): int
	if argc < 1 then lib.bail('bad invocation!') end

	lib.noise.init(2)
	[lib.init]

	var srv: lib.srv.overlord
	var dlg = idelegate {
		emperor = &emp, srv = &srv;
		src = nil, sid = 0, iname = nil, all = false;
	}

	var mode: ctloptions
	mode:parse(argc,argv) defer mode:free()
	if mode.version then version() return 0 end
	if mode.help then
		[ lib.emit(false, 1, 'usage: ', `argv[0], ' ', ctloptions.helptxt.flags, ' <cmd> [<args>…]', ctloptions.helptxt.opts, cmdhelp(ctlcmds)) ]
		return 0
................................................................................
	var cnf: rawstring
	if mode.backend_file ~= nil
		then cnf = @mode.backend_file
		else cnf = lib.proc.getenv('parsav_backend_file')
	end
	if cnf == nil then cnf = [config.prefix_conf .. "/backend.conf"] end
	if mode.all then dlg.all = true else
		-- iterate through and pick the right backend, if one is indicated 
	end
	
	if mode.instance_id ~= nil and mode.instance_serial ~= nil then
		lib.bail('conflicting flags passed')
	end

	if mode.instance_id ~= nil then
		dlg.iname = @mode.instance_id
	elseif mode.instance_serial ~= nil then
		-- decode serial
	end

	if mode.arglist.ct == 0 then lib.bail('no command') return 1 end

	if lib.str.cmp(mode.arglist(0),'start') ~= 0 then
	-- hack to save us some pain around forking
		emp = lib.ipc.emperor.mk(false)
	end
	defer emp:release()

	if lib.str.cmp(mode.arglist(0),'attach') == 0 then
	elseif lib.str.cmp(mode.arglist(0),'start') == 0 then
		var smode: lib.cmdparse {
			help = {'h', 'display this list'};
			log = {'l', 'send server\'s logging output to a file', consume=1};
			pid = {'p', 'report PID of launched process'};
			instance_serial = {'s', 'report the instance serial of the launched process'};
			keep_attached = {'k', 'don\'t detach from the calling terminal until a successful startup (or ever, if passed twice)', inc=1};
		}
		smode:parse(mode.arglist.ct,mode.arglist.ptr)
		if smode.help then
			[ lib.emit(false, 1, 'usage: ', `argv[0], ' start ', smode.type.helptxt.flags, ' [<instance args>…] [-- <instance flags>…]', smode.type.helptxt.opts) ]
			return 1
		end
		var lsr = lib.ipc.listener.mk()
		var chpid = lib.proc.fork()
		if chpid == 0 then
			lsr:release()
			var chargv = lib.mem.heapa(rawstring, smode.arglist.ct + 2)
			chargv(0) = '-'
			for i = 1, chargv.ct - 1 do
				chargv(i) = smode.arglist(i-1)
			end
			chargv(chargv.ct-1) = nil
			if smode.keep_attached == 0 then
				lib.io.close(0) lib.io.close(1) lib.io.close(2)
			end
			lib.proc.exec([config.prefix_bin .. '/parsavd'], chargv.ptr)
			lib.proc.execp([config.prefix_bin .. '/parsavd'], chargv.ptr)
			lib.ipc.notify_parent(lib.ipc.signals.state_fail_find)
			lib.bail('cannot find parsav program')
			-- chargv:free()
		else
			lib.report('starting parsav daemon')
			while true do
				var sig = lsr:block()
				if sig.system then lib.dbg('got system signal') end
				if sig.from == chpid then
					if sig.system and sig.sig == lib.ipc.signals.sys_child then 
................................................................................
					else lib.warn('got unrecognized signal, ignoring')
					end
				end
			end
			lsr:release() -- just because i feel distinctly uncomfortable leaving it out
		end
	elseif lib.str.cmp(mode.arglist(0),'stop') == 0 then
		if mode.arglist.ct ~= 1 then goto cmderr end
		var acks = dlg:ipc_send(lib.ipc.cmd.stop, 0)
		if acks:ref() then
			ipc_report(acks, 'step-down')
			acks:free()


		end
	elseif lib.str.cmp(mode.arglist(0),'ls') == 0 then
		if mode.arglist.ct ~= 1 then goto cmderr end
		if dlg.sid == 0 and dlg.iname == nil then dlg.all = true end
		var acks = dlg:ipc_send(lib.ipc.cmd.enumerate, 0)
		if acks:ref() then
			for i=0,acks.ct do
				var decbuf: int8[21]
				var num = lib.math.decstr(acks(i).clid, &decbuf[20])
				[ lib.emit(true,1, '\27[1m(', `num, ')\27[m ',`&acks(i).iname[0],' \27[1;32mactive\27[m') ]
			end
			acks:free()
		else lib.bail('no active instances') end
	else
		if lib.str.cmp(mode.arglist(0),'db') == 0 then
			var dbmode: pbasic dbmode:parse(mode.arglist.ct, &mode.arglist(0))
			if dbmode.help then
				[ lib.emit(false, 1, 'usage: ', `argv[0], ' db ', dbmode.type.helptxt.flags, ' <cmd> [<args>…]', dbmode.type.helptxt.opts, cmdhelp {
					{ 'db init <domain>', 'initialize backend databases (or a single specified database) with the necessary schema and structures for the given FQDN' };
					{ 'db vacuum', 'delete old remote content from the database' };

Modified parsav.t from [1565f096a3] to [b85f6f7647].

429
430
431
432
433
434
435


436
437
438
439
440
441
442
	quiet = {'q', 'do not print to standard out'};
	help = {'h', 'display this list'};
	backend_file = {'B', 'init from specified backend file', consume=1};
	static_dir = {'S', 'directory with overrides for static content', consume=1};
	builtin_data = {'D', 'do not load static content overrides at runtime under any circumstances'};
	instance = {'i', 'set an instance name to make it easier to control multiple daemons', consume = 1};
	no_ipc = {'I', 'disable IPC'};


}


local static_setup = quote end
local mapin = quote end
local odir = symbol(rawstring)
local pathbuf = symbol(lib.str.acc)







>
>







429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
	quiet = {'q', 'do not print to standard out'};
	help = {'h', 'display this list'};
	backend_file = {'B', 'init from specified backend file', consume=1};
	static_dir = {'S', 'directory with overrides for static content', consume=1};
	builtin_data = {'D', 'do not load static content overrides at runtime under any circumstances'};
	instance = {'i', 'set an instance name to make it easier to control multiple daemons', consume = 1};
	no_ipc = {'I', 'disable IPC'};
	chroot = {'C', 'chroot to the specified directory after starting and connecting to backends', consume=1};
	no_lockdown = {'L', 'don\'t drop privileges or apply other security measures that could cause compatibility or communication problems'}
}


local static_setup = quote end
local mapin = quote end
local odir = symbol(rawstring)
local pathbuf = symbol(lib.str.acc)

Modified srv.t from [7c204f248d] to [7727a773dd].

619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
	lib.net.mg_mgr_init(&self.webmgr)
	self.webcon = lib.net.mg_http_listen(&self.webmgr, bind, handle.http, self)

	if dbbind.ptr ~= nil then dbbind:free() end
end

terra srv:poll()
	lib.net.mg_mgr_poll(&self.webmgr,1000)
end

terra srv:shutdown()
	lib.net.mg_mgr_free(&self.webmgr)
	for i=0,self.sources.ct do var src = self.sources.ptr + i
		lib.report('closing data source ', src.id.ptr, '(', src.backend.id, ')')
		src:close()







|







619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
	lib.net.mg_mgr_init(&self.webmgr)
	self.webcon = lib.net.mg_http_listen(&self.webmgr, bind, handle.http, self)

	if dbbind.ptr ~= nil then dbbind:free() end
end

terra srv:poll()
	lib.net.mg_mgr_poll(&self.webmgr,300)
end

terra srv:shutdown()
	lib.net.mg_mgr_free(&self.webmgr)
	for i=0,self.sources.ct do var src = self.sources.ptr + i
		lib.report('closing data source ', src.id.ptr, '(', src.backend.id, ')')
		src:close()