2 * Copyright (C) 2006 by Latchesar Ionkov <lucho@ionkov.net>
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * LATCHESAR IONKOV AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
28 #include <sys/socket.h>
34 typedef struct Spcrpc Spcrpc
;
44 int spc_msize
= 32768 + IOHDRSZ
;
45 char *Econn
= "connection closed";
46 static char *Emismatch
= "response mismatch";
47 static char *Eflush
= "request flushed";
49 static Spfcall
*spc_fcall_alloc(u32 msize
);
50 static void spc_notify(Spfd
*spfd
, void *aux
);
53 spc_create_fsys(int fd
, int msize
)
57 fs
= sp_malloc(sizeof(*fs
));
71 fs
->pend_first
= NULL
;
81 fs
->spfd
= spfd_add(fd
, spc_notify
, fs
);
85 fs
->tagpool
= spc_create_pool(NOTAG
);
89 fs
->fidpool
= spc_create_pool(NOFID
);
96 spc_disconnect_fsys(fs
);
101 spc_remount(Spcfsys
*fs
)
103 fs
->spfd
= spfd_add(fs
->fd
, spc_notify
, fs
);
107 spc_disconnect_fsys(Spcfsys
*fs
)
113 sp_rerror(&fs
->ename
, &fs
->ecode
);
115 fs
->ename
= strdup(fs
->ename
);
121 spc_fid_free(fs
->root
);
126 spc_fid_free(fs
->afid
);
137 spfd_remove(fs
->spfd
);
141 sp_rerror(&ename
, &ecode
);
143 ename
= strdup(ename
);
150 sp_werror(Econn
, ECONNRESET
);
151 req
= fs
->pend_first
;
152 while (req
!= NULL
) {
153 (*req
->cb
)(req
->cba
, NULL
);
158 fs
->pend_first
= NULL
;
161 while (req
!= NULL
) {
162 (*req
->cb
)(req
->cba
, NULL
);
167 fs
->sent_reqs
= NULL
;
169 sp_werror(ename
, ecode
);
175 spc_destroy_fsys(Spcfsys
*fs
)
179 spc_destroy_pool(fs
->tagpool
);
184 spc_destroy_pool(fs
->fidpool
);
189 if (fs
->ename
!= Enomem
)
203 spc_get_local_address(Spcfsys
*fs
)
209 spc_get_remote_address(Spcfsys
*fs
)
215 spc_request_flushed(Spcreq
*r
)
223 for(preq
=NULL
, req
= fs
->sent_reqs
; req
!= NULL
; preq
=req
, req
= req
->next
)
229 preq
->next
= req
->next
;
231 fs
->sent_reqs
= req
->next
;
233 sp_rerror(&ename
, &ecode
);
235 ename
= strdup(ename
);
237 sp_werror(Eflush
, EIO
);
238 (*req
->cb
)(req
->cba
, NULL
);
239 sp_werror(ename
, ecode
);
243 /* if req->flushed is set, the request is not freed if response arrives */
244 spc_put_id(fs
->tagpool
, r
->tag
);
249 spc_flush_cb(void *aux
, Spfcall
*rc
)
252 spc_request_flushed((Spcreq
*) aux
);
256 spc_flush_request(Spcreq
*req
)
266 fc
= sp_create_tflush(req
->tag
);
267 if (sp_poll_looping())
268 spc_rpcnb(fs
, fc
, spc_flush_cb
, req
);
270 spc_rpc(fs
, fc
, NULL
);
271 spc_request_flushed(req
);
276 spc_flush_requests(Spcfsys
*fs
, Spcfid
*fid
)
280 Spcreq
*preq
, *req
, *req1
;
285 // check the unsent requests
286 sp_rerror(&ename
, &ecode
);
288 ename
= strdup(ename
);
290 sp_werror(Eflush
, EIO
);
292 req
= fs
->pend_first
;
293 while (req
!= NULL
) {
294 if (req
->tc
->fid
== fid
->fid
) {
296 preq
->next
= req
->next
;
298 fs
->pend_first
= req
->next
;
300 if (req
== fs
->pend_last
)
301 fs
->pend_last
= preq
;
303 (*req
->cb
)(req
->cba
, NULL
);
313 // check the sent ones
315 while (req
!= NULL
) {
316 if (req
->tc
->fid
== fid
->fid
&& !req
->flushed
) {
317 spc_flush_request(req
);
323 sp_werror(ename
, ecode
);
328 spc_fd_read(Spcfsys
*fs
)
335 fs
->ifcall
= spc_fcall_alloc(fs
->msize
);
337 spc_disconnect_fsys(fs
);
341 fs
->ifcall
->size
= 0;
345 n
= spfd_read(fs
->spfd
, fc
->pkt
+ fc
->size
, fs
->msize
- fc
->size
);
348 spc_disconnect_fsys(fs
);
359 size
= fc
->pkt
[0] | (fc
->pkt
[1]<<8) | (fc
->pkt
[2]<<16) | (fc
->pkt
[3]<<24);
360 if (size
> fs
->msize
) {
361 sp_werror("invalid fcall size greater than msize", EIO
);
362 spc_disconnect_fsys(fs
);
369 if (!sp_deserialize(fc
, fc
->pkt
, fs
->dotu
)) {
370 sp_werror("invalid fcall", EIO
);
371 spc_disconnect_fsys(fs
);
376 fprintf(stderr
, "-->>> (%p) ", fs
);
377 sp_printfcall(stderr
, fc
, fs
->dotu
);
378 fprintf(stderr
, "\n");
381 fs
->ifcall
= spc_fcall_alloc(fs
->msize
);
383 spc_disconnect_fsys(fs
);
388 memmove(fs
->ifcall
->pkt
, fc
->pkt
+ size
, n
- size
);
390 fs
->ifcall
->size
= n
- size
;
392 for(preq
= NULL
, req
= fs
->sent_reqs
; req
!= NULL
; preq
= req
, req
= req
->next
)
393 if (fc
->tag
== req
->tag
)
397 sp_werror("unexpected fcall", EIO
);
403 preq
->next
= req
->next
;
405 fs
->sent_reqs
= req
->next
;
407 if (fc
->type
!=Rerror
&& req
->tc
->type
+1!=fc
->type
) {
408 sp_werror(Emismatch
, EIO
);
413 (*req
->cb
)(req
->cba
, fc
);
420 spc_put_id(fs
->tagpool
, req
->tag
);
424 if (fs
->ifcall
->size
) {
431 spc_fd_write(Spcfsys
*fs
)
440 req
= fs
->pend_first
;
443 if (spc_chatty
&& fs
->pend_pos
== 0) {
444 fprintf(stderr
, "<<<-- (%p) ", fs
);
445 sp_printfcall(stderr
, tc
, fs
->dotu
);
446 fprintf(stderr
, "\n");
449 n
= spfd_write(fs
->spfd
, tc
->pkt
+ fs
->pend_pos
, tc
->size
- fs
->pend_pos
);
452 spc_disconnect_fsys(fs
);
457 if (tc
->size
== fs
->pend_pos
) {
459 fs
->pend_first
= req
->next
;
460 if (req
== fs
->pend_last
)
461 fs
->pend_last
= NULL
;
463 req
->next
= fs
->sent_reqs
;
469 spc_notify(Spfd
*spfd
, void *aux
)
477 sp_rerror(&ename
, &ecode
);
479 ename
= strdup(ename
);
482 if (spfd_can_read(spfd
))
493 if (spfd_can_write(spfd
))
496 if (spfd_has_error(spfd
))
497 spc_disconnect_fsys(fs
);
503 fprintf(stderr
, "Error: %s: %d\n", en
, ec
);
508 sp_werror(ename
, ecode
);
515 spc_rpcnb(Spcfsys
*fs
, Spfcall
*tc
, void (*cb
)(void *, Spfcall
*), void *cba
)
520 sp_werror("disconnected", ECONNRESET
);
525 sp_werror(fs
->ename
, fs
->ecode
);
529 req
= sp_malloc(sizeof(*req
));
533 if (tc
->type
!= Tversion
) {
534 tc
->tag
= spc_get_id(fs
->tagpool
);
535 if (tc
->tag
== NOTAG
) {
537 sp_werror("tag pool full", EIO
);
541 sp_set_tag(tc
, tc
->tag
);
554 fs
->pend_last
->next
= req
;
556 fs
->pend_first
= req
;
559 if (!fs
->pend_first
->next
&& spfd_can_write(fs
->spfd
))
570 spc_rpc_cb(void *cba
, Spfcall
*rc
)
578 sp_rerror(&ename
, &ecode
);
580 ename
= r
->fs
->ename
;
581 ecode
= r
->fs
->ecode
;
586 r
->ename
= strdup(ename
);
595 spc_rpc(Spcfsys
*fs
, Spfcall
*tc
, Spfcall
**rc
)
609 spc_rpcnb(fs
, tc
, spc_rpc_cb
, &r
);
610 while (!r
.ename
&& !r
.rc
)
614 sp_werror(r
.ename
, r
.ecode
);
618 if (r
.rc
&& r
.rc
->type
== Rerror
) {
619 ename
= sp_strdup(&r
.rc
->ename
);
621 sp_werror(ename
, r
.rc
->ecode
);
636 if (r
.ename
!= Enomem
)
643 spc_fcall_alloc(u32 msize
)
647 fc
= sp_malloc(sizeof(*fc
) + msize
);
651 fc
->pkt
= (u8
*) fc
+ sizeof(*fc
);