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

# Content
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 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 MODULE = Linux::NBD PACKAGE = Linux::NBD::Client
32
33 PROTOTYPES: DISABLE
34
35 void
36 _set_sock (int dev, int fd)
37 CODE:
38 ioctl (dev, NBD_SET_SOCK, (unsigned long)fd);
39
40 void
41 _doit (int dev, int server = 0)
42 CODE:
43 if (server)
44 for (server = 0; server < 4095; server++)
45 if (server != dev)
46 close (server);
47
48 ioctl (dev, NBD_DO_IT);
49
50 if (server)
51 _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 ioctl (dev, NBD_SET_SIZE, size);
77
78 void
79 _set_size_blocks (int dev, unsigned long nblocks)
80 CODE:
81 ioctl (dev, NBD_SET_SIZE_BLOCKS, nblocks);
82
83 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 MODULE = Linux::NBD PACKAGE = Linux::NBD::Server
94
95 void
96 _one_request (SV *obj, int fd)
97 CODE:
98 {
99 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
116 if (s->req_read < sizeof (struct nbd_request))
117 {
118 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
129 if (s->req_read < sizeof (struct nbd_request))
130 XSRETURN_NO;
131 }
132
133 /* 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
162 if (s->data_read < len)
163 XSRETURN_NO;
164 }
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 XSRETURN_YES;
211 }
212
213 SV *
214 format_reply (SV *unused, SV *handle, unsigned int error = 0, SV *data = 0)
215 CODE:
216 {
217 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 }
233 OUTPUT:
234 RETVAL
235