1/*
2 * Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26#include <stdlib.h>
27#include <sys/types.h>
28#include <sys/socket.h>
29#include <netinet/in.h>
30#include <arpa/inet.h>
31#include <unistd.h>
32#include <fcntl.h>
33#include <errno.h>
34#include <string.h>
35#include <sys/time.h>
36#ifdef __solaris__
37#include <thread.h>
38#else
39#include <pthread.h>
40#include <poll.h>
41#endif
42
43#include "socket_md.h"
44#include "sysSocket.h"
45
46int
47dbgsysListen(int fd, int backlog) {
48    return listen(fd, backlog);
49}
50
51int
52dbgsysConnect(int fd, struct sockaddr *name, socklen_t namelen) {
53    int rv = connect(fd, name, namelen);
54    if (rv < 0 && (errno == EINPROGRESS || errno == EINTR)) {
55        return DBG_EINPROGRESS;
56    } else {
57        return rv;
58    }
59}
60
61int
62dbgsysFinishConnect(int fd, int timeout) {
63    int rv = dbgsysPoll(fd, 0, 1, timeout);
64    if (rv == 0) {
65        return DBG_ETIMEOUT;
66    }
67    if (rv > 0) {
68        return 0;
69    }
70    return rv;
71}
72
73int
74dbgsysAccept(int fd, struct sockaddr *name, socklen_t *namelen) {
75    int rv;
76    for (;;) {
77        rv = accept(fd, name, namelen);
78        if (rv >= 0) {
79            return rv;
80        }
81        if (errno != ECONNABORTED && errno != EINTR) {
82            return rv;
83        }
84    }
85}
86
87int
88dbgsysRecvFrom(int fd, char *buf, size_t nBytes,
89                  int flags, struct sockaddr *from, socklen_t *fromlen) {
90    int rv;
91    do {
92        rv = recvfrom(fd, buf, nBytes, flags, from, fromlen);
93    } while (rv == -1 && errno == EINTR);
94
95    return rv;
96}
97
98int
99dbgsysSendTo(int fd, char *buf, size_t len,
100                int flags, struct sockaddr *to, socklen_t tolen) {
101    int rv;
102    do {
103        rv = sendto(fd, buf, len, flags, to, tolen);
104    } while (rv == -1 && errno == EINTR);
105
106    return rv;
107}
108
109int
110dbgsysRecv(int fd, char *buf, size_t nBytes, int flags) {
111    int rv;
112    do {
113        rv = recv(fd, buf, nBytes, flags);
114    } while (rv == -1 && errno == EINTR);
115
116    return rv;
117}
118
119int
120dbgsysSend(int fd, char *buf, size_t nBytes, int flags) {
121    int rv;
122    do {
123        rv = send(fd, buf, nBytes, flags);
124    } while (rv == -1 && errno == EINTR);
125
126    return rv;
127}
128
129struct hostent *
130dbgsysGetHostByName(char *hostname) {
131    return gethostbyname(hostname);
132}
133
134unsigned short
135dbgsysHostToNetworkShort(unsigned short hostshort) {
136    return htons(hostshort);
137}
138
139int
140dbgsysSocket(int domain, int type, int protocol) {
141    return socket(domain, type, protocol);
142}
143
144int dbgsysSocketClose(int fd) {
145    int rv;
146    do {
147        rv = close(fd);
148    } while (rv == -1 && errno == EINTR);
149
150    return rv;
151}
152
153int
154dbgsysBind(int fd, struct sockaddr *name, socklen_t namelen) {
155    return bind(fd, name, namelen);
156}
157
158uint32_t
159dbgsysInetAddr(const char* cp) {
160    return (uint32_t)inet_addr(cp);
161}
162
163uint32_t
164dbgsysHostToNetworkLong(uint32_t hostlong) {
165    return htonl(hostlong);
166}
167
168unsigned short
169dbgsysNetworkToHostShort(unsigned short netshort) {
170    return ntohs(netshort);
171}
172
173int
174dbgsysGetSocketName(int fd, struct sockaddr *name, socklen_t *namelen) {
175    return getsockname(fd, name, namelen);
176}
177
178uint32_t
179dbgsysNetworkToHostLong(uint32_t netlong) {
180    return ntohl(netlong);
181}
182
183
184int
185dbgsysSetSocketOption(int fd, jint cmd, jboolean on, jvalue value)
186{
187    if (cmd == TCP_NODELAY) {
188        struct protoent *proto = getprotobyname("TCP");
189        int tcp_level = (proto == 0 ? IPPROTO_TCP: proto->p_proto);
190        uint32_t onl = (uint32_t)on;
191
192        if (setsockopt(fd, tcp_level, TCP_NODELAY,
193                       (char *)&onl, sizeof(uint32_t)) < 0) {
194                return SYS_ERR;
195        }
196    } else if (cmd == SO_LINGER) {
197        struct linger arg;
198        arg.l_onoff = on;
199        arg.l_linger = (on) ? (unsigned short)value.i : 0;
200        if (setsockopt(fd, SOL_SOCKET, SO_LINGER,
201                       (char*)&arg, sizeof(arg)) < 0) {
202          return SYS_ERR;
203        }
204    } else if (cmd == SO_SNDBUF) {
205        jint buflen = value.i;
206        if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF,
207                       (char *)&buflen, sizeof(buflen)) < 0) {
208            return SYS_ERR;
209        }
210    } else if (cmd == SO_REUSEADDR) {
211        int oni = (int)on;
212        if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
213                       (char *)&oni, sizeof(oni)) < 0) {
214            return SYS_ERR;
215
216        }
217    } else {
218        return SYS_ERR;
219    }
220    return SYS_OK;
221}
222
223int
224dbgsysConfigureBlocking(int fd, jboolean blocking) {
225    int flags = fcntl(fd, F_GETFL);
226
227    if ((blocking == JNI_FALSE) && !(flags & O_NONBLOCK)) {
228        return fcntl(fd, F_SETFL, flags | O_NONBLOCK);
229    }
230    if ((blocking == JNI_TRUE) && (flags & O_NONBLOCK)) {
231        return fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
232    }
233    return 0;
234}
235
236int
237dbgsysPoll(int fd, jboolean rd, jboolean wr, long timeout) {
238    struct pollfd fds[1];
239    int rv;
240
241    fds[0].fd = fd;
242    fds[0].events = 0;
243    if (rd) {
244        fds[0].events |= POLLIN;
245    }
246    if (wr) {
247        fds[0].events |= POLLOUT;
248    }
249    fds[0].revents = 0;
250
251    rv = poll(&fds[0], 1, timeout);
252    if (rv >= 0) {
253        rv = 0;
254        if (fds[0].revents & POLLIN) {
255            rv |= DBG_POLLIN;
256        }
257        if (fds[0].revents & POLLOUT) {
258            rv |= DBG_POLLOUT;
259        }
260    }
261    return rv;
262}
263
264int
265dbgsysGetLastIOError(char *buf, jint size) {
266    char *msg = strerror(errno);
267    strncpy(buf, msg, size-1);
268    buf[size-1] = '\0';
269    return 0;
270}
271
272#ifdef __solaris__
273int
274dbgsysTlsAlloc() {
275    thread_key_t tk;
276    if (thr_keycreate(&tk, NULL)) {
277        perror("thr_keycreate");
278        exit(-1);
279    }
280    return (int)tk;
281}
282
283void
284dbgsysTlsFree(int index) {
285   /* no-op */
286}
287
288void
289dbgsysTlsPut(int index, void *value) {
290    thr_setspecific((thread_key_t)index, value) ;
291}
292
293void *
294dbgsysTlsGet(int index) {
295    void* r = NULL;
296    thr_getspecific((thread_key_t)index, &r);
297    return r;
298}
299
300#else
301int
302dbgsysTlsAlloc() {
303    pthread_key_t key;
304    if (pthread_key_create(&key, NULL)) {
305        perror("pthread_key_create");
306        exit(-1);
307    }
308    return (int)key;
309}
310
311void
312dbgsysTlsFree(int index) {
313    pthread_key_delete((pthread_key_t)index);
314}
315
316void
317dbgsysTlsPut(int index, void *value) {
318    pthread_setspecific((pthread_key_t)index, value) ;
319}
320
321void *
322dbgsysTlsGet(int index) {
323    return pthread_getspecific((pthread_key_t)index);
324}
325
326#endif
327
328long
329dbgsysCurrentTimeMillis() {
330    struct timeval t;
331    gettimeofday(&t, 0);
332    return ((jlong)t.tv_sec) * 1000 + (jlong)(t.tv_usec/1000);
333}
334