]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/ankh/lib/libc_be_socket/sock_fs.cc
update
[l4.git] / l4 / pkg / ankh / lib / libc_be_socket / sock_fs.cc
1 #include <l4/l4re_vfs/vfs.h>
2 #include <l4/l4re_vfs/backend>
3 #include <l4/util/util.h>
4 #include <l4/sys/kdebug.h>
5 #include <l4/cxx/ref_ptr>
6 #include <errno.h>
7 #include <cstdio>
8
9 EXTERN_C_BEGIN
10 #include "lwip/sockets.h"
11 EXTERN_C_END
12
13 /*
14  * lwIP file backend for integrating lwIP sockets into L4Re VFS
15  *
16  * lwip maintains its own internal socket numbers and clients expect these to
17  * be normal file descriptors from which to read/write. L4Re's VFS however has
18  * a different view on fds and so we need an indirection that translates
19  * between VFS fds and lwIP socket IDs. This translation is used by the BSD
20  * socket API wrappers in this library to convert between these two
21  * abstractions.
22  *
23  * Every time a client application creates a socket using the socket() wrapper
24  * in this library, we register a new Socket_file with VFS. This allows us to
25  * intercept readv/writev calls to this fd and map them to lwip_read(),
26  * lwip_write().
27  */
28 class Socket_file : public L4Re::Vfs::Be_file
29 {
30         private:
31                 int _lwip_fd; // underlying lwIP file descriptor
32                 bool _connected; // socket connected?
33
34         public:
35                 /* _connected is initially false, as we cannot read/write
36                  * from a socket until it has been connected/bound
37                  */
38                 explicit Socket_file(int lwip_fd = -1) throw()
39                     : L4Re::Vfs::Be_file(),
40                       _lwip_fd(lwip_fd),
41                       _connected(false)
42                 { }
43
44
45                 ~Socket_file() throw()
46                 {
47                         if (_lwip_fd > 0)
48                                 lwip_close(_lwip_fd);
49                 }
50
51                 bool connected() { return _connected; }
52                 void connected(bool t) { _connected = t; }
53
54                 int lwip_fd() { return _lwip_fd; }
55
56                 ssize_t readv(const struct iovec*, int) throw();
57                 ssize_t writev(const struct iovec*, int) throw();
58                 
59                 // should be in L4Re::Vfs::Be_file ?
60                 int fstat64(struct stat64 *) const throw()
61                 { return -EINVAL; }
62 };
63
64
65 ssize_t Socket_file::readv(const struct iovec* iov,
66                            int iov_cnt) throw()
67 {
68         ssize_t read_cnt = 0;
69
70         if (!connected()) {
71                 errno = EINVAL;
72                 return -1;
73         }
74
75         for (int i = 0; i < iov_cnt; ++i)
76                 read_cnt += lwip_read(_lwip_fd, iov[i].iov_base,
77                                                           iov[i].iov_len);
78
79         return read_cnt;
80 }
81
82
83 ssize_t Socket_file::writev(const struct iovec* iov,
84                             int iov_cnt) throw()
85 {
86         ssize_t write_cnt = 0;
87
88         if (!connected()) {
89                 errno = EINVAL;
90                 return -1;
91         }
92
93         for (int i = 0; i < iov_cnt; ++i)
94                 write_cnt += lwip_write(_lwip_fd, iov[i].iov_base,
95                                                                 iov[i].iov_len);
96
97         return write_cnt;
98 }
99
100
101 EXTERN_C int assign_fd_to_socket(int sockfd)
102 {
103         using cxx::Ref_ptr;
104
105         Ref_ptr<Socket_file> f(new Socket_file(sockfd));
106         int vfs_fd = L4Re::Vfs::vfs_ops->alloc_fd(f);
107
108         return vfs_fd;
109 }
110
111
112 EXTERN_C int socket_for_fd(int sock)
113 {
114         using namespace cxx;
115
116         // XXX: why doesn't ref_ptr_static_cast() work?
117         Ref_ptr<L4Re::Vfs::File> vf = L4Re::Vfs::vfs_ops->get_file(sock);
118         Ref_ptr<Socket_file> f = ref_ptr(static_cast<Socket_file*>(vf.ptr()));
119         return f->lwip_fd();
120 }
121
122
123 EXTERN_C void mark_connected(int sock, int val)
124 {
125         using namespace cxx;
126         Ref_ptr<L4Re::Vfs::File> vf = L4Re::Vfs::vfs_ops->get_file(sock);
127         Ref_ptr<Socket_file> f = ref_ptr(static_cast<Socket_file*>(vf.ptr()));
128         f->connected(val == 1);
129 }