ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Linux-NBD/NBD.xs
Revision: 1.7
Committed: Tue Sep 21 11:51:55 2010 UTC (13 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rel-1_0
Changes since 1.6: +6 -6 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5     #include <inttypes.h>
6     #include <unistd.h>
7     #include <endian.h>
8    
9     #include <sys/ioctl.h>
10     #include <netinet/in.h>
11     #include <byteswap.h>
12    
13     typedef uint32_t u32;
14     typedef uint64_t u64;
15     #include <linux/nbd.h>
16    
17     #if __BYTE_ORDER == __BIG_ENDIAN
18     #define ntohll(netlong) (netlong)
19     #elif __BYTE_ORDER == __LITTLE_ENDIAN
20     #define ntohll(netlong) __bswap_64(netlong)
21     #else
22     error, you should not exist
23     #endif
24    
25 root 1.6 struct rstate {
26     struct nbd_request req;
27     u32 req_read; /* how many octets of req are valid */
28     u32 data_read; /* how many octets of the data sv are valid */
29     };
30    
31 root 1.1 MODULE = Linux::NBD PACKAGE = Linux::NBD::Client
32    
33 root 1.6 PROTOTYPES: DISABLE
34    
35 root 1.1 void
36     _set_sock (int dev, int fd)
37     CODE:
38     ioctl (dev, NBD_SET_SOCK, (unsigned long)fd);
39    
40     void
41 root 1.2 _doit (int dev, int server = 0)
42 root 1.1 CODE:
43 root 1.2 if (server)
44     for (server = 0; server < 4095; server++)
45     if (server != dev)
46     close (server);
47    
48 root 1.1 ioctl (dev, NBD_DO_IT);
49 root 1.2
50     if (server)
51 root 1.1 _exit (0);
52    
53     void
54     _disconnect (int dev)
55     CODE:
56     ioctl (dev, NBD_DISCONNECT);
57    
58     void
59     _clear_sock (int dev)
60     CODE:
61     ioctl (dev, NBD_CLEAR_SOCK);
62    
63     void
64     _clear_que (int dev)
65     CODE:
66     ioctl (dev, NBD_CLEAR_QUE);
67    
68     void
69     _set_blksize (int dev, unsigned long blocksize)
70     CODE:
71     ioctl (dev, NBD_SET_BLKSIZE, blocksize);
72    
73     void
74     _set_size (int dev, unsigned long size)
75     CODE:
76 root 1.5 ioctl (dev, NBD_SET_SIZE, size);
77 root 1.1
78     void
79     _set_size_blocks (int dev, unsigned long nblocks)
80     CODE:
81     ioctl (dev, NBD_SET_SIZE_BLOCKS, nblocks);
82    
83 root 1.5 void
84     _set_timeout (int dev, unsigned long timeout)
85     CODE:
86     ioctl (dev, NBD_SET_TIMEOUT, timeout);
87    
88     void
89     _print_debug (int dev)
90     CODE:
91     ioctl (dev, NBD_PRINT_DEBUG, 0);
92    
93 root 1.1 MODULE = Linux::NBD PACKAGE = Linux::NBD::Server
94    
95     void
96     _one_request (SV *obj, int fd)
97     CODE:
98 root 1.3 {
99 root 1.6 struct rstate *s;
100     u64 from;
101     u32 len;
102     char *method;
103     MAGIC *mg = mg_find (SvRV (obj), PERL_MAGIC_ext);
104    
105     if (!mg)
106     {
107     mg = sv_magicext (SvRV (obj), 0, PERL_MAGIC_ext, 0, 0, 0);
108     mg->mg_len = sizeof (struct rstate);
109     New (0, mg->mg_ptr, mg->mg_len, char);
110    
111     ((struct rstate *)mg->mg_ptr)->req_read = 0; /* initialise the state machine */
112     }
113    
114     s = (struct rstate *)mg->mg_ptr;
115 root 1.1
116 root 1.6 if (s->req_read < sizeof (struct nbd_request))
117 root 1.1 {
118 root 1.6 int res = read (fd, s->req_read + (char *)&s->req, sizeof (struct nbd_request) - s->req_read);
119    
120     if (res > 0)
121     s->req_read += res;
122     else if (res == 0)
123     XSRETURN_UNDEF; /* should req->eof */
124     else if (errno != EAGAIN && errno != EWOULDBLOCK)
125     XSRETURN_UNDEF; /* should req->error */
126    
127     s->data_read = 0;
128 root 1.7
129     if (s->req_read < sizeof (struct nbd_request))
130     XSRETURN_NO;
131 root 1.1 }
132    
133 root 1.6 /* now we have a full request, so check for data */
134     if (s->req.magic != htonl (NBD_REQUEST_MAGIC))
135     croak ("Linux::NBD::Server received illegal request magic %08lx - protocol error.\n", ntohl (s->req.magic));
136    
137     from = ntohll (s->req.from);
138     len = ntohl (s->req.len);
139    
140     switch (ntohl (s->req.type))
141     {
142     case NBD_CMD_WRITE:
143     if (!mg->mg_obj)
144     {
145     mg->mg_flags |= MGf_REFCOUNTED;
146     mg->mg_obj = NEWSV (0, len);
147     SvPOK_only (mg->mg_obj);
148     SvCUR_set (mg->mg_obj, len);
149     }
150    
151     if (s->data_read < len)
152     {
153     int res = read (fd, s->data_read + SvPVX (mg->mg_obj), len - s->data_read);
154    
155     if (res > 0)
156     s->data_read += res;
157     else if (res == 0)
158     XSRETURN_UNDEF; /* should req->eof */
159     else if (errno != EAGAIN && errno != EWOULDBLOCK)
160     XSRETURN_UNDEF; /* should req->error */
161 root 1.7
162     if (s->data_read < len)
163     XSRETURN_NO;
164 root 1.6 }
165    
166     /* fallthrough */
167     case NBD_CMD_READ:
168     s->req_read = 0;
169    
170     PUSHMARK (SP);
171     EXTEND (SP, 4);
172     PUSHs (obj);
173     PUSHs (sv_2mortal (newSVpvn (s->req.handle, sizeof (s->req.handle))));
174     PUSHs (sv_2mortal (sizeof (UV) < 8 && from > 0xffffffffUL
175     ? newSVnv (from)
176     : newSVuv (from)));
177    
178     if (mg->mg_obj)
179     {
180     PUSHs (sv_2mortal (mg->mg_obj));
181     mg->mg_obj = 0;
182     method = "req_write";
183     }
184     else
185     {
186     PUSHs (sv_2mortal (newSVuv (len)));
187     method = "req_read";
188     }
189    
190     break;
191    
192     case NBD_CMD_DISC:
193     s->req_read = 0;
194    
195     method = "req_disc";
196    
197     PUSHMARK (SP);
198     XPUSHs (obj);
199    
200     break;
201    
202     default:
203     croak ("Linux::NBD::Server received unsupported request type %d.\n", ntohl (s->req.type));
204     }
205    
206     PUTBACK;
207     call_method (method, G_DISCARD);
208     SPAGAIN;
209    
210 root 1.1 XSRETURN_YES;
211 root 1.3 }
212 root 1.1
213     SV *
214 root 1.6 format_reply (SV *unused, SV *handle, unsigned int error = 0, SV *data = 0)
215 root 1.1 CODE:
216 root 1.3 {
217 root 1.1 struct nbd_reply rep;
218     STRLEN len;
219     char *h = SvPV (handle, len);
220    
221     if (len != sizeof (rep.handle))
222     croak ("format_reply: illegal handle (length %d, should be %d)", len, sizeof (rep.handle));
223    
224     rep.magic = htonl (NBD_REPLY_MAGIC);
225     rep.error = htonl (error);
226     memcpy (rep.handle, h, sizeof (rep.handle));
227    
228     RETVAL = newSVpvn ((char *)&rep, sizeof (rep));
229    
230     if (data && !error)
231     sv_catsv (RETVAL, data);
232 root 1.3 }
233 root 1.1 OUTPUT:
234     RETVAL
235