Tizen 2.1 base
[platform/upstream/gcd.git] / kqueue-1.0.4 / src / solaris / socket.c
1 /*
2  * Copyright (c) 2009 Mark Heily <mark@heily.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <errno.h>
18 #include <fcntl.h>
19 #include <signal.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <sys/queue.h>
23 #include <sys/socket.h>
24 #include <sys/types.h>
25 #include <string.h>
26 #include <unistd.h>
27
28 #include <port.h>
29
30 #include "sys/event.h"
31 #include "private.h"
32
33 static int
34 socket_knote_create(int port, int filter, int fd, void *udata)
35 {
36     int rv, events;
37
38     switch (filter) {
39         case EVFILT_READ:
40                 events = POLLIN;
41                 break;
42         case EVFILT_WRITE:
43                 events = POLLOUT;
44                 break;
45         default:
46                 dbg_puts("invalid filter");
47                 return (-1);
48     }
49
50     rv = port_associate(port, PORT_SOURCE_FD, fd, events, udata);
51     if (rv < 0) {
52             dbg_perror("port_associate(2)");
53             return (-1);
54         }
55
56     return (0);
57 }
58
59 static int
60 socket_knote_delete(int port, int fd)
61 {
62    if (port_dissociate(port, PORT_SOURCE_FD, fd) < 0) {
63             dbg_perror("port_dissociate(2)");
64             return (-1);
65    } else {
66         return (0);
67    }
68 }
69    
70 int
71 evfilt_socket_init(struct filter *filt)
72 {
73     return (0);
74 }
75
76 void
77 evfilt_socket_destroy(struct filter *filt)
78 {
79     ;
80 }
81
82 int
83 evfilt_socket_knote_create(struct filter *filt, struct knote *kn)
84 {
85     return socket_knote_create(filt->kf_kqueue->kq_port,
86                 kn->kev.filter, kn->kev.ident, filt);
87 }
88
89 int
90 evfilt_socket_knote_modify(struct filter *filt, struct knote *kn, 
91         const struct kevent *kev)
92 {
93     return (-1); /* STUB */
94 }
95
96 int
97 evfilt_socket_knote_delete(struct filter *filt, struct knote *kn)
98 {
99     if (kn->kev.flags & EV_DISABLE)
100         return (0);
101     else
102         return (socket_knote_delete(filt->kf_kqueue->kq_port, kn->kev.ident));
103 }
104
105 int
106 evfilt_socket_knote_enable(struct filter *filt, struct knote *kn)
107 {
108     return socket_knote_create(filt->kf_kqueue->kq_port,
109                 kn->kev.filter, kn->kev.ident, filt);
110 }
111
112 int
113 evfilt_socket_knote_disable(struct filter *filt, struct knote *kn)
114 {
115     return socket_knote_delete(filt->kf_kqueue->kq_port, kn->kev.ident);
116 }
117
118 int
119 evfilt_socket_copyout(struct filter *filt, 
120             struct kevent *dst, 
121             int nevents)
122 {
123     port_event_t *pe = (port_event_t *) pthread_getspecific(filt->kf_kqueue->kq_port_event);
124     struct knote *kn;
125
126     kn = knote_lookup(filt, pe->portev_object);
127     if (kn == NULL)
128         return (-1);
129
130     memcpy(dst, &kn->kev, sizeof(*dst));
131     if (pe->portev_events == 8) //XXX-FIXME Should be POLLHUP)
132         dst->flags |= EV_EOF;
133     else if (pe->portev_events & POLLERR)
134         dst->fflags = 1; /* FIXME: Return the actual socket error */
135           
136     if (pe->portev_events & POLLIN) {
137         if (kn->flags & KNFL_PASSIVE_SOCKET) {
138             /* On return, data contains the length of the 
139                socket backlog. This is not available under Solaris (?).
140              */
141             dst->data = 1;
142         } else {
143             /* On return, data contains the number of bytes of protocol
144                data available to read.
145              */
146 #if FIXME
147             if (ioctl(dst->ident, 
148                         (dst->filter == EVFILT_READ) ? SIOCINQ : SIOCOUTQ, 
149                         &dst->data) < 0) {
150                 /* race condition with socket close, so ignore this error */
151                 dbg_puts("ioctl(2) of socket failed");
152                 dst->data = 0;
153             }
154 #else
155             /* Workaround */
156             dst->data = 1;
157 #endif
158         }
159     }
160
161     if (kn->kev.flags & EV_DISPATCH) {
162         socket_knote_delete(filt->kf_kqueue->kq_port, kn->kev.ident);
163         KNOTE_DISABLE(kn);
164     } else if (kn->kev.flags & EV_ONESHOT) {
165         socket_knote_delete(filt->kf_kqueue->kq_port, kn->kev.ident);
166         knote_free(filt, kn);
167     } else {
168         /* Solaris automatically disassociates a FD event after it
169            is delivered. This effectively disables the knote. */
170         KNOTE_DISABLE(kn);
171     }
172
173     return (1);
174 }
175
176 const struct filter evfilt_read = {
177     EVFILT_READ,
178     evfilt_socket_init,
179     evfilt_socket_destroy,
180     evfilt_socket_copyout,
181     evfilt_socket_knote_create,
182     evfilt_socket_knote_modify,
183     evfilt_socket_knote_delete,
184     evfilt_socket_knote_enable,
185     evfilt_socket_knote_disable,         
186 };
187
188 const struct filter evfilt_write = {
189     EVFILT_WRITE,
190     evfilt_socket_init,
191     evfilt_socket_destroy,
192     evfilt_socket_copyout,
193     evfilt_socket_knote_create,
194     evfilt_socket_knote_modify,
195     evfilt_socket_knote_delete,
196     evfilt_socket_knote_enable,
197     evfilt_socket_knote_disable,         
198 };