1 // Written in the D programming language.
2 
3 /**
4 This module contains a set of various useful functions for more convenient work with 9P / Styx messages.
5 Note: This module contains helpers for building all types of messages, except stat, wstat and walk, since these messages have a complex structure and must be processed directly in the code that forms them.
6 
7 Copyright: LightHouse Software, 2021
8 License:   $(HTTP https://github.com/aquaratixc/ESL-License, Experimental Software License 1.0).
9 Authors:   Oleg Bakharev,
10 		   Ilya Pertsev   
11 */
12 module styx2000.extrautil.styxmessage;
13 
14 private {
15 	import styx2000.protoconst;
16 	
17 	import styx2000.protobj;
18 }
19 
20 /// Convenient alias
21 alias StyxMessage = StyxObject[];
22 
23 /// StyxMessage is client message ?
24 bool isTmessage(StyxMessage msg)
25 {
26 	bool isMessage = false;
27 	Type type = cast(Type) msg[1];
28 	
29 	if (type !is null)
30 	{
31 		with (STYX_MESSAGE_TYPE)
32 		{
33 			switch(type.getType) 
34 			{
35 				// version
36 				case T_VERSION:
37 					isMessage = true;
38 					break;
39 				// auth
40 				case T_AUTH:
41 					isMessage = true;
42 					break;
43 				// flush
44 				case T_FLUSH:
45 					isMessage = true;
46 					break;
47 				// attach
48 				case T_ATTACH:
49 					isMessage = true;
50 					break;
51 				// walk
52 				case T_WALK:
53 					isMessage = true;
54 					break;
55 				case T_OPEN:
56 					isMessage = true;
57 					break;
58 				// create
59 				case T_CREATE:
60 					isMessage = true;
61 					break;
62 				// read
63 				case T_READ:
64 					isMessage = true;
65 					break;
66 				// write
67 				case T_WRITE:
68 					isMessage = true;
69 					break;
70 				// clunk
71 				case T_CLUNK:
72 					isMessage = true;
73 					break;
74 				// remove
75 				case T_REMOVE:
76 					isMessage = true;
77 					break;
78 				// stat
79 				case T_STAT:
80 					isMessage = true;
81 					break;
82 				// wstat
83 				case T_WSTAT:
84 					isMessage = true;
85 					break;
86 				default:
87 					break;
88 			}
89 		}
90 	}
91 	
92 	return isMessage;
93 }
94 
95 /// StyxMessage is server message ?
96 bool isRmessage(StyxMessage msg)
97 {
98 	bool isMessage = false;
99 	Type type = cast(Type) msg[1];
100 	
101 	if (type !is null)
102 	{
103 		with (STYX_MESSAGE_TYPE)
104 		{
105 			switch(type.getType) 
106 			{
107 				// version
108 				case R_VERSION:
109 					isMessage = true;
110 					break;
111 				// auth
112 				case R_AUTH:
113 					isMessage = true;
114 					break;
115 				// flush
116 				case R_FLUSH:
117 					isMessage = true;
118 					break;
119 				// attach
120 				case R_ATTACH:
121 					isMessage = true;
122 					break;
123 				// walk
124 				case R_WALK:
125 					isMessage = true;
126 					break;
127 				case R_OPEN:
128 					isMessage = true;
129 					break;
130 				// create
131 				case R_CREATE:
132 					isMessage = true;
133 					break;
134 				// read
135 				case R_READ:
136 					isMessage = true;
137 					break;
138 				// write
139 				case R_WRITE:
140 					isMessage = true;
141 					break;
142 				// clunk
143 				case R_CLUNK:
144 					isMessage = true;
145 					break;
146 				// remove
147 				case R_REMOVE:
148 					isMessage = true;
149 					break;
150 				// stat
151 				case R_STAT:
152 					isMessage = true;
153 					break;
154 				// wstat
155 				case R_WSTAT:
156 					isMessage = true;
157 					break;
158 				// error
159 				case R_ERROR:
160 					isMessage = true;
161 					break;
162 				default:
163 					break;
164 			}
165 		}
166 	}
167 	
168 	return isMessage;
169 }
170 
171 /// StyxMessage is error message ?
172 bool isErrorMessage(StyxMessage msg)
173 {
174 	bool isMessage = false;
175 	Type type = cast(Type) msg[1];
176 	
177 	if (type !is null)
178 	{
179 		if (type.getType == STYX_MESSAGE_TYPE.R_ERROR)
180 		{
181 			isMessage = true;
182 		}
183 	}
184 	
185 	return isMessage;
186 }
187 
188 /// Create base header for 9P / Styx messages
189 auto createHeader(uint size = 0, STYX_MESSAGE_TYPE type = STYX_MESSAGE_TYPE.R_ERROR, ushort tag = STYX_NOTAG)
190 {
191 	return cast(StyxMessage) [
192 		new Size(size),
193 		new Type(type),
194 		new Tag(tag)
195 	];
196 }
197 
198 /// Create version message from client
199 auto createTmsgVersion(ushort tag = STYX_NOTAG, uint maximalSize = 8192, string vers = STYX_VERSION)
200 {
201 	return createHeader(0, STYX_MESSAGE_TYPE.T_VERSION, tag) ~ cast(StyxMessage) [
202 		new Msize(maximalSize),
203 		new Version(vers)
204 	];
205 }
206 
207 /// Create version message from server
208 auto createRmsgVersion(ushort tag = STYX_NOTAG, uint maximalSize = 8192, string vers = STYX_VERSION)
209 {
210 	return createHeader(0, STYX_MESSAGE_TYPE.R_VERSION, tag) ~ cast(StyxMessage) [
211 		new Msize(maximalSize),
212 		new Version(vers)
213 	];
214 }
215 
216 /// Create auth message from client
217 auto createTmsgAuth(ushort tag = STYX_NOTAG, uint afid = STYX_NOFID, string uname = "", string aname = "")
218 {
219 	return createHeader(0, STYX_MESSAGE_TYPE.T_AUTH, tag) ~ cast(StyxMessage) [
220 		new Afid(afid),
221 		new Uname(uname),
222 		new Aname(aname)
223 	];
224 }
225 
226 /// Create auth message from server
227 auto createRmsgAuth(ushort tag = STYX_NOTAG, STYX_QID_TYPE type = STYX_QID_TYPE.QTFILE, uint vers = 0, ulong path = 0)
228 {
229 	return createHeader(0, STYX_MESSAGE_TYPE.R_AUTH, tag) ~ cast(StyxMessage) [
230 		new Aqid(type, vers, path)
231 	];
232 }
233 
234 /// Create attach message from client
235 auto createTmsgAttach(ushort tag = STYX_NOTAG, uint fid = STYX_NOFID, uint afid = STYX_NOFID, string uname = "", string aname = "")
236 {
237 	return createHeader(0, STYX_MESSAGE_TYPE.T_ATTACH, tag) ~ cast(StyxMessage) [
238 		new Fid(fid),
239 		new Afid(afid),
240 		new Uname(uname),
241 		new Aname(aname)
242 	];
243 }
244 
245 /// Create attach message from server
246 auto createRmsgAttach(ushort tag = STYX_NOTAG, STYX_QID_TYPE type = STYX_QID_TYPE.QTFILE, uint vers = 0, ulong path = 0)
247 {
248 	return createHeader(0, STYX_MESSAGE_TYPE.R_ATTACH, tag) ~ cast(StyxMessage) [
249 		new Qid(type, vers, path)
250 	];
251 }
252 
253 /// Create error message from server (for client this type of message does not exists)
254 auto createRmsgError(ushort tag = STYX_NOTAG, string ename = "")
255 {
256 	return createHeader(0, STYX_MESSAGE_TYPE.R_ERROR, tag) ~ cast(StyxMessage) [
257 		new Ename(ename)
258 	];
259 }
260 
261 /// Create clunk message from client
262 auto createTmsgClunk(ushort tag = STYX_NOTAG, uint fid = STYX_NOFID)
263 {
264 	return createHeader(0, STYX_MESSAGE_TYPE.T_CLUNK, tag) ~ cast(StyxMessage) [
265 		new Fid(fid)
266 	];
267 }
268 
269 /// Create clunk message from server
270 auto createRmsgClunk(ushort tag = STYX_NOTAG)
271 {
272 	return createHeader(0, STYX_MESSAGE_TYPE.R_CLUNK, tag);
273 }
274 
275 /// Create flush message from client
276 auto createTmsgFlush(ushort tag = STYX_NOTAG, ushort oldTag = STYX_NOTAG)
277 {
278 	return createHeader(0, STYX_MESSAGE_TYPE.T_FLUSH, tag) ~ cast(StyxMessage) [
279 		new OldTag(oldTag)
280 	];
281 }
282 
283 /// Create flush message from server
284 auto createRmsgFlush(ushort tag = STYX_NOTAG)
285 {
286 	return createHeader(0, STYX_MESSAGE_TYPE.R_FLUSH, tag);
287 }
288 
289 /// Create remove message from client
290 auto createTmsgRemove(ushort tag = STYX_NOTAG, uint fid = STYX_NOFID)
291 {
292 	return createHeader(0, STYX_MESSAGE_TYPE.T_REMOVE, tag) ~ cast(StyxMessage) [
293 		new Fid(fid)
294 	];
295 }
296 
297 /// Create remove message from server
298 auto createRmsgRemove(ushort tag = STYX_NOTAG)
299 {
300 	return createHeader(0, STYX_MESSAGE_TYPE.R_REMOVE, tag);
301 }
302 
303 /// Create open message from client
304 auto createTmsgOpen(ushort tag = STYX_NOTAG, uint fid = STYX_NOFID, STYX_FILE_MODE mode = STYX_FILE_MODE.OREAD)
305 {
306 	return createHeader(0, STYX_MESSAGE_TYPE.T_OPEN, tag) ~ cast(StyxMessage) [
307 		new Fid(fid),
308 		new Mode(mode)
309 	];
310 }
311 
312 /// Create open message from server
313 auto createRmsgOpen(ushort tag = STYX_NOTAG, STYX_QID_TYPE type = STYX_QID_TYPE.QTFILE, uint vers = 0, ulong path = 0, uint iounit = 8164)
314 {
315 	return createHeader(0, STYX_MESSAGE_TYPE.R_OPEN, tag) ~ cast(StyxMessage) [
316 		new Qid(type, vers, path),
317 		new Iounit(iounit)
318 	];
319 }
320 
321 /// Create create message from client
322 auto createTmsgCreate(ushort tag = STYX_NOTAG, uint fid = STYX_NOFID, STYX_FILE_MODE mode = STYX_FILE_MODE.OREAD, STYX_FILE_PERMISSION[] perms = [STYX_FILE_PERMISSION.OWNER_READ, STYX_FILE_PERMISSION.OWNER_WRITE, STYX_FILE_PERMISSION.OWNER_EXEC])
323 {
324 	auto perm = new Perm;
325 	perm.setPerm(perms);
326 	return createHeader(0, STYX_MESSAGE_TYPE.T_CREATE, tag) ~ cast(StyxMessage) [
327 		new Fid(fid),
328 		perm,
329 		new Mode(mode)
330 	];
331 }
332 
333 /// Create create message from server
334 auto createRmsgCreate(ushort tag = STYX_NOTAG, STYX_QID_TYPE type = STYX_QID_TYPE.QTFILE, uint vers = 0, ulong path = 0, uint iounit = 8164)
335 {
336 	return createHeader(0, STYX_MESSAGE_TYPE.R_CREATE, tag) ~ cast(StyxMessage) [
337 		new Qid(type, vers, path),
338 		new Iounit(iounit)
339 	];
340 }
341 
342 /// Create read message from client
343 auto createTmsgRead(ushort tag = STYX_NOTAG, uint fid = STYX_NOFID, ulong offset = 0, uint count = 0)
344 {
345 	return createHeader(0, STYX_MESSAGE_TYPE.T_READ, tag) ~ cast(StyxMessage) [
346 		new Fid(fid),
347 		new Offset(offset),
348 		new Count(count)
349 	];
350 }
351 
352 /// Create read message from server
353 auto createRmsgRead(ushort tag = STYX_NOTAG, uint count = 0, ubyte[] data = [])
354 {
355 	return createHeader(0, STYX_MESSAGE_TYPE.R_READ, tag) ~ cast(StyxMessage) [
356 		new Count(count),
357 		new Data(data)
358 	];
359 }
360 
361 /// Create write message from client
362 auto createTmsgWrite(ushort tag = STYX_NOTAG, uint fid = STYX_NOFID, ulong offset = 0, uint count = 0, ubyte[] data = [])
363 {
364 	return createHeader(0, STYX_MESSAGE_TYPE.T_WRITE, tag) ~ cast(StyxMessage) [
365 		new Fid(fid),
366 		new Offset(offset),
367 		new Count(count),
368 		new Data(data)
369 	];
370 }
371 
372 /// Create write message from server
373 auto createRmsgWrite(ushort tag = STYX_NOTAG, uint count = 0)
374 {
375 	return createHeader(0, STYX_MESSAGE_TYPE.R_WRITE, tag) ~ cast(StyxMessage) [
376 		new Count(count)
377 	];
378 }