OSDN Git Service

1999-05-26 Bryce McKinlay <bryce@albatross.co.nz>
[pf3gnuchains/gcc-fork.git] / libjava / java / net / natPlainSocketImpl.cc
1 /* Copyright (C) 1998, 1999  Cygnus Solutions
2
3    This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8
9 #include <config.h>
10
11 #include <sys/types.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <netinet/tcp.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include <cni.h>
20 #include <javaprims.h>
21 #include <java/io/IOException.h>
22 #include <java/io/FileDescriptor.h>
23 #include <java/net/BindException.h>
24 #include <java/net/ConnectException.h>
25 #include <java/net/PlainSocketImpl.h>
26 #include <java/net/InetAddress.h>
27 #include <java/net/SocketException.h>
28 #include <java/lang/InternalError.h>
29 #include <java/lang/Object.h>
30 #include <java/lang/Boolean.h>
31 #include <java/lang/Class.h>
32 #include <java/lang/Integer.h>
33
34 #ifndef HAVE_SOCKLEN_T
35 typedef int socklen_t;
36 #endif
37
38 union SockAddr
39 {
40   struct sockaddr_in address;
41 #ifdef HAVE_INET6
42   struct sockaddr_in6 address6;
43 #endif
44 };
45
46 void
47 java::net::PlainSocketImpl::create (jboolean stream)
48 {
49   int sock = ::socket (AF_INET, stream ? SOCK_STREAM : SOCK_DGRAM, 0);
50   if (sock < 0)
51     {
52       char msg[100];
53       char* strerr = strerror (errno);
54       sprintf (msg, "SocketImpl.create: %.*s", 80, strerr);
55       JvThrow (new java::io::IOException (JvNewStringUTF (msg)));
56     }
57   fnum = sock;
58   fd = new java::io::FileDescriptor (sock);
59 }
60
61 void
62 java::net::PlainSocketImpl::bind (java::net::InetAddress *host, jint lport)
63 {
64   union SockAddr u;
65   jbyteArray haddress = host->address;
66   jbyte *bytes = elements (haddress);
67   int len = haddress->length;
68   struct sockaddr *ptr = (struct sockaddr *) &u.address;
69   if (len == 4)
70     {
71       u.address.sin_family = AF_INET;
72       memcpy (&u.address.sin_addr, bytes, len);
73       len = sizeof (struct sockaddr_in);
74       u.address.sin_port = htons (lport);
75     }
76 #ifdef HAVE_INET6
77   else if (len == 16)
78     {
79       u.address6.sin6_family = AF_INET6;
80       memcpy (&u.address6.sin6_addr, bytes, len);
81       len = sizeof (struct sockaddr_in6);
82       u.address6.sin6_port = htons (lport);
83     }
84 #endif
85   else
86     goto error;
87   if (::bind (fnum, ptr, len) == 0)
88     {
89       address = host;
90       localport = lport;
91       return;
92     }
93  error:
94   char msg[100];
95   char* strerr = strerror (errno);
96   sprintf (msg, "SocketImpl.bind: %.*s", 80, strerr);
97   JvThrow (new java::net::BindException (JvNewStringUTF (msg)));
98 }
99
100 void
101 java::net::PlainSocketImpl::connect (java::net::InetAddress *host, jint rport)
102 {
103   union SockAddr u;
104   socklen_t addrlen = sizeof(u);
105   jbyteArray haddress = host->address;
106   jbyte *bytes = elements (haddress);
107   int len = haddress->length;
108   struct sockaddr *ptr = (struct sockaddr *) &u.address;
109   if (len == 4)
110     {
111       u.address.sin_family = AF_INET;
112       memcpy (&u.address.sin_addr, bytes, len);
113       len = sizeof (struct sockaddr_in);
114       u.address.sin_port = htons (rport);
115     }
116 #ifdef HAVE_INET6
117   else if (len == 16)
118     {
119       u.address6.sin6_family = AF_INET6;
120       memcpy (&u.address6.sin6_addr, bytes, len);
121       len = sizeof (struct sockaddr_in6);
122       u.address6.sin6_port = htons (rport);
123     }
124 #endif
125   else
126     goto error;
127   if (::connect (fnum, ptr, len) != 0)
128     goto error;
129   address = host;
130   port = rport;
131   if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
132     goto error;
133   localport = ntohs (u.address.sin_port);
134   return;  
135  error:
136   char msg[100];
137   char* strerr = strerror (errno);
138   sprintf (msg, "SocketImpl.connect: %.*s", 80, strerr);
139   JvThrow (new java::net::ConnectException (JvNewStringUTF (msg)));
140 }
141
142 void
143 java::net::PlainSocketImpl::listen (jint backlog)
144 {
145   if (::listen (fnum, backlog) != 0)
146     {
147       char msg[100];
148       char* strerr = strerror (errno);
149       sprintf (msg, "SocketImpl.listen: %.*s", 80, strerr);
150       JvThrow (new java::io::IOException (JvNewStringUTF (msg)));
151     }
152 }
153
154 void
155 java::net::PlainSocketImpl::accept (java::net::PlainSocketImpl *s)
156 {
157   union SockAddr u;
158   socklen_t addrlen = sizeof(u);
159   int new_socket = ::accept (fnum, (sockaddr*) &u, &addrlen);
160   if (new_socket < 0)
161     goto error;
162   jbyteArray raddr;
163   jint rport;
164   if (u.address.sin_family == AF_INET)
165     {
166       raddr = JvNewByteArray (4);
167       memcpy (elements (raddr), &u.address.sin_addr, 4);
168       rport = ntohs (u.address.sin_port);
169     }
170 #ifdef HAVE_INET6
171   else if (u.address.sin_family == AF_INET6)
172     {
173       raddr = JvNewByteArray (16);
174       memcpy (elements (raddr), &u.address6.sin6_addr, 16);
175       rport = ntohs (u.address6.sin6_port);
176     }
177 #endif
178   else
179     goto error;
180   s->fnum = new_socket;
181   s->localport = localport;
182   s->address = new InetAddress (raddr, NULL);
183   s->port = rport;
184   s->fd = new java::io::FileDescriptor (new_socket);
185   return;
186  error:
187   char msg[100];
188   char* strerr = strerror (errno);
189   sprintf (msg, "SocketImpl.accept: %.*s", 80, strerr);
190   JvThrow (new java::io::IOException (JvNewStringUTF (msg)));
191 }
192
193 void
194 java::net::PlainSocketImpl::setOption (jint optID, java::lang::Object *value)
195 {
196   int val;
197   socklen_t val_len = sizeof (val);
198
199   if ( _Jv_IsInstanceOf(value,
200     java::lang::Class::forName(JvNewStringUTF("java.lang.Boolean"))))
201     {
202       java::lang::Boolean *boolobj = 
203         static_cast<java::lang::Boolean *> (value);
204       if (boolobj->booleanValue())
205         val = 1; 
206       else 
207         {
208           if (optID == _Jv_SO_LINGER_)
209             val = -1;
210           else
211             val = 0;
212         }
213     }
214   else  // assume value is an Integer
215     {
216       java::lang::Integer *intobj = 
217         static_cast<java::lang::Integer *> (value);          
218       val = (int) intobj->intValue();
219     }
220
221   switch (optID) 
222     {
223       case _Jv_TCP_NODELAY_ :
224 #ifdef TCP_NODELAY
225         if (::setsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
226             val_len) != 0)
227           goto error;    
228 #else
229         JvThrow (new java::lang::InternalError (
230           JvNewStringUTF ("TCP_NODELAY not supported")));      
231 #endif /* TCP_NODELAY */
232         return;
233       case _Jv_SO_LINGER_ :
234 #ifdef SO_LINGER
235         struct linger l_val;
236         l_val.l_onoff = (val != -1);
237         l_val.l_linger = val;
238         if (::setsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
239             sizeof(l_val)) != 0)
240           goto error;    
241 #else
242         JvThrow (new java::lang::InternalError (
243           JvNewStringUTF ("SO_LINGER not supported")));      
244 #endif /* SO_LINGER */
245         return;
246       case _Jv_SO_SNDBUF_ :
247       case _Jv_SO_RCVBUF_ :
248 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
249         int opt;
250         optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
251         if (::setsockopt (fnum, SOL_SOCKET, opt, (char *) &val, val_len) != 0)
252           goto error;    
253 #else
254         JvThrow (new java::lang::InternalError (
255           JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported")));
256 #endif 
257         return;
258       case _Jv_SO_BINDADDR_ :
259         JvThrow (new java::net::SocketException (
260           JvNewStringUTF ("SO_BINDADDR: read only option")));
261         return;
262       case _Jv_IP_MULTICAST_IF_ :
263         JvThrow (new java::lang::InternalError (
264           JvNewStringUTF ("IP_MULTICAST_IF: not valid for TCP")));
265         return;
266       case _Jv_SO_REUSEADDR_ :
267         JvThrow (new java::lang::InternalError (
268           JvNewStringUTF ("SO_REUSEADDR: option not implemented")));
269         return;
270       case _Jv_SO_TIMEOUT_ :
271         JvThrow (new java::lang::InternalError (
272           JvNewStringUTF ("SO_TIMEOUT: option not implemented")));
273         return;
274       default :
275         errno = ENOPROTOOPT;
276     }
277
278  error:
279   char msg[100];
280   char* strerr = strerror (errno);
281   sprintf (msg, "SocketImpl.setOption: %.*s", 80, strerr);
282   JvThrow (new java::net::SocketException (JvNewStringUTF (msg)));
283 }
284
285 java::lang::Object *
286 java::net::PlainSocketImpl::getOption (jint optID)
287 {
288   int val;
289   socklen_t val_len = sizeof(val);
290   union SockAddr u;
291   socklen_t addrlen = sizeof(u);
292   struct linger l_val;
293   socklen_t l_val_len = sizeof(l_val);
294
295   switch (optID)
296     {
297 #ifdef TCP_NODELAY
298       case _Jv_TCP_NODELAY_ :
299         if (::getsockopt (fnum, IPPROTO_TCP, TCP_NODELAY, (char *) &val,
300             &val_len) != 0)
301           goto error;
302         else
303           return new java::lang::Boolean (val != 0);
304 #else
305         JvThrow (new java::lang::InternalError (
306           JvNewStringUTF ("TCP_NODELAY not supported")));      
307 #endif       
308         break;
309
310       case _Jv_SO_LINGER_ :
311 #ifdef SO_LINGER
312         if (::getsockopt (fnum, SOL_SOCKET, SO_LINGER, (char *) &l_val,
313             &l_val_len) != 0)
314           goto error;    
315         if (l_val.l_onoff)
316           return new java::lang::Integer (l_val.l_linger);
317         else
318           return new java::lang::Boolean (false);
319 #else
320         JvThrow (new java::lang::InternalError (
321           JvNewStringUTF ("SO_LINGER not supported")));      
322 #endif
323         break;    
324       case _Jv_SO_RCVBUF_ :
325       case _Jv_SO_SNDBUF_ :
326 #if defined(SO_SNDBUF) && defined(SO_RCVBUF)
327         int opt;
328         optID == _Jv_SO_SNDBUF_ ? opt = SO_SNDBUF : opt = SO_RCVBUF;
329         if (::getsockopt (fnum, SOL_SOCKET, opt, (char *) &val, &val_len) != 0)
330           goto error;    
331         else
332           return new java::lang::Integer (val);
333 #else
334         JvThrow (new java::lang::InternalError (
335           JvNewStringUTF ("SO_RCVBUF/SO_SNDBUF not supported")));
336 #endif    
337         break;
338       case _Jv_SO_BINDADDR_:
339         jbyteArray laddr;
340         if (::getsockname (fnum, (sockaddr*) &u, &addrlen) != 0)
341           goto error;
342         if (u.address.sin_family == AF_INET)
343           {
344             laddr = JvNewByteArray (4);
345             memcpy (elements (laddr), &u.address.sin_addr, 4);
346           }
347 #ifdef HAVE_INET6
348         else if (u.address.sin_family == AF_INET6)
349           {
350             laddr = JvNewByteArray (16);
351             memcpy (elements (laddr), &u.address6.sin6_addr, 16);
352           }
353 #endif
354         else
355           goto error;
356         return new java::net::InetAddress (laddr, NULL);
357         break;
358       case _Jv_IP_MULTICAST_IF_ :
359         JvThrow (new java::lang::InternalError (
360           JvNewStringUTF ("IP_MULTICAST_IF: option not implemented")));
361         break;
362       case _Jv_SO_REUSEADDR_ :
363         JvThrow (new java::lang::InternalError (
364           JvNewStringUTF ("SO_REUSEADDR: option not implemented")));
365         break;
366       case _Jv_SO_TIMEOUT_ :
367         JvThrow (new java::lang::InternalError (
368           JvNewStringUTF ("SO_TIMEOUT: option not implemented")));
369         break;
370       default :
371         errno = ENOPROTOOPT;
372     }
373
374  error:
375   char msg[100];
376   char* strerr = strerror (errno);
377   sprintf (msg, "SocketImpl.getOption: %.*s", 80, strerr);
378   JvThrow (new java::net::SocketException (JvNewStringUTF (msg)));
379 }