1 /*
   2  * Copyright (c) 2003, 2012, Oracle and/or its affiliates. All rights reserved.
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  *
   8  *   - Redistributions of source code must retain the above copyright
   9  *     notice, this list of conditions and the following disclaimer.
  10  *
  11  *   - Redistributions in binary form must reproduce the above copyright
  12  *     notice, this list of conditions and the following disclaimer in the
  13  *     documentation and/or other materials provided with the distribution.
  14  *
  15  *   - Neither the name of Oracle nor the names of its
  16  *     contributors may be used to endorse or promote products derived
  17  *     from this software without specific prior written permission.
  18  *
  19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  20  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  21  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  23  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  24  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  26  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  27  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  28  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  29  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30  */
  31 
  32 /*
  33  * This source code is provided to illustrate the usage of a given feature
  34  * or technique and has been deliberately simplified. Additional steps
  35  * required for a production-quality application, such as security checks,
  36  * input validation and proper error handling, might not be present in
  37  * this sample code.
  38  */
  39 
  40 
  41 #include <sys/types.h>
  42 #include <sys/stat.h>
  43 #include <fcntl.h>
  44 
  45 #if !defined(LINUX) && !defined(_ALLBSD_SOURCE)
  46 #include <procfs.h>
  47 #endif
  48 
  49 #include <stdio.h>
  50 #include <stdlib.h>
  51 #include <string.h>
  52 #include <sys/socket.h>
  53 #include <sys/errno.h>
  54 #include <unistd.h>
  55 #include <errno.h>
  56 #include <dlfcn.h>
  57 #include <sys/time.h>
  58 
  59 #include <netdb.h>
  60 #include <netinet/in.h>
  61 #include <sys/param.h>
  62 #include <time.h>
  63 
  64 #include "jni.h"
  65 #include "jvm_md.h"
  66 #include "hprof.h"
  67 
  68 int
  69 md_getpid(void)
  70 {
  71     static int pid = -1;
  72 
  73     if ( pid >= 0 ) {
  74         return pid;
  75     }
  76     pid = getpid();
  77     return pid;
  78 }
  79 
  80 void
  81 md_sleep(unsigned seconds)
  82 {
  83     sleep(seconds);
  84 }
  85 
  86 void
  87 md_init(void)
  88 {
  89 #if defined(LINUX) || defined(_ALLBSD_SOURCE)
  90     /* No Hi-Res timer option? */
  91 #else
  92     if ( gdata->micro_state_accounting ) {
  93         char proc_ctl_fn[48];
  94         int  procfd;
  95 
  96         /* Turn on micro state accounting, once per process */
  97         (void)md_snprintf(proc_ctl_fn, sizeof(proc_ctl_fn),
  98                 "/proc/%d/ctl", md_getpid());
  99 
 100         procfd = open(proc_ctl_fn, O_WRONLY);
 101         if (procfd >= 0) {
 102             long ctl_op[2];
 103 
 104             ctl_op[0] = PCSET;
 105             ctl_op[1] = PR_MSACCT;
 106             (void)write(procfd, ctl_op, sizeof(ctl_op));
 107             (void)close(procfd);
 108         }
 109     }
 110 #endif
 111 }
 112 
 113 int
 114 md_connect(char *hostname, unsigned short port)
 115 {
 116     struct hostent *hentry;
 117     struct sockaddr_in s;
 118     int fd;
 119 
 120     /* create a socket */
 121     fd = socket(AF_INET, SOCK_STREAM, 0);
 122     if ( fd < 0 ) {
 123         return -1;
 124     }
 125 
 126     /* find remote host's addr from name */
 127     if ((hentry = gethostbyname(hostname)) == NULL) {
 128         (void)close(fd);
 129         return -1;
 130     }
 131     (void)memset((char *)&s, 0, sizeof(s));
 132     /* set remote host's addr; its already in network byte order */
 133     (void)memcpy(&s.sin_addr.s_addr, *(hentry->h_addr_list),
 134            (int)sizeof(s.sin_addr.s_addr));
 135     /* set remote host's port */
 136     s.sin_port = htons(port);
 137     s.sin_family = AF_INET;
 138 
 139     /* now try connecting */
 140     if (-1 == connect(fd, (struct sockaddr*)&s, sizeof(s))) {
 141         (void)close(fd);
 142         return 0;
 143     }
 144     return fd;
 145 }
 146 
 147 int
 148 md_recv(int f, char *buf, int len, int option)
 149 {
 150     return recv(f, buf, len, option);
 151 }
 152 
 153 int
 154 md_shutdown(int filedes, int option)
 155 {
 156     return shutdown(filedes, option);
 157 }
 158 
 159 int
 160 md_open(const char *filename)
 161 {
 162     return open(filename, O_RDONLY);
 163 }
 164 
 165 int
 166 md_open_binary(const char *filename)
 167 {
 168     return md_open(filename);
 169 }
 170 
 171 int
 172 md_creat(const char *filename)
 173 {
 174     return open(filename, O_WRONLY | O_CREAT | O_TRUNC,
 175             S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 176 }
 177 
 178 int
 179 md_creat_binary(const char *filename)
 180 {
 181     return md_creat(filename);
 182 }
 183 
 184 jlong
 185 md_seek(int filedes, jlong cur)
 186 {
 187     jlong new_pos;
 188 
 189     if ( cur == (jlong)-1 ) {
 190         new_pos = lseek(filedes, 0, SEEK_END);
 191     } else {
 192         new_pos = lseek(filedes, cur, SEEK_SET);
 193     }
 194     return new_pos;
 195 }
 196 
 197 void
 198 md_close(int filedes)
 199 {
 200     (void)close(filedes);
 201 }
 202 
 203 int
 204 md_send(int s, const char *msg, int len, int flags)
 205 {
 206     int res;
 207 
 208     do {
 209         res = send(s, msg, len, flags);
 210     } while ((res < 0) && (errno == EINTR));
 211 
 212     return res;
 213 }
 214 
 215 int
 216 md_write(int filedes, const void *buf, int nbyte)
 217 {
 218     int res;
 219 
 220     do {
 221         res = write(filedes, buf, nbyte);
 222     } while ((res < 0) && (errno == EINTR));
 223 
 224     return res;
 225 }
 226 
 227 int
 228 md_read(int filedes, void *buf, int nbyte)
 229 {
 230     int res;
 231 
 232     do {
 233         res = read(filedes, buf, nbyte);
 234     } while ((res < 0) && (errno == EINTR));
 235 
 236     return res;
 237 }
 238 
 239 /* Time of day in milli-seconds */
 240 static jlong
 241 md_timeofday(void)
 242 {
 243     struct timeval tv;
 244 
 245     if ( gettimeofday(&tv, (void *)0) != 0 ) {
 246         return (jlong)0; /* EOVERFLOW ? */
 247     }
 248     /*LINTED*/
 249     return ((jlong)tv.tv_sec * (jlong)1000) + (jlong)(tv.tv_usec / 1000);
 250 }
 251 
 252 /* Hi-res timer in micro-seconds */
 253 jlong
 254 md_get_microsecs(void)
 255 {
 256 #if defined(LINUX) || defined(_ALLBSD_SOURCE)
 257     return (jlong)(md_timeofday() * (jlong)1000); /* Milli to micro */
 258 #else
 259     return (jlong)(gethrtime()/(hrtime_t)1000); /* Nano seconds to micro seconds */
 260 #endif
 261 }
 262 
 263 /* Time of day in milli-seconds */
 264 jlong
 265 md_get_timemillis(void)
 266 {
 267     return md_timeofday();
 268 }
 269 
 270 /* Current CPU hi-res CPU time used */
 271 jlong
 272 md_get_thread_cpu_timemillis(void)
 273 {
 274 #if defined(LINUX) || defined(_ALLBSD_SOURCE)
 275     return md_timeofday();
 276 #else
 277     return (jlong)(gethrvtime()/1000); /* Nano seconds to milli seconds */
 278 #endif
 279 }
 280 
 281 void
 282 md_get_prelude_path(char *path, int path_len, char *filename)
 283 {
 284     void *addr;
 285     char libdir[FILENAME_MAX+1];
 286     Dl_info dlinfo;
 287 
 288     libdir[0] = 0;
 289 #if defined(LINUX) || defined(_ALLBSD_SOURCE)
 290     addr = (void*)&Agent_OnLoad;
 291 #else
 292     /* Just using &Agent_OnLoad will get the first external symbol with
 293      *   this name in the first .so, which may not be libhprof.so.
 294      *   On Solaris we can actually ask for the address of our Agent_OnLoad.
 295      */
 296     addr = dlsym(RTLD_SELF, "Agent_OnLoad");
 297     /* Just in case the above didn't work (missing linker patch?). */
 298     if ( addr == NULL ) {
 299         addr = (void*)&Agent_OnLoad;
 300     }
 301 #endif
 302 
 303     /* Use dladdr() to get the full path to libhprof.so, which we use to find
 304      *  the prelude file.
 305      */
 306     dlinfo.dli_fname = NULL;
 307     (void)dladdr(addr, &dlinfo);
 308     if ( dlinfo.dli_fname != NULL ) {
 309         char * lastSlash;
 310 
 311         /* Full path to library name, need to move up one directory to 'lib' */
 312         (void)strcpy(libdir, (char *)dlinfo.dli_fname);
 313         lastSlash = strrchr(libdir, '/');
 314         if ( lastSlash != NULL ) {
 315             *lastSlash = '\0';
 316         }
 317 #ifndef __APPLE__
 318         // not sure why other platforms have to go up two levels, but on macos we only need up one
 319         lastSlash = strrchr(libdir, '/');
 320         if ( lastSlash != NULL ) {
 321             *lastSlash = '\0';
 322         }
 323 #endif /* __APPLE__ */
 324     }
 325     (void)snprintf(path, path_len, "%s/%s", libdir, filename);
 326 }
 327 
 328 
 329 int
 330 md_vsnprintf(char *s, int n, const char *format, va_list ap)
 331 {
 332     return vsnprintf(s, n, format, ap);
 333 }
 334 
 335 int
 336 md_snprintf(char *s, int n, const char *format, ...)
 337 {
 338     int ret;
 339     va_list ap;
 340 
 341     va_start(ap, format);
 342     ret = md_vsnprintf(s, n, format, ap);
 343     va_end(ap);
 344     return ret;
 345 }
 346 
 347 void
 348 md_system_error(char *buf, int len)
 349 {
 350     char *p;
 351 
 352     buf[0] = 0;
 353     p = strerror(errno);
 354     if ( p != NULL ) {
 355         (void)strcpy(buf, p);
 356     }
 357 }
 358 
 359 unsigned
 360 md_htons(unsigned short s)
 361 {
 362     return htons(s);
 363 }
 364 
 365 unsigned
 366 md_htonl(unsigned l)
 367 {
 368     return htonl(l);
 369 }
 370 
 371 unsigned
 372 md_ntohs(unsigned short s)
 373 {
 374     return ntohs(s);
 375 }
 376 
 377 unsigned
 378 md_ntohl(unsigned l)
 379 {
 380     return ntohl(l);
 381 }
 382 
 383 static void dll_build_name(char* buffer, size_t buflen,
 384                            const char* pname, const char* fname) {
 385     // Loosely based on os_solaris.cpp
 386 
 387       char *pathname = (char *)pname;
 388       while (strlen(pathname) > 0) {
 389           char *p = strchr(pathname, ':');
 390           if (p == NULL) {
 391               p = pathname + strlen(pathname);
 392           }
 393           /* check for NULL path */
 394           if (p == pathname) {
 395               continue;
 396           }
 397           (void)snprintf(buffer, buflen, "%.*s/lib%s" JNI_LIB_SUFFIX,
 398                          (p - pathname), pathname, fname);
 399 
 400           if (access(buffer, F_OK) == 0) {
 401             break;
 402           }
 403           pathname = p + 1;
 404           *buffer = '\0';
 405       }
 406 }
 407 
 408 /* Create the actual fill filename for a dynamic library.  */
 409 void
 410 md_build_library_name(char *holder, int holderlen, char *pname, char *fname)
 411 {
 412     int   pnamelen;
 413 
 414     /* Length of options directory location. */
 415     pnamelen = pname ? strlen(pname) : 0;
 416 
 417     *holder = '\0';
 418     /* Quietly truncate on buffer overflow.  Should be an error. */
 419     if (pnamelen + (int)strlen(fname) + 10 > holderlen) {
 420         return;
 421     }
 422 
 423     /* Construct path to library */
 424     if (pnamelen == 0) {
 425         (void)snprintf(holder, holderlen, "lib%s" JNI_LIB_SUFFIX, fname);
 426     } else {
 427       dll_build_name(holder, holderlen, pname, fname);
 428     }
 429 }
 430 
 431 /* Load this library (return NULL on error, and error message in err_buf) */
 432 void *
 433 md_load_library(const char *name, char *err_buf, int err_buflen)
 434 {
 435     void * result;
 436 
 437     result = dlopen(name, RTLD_LAZY);
 438     if (result == NULL) {
 439         (void)strncpy(err_buf, dlerror(), err_buflen-2);
 440         err_buf[err_buflen-1] = '\0';
 441     }
 442     return result;
 443 }
 444 
 445 /* Unload this library */
 446 void
 447 md_unload_library(void *handle)
 448 {
 449     (void)dlclose(handle);
 450 }
 451 
 452 /* Find an entry point inside this library (return NULL if not found) */
 453 void *
 454 md_find_library_entry(void *handle, const char *name)
 455 {
 456     void * sym;
 457 
 458     sym =  dlsym(handle, name);
 459     return sym;
 460 }