Whamcloud - gitweb
Land b_release_1_4_6 onto HEAD (20060223_1455)
[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/syscall.h>
61 #include <sys/socket.h>
62 #ifdef __linux__
63 #include <linux/net.h>
64 #endif
65 #include <sys/uio.h>
66 #include <sys/queue.h>
67
68 #include "sysio.h"
69 #include "xtio.h"
70 #include "native.h"
71 #include "fs.h"
72 #include "inode.h"
73 #include "file.h"
74 #include "dev.h"                                        /* _sysio_nodev_ops */
75
76 /*
77  * Sockets interface driver
78  */
79
80 /*
81  * Sockets file identifiers format.
82  */
83 struct sockets_ino_identifier {
84         ino_t   inum;                                   /* i-number */
85 };
86
87 /*
88  * Driver-private i-node information we keep about in-use sockets.
89  */
90 struct socket_info {
91         struct sockets_ino_identifier ski_ident;        /* unique identifier */
92         struct file_identifier ski_fileid;              /* ditto */
93         int     ski_fd;                         /* host fildes */
94 };
95
96 static int sockets_inop_close(struct inode *ino);
97 static int sockets_inop_read(struct inode *ino,
98                              struct ioctx *ioctx);
99 static int sockets_inop_write(struct inode *ino,
100                               struct ioctx *ioctxp);
101 static _SYSIO_OFF_T sockets_inop_pos(struct inode *ino,
102                                      _SYSIO_OFF_T off);
103 static int sockets_inop_iodone(struct ioctx *ioctx);
104 static int sockets_inop_sync(struct inode *ino);
105 static int sockets_inop_datasync(struct inode *ino);
106 static int sockets_inop_fcntl(struct inode *ino, int cmd, va_list ap, int *rtn);
107 static int sockets_inop_ioctl(struct inode *ino,
108                              unsigned long int request,
109                              va_list ap);
110 static void sockets_inop_gone(struct inode *ino);
111 static void sockets_illop(void);
112
113 /*
114  * Given i-node, return driver private part.
115  */
116 #define I2SKI(ino)      ((struct socket_info *)((ino)->i_private))
117
118 struct filesys_ops sockets_filesys_ops = {
119         (void (*)(struct filesys *))sockets_illop
120 };
121
122 static struct filesys *sockets_fs = NULL;
123
124 static struct inode_ops sockets_i_ops;
125
126 /*
127  * Initialize this driver.
128  */
129 int
130 _sysio_sockets_init()
131 {
132
133         assert(!sockets_fs);
134
135         sockets_i_ops = _sysio_nodev_ops;
136         sockets_i_ops.inop_close = sockets_inop_close;
137         sockets_i_ops.inop_read = sockets_inop_read;
138         sockets_i_ops.inop_write = sockets_inop_write;
139         sockets_i_ops.inop_pos = sockets_inop_pos;
140         sockets_i_ops.inop_iodone = sockets_inop_iodone;
141         sockets_i_ops.inop_fcntl = sockets_inop_fcntl;
142         sockets_i_ops.inop_sync = sockets_inop_sync;
143         sockets_i_ops.inop_datasync = sockets_inop_datasync;
144         sockets_i_ops.inop_ioctl = sockets_inop_ioctl;
145         sockets_i_ops.inop_gone = sockets_inop_gone;
146
147         sockets_fs = _sysio_fs_new(&sockets_filesys_ops, 0, NULL);
148         if (!sockets_fs)
149                 return -ENOMEM;
150
151         return 0;
152 }
153
154 static int
155 sockets_inop_close(struct inode *ino)
156 {
157         struct socket_info *ski = I2SKI(ino);
158         int     err;
159
160         if (ski->ski_fd < 0)
161                 return -EBADF;
162
163         err = syscall(SYSIO_SYS_close, ski->ski_fd);
164         if (err)
165                 return -errno;
166         ski->ski_fd = -1;
167         return 0;
168 }
169
170 /*
171  * A helper function performing the real IO operation work.
172  *
173  * We don't really have async IO. We'll just perform the function
174  * now.
175  */
176 static int
177 doio(ssize_t (*f)(int, const struct iovec *, int),
178      struct inode *ino,
179      struct ioctx *ioctx)
180 {
181         struct socket_info *ski = I2SKI(ino);
182
183         assert(ski->ski_fd >= 0);
184
185         /* XXX there's no way to check the position
186          * here we only could ingore the extends
187          */
188         if (ioctx->ioctx_xtvlen != 1)
189                 return -EINVAL;
190
191         if (ioctx->ioctx_iovlen && (int) ioctx->ioctx_iovlen < 0)
192                 return -EINVAL;
193
194         /*
195          * Call the appropriate (read/write) IO function to
196          * transfer the data now.
197          */
198         ioctx->ioctx_cc =
199             (*f)(ski->ski_fd, ioctx->ioctx_iov, ioctx->ioctx_iovlen);
200         if (ioctx->ioctx_cc < 0)
201                 ioctx->ioctx_errno = errno;
202
203         ioctx->ioctx_done = 1;
204         return 0;
205 }
206
207 /*
208  * Helper function passed to doio(), above, to accomplish a real readv.
209  */
210 static ssize_t
211 _readv(int fd, const struct iovec *vector, int count)
212 {
213
214         return syscall(SYSIO_SYS_readv, fd, vector, count);
215 }
216
217 static int
218 sockets_inop_read(struct inode *ino,
219                   struct ioctx *ioctx)
220 {
221
222         return doio(_readv, ino, ioctx);
223 }
224
225 /*
226  * Helper function passed to doio(), above, to accomplish a real writev.
227  */
228 static ssize_t
229 _writev(int fd, const struct iovec *vector, int count)
230 {
231
232         return syscall(SYSIO_SYS_writev, fd, vector, count);
233 }
234
235 static int
236 sockets_inop_write(struct inode *ino,
237                    struct ioctx *ioctx)
238 {
239
240         return doio(_writev, ino, ioctx);
241 }
242
243 static _SYSIO_OFF_T
244 sockets_inop_pos(struct inode *ino __IS_UNUSED, _SYSIO_OFF_T off __IS_UNUSED)
245 {
246         return -EINVAL;
247 }
248
249 static int
250 sockets_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
251 {
252
253         /*
254          * It's always done in this driver. It completed when posted.
255          */
256         return 1;
257 }
258
259 static int
260 sockets_inop_fcntl(struct inode *ino __IS_UNUSED,
261                   int cmd __IS_UNUSED,
262                   va_list ap __IS_UNUSED,
263                   int *rtn)
264 {
265         long arg;
266
267         assert(I2SKI(ino)->ski_fd >= 0);
268
269         switch (cmd) {
270         case F_GETFD:
271         case F_GETFL:
272         case F_GETOWN:
273                 *rtn = syscall(SYSIO_SYS_fcntl, I2SKI(ino)->ski_fd, cmd);
274                 break;
275         case F_DUPFD:
276         case F_SETFD:
277         case F_SETFL:
278         case F_GETLK:
279         case F_SETLK:
280         case F_SETLKW:
281         case F_SETOWN:
282                 arg = va_arg(ap, long);
283                 *rtn = syscall(SYSIO_SYS_fcntl, I2SKI(ino)->ski_fd, cmd, arg);
284                 break;
285         default:
286                 *rtn = -1;
287                 errno = EINVAL;
288         }
289         return *rtn == -1 ? -errno : 0;
290 }
291
292 static int
293 sockets_inop_sync(struct inode *ino)
294 {
295
296         assert(I2SKI(ino)->ski_fd >= 0);
297
298         return syscall(SYSIO_SYS_fsync, I2SKI(ino)->ski_fd);
299 }
300
301 static int
302 sockets_inop_datasync(struct inode *ino)
303 {
304
305         assert(I2SKI(ino)->ski_fd >= 0);
306
307         return syscall(SYSIO_SYS_fdatasync, I2SKI(ino)->ski_fd);
308 }
309
310 #ifdef HAVE_LUSTRE_HACK
311 /*
312  * we blindly extract 4 params and pass to host kernel, the stack
313  * should be ok. hope no ioctl will consume more then 4 params...
314  */
315 static int
316 sockets_inop_ioctl(struct inode *ino,
317                   unsigned long int request,
318                   va_list ap)
319 {
320         long arg1, arg2, arg3, arg4;
321
322         assert(I2SKI(ino)->ski_fd >= 0);
323
324         arg1 = va_arg(ap, long);
325         arg2 = va_arg(ap, long);
326         arg3 = va_arg(ap, long);
327         arg4 = va_arg(ap, long);
328
329         return syscall(SYSIO_SYS_ioctl, I2SKI(ino)->ski_fd, request,
330                        arg1, arg2, arg3, arg4);
331 }
332 #else
333 static int
334 sockets_inop_ioctl(struct inode *ino __IS_UNUSED,
335                   unsigned long int request __IS_UNUSED,
336                   va_list ap __IS_UNUSED)
337 {
338         /*
339          * I'm lazy. Maybe implemented later.
340          */
341         return -ENOTTY;
342 }
343 #endif
344
345 static void
346 sockets_inop_gone(struct inode *ino)
347 {
348
349         (void )sockets_inop_close(ino);
350         free(ino->i_private);
351 }
352
353 static void
354 sockets_illop(void)
355 {
356
357         abort();
358 }
359
360 static struct inode *
361 _sysio_sockets_inew()
362 {
363         static ino_t inum = 1;
364         struct socket_info *ski;
365         struct inode *ino;
366         static struct intnl_stat zero_stat;
367
368         ski = malloc(sizeof(struct socket_info));
369         if (!ski)
370                 return NULL;
371         ski->ski_ident.inum = inum++;
372         ski->ski_fileid.fid_data = &ski->ski_ident;
373         ski->ski_fileid.fid_len = sizeof(ski->ski_ident);
374         ski->ski_fd = -1;
375
376         ino =
377             _sysio_i_new(sockets_fs,
378                          &ski->ski_fileid,
379                          &zero_stat,
380                          0,
381                          &sockets_i_ops,
382                          ski);
383         if (!ino)
384                 free(ski);
385
386         return ino;
387 }
388
389 int
390 SYSIO_INTERFACE_NAME(socket)(int domain, int type, int protocol)
391 {
392         int     err;
393         struct inode *ino;
394         struct socket_info *ski;
395         struct file *fil;
396
397         err = 0;
398         fil = NULL;
399
400         ino = _sysio_sockets_inew();
401         if (!ino) {
402                 err = -ENOMEM;
403                 goto error;
404         }
405
406         ski = I2SKI(ino);
407 #ifndef SYSIO_SYS_socketcall
408         ski->ski_fd = syscall(SYSIO_SYS_socket, domain, type, protocol);
409 #else
410         {
411                 unsigned long avec[3] = {domain, type, protocol};
412                 ski->ski_fd =
413                     syscall(SYSIO_SYS_socketcall, SYS_SOCKET, avec);
414         }
415 #endif
416         if (ski->ski_fd < 0) {
417                 err = -errno;
418                 goto error;
419         }
420
421         fil = _sysio_fnew(ino, O_RDWR);
422         if (!fil) {
423                 err = -ENOMEM;
424                 goto error;
425         }
426
427 #ifdef HAVE_LUSTRE_HACK
428         err = _sysio_fd_set(fil, ski->ski_fd, 1);
429 #else
430         err = _sysio_fd_set(fil, -1, 0);
431 #endif
432         if (err < 0)
433                 goto error;
434
435         return err;
436
437 error:
438         if (fil)
439                 F_RELE(fil);
440         if (ino)
441                 I_RELE(ino);
442
443         errno = -err;
444         return -1;
445 }
446
447 int
448 SYSIO_INTERFACE_NAME(accept)(int s, struct sockaddr *addr, socklen_t *addrlen)
449 {
450         int     err;
451         struct inode *ino;
452         struct socket_info *ski;
453         struct file *ofil, *nfil;
454
455         err = 0;
456         nfil = NULL;
457         ino = NULL;
458
459         ofil = _sysio_fd_find(s);
460         if (!ofil) {
461                 err = -EBADF;
462                 goto error;
463         }
464
465         ino = _sysio_sockets_inew();
466         if (!ino) {
467                 err = -ENOMEM;
468                 goto error;
469         }
470
471         nfil = _sysio_fnew(ino, O_RDWR);
472         if (!nfil) {
473                 err = -ENOMEM;
474                 goto error;
475         }
476
477         ski = I2SKI(ino);
478 #ifndef SYSIO_SYS_socketcall
479         ski->ski_fd =
480             syscall(SYSIO_SYS_accept,
481                     I2SKI(ofil->f_ino)->ski_fd,
482                     addr,
483                     addrlen);
484 #else
485         {
486                 unsigned long avec[3] = {
487                         (unsigned long) I2SKI(ofil->f_ino)->ski_fd,
488                         (unsigned long) addr,
489                         (unsigned long) addrlen};
490                 ski->ski_fd =
491                     syscall(SYSIO_SYS_socketcall, SYS_ACCEPT, avec);
492         }
493 #endif
494         if (ski->ski_fd < 0) {
495                 err = -errno;
496                 goto error;
497         }
498
499 #ifdef HAVE_LUSTRE_HACK
500         err = _sysio_fd_set(nfil, ski->ski_fd, 1);
501 #else
502         err = _sysio_fd_set(nfil, -1, 0);
503 #endif
504         if (err < 0)
505                 goto error;
506
507         return err;
508
509 error:
510         if (nfil)
511                 F_RELE(nfil);
512         if (ino)
513                 I_RELE(ino);
514
515         errno = -err;
516         return -1;
517 }
518
519 int
520 SYSIO_INTERFACE_NAME(bind)(int sockfd,
521                            const struct sockaddr *my_addr,
522                            socklen_t addrlen)
523 {
524         int     err;
525         struct file *fil;
526         unsigned long avec[3];
527
528         err = 0;
529
530         fil = _sysio_fd_find(sockfd);
531         if (!fil) {
532                 err = -EBADF;
533                 goto out;
534         }
535
536 #ifndef SYSIO_SYS_socketcall
537         if (syscall(SYSIO_SYS_bind,
538                     I2SKI(fil->f_ino)->ski_fd,
539                     my_addr,
540                     addrlen)) {
541 #else
542         avec[0] = I2SKI(fil->f_ino)->ski_fd;
543         avec[1] = (unsigned long )my_addr;
544         avec[2] = addrlen;
545         if (syscall(SYSIO_SYS_socketcall, SYS_BIND, avec) != 0) {
546 #endif
547                 err = -errno;
548                 goto out;
549         }
550
551         return 0;
552 out:
553         errno = -err;
554         return -1;
555 }
556
557 int
558 SYSIO_INTERFACE_NAME(listen)(int s, int backlog)
559 {
560         int     err;
561         struct file *fil;
562         unsigned long avec[2];
563
564         err = 0;
565
566         fil = _sysio_fd_find(s);
567         if (!fil) {
568                 err = -EBADF;
569                 goto out;
570         }
571
572 #ifndef SYSIO_SYS_socketcall
573         if (syscall(SYSIO_SYS_listen,
574                     I2SKI(fil->f_ino)->ski_fd,
575                     backlog) != 0) {
576 #else
577         avec[0] = I2SKI(fil->f_ino)->ski_fd;
578         avec[1] = backlog;
579         if (syscall(SYSIO_SYS_socketcall, SYS_LISTEN, avec) != 0) {
580 #endif
581                 err = -errno;
582                 goto out;
583         }
584
585         return 0;
586 out:
587         errno = -err;
588         return -1;
589 }
590
591 int
592 SYSIO_INTERFACE_NAME(connect)(int sockfd,
593                               const struct sockaddr *serv_addr,
594                               socklen_t addrlen)
595 {
596         int     err;
597         struct file *fil;
598         unsigned long avec[3];
599
600         err = 0;
601
602         fil = _sysio_fd_find(sockfd);
603         if (!fil) {
604                 err = -EBADF;
605                 goto out;
606         }
607
608 #ifndef SYSIO_SYS_socketcall
609         if (syscall(SYSIO_SYS_connect,
610                     I2SKI(fil->f_ino)->ski_fd,
611                     serv_addr,
612                     addrlen) != 0) {
613 #else
614         avec[0] = I2SKI(fil->f_ino)->ski_fd;
615         avec[1] = (unsigned long )serv_addr;
616         avec[2] = addrlen;
617         if (syscall(SYSIO_SYS_socketcall, SYS_CONNECT, avec) != 0) {
618 #endif
619                 err = -errno;
620                 goto out;
621         }
622
623         return 0;
624 out:
625         errno = -err;
626         return -1;
627 }