Whamcloud - gitweb
import older libsysio snapshot.
[fs/lustre-release.git] / libsysio / drivers / sockets / sockets.c
1 /*
2  *    This Cplant(TM) source code is the property of Sandia National
3  *    Laboratories.
4  *
5  *    This Cplant(TM) source code is copyrighted by Sandia National
6  *    Laboratories.
7  *
8  *    The redistribution of this Cplant(TM) source code is subject to the
9  *    terms of the GNU Lesser General Public License
10  *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
11  *
12  *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
13  *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14  *    license for use of this work by or on behalf of the US Government.
15  *    Export of this program may require a license from the United States
16  *    Government.
17  */
18
19 /*
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  * 
25  * This library is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  * 
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33  *
34  * Questions or comments about this library should be sent to:
35  *
36  * Lee Ward
37  * Sandia National Laboratories, New Mexico
38  * P.O. Box 5800
39  * Albuquerque, NM 87185-1110
40  *
41  * lee@sandia.gov
42  */
43
44 #ifdef __linux__
45 #define _BSD_SOURCE
46 #endif
47
48 #include <stdio.h>                                      /* for NULL */
49 #include <stdlib.h>
50 #ifdef __linux__
51 #include <string.h>
52 #endif
53 #include <unistd.h>
54 #include <errno.h>
55 #include <assert.h>
56 #include <syscall.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <sys/fcntl.h>
60 #include <sys/queue.h>
61 #include <sys/syscall.h>
62 #include <sys/socket.h>
63 #include <linux/net.h>
64
65 #include "sysio.h"
66 #include "fs.h"
67 #include "inode.h"
68 #include "file.h"
69 #include "dev.h"                                        /* _sysio_nodev_ops */
70
71 /*
72  * Sockets interface driver
73  */
74
75 /*
76  * Sockets file identifiers format.
77  */
78 struct sockets_ino_identifier {
79         ino_t   inum;                                   /* i-number */
80 };
81
82 /*
83  * Driver-private i-node information we keep about in-use sockets.
84  */
85 struct socket_info {
86         struct sockets_ino_identifier ski_ident;        /* unique identifier */
87         struct file_identifier ski_fileid;              /* ditto */
88         int     ski_fd;                         /* host fildes */
89 };
90
91 static int sockets_inop_close(struct inode *ino);
92 static int sockets_inop_read(struct inode *ino,
93                              struct ioctx *ioctx);
94 static int sockets_inop_write(struct inode *ino,
95                               struct ioctx *ioctxp);
96 static _SYSIO_OFF_T sockets_inop_pos(struct inode *ino,
97                                      _SYSIO_OFF_T off);
98 static int sockets_inop_iodone(struct ioctx *ioctx);
99 static int sockets_inop_sync(struct inode *ino);
100 static int sockets_inop_datasync(struct inode *ino);
101 static int sockets_inop_fcntl(struct inode *ino, int cmd, va_list ap);
102 static int sockets_inop_ioctl(struct inode *ino,
103                              unsigned long int request,
104                              va_list ap);
105 static void sockets_inop_gone(struct inode *ino);
106 static void sockets_illop(void);
107
108 /*
109  * Given i-node, return driver private part.
110  */
111 #define I2SKI(ino)      ((struct socket_info *)((ino)->i_private))
112
113 struct filesys_ops sockets_filesys_ops = {
114         (void (*)(struct filesys *))sockets_illop
115 };
116
117 static struct filesys *sockets_fs;
118
119 static struct inode_ops sockets_i_ops;
120
121 /*
122  * Initialize this driver.
123  */
124 int
125 _sysio_sockets_init()
126 {
127
128         sockets_i_ops = _sysio_nodev_ops;
129         sockets_i_ops.inop_close = sockets_inop_close;
130         sockets_i_ops.inop_read = sockets_inop_read;
131         sockets_i_ops.inop_write = sockets_inop_write;
132         sockets_i_ops.inop_pos = sockets_inop_pos;
133         sockets_i_ops.inop_iodone = sockets_inop_iodone;
134         sockets_i_ops.inop_fcntl = sockets_inop_fcntl;
135         sockets_i_ops.inop_sync = sockets_inop_sync;
136         sockets_i_ops.inop_datasync = sockets_inop_datasync;
137         sockets_i_ops.inop_ioctl = sockets_inop_ioctl;
138         sockets_i_ops.inop_gone = sockets_inop_gone;
139
140         sockets_fs = _sysio_fs_new(&sockets_filesys_ops, 0, NULL);
141         if (!sockets_fs)
142                 return -ENOMEM;
143
144         return 0;
145 }
146
147 static int
148 sockets_inop_close(struct inode *ino)
149 {
150         struct socket_info *ski = I2SKI(ino);
151         int     err;
152
153         if (ski->ski_fd < 0)
154                 return -EBADF;
155
156         err = syscall(SYS_close, ski->ski_fd);
157         if (err)
158                 return -errno;
159         ski->ski_fd = -1;
160         return 0;
161 }
162
163 /*
164  * A helper function performing the real IO operation work.
165  *
166  * We don't really have async IO. We'll just perform the function
167  * now.
168  */
169 static int
170 doio(ssize_t (*f)(int, const struct iovec *, int),
171      struct inode *ino,
172      struct ioctx *ioctx)
173 {
174         struct socket_info *ski = I2SKI(ino);
175
176         assert(ski->ski_fd >= 0);
177
178         /* XXX there's no way to check the position
179          * here we only could ingore the extends
180          */
181         if (ioctx->ioctx_xtvlen != 1)
182                 return -EINVAL;
183
184         if (ioctx->ioctx_iovlen && (int) ioctx->ioctx_iovlen < 0)
185                 return -EINVAL;
186
187         /*
188          * Call the appropriate (read/write) IO function to
189          * transfer the data now.
190          */
191         ioctx->ioctx_cc =
192             (*f)(ski->ski_fd, ioctx->ioctx_iov, ioctx->ioctx_iovlen);
193         if (ioctx->ioctx_cc < 0)
194                 ioctx->ioctx_errno = errno;
195
196         ioctx->ioctx_done = 1;
197         return 0;
198 }
199
200 /*
201  * Helper function passed to doio(), above, to accomplish a real readv.
202  */
203 static ssize_t
204 _readv(int fd, const struct iovec *vector, int count)
205 {
206
207         return syscall(SYS_readv, fd, vector, count);
208 }
209
210 static int
211 sockets_inop_read(struct inode *ino,
212                   struct ioctx *ioctx)
213 {
214
215         return doio(_readv, ino, ioctx);
216 }
217
218 /*
219  * Helper function passed to doio(), above, to accomplish a real writev.
220  */
221 static ssize_t
222 _writev(int fd, const struct iovec *vector, int count)
223 {
224
225         return syscall(SYS_writev, fd, vector, count);
226 }
227
228 static int
229 sockets_inop_write(struct inode *ino,
230                    struct ioctx *ioctx)
231 {
232
233         return doio(_writev, ino, ioctx);
234 }
235
236 static _SYSIO_OFF_T
237 sockets_inop_pos(struct inode *ino, _SYSIO_OFF_T off)
238 {
239         return -EINVAL;
240 }
241
242 static int
243 sockets_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
244 {
245
246         /*
247          * It's always done in this driver. It completed when posted.
248          */
249         return 1;
250 }
251
252 static int
253 sockets_inop_fcntl(struct inode *ino __IS_UNUSED,
254                   int cmd __IS_UNUSED,
255                   va_list ap __IS_UNUSED)
256 {
257         long arg;
258
259         assert(I2SKI(ino)->ski_fd >= 0);
260
261         switch (cmd) {
262         case F_GETFD:
263         case F_GETFL:
264         case F_GETOWN:
265                 return syscall(SYS_fcntl, I2SKI(ino)->ski_fd, cmd);
266         case F_DUPFD:
267         case F_SETFD:
268         case F_SETFL:
269         case F_GETLK:
270         case F_SETLK:
271         case F_SETLKW:
272         case F_SETOWN:
273                 arg = va_arg(ap, long);
274                 return syscall(SYS_fcntl, I2SKI(ino)->ski_fd, cmd, arg);
275         default:
276                 printf("uncatched cmd %d\n", cmd);
277                 abort();
278         }
279         return -1;
280 }
281
282 static int
283 sockets_inop_sync(struct inode *ino)
284 {
285
286         assert(I2SKI(ino)->ski_fd >= 0);
287
288         return syscall(SYS_fsync, I2SKI(ino)->ski_fd);
289 }
290
291 static int
292 sockets_inop_datasync(struct inode *ino)
293 {
294
295         assert(I2SKI(ino)->ski_fd >= 0);
296
297         return syscall(SYS_fdatasync, I2SKI(ino)->ski_fd);
298 }
299
300 static int
301 sockets_inop_ioctl(struct inode *ino __IS_UNUSED,
302                   unsigned long int request __IS_UNUSED,
303                   va_list ap __IS_UNUSED)
304 {
305         /*
306          * I'm lazy. Maybe implemented later.
307          */
308         return -ENOTTY;
309 }
310
311 static void
312 sockets_inop_gone(struct inode *ino)
313 {
314
315         (void )sockets_inop_close(ino);
316         free(ino->i_private);
317 }
318
319 static void
320 sockets_illop(void)
321 {
322
323         abort();
324 }
325
326 static struct inode *
327 _sysio_sockets_inew()
328 {
329         static ino_t inum = 1;
330         struct socket_info *ski;
331         struct inode *ino;
332
333         ski = malloc(sizeof(struct socket_info));
334         if (!ski)
335                 return NULL;
336         ski->ski_ident.inum = inum++;
337         ski->ski_fileid.fid_data = &ski->ski_ident;
338         ski->ski_fileid.fid_len = sizeof(ski->ski_ident);
339         ski->ski_fd = -1;
340
341         ino =
342             _sysio_i_new(sockets_fs,
343                          &ski->ski_fileid,
344                          0,
345                          0,
346                          0,
347                          &sockets_i_ops,
348                          ski);
349         if (!ino)
350                 free(ski);
351
352         return ino;
353 }
354
355 int
356 socket(int domain, int type, int protocol)
357 {
358         int     err;
359         struct inode *ino;
360         struct socket_info *ski;
361         struct file *fil;
362
363         err = 0;
364         fil = NULL;
365
366         ino = _sysio_sockets_inew();
367         if (!ino) {
368                 err = -ENOMEM;
369                 goto error;
370         }
371
372         ski = I2SKI(ino);
373 #ifndef SYS_socketcall
374         ski->ski_fd = syscall(SYS_socket, domain, type, protocol);
375 #else
376         {
377                 unsigned long avec[3] = {domain, type, protocol};
378                 ski->ski_fd = syscall(SYS_socketcall, SYS_SOCKET, avec);
379         }
380 #endif
381         if (ski->ski_fd < 0) {
382                 err = -errno;
383                 goto error;
384         }
385
386         fil = _sysio_fnew(ino, O_RDWR);
387         if (!fil) {
388                 err = -ENOMEM;
389                 goto error;
390         }
391
392         err = _sysio_fd_set(fil, ski->ski_fd);
393         if (err < 0)
394                 goto error;
395
396         return err;
397
398 error:
399         if (fil)
400                 F_RELE(fil);
401         if (ino)
402                 I_RELE(ino);
403
404         errno = -err;
405         return -1;
406 }
407
408 int
409 accept(int s, struct sockaddr *addr, socklen_t *addrlen)
410 {
411         int     err;
412         struct inode *ino;
413         struct socket_info *ski;
414         struct file *ofil, *nfil;
415
416         err = 0;
417         nfil = NULL;
418         ino = NULL;
419
420         ofil = _sysio_fd_find(s);
421         if (!ofil) {
422                 err = -EBADF;
423                 goto error;
424         }
425
426         ino = _sysio_sockets_inew();
427         if (!ino) {
428                 err = -ENOMEM;
429                 goto error;
430         }
431
432         nfil = _sysio_fnew(ino, O_RDWR);
433         if (!nfil) {
434                 err = -ENOMEM;
435                 goto error;
436         }
437
438         ski = I2SKI(ino);
439 #ifndef SYS_socketcall
440         ski->ski_fd = syscall(SYS_accept, I2SKI(ofil->f_ino)->ski_fd,
441                                 addr, addrlen);
442 #else
443         {
444                 unsigned long avec[3] = {
445                         (unsigned long) I2SKI(ofil->f_ino)->ski_fd,
446                         (unsigned long) addr,
447                         (unsigned long) addrlen};
448                 ski->ski_fd = syscall(SYS_socketcall, SYS_ACCEPT, avec);
449         }
450 #endif
451         if (ski->ski_fd < 0) {
452                 err = -errno;
453                 goto error;
454         }
455
456         err = _sysio_fd_set(nfil, ski->ski_fd);
457         if (err < 0)
458                 goto error;
459
460         return err;
461
462 error:
463         if (nfil)
464                 F_RELE(nfil);
465         if (ino)
466                 I_RELE(ino);
467
468         errno = -err;
469         return -1;
470 }
471
472 int
473 bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)
474 {
475         int     err;
476         struct file *fil;
477         unsigned long avec[3];
478
479         err = 0;
480
481         fil = _sysio_fd_find(sockfd);
482         if (!fil) {
483                 err = -EBADF;
484                 goto out;
485         }
486
487 #ifndef SYS_socketcall
488         if (syscall(SYS_bind, I2SKI(fil->f_ino)->ski_fd, my_addr, addrlen)) {
489 #else
490         avec[0] = I2SKI(fil->f_ino)->ski_fd;
491         avec[1] = (unsigned long )my_addr;
492         avec[2] = addrlen;
493         if (syscall(SYS_socketcall, SYS_BIND, avec) != 0) {
494 #endif
495                 err = -errno;
496                 goto out;
497         }
498
499         return 0;
500 out:
501         errno = -err;
502         return -1;
503 }
504
505 int
506 listen(int s, int backlog)
507 {
508         int     err;
509         struct file *fil;
510         unsigned long avec[2];
511
512         err = 0;
513
514         fil = _sysio_fd_find(s);
515         if (!fil) {
516                 err = -EBADF;
517                 goto out;
518         }
519
520 #ifndef SYS_socketcall
521         if (syscall(SYS_listen, I2SKI(fil->f_ino)->ski_fd, backlog) != 0) {
522 #else
523         avec[0] = I2SKI(fil->f_ino)->ski_fd;
524         avec[1] = backlog;
525         if (syscall(SYS_socketcall, SYS_LISTEN, avec) != 0) {
526 #endif
527                 err = -errno;
528                 goto out;
529         }
530
531         return 0;
532 out:
533         errno = -err;
534         return -1;
535 }
536
537 int
538 connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
539 {
540         int     err;
541         struct file *fil;
542         unsigned long avec[3];
543
544         err = 0;
545
546         fil = _sysio_fd_find(sockfd);
547         if (!fil) {
548                 err = -EBADF;
549                 goto out;
550         }
551
552 #ifndef SYS_socketcall
553         if (syscall(SYS_connect, I2SKI(fil->f_ino)->ski_fd,
554                     serv_addr, addrlen) != 0) {
555 #else
556         avec[0] = I2SKI(fil->f_ino)->ski_fd;
557         avec[1] = (unsigned long )serv_addr;
558         avec[2] = addrlen;
559         if (syscall(SYS_socketcall, SYS_CONNECT, avec) != 0) {
560 #endif
561                 err = -errno;
562                 goto out;
563         }
564
565         return 0;
566 out:
567         errno = -err;
568         return -1;
569 }