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 }