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