src/os/bsd/vm/attachListener_bsd.cpp

Wed, 27 Feb 2013 09:40:30 +0100

author
simonis
date
Wed, 27 Feb 2013 09:40:30 +0100
changeset 4675
63e54c37ac64
parent 4229
0af5da0c9d9d
child 5264
e95fc50106cf
permissions
-rw-r--r--

8008959: Fix non-PCH build on Linux, Windows and MacOS X
Summary: Fix the build without precompiled headers by either including the missing ".inline.hpp" files into the appropriate files or by turning inline-functions declared in header files into ordinary functions in ".cpp" files.
Reviewed-by: coleenp, stefank, dholmes

never@3156 1 /*
sla@3648 2 * Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
never@3156 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
never@3156 4 *
never@3156 5 * This code is free software; you can redistribute it and/or modify it
never@3156 6 * under the terms of the GNU General Public License version 2 only, as
never@3156 7 * published by the Free Software Foundation.
never@3156 8 *
never@3156 9 * This code is distributed in the hope that it will be useful, but WITHOUT
never@3156 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
never@3156 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
never@3156 12 * version 2 for more details (a copy is included in the LICENSE file that
never@3156 13 * accompanied this code).
never@3156 14 *
never@3156 15 * You should have received a copy of the GNU General Public License version
never@3156 16 * 2 along with this work; if not, write to the Free Software Foundation,
never@3156 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
never@3156 18 *
never@3156 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
never@3156 20 * or visit www.oracle.com if you need additional information or have any
never@3156 21 * questions.
never@3156 22 *
never@3156 23 */
never@3156 24
never@3156 25 #include "precompiled.hpp"
never@3156 26 #include "runtime/interfaceSupport.hpp"
never@3156 27 #include "runtime/os.hpp"
never@3156 28 #include "services/attachListener.hpp"
never@3156 29 #include "services/dtraceAttacher.hpp"
never@3156 30
never@3156 31 #include <unistd.h>
never@3156 32 #include <signal.h>
never@3156 33 #include <sys/types.h>
never@3156 34 #include <sys/socket.h>
never@3156 35 #include <sys/un.h>
never@3156 36 #include <sys/stat.h>
never@3156 37
never@3156 38 #ifndef UNIX_PATH_MAX
never@3156 39 #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path)
never@3156 40 #endif
never@3156 41
never@3156 42 // The attach mechanism on Bsd uses a UNIX domain socket. An attach listener
never@3156 43 // thread is created at startup or is created on-demand via a signal from
never@3156 44 // the client tool. The attach listener creates a socket and binds it to a file
never@3156 45 // in the filesystem. The attach listener then acts as a simple (single-
never@3156 46 // threaded) server - it waits for a client to connect, reads the request,
never@3156 47 // executes it, and returns the response to the client via the socket
never@3156 48 // connection.
never@3156 49 //
never@3156 50 // As the socket is a UNIX domain socket it means that only clients on the
never@3156 51 // local machine can connect. In addition there are two other aspects to
never@3156 52 // the security:
never@3156 53 // 1. The well known file that the socket is bound to has permission 400
never@3156 54 // 2. When a client connect, the SO_PEERCRED socket option is used to
never@3156 55 // obtain the credentials of client. We check that the effective uid
never@3156 56 // of the client matches this process.
never@3156 57
never@3156 58 // forward reference
never@3156 59 class BsdAttachOperation;
never@3156 60
never@3156 61 class BsdAttachListener: AllStatic {
never@3156 62 private:
never@3156 63 // the path to which we bind the UNIX domain socket
never@3156 64 static char _path[UNIX_PATH_MAX];
never@3156 65 static bool _has_path;
never@3156 66
never@3156 67 // the file descriptor for the listening socket
never@3156 68 static int _listener;
never@3156 69
never@3156 70 static void set_path(char* path) {
never@3156 71 if (path == NULL) {
never@3156 72 _has_path = false;
never@3156 73 } else {
never@3156 74 strncpy(_path, path, UNIX_PATH_MAX);
never@3156 75 _path[UNIX_PATH_MAX-1] = '\0';
never@3156 76 _has_path = true;
never@3156 77 }
never@3156 78 }
never@3156 79
never@3156 80 static void set_listener(int s) { _listener = s; }
never@3156 81
never@3156 82 // reads a request from the given connected socket
never@3156 83 static BsdAttachOperation* read_request(int s);
never@3156 84
never@3156 85 public:
never@3156 86 enum {
never@3156 87 ATTACH_PROTOCOL_VER = 1 // protocol version
never@3156 88 };
never@3156 89 enum {
never@3156 90 ATTACH_ERROR_BADVERSION = 101 // error codes
never@3156 91 };
never@3156 92
never@3156 93 // initialize the listener, returns 0 if okay
never@3156 94 static int init();
never@3156 95
never@3156 96 static char* path() { return _path; }
never@3156 97 static bool has_path() { return _has_path; }
never@3156 98 static int listener() { return _listener; }
never@3156 99
never@3156 100 // write the given buffer to a socket
never@3156 101 static int write_fully(int s, char* buf, int len);
never@3156 102
never@3156 103 static BsdAttachOperation* dequeue();
never@3156 104 };
never@3156 105
never@3156 106 class BsdAttachOperation: public AttachOperation {
never@3156 107 private:
never@3156 108 // the connection to the client
never@3156 109 int _socket;
never@3156 110
never@3156 111 public:
never@3156 112 void complete(jint res, bufferedStream* st);
never@3156 113
never@3156 114 void set_socket(int s) { _socket = s; }
never@3156 115 int socket() const { return _socket; }
never@3156 116
never@3156 117 BsdAttachOperation(char* name) : AttachOperation(name) {
never@3156 118 set_socket(-1);
never@3156 119 }
never@3156 120 };
never@3156 121
never@3156 122 // statics
never@3156 123 char BsdAttachListener::_path[UNIX_PATH_MAX];
never@3156 124 bool BsdAttachListener::_has_path;
never@3156 125 int BsdAttachListener::_listener = -1;
never@3156 126
never@3156 127 // Supporting class to help split a buffer into individual components
never@3156 128 class ArgumentIterator : public StackObj {
never@3156 129 private:
never@3156 130 char* _pos;
never@3156 131 char* _end;
never@3156 132 public:
never@3156 133 ArgumentIterator(char* arg_buffer, size_t arg_size) {
never@3156 134 _pos = arg_buffer;
never@3156 135 _end = _pos + arg_size - 1;
never@3156 136 }
never@3156 137 char* next() {
never@3156 138 if (*_pos == '\0') {
never@3156 139 return NULL;
never@3156 140 }
never@3156 141 char* res = _pos;
never@3156 142 char* next_pos = strchr(_pos, '\0');
never@3156 143 if (next_pos < _end) {
never@3156 144 next_pos++;
never@3156 145 }
never@3156 146 _pos = next_pos;
never@3156 147 return res;
never@3156 148 }
never@3156 149 };
never@3156 150
never@3156 151
never@3156 152 // atexit hook to stop listener and unlink the file that it is
never@3156 153 // bound too.
never@3156 154 extern "C" {
never@3156 155 static void listener_cleanup() {
never@3156 156 static int cleanup_done;
never@3156 157 if (!cleanup_done) {
never@3156 158 cleanup_done = 1;
never@3156 159 int s = BsdAttachListener::listener();
never@3156 160 if (s != -1) {
never@3156 161 ::close(s);
never@3156 162 }
never@3156 163 if (BsdAttachListener::has_path()) {
never@3156 164 ::unlink(BsdAttachListener::path());
never@3156 165 }
never@3156 166 }
never@3156 167 }
never@3156 168 }
never@3156 169
never@3156 170 // Initialization - create a listener socket and bind it to a file
never@3156 171
never@3156 172 int BsdAttachListener::init() {
never@3156 173 char path[UNIX_PATH_MAX]; // socket file
never@3156 174 char initial_path[UNIX_PATH_MAX]; // socket file during setup
never@3156 175 int listener; // listener socket (file descriptor)
never@3156 176
never@3156 177 // register function to cleanup
never@3156 178 ::atexit(listener_cleanup);
never@3156 179
never@3156 180 int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d",
never@3156 181 os::get_temp_directory(), os::current_process_id());
never@3156 182 if (n < (int)UNIX_PATH_MAX) {
never@3156 183 n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path);
never@3156 184 }
never@3156 185 if (n >= (int)UNIX_PATH_MAX) {
never@3156 186 return -1;
never@3156 187 }
never@3156 188
never@3156 189 // create the listener socket
never@3156 190 listener = ::socket(PF_UNIX, SOCK_STREAM, 0);
never@3156 191 if (listener == -1) {
never@3156 192 return -1;
never@3156 193 }
never@3156 194
never@3156 195 // bind socket
never@3156 196 struct sockaddr_un addr;
never@3156 197 addr.sun_family = AF_UNIX;
never@3156 198 strcpy(addr.sun_path, initial_path);
never@3156 199 ::unlink(initial_path);
never@3156 200 int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr));
never@3156 201 if (res == -1) {
never@3156 202 RESTARTABLE(::close(listener), res);
never@3156 203 return -1;
never@3156 204 }
never@3156 205
never@3156 206 // put in listen mode, set permissions, and rename into place
never@3156 207 res = ::listen(listener, 5);
never@3156 208 if (res == 0) {
sla@3648 209 RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res);
sla@3648 210 if (res == 0) {
sla@3648 211 // make sure the file is owned by the effective user and effective group
sla@3648 212 // (this is the default on linux, but not on mac os)
sla@3648 213 RESTARTABLE(::chown(initial_path, geteuid(), getegid()), res);
never@3156 214 if (res == 0) {
sla@3648 215 res = ::rename(initial_path, path);
never@3156 216 }
sla@3648 217 }
never@3156 218 }
never@3156 219 if (res == -1) {
never@3156 220 RESTARTABLE(::close(listener), res);
never@3156 221 ::unlink(initial_path);
never@3156 222 return -1;
never@3156 223 }
never@3156 224 set_path(path);
never@3156 225 set_listener(listener);
never@3156 226
never@3156 227 return 0;
never@3156 228 }
never@3156 229
never@3156 230 // Given a socket that is connected to a peer we read the request and
never@3156 231 // create an AttachOperation. As the socket is blocking there is potential
never@3156 232 // for a denial-of-service if the peer does not response. However this happens
never@3156 233 // after the peer credentials have been checked and in the worst case it just
never@3156 234 // means that the attach listener thread is blocked.
never@3156 235 //
never@3156 236 BsdAttachOperation* BsdAttachListener::read_request(int s) {
never@3156 237 char ver_str[8];
never@3156 238 sprintf(ver_str, "%d", ATTACH_PROTOCOL_VER);
never@3156 239
never@3156 240 // The request is a sequence of strings so we first figure out the
never@3156 241 // expected count and the maximum possible length of the request.
never@3156 242 // The request is:
never@3156 243 // <ver>0<cmd>0<arg>0<arg>0<arg>0
never@3156 244 // where <ver> is the protocol version (1), <cmd> is the command
never@3156 245 // name ("load", "datadump", ...), and <arg> is an argument
never@3156 246 int expected_str_count = 2 + AttachOperation::arg_count_max;
never@3156 247 const int max_len = (sizeof(ver_str) + 1) + (AttachOperation::name_length_max + 1) +
never@3156 248 AttachOperation::arg_count_max*(AttachOperation::arg_length_max + 1);
never@3156 249
never@3156 250 char buf[max_len];
never@3156 251 int str_count = 0;
never@3156 252
never@3156 253 // Read until all (expected) strings have been read, the buffer is
never@3156 254 // full, or EOF.
never@3156 255
never@3156 256 int off = 0;
never@3156 257 int left = max_len;
never@3156 258
never@3156 259 do {
never@3156 260 int n;
never@3156 261 RESTARTABLE(read(s, buf+off, left), n);
never@3156 262 if (n == -1) {
never@3156 263 return NULL; // reset by peer or other error
never@3156 264 }
never@3156 265 if (n == 0) {
never@3156 266 break;
never@3156 267 }
never@3156 268 for (int i=0; i<n; i++) {
never@3156 269 if (buf[off+i] == 0) {
never@3156 270 // EOS found
never@3156 271 str_count++;
never@3156 272
never@3156 273 // The first string is <ver> so check it now to
never@3156 274 // check for protocol mis-match
never@3156 275 if (str_count == 1) {
never@3156 276 if ((strlen(buf) != strlen(ver_str)) ||
never@3156 277 (atoi(buf) != ATTACH_PROTOCOL_VER)) {
never@3156 278 char msg[32];
never@3156 279 sprintf(msg, "%d\n", ATTACH_ERROR_BADVERSION);
never@3156 280 write_fully(s, msg, strlen(msg));
never@3156 281 return NULL;
never@3156 282 }
never@3156 283 }
never@3156 284 }
never@3156 285 }
never@3156 286 off += n;
never@3156 287 left -= n;
never@3156 288 } while (left > 0 && str_count < expected_str_count);
never@3156 289
never@3156 290 if (str_count != expected_str_count) {
never@3156 291 return NULL; // incomplete request
never@3156 292 }
never@3156 293
never@3156 294 // parse request
never@3156 295
never@3156 296 ArgumentIterator args(buf, (max_len)-left);
never@3156 297
never@3156 298 // version already checked
never@3156 299 char* v = args.next();
never@3156 300
never@3156 301 char* name = args.next();
never@3156 302 if (name == NULL || strlen(name) > AttachOperation::name_length_max) {
never@3156 303 return NULL;
never@3156 304 }
never@3156 305
never@3156 306 BsdAttachOperation* op = new BsdAttachOperation(name);
never@3156 307
never@3156 308 for (int i=0; i<AttachOperation::arg_count_max; i++) {
never@3156 309 char* arg = args.next();
never@3156 310 if (arg == NULL) {
never@3156 311 op->set_arg(i, NULL);
never@3156 312 } else {
never@3156 313 if (strlen(arg) > AttachOperation::arg_length_max) {
never@3156 314 delete op;
never@3156 315 return NULL;
never@3156 316 }
never@3156 317 op->set_arg(i, arg);
never@3156 318 }
never@3156 319 }
never@3156 320
never@3156 321 op->set_socket(s);
never@3156 322 return op;
never@3156 323 }
never@3156 324
never@3156 325
never@3156 326 // Dequeue an operation
never@3156 327 //
never@3156 328 // In the Bsd implementation there is only a single operation and clients
never@3156 329 // cannot queue commands (except at the socket level).
never@3156 330 //
never@3156 331 BsdAttachOperation* BsdAttachListener::dequeue() {
never@3156 332 for (;;) {
never@3156 333 int s;
never@3156 334
never@3156 335 // wait for client to connect
never@3156 336 struct sockaddr addr;
never@3156 337 socklen_t len = sizeof(addr);
never@3156 338 RESTARTABLE(::accept(listener(), &addr, &len), s);
never@3156 339 if (s == -1) {
never@3156 340 return NULL; // log a warning?
never@3156 341 }
never@3156 342
never@3156 343 // get the credentials of the peer and check the effective uid/guid
never@3156 344 // - check with jeff on this.
never@3156 345 uid_t puid;
never@3156 346 gid_t pgid;
never@3156 347 if (::getpeereid(s, &puid, &pgid) != 0) {
never@3156 348 int res;
never@3156 349 RESTARTABLE(::close(s), res);
never@3156 350 continue;
never@3156 351 }
never@3156 352 uid_t euid = geteuid();
never@3156 353 gid_t egid = getegid();
never@3156 354
never@3156 355 if (puid != euid || pgid != egid) {
never@3156 356 int res;
never@3156 357 RESTARTABLE(::close(s), res);
never@3156 358 continue;
never@3156 359 }
never@3156 360
never@3156 361 // peer credential look okay so we read the request
never@3156 362 BsdAttachOperation* op = read_request(s);
never@3156 363 if (op == NULL) {
never@3156 364 int res;
never@3156 365 RESTARTABLE(::close(s), res);
never@3156 366 continue;
never@3156 367 } else {
never@3156 368 return op;
never@3156 369 }
never@3156 370 }
never@3156 371 }
never@3156 372
never@3156 373 // write the given buffer to the socket
never@3156 374 int BsdAttachListener::write_fully(int s, char* buf, int len) {
never@3156 375 do {
never@3156 376 int n = ::write(s, buf, len);
never@3156 377 if (n == -1) {
never@3156 378 if (errno != EINTR) return -1;
never@3156 379 } else {
never@3156 380 buf += n;
never@3156 381 len -= n;
never@3156 382 }
never@3156 383 }
never@3156 384 while (len > 0);
never@3156 385 return 0;
never@3156 386 }
never@3156 387
never@3156 388 // Complete an operation by sending the operation result and any result
never@3156 389 // output to the client. At this time the socket is in blocking mode so
never@3156 390 // potentially we can block if there is a lot of data and the client is
never@3156 391 // non-responsive. For most operations this is a non-issue because the
never@3156 392 // default send buffer is sufficient to buffer everything. In the future
never@3156 393 // if there are operations that involves a very big reply then it the
never@3156 394 // socket could be made non-blocking and a timeout could be used.
never@3156 395
never@3156 396 void BsdAttachOperation::complete(jint result, bufferedStream* st) {
never@3156 397 JavaThread* thread = JavaThread::current();
never@3156 398 ThreadBlockInVM tbivm(thread);
never@3156 399
never@3156 400 thread->set_suspend_equivalent();
never@3156 401 // cleared by handle_special_suspend_equivalent_condition() or
never@3156 402 // java_suspend_self() via check_and_wait_while_suspended()
never@3156 403
never@3156 404 // write operation result
never@3156 405 char msg[32];
never@3156 406 sprintf(msg, "%d\n", result);
never@3156 407 int rc = BsdAttachListener::write_fully(this->socket(), msg, strlen(msg));
never@3156 408
never@3156 409 // write any result data
never@3156 410 if (rc == 0) {
never@3156 411 BsdAttachListener::write_fully(this->socket(), (char*) st->base(), st->size());
never@3156 412 ::shutdown(this->socket(), 2);
never@3156 413 }
never@3156 414
never@3156 415 // done
never@3156 416 RESTARTABLE(::close(this->socket()), rc);
never@3156 417
never@3156 418 // were we externally suspended while we were waiting?
never@3156 419 thread->check_and_wait_while_suspended();
never@3156 420
never@3156 421 delete this;
never@3156 422 }
never@3156 423
never@3156 424
never@3156 425 // AttachListener functions
never@3156 426
never@3156 427 AttachOperation* AttachListener::dequeue() {
never@3156 428 JavaThread* thread = JavaThread::current();
never@3156 429 ThreadBlockInVM tbivm(thread);
never@3156 430
never@3156 431 thread->set_suspend_equivalent();
never@3156 432 // cleared by handle_special_suspend_equivalent_condition() or
never@3156 433 // java_suspend_self() via check_and_wait_while_suspended()
never@3156 434
never@3156 435 AttachOperation* op = BsdAttachListener::dequeue();
never@3156 436
never@3156 437 // were we externally suspended while we were waiting?
never@3156 438 thread->check_and_wait_while_suspended();
never@3156 439
never@3156 440 return op;
never@3156 441 }
never@3156 442
never@3156 443 int AttachListener::pd_init() {
never@3156 444 JavaThread* thread = JavaThread::current();
never@3156 445 ThreadBlockInVM tbivm(thread);
never@3156 446
never@3156 447 thread->set_suspend_equivalent();
never@3156 448 // cleared by handle_special_suspend_equivalent_condition() or
never@3156 449 // java_suspend_self() via check_and_wait_while_suspended()
never@3156 450
never@3156 451 int ret_code = BsdAttachListener::init();
never@3156 452
never@3156 453 // were we externally suspended while we were waiting?
never@3156 454 thread->check_and_wait_while_suspended();
never@3156 455
never@3156 456 return ret_code;
never@3156 457 }
never@3156 458
never@3156 459 // Attach Listener is started lazily except in the case when
never@3156 460 // +ReduseSignalUsage is used
never@3156 461 bool AttachListener::init_at_startup() {
never@3156 462 if (ReduceSignalUsage) {
never@3156 463 return true;
never@3156 464 } else {
never@3156 465 return false;
never@3156 466 }
never@3156 467 }
never@3156 468
never@3156 469 // If the file .attach_pid<pid> exists in the working directory
never@3156 470 // or /tmp then this is the trigger to start the attach mechanism
never@3156 471 bool AttachListener::is_init_trigger() {
never@3156 472 if (init_at_startup() || is_initialized()) {
never@3156 473 return false; // initialized at startup or already initialized
never@3156 474 }
never@3156 475 char path[PATH_MAX + 1];
never@3156 476 int ret;
never@3156 477 struct stat st;
never@3156 478
never@3156 479 snprintf(path, PATH_MAX + 1, "%s/.attach_pid%d",
never@3156 480 os::get_temp_directory(), os::current_process_id());
never@3156 481 RESTARTABLE(::stat(path, &st), ret);
never@3156 482 if (ret == 0) {
never@3156 483 // simple check to avoid starting the attach mechanism when
never@3156 484 // a bogus user creates the file
never@3156 485 if (st.st_uid == geteuid()) {
never@3156 486 init();
never@3156 487 return true;
never@3156 488 }
never@3156 489 }
never@3156 490 return false;
never@3156 491 }
never@3156 492
never@3156 493 // if VM aborts then remove listener
never@3156 494 void AttachListener::abort() {
never@3156 495 listener_cleanup();
never@3156 496 }
never@3156 497
never@3156 498 void AttachListener::pd_data_dump() {
never@3156 499 os::signal_notify(SIGQUIT);
never@3156 500 }
never@3156 501
never@3156 502 AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* n) {
never@3156 503 return NULL;
never@3156 504 }
never@3156 505
never@3156 506 jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) {
never@3156 507 out->print_cr("flag '%s' cannot be changed", op->arg(0));
never@3156 508 return JNI_ERR;
never@3156 509 }
never@3156 510
never@3156 511 void AttachListener::pd_detachall() {
never@3156 512 // do nothing for now
never@3156 513 }

mercurial