30 #include <sys/types.h> |
30 #include <sys/types.h> |
31 #include <sys/socket.h> |
31 #include <sys/socket.h> |
32 #include <sys/un.h> |
32 #include <sys/un.h> |
33 #include <sys/stat.h> |
33 #include <sys/stat.h> |
34 |
34 |
|
35 #ifndef UNIX_PATH_MAX |
|
36 #define UNIX_PATH_MAX sizeof(((struct sockaddr_un *)0)->sun_path) |
|
37 #endif |
|
38 |
35 // The attach mechanism on Linux uses a UNIX domain socket. An attach listener |
39 // The attach mechanism on Linux uses a UNIX domain socket. An attach listener |
36 // thread is created at startup or is created on-demand via a signal from |
40 // thread is created at startup or is created on-demand via a signal from |
37 // the client tool. The attach listener creates a socket and binds it to a file |
41 // the client tool. The attach listener creates a socket and binds it to a file |
38 // in the filesystem. The attach listener then acts as a simple (single- |
42 // in the filesystem. The attach listener then acts as a simple (single- |
39 // threaded) server - tt waits for a client to connect, reads the request, |
43 // threaded) server - it waits for a client to connect, reads the request, |
40 // executes it, and returns the response to the client via the socket |
44 // executes it, and returns the response to the client via the socket |
41 // connection. |
45 // connection. |
42 // |
46 // |
43 // As the socket is a UNIX domain socket it means that only clients on the |
47 // As the socket is a UNIX domain socket it means that only clients on the |
44 // local machine can connect. In addition there are two other aspects to |
48 // local machine can connect. In addition there are two other aspects to |
52 class LinuxAttachOperation; |
56 class LinuxAttachOperation; |
53 |
57 |
54 class LinuxAttachListener: AllStatic { |
58 class LinuxAttachListener: AllStatic { |
55 private: |
59 private: |
56 // the path to which we bind the UNIX domain socket |
60 // the path to which we bind the UNIX domain socket |
57 static char _path[PATH_MAX+1]; |
61 static char _path[UNIX_PATH_MAX]; |
58 static bool _has_path; |
62 static bool _has_path; |
59 |
63 |
60 // the file descriptor for the listening socket |
64 // the file descriptor for the listening socket |
61 static int _listener; |
65 static int _listener; |
62 |
66 |
63 static void set_path(char* path) { |
67 static void set_path(char* path) { |
64 if (path == NULL) { |
68 if (path == NULL) { |
65 _has_path = false; |
69 _has_path = false; |
66 } else { |
70 } else { |
67 strncpy(_path, path, PATH_MAX); |
71 strncpy(_path, path, UNIX_PATH_MAX); |
68 _path[PATH_MAX] = '\0'; |
72 _path[UNIX_PATH_MAX-1] = '\0'; |
69 _has_path = true; |
73 _has_path = true; |
70 } |
74 } |
71 } |
75 } |
72 |
76 |
73 static void set_listener(int s) { _listener = s; } |
77 static void set_listener(int s) { _listener = s; } |
161 } |
165 } |
162 |
166 |
163 // Initialization - create a listener socket and bind it to a file |
167 // Initialization - create a listener socket and bind it to a file |
164 |
168 |
165 int LinuxAttachListener::init() { |
169 int LinuxAttachListener::init() { |
166 char path[PATH_MAX+1]; // socket file |
170 char path[UNIX_PATH_MAX]; // socket file |
167 int listener; // listener socket (file descriptor) |
171 char initial_path[UNIX_PATH_MAX]; // socket file during setup |
|
172 int listener; // listener socket (file descriptor) |
168 |
173 |
169 // register function to cleanup |
174 // register function to cleanup |
170 ::atexit(listener_cleanup); |
175 ::atexit(listener_cleanup); |
|
176 |
|
177 int n = snprintf(path, UNIX_PATH_MAX, "%s/.java_pid%d", |
|
178 os::get_temp_directory(), os::current_process_id()); |
|
179 if (n <= (int)UNIX_PATH_MAX) { |
|
180 n = snprintf(initial_path, UNIX_PATH_MAX, "%s.tmp", path); |
|
181 } |
|
182 if (n > (int)UNIX_PATH_MAX) { |
|
183 return -1; |
|
184 } |
171 |
185 |
172 // create the listener socket |
186 // create the listener socket |
173 listener = ::socket(PF_UNIX, SOCK_STREAM, 0); |
187 listener = ::socket(PF_UNIX, SOCK_STREAM, 0); |
174 if (listener == -1) { |
188 if (listener == -1) { |
175 return -1; |
189 return -1; |
176 } |
190 } |
177 |
191 |
178 int res = -1; |
192 // bind socket |
179 struct sockaddr_un addr; |
193 struct sockaddr_un addr; |
180 addr.sun_family = AF_UNIX; |
194 addr.sun_family = AF_UNIX; |
181 |
195 strcpy(addr.sun_path, initial_path); |
182 // FIXME: Prior to b39 the tool-side API expected to find the well |
196 ::unlink(initial_path); |
183 // known file in the working directory. To allow this libjvm.so work with |
197 int res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); |
184 // a pre-b39 SDK we create it in the working directory if |
|
185 // +StartAttachListener is used is used. All unit tests for this feature |
|
186 // currently used this flag. Once b39 SDK has been promoted we can remove |
|
187 // this code. |
|
188 if (StartAttachListener) { |
|
189 sprintf(path, ".java_pid%d", os::current_process_id()); |
|
190 strcpy(addr.sun_path, path); |
|
191 ::unlink(path); |
|
192 res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); |
|
193 } |
|
194 if (res == -1) { |
|
195 snprintf(path, PATH_MAX+1, "%s/.java_pid%d", |
|
196 os::get_temp_directory(), os::current_process_id()); |
|
197 strcpy(addr.sun_path, path); |
|
198 ::unlink(path); |
|
199 res = ::bind(listener, (struct sockaddr*)&addr, sizeof(addr)); |
|
200 } |
|
201 if (res == -1) { |
198 if (res == -1) { |
202 RESTARTABLE(::close(listener), res); |
199 RESTARTABLE(::close(listener), res); |
203 return -1; |
200 return -1; |
204 } |
201 } |
|
202 |
|
203 // put in listen mode, set permissions, and rename into place |
|
204 res = ::listen(listener, 5); |
|
205 if (res == 0) { |
|
206 RESTARTABLE(::chmod(initial_path, S_IREAD|S_IWRITE), res); |
|
207 if (res == 0) { |
|
208 res = ::rename(initial_path, path); |
|
209 } |
|
210 } |
|
211 if (res == -1) { |
|
212 RESTARTABLE(::close(listener), res); |
|
213 ::unlink(initial_path); |
|
214 return -1; |
|
215 } |
205 set_path(path); |
216 set_path(path); |
206 |
|
207 // put in listen mode and set permission |
|
208 if ((::listen(listener, 5) == -1) || (::chmod(path, S_IREAD|S_IWRITE) == -1)) { |
|
209 RESTARTABLE(::close(listener), res); |
|
210 ::unlink(path); |
|
211 set_path(NULL); |
|
212 return -1; |
|
213 } |
|
214 set_listener(listener); |
217 set_listener(listener); |
215 |
218 |
216 return 0; |
219 return 0; |
217 } |
220 } |
218 |
221 |