Node.js  v8.x
Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine
node_dtrace.cc
Go to the documentation of this file.
1 // Copyright Joyent, Inc. and other Node contributors.
2 //
3 // Permission is hereby granted, free of charge, to any person obtaining a
4 // copy of this software and associated documentation files (the
5 // "Software"), to deal in the Software without restriction, including
6 // without limitation the rights to use, copy, modify, merge, publish,
7 // distribute, sublicense, and/or sell copies of the Software, and to permit
8 // persons to whom the Software is furnished to do so, subject to the
9 // following conditions:
10 //
11 // The above copyright notice and this permission notice shall be included
12 // in all copies or substantial portions of the Software.
13 //
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
17 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
18 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
19 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
20 // USE OR OTHER DEALINGS IN THE SOFTWARE.
21 
22 #include "node_dtrace.h"
23 
24 #ifdef HAVE_DTRACE
25 #include "node_provider.h"
26 #elif HAVE_ETW
29 #else
30 #define NODE_HTTP_SERVER_REQUEST(arg0, arg1)
31 #define NODE_HTTP_SERVER_REQUEST_ENABLED() (0)
32 #define NODE_HTTP_SERVER_RESPONSE(arg0)
33 #define NODE_HTTP_SERVER_RESPONSE_ENABLED() (0)
34 #define NODE_HTTP_CLIENT_REQUEST(arg0, arg1)
35 #define NODE_HTTP_CLIENT_REQUEST_ENABLED() (0)
36 #define NODE_HTTP_CLIENT_RESPONSE(arg0)
37 #define NODE_HTTP_CLIENT_RESPONSE_ENABLED() (0)
38 #define NODE_NET_SERVER_CONNECTION(arg0)
39 #define NODE_NET_SERVER_CONNECTION_ENABLED() (0)
40 #define NODE_NET_STREAM_END(arg0)
41 #define NODE_NET_STREAM_END_ENABLED() (0)
42 #define NODE_GC_START(arg0, arg1, arg2)
43 #define NODE_GC_DONE(arg0, arg1, arg2)
44 #endif
45 
46 #include "env.h"
47 #include "env-inl.h"
48 
49 #include "util.h"
50 
51 #include <string.h>
52 
53 namespace node {
54 
55 using v8::FunctionCallbackInfo;
56 using v8::GCCallbackFlags;
57 using v8::GCType;
58 using v8::HandleScope;
59 using v8::Isolate;
60 using v8::Local;
61 using v8::Object;
62 using v8::String;
63 using v8::Value;
64 
65 #define SLURP_STRING(obj, member, valp) \
66  if (!(obj)->IsObject()) { \
67  return env->ThrowError( \
68  "expected object for " #obj " to contain string member " #member); \
69  } \
70  node::Utf8Value _##member(env->isolate(), \
71  obj->Get(OneByteString(env->isolate(), #member))); \
72  if ((*(const char **)valp = *_##member) == nullptr) \
73  *(const char **)valp = "<unknown>";
74 
75 #define SLURP_INT(obj, member, valp) \
76  if (!(obj)->IsObject()) { \
77  return env->ThrowError( \
78  "expected object for " #obj " to contain integer member " #member); \
79  } \
80  *valp = obj->Get(OneByteString(env->isolate(), #member)) \
81  ->Int32Value();
82 
83 #define SLURP_OBJECT(obj, member, valp) \
84  if (!(obj)->IsObject()) { \
85  return env->ThrowError( \
86  "expected object for " #obj " to contain object member " #member); \
87  } \
88  *valp = Local<Object>::Cast(obj->Get(OneByteString(env->isolate(), #member)));
89 
90 #define SLURP_CONNECTION(arg, conn) \
91  if (!(arg)->IsObject()) { \
92  return env->ThrowError( \
93  "expected argument " #arg " to be a connection object"); \
94  } \
95  node_dtrace_connection_t conn; \
96  Local<Object> _##conn = Local<Object>::Cast(arg); \
97  Local<Value> _handle = \
98  (_##conn)->Get(FIXED_ONE_BYTE_STRING(env->isolate(), "_handle")); \
99  if (_handle->IsObject()) { \
100  SLURP_INT(_handle.As<Object>(), fd, &conn.fd); \
101  } else { \
102  conn.fd = -1; \
103  } \
104  SLURP_STRING(_##conn, remoteAddress, &conn.remote); \
105  SLURP_INT(_##conn, remotePort, &conn.port); \
106  SLURP_INT(_##conn, bufferSize, &conn.buffered);
107 
108 #define SLURP_CONNECTION_HTTP_CLIENT(arg, conn) \
109  if (!(arg)->IsObject()) { \
110  return env->ThrowError( \
111  "expected argument " #arg " to be a connection object"); \
112  } \
113  node_dtrace_connection_t conn; \
114  Local<Object> _##conn = Local<Object>::Cast(arg); \
115  SLURP_INT(_##conn, fd, &conn.fd); \
116  SLURP_STRING(_##conn, host, &conn.remote); \
117  SLURP_INT(_##conn, port, &conn.port); \
118  SLURP_INT(_##conn, bufferSize, &conn.buffered);
119 
120 #define SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(arg0, arg1, conn) \
121  if (!(arg0)->IsObject()) { \
122  return env->ThrowError( \
123  "expected argument " #arg0 " to be a connection object"); \
124  } \
125  if (!(arg1)->IsObject()) { \
126  return env->ThrowError( \
127  "expected argument " #arg1 " to be a connection object"); \
128  } \
129  node_dtrace_connection_t conn; \
130  Local<Object> _##conn = Local<Object>::Cast(arg0); \
131  SLURP_INT(_##conn, fd, &conn.fd); \
132  SLURP_INT(_##conn, bufferSize, &conn.buffered); \
133  _##conn = Local<Object>::Cast(arg1); \
134  SLURP_STRING(_##conn, host, &conn.remote); \
135  SLURP_INT(_##conn, port, &conn.port);
136 
137 
138 void DTRACE_NET_SERVER_CONNECTION(const FunctionCallbackInfo<Value>& args) {
140  return;
141  Environment* env = Environment::GetCurrent(args);
142  SLURP_CONNECTION(args[0], conn);
143  NODE_NET_SERVER_CONNECTION(&conn, conn.remote, conn.port, conn.fd);
144 }
145 
146 
147 void DTRACE_NET_STREAM_END(const FunctionCallbackInfo<Value>& args) {
149  return;
150  Environment* env = Environment::GetCurrent(args);
151  SLURP_CONNECTION(args[0], conn);
152  NODE_NET_STREAM_END(&conn, conn.remote, conn.port, conn.fd);
153 }
154 
155 void DTRACE_HTTP_SERVER_REQUEST(const FunctionCallbackInfo<Value>& args) {
157 
159  return;
160 
161  Environment* env = Environment::GetCurrent(args);
162  HandleScope scope(env->isolate());
163  Local<Object> arg0 = Local<Object>::Cast(args[0]);
164  Local<Object> headers;
165 
166  memset(&req, 0, sizeof(req));
167  req._un.version = 1;
168  SLURP_STRING(arg0, url, &req.url);
169  SLURP_STRING(arg0, method, &req.method);
170  SLURP_OBJECT(arg0, headers, &headers);
171 
172  if (!(headers)->IsObject()) {
173  return env->ThrowError(
174  "expected object for request to contain string member headers");
175  }
176 
177  Local<Value> strfwdfor = headers->Get(env->x_forwarded_string());
178  node::Utf8Value fwdfor(env->isolate(), strfwdfor);
179 
180  if (!strfwdfor->IsString() || (req.forwardedFor = *fwdfor) == nullptr)
181  req.forwardedFor = const_cast<char*>("");
182 
183  SLURP_CONNECTION(args[1], conn);
184  NODE_HTTP_SERVER_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \
185  req.url, conn.fd);
186 }
187 
188 
189 void DTRACE_HTTP_SERVER_RESPONSE(const FunctionCallbackInfo<Value>& args) {
191  return;
192  Environment* env = Environment::GetCurrent(args);
193  SLURP_CONNECTION(args[0], conn);
194  NODE_HTTP_SERVER_RESPONSE(&conn, conn.remote, conn.port, conn.fd);
195 }
196 
197 
198 void DTRACE_HTTP_CLIENT_REQUEST(const FunctionCallbackInfo<Value>& args) {
200  char *header;
201 
203  return;
204 
205  Environment* env = Environment::GetCurrent(args);
206  HandleScope scope(env->isolate());
207 
208  /*
209  * For the method and URL, we're going to dig them out of the header. This
210  * is not as efficient as it could be, but we would rather not force the
211  * caller here to retain their method and URL until the time at which
212  * DTRACE_HTTP_CLIENT_REQUEST can be called.
213  */
214  Local<Object> arg0 = Local<Object>::Cast(args[0]);
215  SLURP_STRING(arg0, _header, &header);
216 
217  req.method = header;
218 
219  while (*header != '\0' && *header != ' ')
220  header++;
221 
222  if (*header != '\0')
223  *header++ = '\0';
224 
225  req.url = header;
226 
227  while (*header != '\0' && *header != ' ')
228  header++;
229 
230  *header = '\0';
231 
232  SLURP_CONNECTION_HTTP_CLIENT(args[1], conn);
233  NODE_HTTP_CLIENT_REQUEST(&req, &conn, conn.remote, conn.port, req.method, \
234  req.url, conn.fd);
235 }
236 
237 
238 void DTRACE_HTTP_CLIENT_RESPONSE(const FunctionCallbackInfo<Value>& args) {
240  return;
241  Environment* env = Environment::GetCurrent(args);
242  SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(args[0], args[1], conn);
243  NODE_HTTP_CLIENT_RESPONSE(&conn, conn.remote, conn.port, conn.fd);
244 }
245 
246 
247 void dtrace_gc_start(Isolate* isolate, GCType type, GCCallbackFlags flags) {
248  // Previous versions of this probe point only logged type and flags.
249  // That's why for reasons of backwards compatibility the isolate goes last.
250  NODE_GC_START(type, flags, isolate);
251 }
252 
253 
254 void dtrace_gc_done(Isolate* isolate, GCType type, GCCallbackFlags flags) {
255  // Previous versions of this probe point only logged type and flags.
256  // That's why for reasons of backwards compatibility the isolate goes last.
257  NODE_GC_DONE(type, flags, isolate);
258 }
259 
260 
261 void InitDTrace(Environment* env, Local<Object> target) {
262  HandleScope scope(env->isolate());
263 
264  static struct {
265  const char *name;
266  void (*func)(const FunctionCallbackInfo<Value>&);
267  } tab[] = {
268 #define NODE_PROBE(name) #name, name
275 #undef NODE_PROBE
276  };
277 
278  for (size_t i = 0; i < arraysize(tab); i++) {
279  Local<String> key = OneByteString(env->isolate(), tab[i].name);
280  Local<Value> val = env->NewFunctionTemplate(tab[i].func)->GetFunction();
281  target->Set(key, val);
282  }
283 
284 #ifdef HAVE_ETW
285  init_etw();
286 #endif
287 
288 #if defined HAVE_DTRACE || defined HAVE_ETW
289  env->isolate()->AddGCPrologueCallback(dtrace_gc_start);
290  env->isolate()->AddGCEpilogueCallback(dtrace_gc_done);
291 #endif
292 }
293 
294 } // namespace node
#define NODE_HTTP_CLIENT_RESPONSE(arg0)
Definition: node_dtrace.cc:36
this func
Definition: v8ustack.d:371
#define NODE_NET_STREAM_END_ENABLED()
Definition: node_dtrace.cc:41
void DTRACE_HTTP_CLIENT_RESPONSE(const FunctionCallbackInfo< Value > &args)
Definition: node_dtrace.cc:238
#define SLURP_CONNECTION(arg, conn)
Definition: node_dtrace.cc:90
#define NODE_NET_STREAM_END(arg0)
Definition: node_dtrace.cc:40
void dtrace_gc_done(Isolate *isolate, GCType type, GCCallbackFlags flags)
Definition: node_dtrace.cc:254
#define NODE_PROBE(name)
void InitDTrace(Environment *env, Local< Object > target)
Definition: node_dtrace.cc:261
#define NODE_GC_DONE(arg0, arg1, arg2)
Definition: node_dtrace.cc:43
void dtrace_gc_start(Isolate *isolate, GCType type, GCCallbackFlags flags)
Definition: node_dtrace.cc:247
#define SLURP_CONNECTION_HTTP_CLIENT(arg, conn)
Definition: node_dtrace.cc:108
void DTRACE_NET_SERVER_CONNECTION(const FunctionCallbackInfo< Value > &args)
Definition: node_dtrace.cc:138
void DTRACE_NET_STREAM_END(const FunctionCallbackInfo< Value > &args)
Definition: node_dtrace.cc:147
#define NODE_HTTP_CLIENT_REQUEST(arg0, arg1)
Definition: node_dtrace.cc:34
#define NODE_HTTP_SERVER_REQUEST_ENABLED()
Definition: node_dtrace.cc:31
#define NODE_NET_SERVER_CONNECTION_ENABLED()
Definition: node_dtrace.cc:39
#define NODE_HTTP_CLIENT_REQUEST_ENABLED()
Definition: node_dtrace.cc:35
#define NODE_HTTP_SERVER_RESPONSE_ENABLED()
Definition: node_dtrace.cc:33
#define NODE_HTTP_CLIENT_RESPONSE_ENABLED()
Definition: node_dtrace.cc:37
void DTRACE_HTTP_SERVER_REQUEST(const FunctionCallbackInfo< Value > &args)
Definition: node_dtrace.cc:155
void DTRACE_HTTP_CLIENT_REQUEST(const FunctionCallbackInfo< Value > &args)
Definition: node_dtrace.cc:198
uv_fs_t req
Definition: node_file.cc:374
#define SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(arg0, arg1, conn)
Definition: node_dtrace.cc:120
#define SLURP_STRING(obj, member, valp)
Definition: node_dtrace.cc:65
method
Definition: node.d:195
#define NODE_NET_SERVER_CONNECTION(arg0)
Definition: node_dtrace.cc:38
#define NODE_GC_START(arg0, arg1, arg2)
Definition: node_dtrace.cc:42
void DTRACE_HTTP_SERVER_RESPONSE(const FunctionCallbackInfo< Value > &args)
Definition: node_dtrace.cc:189
#define SLURP_OBJECT(obj, member, valp)
Definition: node_dtrace.cc:83
#define NODE_HTTP_SERVER_RESPONSE(arg0)
Definition: node_dtrace.cc:32
#define NODE_HTTP_SERVER_REQUEST(arg0, arg1)
Definition: node_dtrace.cc:30