Reversed vftbl movement because of performance considerations
[cacao.git] / nat / PlainSocketImpl.c
1 /* class: java/net/PlainSocketImpl */
2
3 #include <sys/socket.h>
4 #include <sys/ioctl.h>
5 #include <netinet/tcp.h>
6
7 /*
8  * Class:     java/net/PlainSocketImpl
9  * Method:    initProto
10  * Signature: ()V
11  */
12 JNIEXPORT void JNICALL
13 Java_java_net_PlainSocketImpl_initProto (JNIEnv *env )
14 {
15     if (runverbose)
16         log_text("Java_java_net_PlainSocketImpl_initProto called");
17 }
18
19 /*
20  * Class:     java/net/PlainSocketImpl
21  * Method:    socketAccept
22  * Signature: (Ljava/net/SocketImpl;)V
23  */
24 JNIEXPORT void JNICALL
25 Java_java_net_PlainSocketImpl_socketAccept (JNIEnv *env ,  struct java_net_PlainSocketImpl* this , struct java_net_SocketImpl* sock)
26 {
27         int r;
28         int alen;
29         struct sockaddr_in addr;
30
31         if (runverbose)
32             log_text("Java_java_net_PlainSocketImpl_socketAccept called");
33
34         alen = sizeof(addr);
35 #if defined(BSD44)
36         addr.sin_len = sizeof(addr);
37 #endif
38         addr.sin_family = AF_INET;
39         addr.sin_port = htons(sock->localport);
40         addr.sin_addr.s_addr = htonl(sock->address->address);
41
42         r = threadedAccept(this->fd->fd, (struct sockaddr*)&addr, &alen);
43         if (r < 0) {
44                 exceptionptr = native_new_and_init (class_java_io_IOException);
45                 return;
46         }
47         sock->fd->fd = r;
48
49         /* Enter information into socket object */
50         alen = sizeof(addr);
51         r = getpeername(r, (struct sockaddr*)&addr, &alen);
52         if (r < 0) {
53                 exceptionptr = native_new_and_init (class_java_io_IOException);
54                 return;
55         }
56
57         sock->address->address = ntohl(addr.sin_addr.s_addr);
58         sock->port = ntohs(addr.sin_port);
59 }
60
61 /*
62  * Class:     java/net/PlainSocketImpl
63  * Method:    socketAvailable
64  * Signature: ()I
65  */
66 JNIEXPORT s4 JNICALL
67 Java_java_net_PlainSocketImpl_socketAvailable (JNIEnv *env ,  struct java_net_PlainSocketImpl* this )
68 {
69         int r;
70         int len;
71
72         if (runverbose)
73             log_text("Java_java_net_PlainSocketImpl_socketAvailable called");
74
75         r = ioctl(this->fd->fd, FIONREAD, &len);
76         if (r < 0) {
77                 exceptionptr = native_new_and_init (class_java_io_IOException);
78                 return 0;
79         }
80         return (s4)len;
81 }
82
83 /*
84  * Class:     java/net/PlainSocketImpl
85  * Method:    socketBind
86  * Signature: (Ljava/net/InetAddress;I)V
87  */
88 JNIEXPORT void JNICALL
89 Java_java_net_PlainSocketImpl_socketBind (JNIEnv *env ,  struct java_net_PlainSocketImpl* this , struct java_net_InetAddress* laddr, s4 lport)
90 {
91         int r;
92         struct sockaddr_in addr;
93         int fd;
94         int on = 1;
95         int alen;
96
97         if (runverbose)
98             log_text("Java_java_net_PlainSocketImpl_socketBind called");
99
100 #if defined(BSD44)
101         addr.sin_len = sizeof(addr);
102 #endif
103         addr.sin_family = AF_INET;
104         addr.sin_port = htons(lport);
105         addr.sin_addr.s_addr = htonl(laddr->address);
106
107         fd = this->fd->fd;
108
109         /* Allow rebinding to socket - ignore errors */
110         (void)setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&on, sizeof(on));
111         r = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
112         if (r < 0) {
113                 exceptionptr = native_new_and_init (class_java_io_IOException);
114                 return;
115         }
116
117         /* Enter information into socket object */
118         this->address = laddr;
119         if (lport == 0) {
120                 alen = sizeof(addr);
121                 r = getsockname(fd, (struct sockaddr*)&addr, &alen);
122                 if (r < 0) {
123                         exceptionptr = native_new_and_init (class_java_io_IOException);
124                         return;
125                 }
126                 lport = ntohs(addr.sin_port);
127         }
128         this->localport = lport;
129 }
130
131 /*
132  * Class:     java/net/PlainSocketImpl
133  * Method:    socketClose
134  * Signature: ()V
135  */
136 JNIEXPORT void JNICALL
137 Java_java_net_PlainSocketImpl_socketClose (JNIEnv *env ,  struct java_net_PlainSocketImpl* this)
138 {
139         int r;
140
141         if (runverbose)
142             log_text("Java_java_net_PlainSocketImpl_socketClose called");
143
144         if (this->fd->fd != -1) {
145                 r = close(this->fd->fd);
146                 this->fd->fd = -1;
147                 if (r < 0) {
148                         exceptionptr = native_new_and_init (class_java_io_IOException);
149                         return;
150                 }
151         }
152 }
153
154 /*
155  * Class:     java/net/PlainSocketImpl
156  * Method:    socketConnect
157  * Signature: (Ljava/net/InetAddress;I)V
158  */
159 JNIEXPORT void JNICALL
160 Java_java_net_PlainSocketImpl_socketConnect (JNIEnv *env ,  struct java_net_PlainSocketImpl* this , struct java_net_InetAddress* daddr, s4 dport)
161 {
162         int fd;
163         int r;
164         struct sockaddr_in addr;
165         int alen;
166
167         if (runverbose)
168             log_text("Java_java_net_PlainSocketImpl_socketConnect called");
169
170 #if defined(BSD44)
171         addr.sin_len = sizeof(addr);
172 #endif
173         addr.sin_family = AF_INET;
174         addr.sin_port = htons(dport);
175         addr.sin_addr.s_addr = htonl(daddr->address);
176
177         fd = this->fd->fd;
178         r = threadedConnect(fd, (struct sockaddr*)&addr, sizeof(addr));
179         if (r < 0) {
180                 exceptionptr = native_new_and_init (class_java_io_IOException);
181                 return;
182         }
183
184         /* Enter information into socket object */
185         alen = sizeof(addr);
186         r = getsockname(fd, (struct sockaddr*)&addr, &alen);
187         if (r < 0) {
188                 exceptionptr = native_new_and_init (class_java_io_IOException);
189                 return;
190         }
191
192         this->address = daddr;
193         this->port = dport;
194         this->localport = ntohs(addr.sin_port);
195 }
196
197 /*
198  * Class:     java/net/PlainSocketImpl
199  * Method:    socketCreate
200  * Signature: (Z)V
201  */
202 JNIEXPORT void JNICALL
203 Java_java_net_PlainSocketImpl_socketCreate (JNIEnv *env ,  struct java_net_PlainSocketImpl* this , s4 /* bool */ stream)
204 {
205         int fd;
206         int type;
207
208         if (runverbose)
209             log_text("Java_java_net_PlainSocketImpl_socketCreate called");
210
211         if (stream == 0) {
212                 type = SOCK_DGRAM;
213         }
214         else {
215                 type = SOCK_STREAM;
216         }
217
218         fd = threadedSocket(AF_INET, type, 0);
219         if (fd < 0) {
220                 exceptionptr = native_new_and_init (class_java_io_IOException);
221                 return;
222         }
223         this->fd->fd = fd;
224 }
225
226 /*
227  * Class:     java/net/PlainSocketImpl
228  * Method:    socketGetOption
229  * Signature: (I)I
230  */
231 JNIEXPORT s4 JNICALL
232 Java_java_net_PlainSocketImpl_socketGetOption (JNIEnv *env ,  struct java_net_PlainSocketImpl* this , s4 opt)
233 {
234     int level;
235     int optname;
236     void *optval;
237     int optlen;
238
239     struct linger linger;
240     int intopt;
241
242     if (runverbose)
243         log_text("Java_java_net_PlainSocketImpl_socketGetOption called");
244
245     switch (opt)
246     {
247         case /* SO_LINGER */ 0x0080 :
248             level = SOL_SOCKET;
249             optname = SO_LINGER;
250             optval = &linger;
251             optlen = sizeof(struct linger);
252             break;
253
254         case /* TCP_NODELAY */ 0x0001 :
255             level = IPPROTO_TCP;
256             optname = TCP_NODELAY;
257             optval = &intopt;
258             optlen = sizeof(int);
259             break;
260
261         case /* SO_SNDBUF */ 0x1001 :
262         case /* SO_RCVBUF */ 0x1002 :
263             level = SOL_SOCKET;
264             optname = (opt == 0x1001) ? SO_SNDBUF : SO_RCVBUF;
265             optval = &intopt;
266             optlen = sizeof(int);
267             break;
268
269         case /* SO_BINDADDR */ 0x000f :
270             return this->address->address;
271
272         default :
273             assert(0);
274     }
275
276     if (getsockopt(this->fd->fd, level, optname, optval, &optlen) == -1)
277         exceptionptr = native_new_and_init(class_java_net_SocketException);
278
279     switch (optname)
280     {
281         case SO_LINGER :
282             if (linger.l_onoff)
283                 return linger.l_linger;
284             return -1;
285
286         case TCP_NODELAY :
287             if (intopt)
288                 return 1;
289             return -1;          /* -1 == false? */
290
291         case SO_SNDBUF :
292         case SO_RCVBUF :
293             return intopt;
294     }
295
296     assert(0);
297
298     return 0;
299 }
300
301 /*
302  * Class:     java/net/PlainSocketImpl
303  * Method:    socketListen
304  * Signature: (I)V
305  */
306 JNIEXPORT void JNICALL
307 Java_java_net_PlainSocketImpl_socketListen (JNIEnv *env ,  struct java_net_PlainSocketImpl* this , s4 count)
308 {
309         int r;
310
311         if (runverbose)
312             log_text("java_net_PlainSocketImpl_socketListen called");
313
314         r = listen(this->fd->fd, count);
315         if (r < 0) {
316                 exceptionptr = native_new_and_init (class_java_io_IOException);
317                 return;
318         }
319 }
320
321 /*
322  * Class:     java/net/PlainSocketImpl
323  * Method:    socketSetOption
324  * Signature: (IZLjava/lang/Object;)V
325  */
326 JNIEXPORT void JNICALL
327 Java_java_net_PlainSocketImpl_socketSetOption (JNIEnv *env,
328                                                struct java_net_PlainSocketImpl* this , s4 cmd, s4 /* bool */ on, struct java_lang_Object* value)
329 {
330     int level;
331     int optname;
332     void *optval;
333     int optlen;
334
335     struct linger linger;
336     int nodelay;
337     int bufsize;
338
339     if (runverbose)
340         log_text("Java_java_net_PlainSocketImpl_socketSetOption called");
341
342     switch (cmd)
343     {
344         case /* SO_LINGER */ 0x0080 :
345             if (on)
346             {
347                 linger.l_onoff = 1;
348                 linger.l_linger = ((java_lang_Integer*)value)->value;
349             }
350             else
351                 linger.l_onoff = 0;
352
353             level = SOL_SOCKET;
354             optname = SO_LINGER;
355             optval = &linger;
356             optlen = sizeof(struct linger);
357             break;
358
359         case /* TCP_NODELAY */ 0x0001 :
360             nodelay = on ? 1 : 0;
361
362             level = IPPROTO_TCP;
363             optname = TCP_NODELAY;
364             optval = &nodelay;
365             optlen = sizeof(int);
366             break;
367
368         case /* SO_SNDBUF */ 0x1001 :
369         case /* SO_RCVBUF */ 0x1002 :
370             bufsize = ((java_lang_Integer*)value)->value;
371
372             level = SOL_SOCKET;
373             optname = (cmd == 0x1001) ? SO_SNDBUF : SO_RCVBUF;
374             optval = &bufsize;
375             optlen = sizeof(int);
376             break;
377
378         default :
379             assert(0);
380     }
381
382     if (setsockopt(this->fd->fd, level, optname, optval, optlen) == -1)
383         exceptionptr = native_new_and_init(class_java_net_SocketException);
384 }