The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / src / node_dtrace.cc @ 06810b29

History | View | Annotate | Download (11.3 KB)

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

    
23
#ifdef HAVE_DTRACE
24
#include "node_dtrace.h"
25
#include <string.h>
26
#include "node_provider.h"
27
#elif HAVE_ETW
28
#include "node_dtrace.h"
29
#include <string.h>
30
#include "node_win32_etw_provider.h"
31
#include "node_win32_etw_provider-inl.h"
32
#elif HAVE_SYSTEMTAP
33
#include <string.h>
34
#include <node.h>
35
#include <v8.h>
36
#include <sys/sdt.h>
37
#include "node_systemtap.h"
38
#include "node_dtrace.h"
39
#else
40
#define NODE_HTTP_SERVER_REQUEST(arg0, arg1)
41
#define NODE_HTTP_SERVER_REQUEST_ENABLED() (0)
42
#define NODE_HTTP_SERVER_RESPONSE(arg0)
43
#define NODE_HTTP_SERVER_RESPONSE_ENABLED() (0)
44
#define NODE_HTTP_CLIENT_REQUEST(arg0, arg1)
45
#define NODE_HTTP_CLIENT_REQUEST_ENABLED() (0)
46
#define NODE_HTTP_CLIENT_RESPONSE(arg0)
47
#define NODE_HTTP_CLIENT_RESPONSE_ENABLED() (0)
48
#define NODE_NET_SERVER_CONNECTION(arg0)
49
#define NODE_NET_SERVER_CONNECTION_ENABLED() (0)
50
#define NODE_NET_STREAM_END(arg0)
51
#define NODE_NET_STREAM_END_ENABLED() (0)
52
#define NODE_NET_SOCKET_READ(arg0, arg1)
53
#define NODE_NET_SOCKET_READ_ENABLED() (0)
54
#define NODE_NET_SOCKET_WRITE(arg0, arg1)
55
#define NODE_NET_SOCKET_WRITE_ENABLED() (0)
56
#define NODE_GC_START(arg0, arg1)
57
#define NODE_GC_DONE(arg0, arg1)
58
#endif
59

    
60
namespace node {
61

    
62
using namespace v8;
63

    
64
#define SLURP_STRING(obj, member, valp) \
65
  if (!(obj)->IsObject()) { \
66
    return (ThrowException(Exception::Error(String::New("expected " \
67
      "object for " #obj " to contain string member " #member)))); \
68
  } \
69
  String::Utf8Value _##member(obj->Get(String::New(#member))); \
70
  if ((*(const char **)valp = *_##member) == NULL) \
71
    *(const char **)valp = "<unknown>";
72

    
73
#define SLURP_INT(obj, member, valp) \
74
  if (!(obj)->IsObject()) { \
75
    return (ThrowException(Exception::Error(String::New("expected " \
76
      "object for " #obj " to contain integer member " #member)))); \
77
  } \
78
  *valp = obj->Get(String::New(#member))->ToInteger()->Value();
79

    
80
#define SLURP_OBJECT(obj, member, valp) \
81
  if (!(obj)->IsObject()) { \
82
    return (ThrowException(Exception::Error(String::New("expected " \
83
      "object for " #obj " to contain object member " #member)))); \
84
  } \
85
  *valp = Local<Object>::Cast(obj->Get(String::New(#member)));
86

    
87
#define SLURP_CONNECTION(arg, conn) \
88
  if (!(arg)->IsObject()) { \
89
    return (ThrowException(Exception::Error(String::New("expected " \
90
      "argument " #arg " to be a connection object")))); \
91
  } \
92
  node_dtrace_connection_t conn; \
93
  Local<Object> _##conn = Local<Object>::Cast(arg); \
94
  SLURP_INT(_##conn, fd, &conn.fd); \
95
  SLURP_STRING(_##conn, remoteAddress, &conn.remote); \
96
  SLURP_INT(_##conn, remotePort, &conn.port); \
97
  SLURP_INT(_##conn, bufferSize, &conn.buffered);
98

    
99
#define SLURP_CONNECTION_HTTP_CLIENT(arg, conn) \
100
  if (!(arg)->IsObject()) { \
101
    return (ThrowException(Exception::Error(String::New("expected " \
102
      "argument " #arg " to be a connection object")))); \
103
  } \
104
  node_dtrace_connection_t conn; \
105
  Local<Object> _##conn = Local<Object>::Cast(arg); \
106
  SLURP_INT(_##conn, fd, &conn.fd); \
107
  SLURP_STRING(_##conn, host, &conn.remote); \
108
  SLURP_INT(_##conn, port, &conn.port); \
109
  SLURP_INT(_##conn, bufferSize, &conn.buffered);
110

    
111
#define SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(arg0, arg1, conn) \
112
  if (!(arg0)->IsObject()) { \
113
    return (ThrowException(Exception::Error(String::New("expected " \
114
      "argument " #arg0 " to be a connection object")))); \
115
  } \
116
  if (!(arg1)->IsObject()) { \
117
    return (ThrowException(Exception::Error(String::New("expected " \
118
      "argument " #arg1 " to be a connection object")))); \
119
  } \
120
  node_dtrace_connection_t conn; \
121
  Local<Object> _##conn = Local<Object>::Cast(arg0); \
122
  SLURP_INT(_##conn, fd, &conn.fd); \
123
  SLURP_INT(_##conn, bufferSize, &conn.buffered); \
124
  _##conn = Local<Object>::Cast(arg1); \
125
  SLURP_STRING(_##conn, host, &conn.remote); \
126
  SLURP_INT(_##conn, port, &conn.port);
127

    
128

    
129
Handle<Value> DTRACE_NET_SERVER_CONNECTION(const Arguments& args) {
130
#ifndef HAVE_SYSTEMTAP
131
  if (!NODE_NET_SERVER_CONNECTION_ENABLED())
132
    return Undefined();
133
#endif
134

    
135
  HandleScope scope;
136

    
137
  SLURP_CONNECTION(args[0], conn);
138
#ifdef HAVE_SYSTEMTAP
139
  NODE_NET_SERVER_CONNECTION(conn.fd, conn.remote, conn.port, \
140
                             conn.buffered);
141
#else
142
  NODE_NET_SERVER_CONNECTION(&conn);
143
#endif
144

    
145
  return Undefined();
146
}
147

    
148
Handle<Value> DTRACE_NET_STREAM_END(const Arguments& args) {
149
#ifndef HAVE_SYSTEMTAP
150
  if (!NODE_NET_STREAM_END_ENABLED())
151
    return Undefined();
152
#endif
153

    
154
  HandleScope scope;
155

    
156
  SLURP_CONNECTION(args[0], conn);
157
#ifdef HAVE_SYSTEMTAP
158
  NODE_NET_STREAM_END(conn.fd, conn.remote, conn.port, conn.buffered);
159
#else
160
  NODE_NET_STREAM_END(&conn);
161
#endif
162

    
163
  return Undefined();
164
}
165

    
166
Handle<Value> DTRACE_NET_SOCKET_READ(const Arguments& args) {
167
#ifndef HAVE_SYSTEMTAP
168
  if (!NODE_NET_SOCKET_READ_ENABLED())
169
    return Undefined();
170
#endif
171

    
172
  HandleScope scope;
173

    
174
  SLURP_CONNECTION(args[0], conn);
175

    
176
#ifdef HAVE_SYSTEMTAP
177
  NODE_NET_SOCKET_READ(conn.fd, conn.remote, conn.port, conn.buffered);
178
#else
179
  if (!args[1]->IsNumber()) {
180
    return (ThrowException(Exception::Error(String::New("expected " 
181
      "argument 1 to be number of bytes"))));
182
  }
183
  int nbytes = args[1]->Int32Value();
184
  NODE_NET_SOCKET_READ(&conn, nbytes);
185
#endif
186

    
187
  return Undefined();
188
}
189

    
190
Handle<Value> DTRACE_NET_SOCKET_WRITE(const Arguments& args) {
191
#ifndef HAVE_SYSTEMTAP
192
  if (!NODE_NET_SOCKET_WRITE_ENABLED())
193
    return Undefined();
194
#endif
195

    
196
  HandleScope scope;
197

    
198
  SLURP_CONNECTION(args[0], conn);
199

    
200
#ifdef HAVE_SYSTEMTAP
201
  NODE_NET_SOCKET_WRITE(conn.fd, conn.remote, conn.port, conn.buffered);
202
#else
203
  if (!args[1]->IsNumber()) {
204
    return (ThrowException(Exception::Error(String::New("expected " 
205
      "argument 1 to be number of bytes"))));
206
  }
207
  int nbytes = args[1]->Int32Value();
208
  NODE_NET_SOCKET_WRITE(&conn, nbytes);
209
#endif
210

    
211
  return Undefined();
212
}
213

    
214
Handle<Value> DTRACE_HTTP_SERVER_REQUEST(const Arguments& args) {
215
  node_dtrace_http_server_request_t req;
216

    
217
#ifndef HAVE_SYSTEMTAP
218
  if (!NODE_HTTP_SERVER_REQUEST_ENABLED())
219
    return Undefined();
220
#endif
221

    
222
  HandleScope scope;
223

    
224
  Local<Object> arg0 = Local<Object>::Cast(args[0]);
225
  Local<Object> headers;
226

    
227
  memset(&req, 0, sizeof(req));
228
  req._un.version = 1;
229
  SLURP_STRING(arg0, url, &req.url);
230
  SLURP_STRING(arg0, method, &req.method);
231

    
232
  SLURP_OBJECT(arg0, headers, &headers);
233

    
234
  if (!(headers)->IsObject())
235
    return (ThrowException(Exception::Error(String::New("expected "
236
      "object for request to contain string member headers"))));
237

    
238
  Local<Value> strfwdfor = headers->Get(String::New("x-forwarded-for"));
239
  String::Utf8Value fwdfor(strfwdfor);
240

    
241
  if (!strfwdfor->IsString() || (req.forwardedFor = *fwdfor) == NULL)
242
    req.forwardedFor = const_cast<char*>("");
243

    
244
  SLURP_CONNECTION(args[1], conn);
245

    
246
#ifdef HAVE_SYSTEMTAP
247
  NODE_HTTP_SERVER_REQUEST(&req, conn.fd, conn.remote, conn.port, \
248
                           conn.buffered);
249
#else
250
  NODE_HTTP_SERVER_REQUEST(&req, &conn);
251
#endif
252
  return Undefined();
253
}
254

    
255
Handle<Value> DTRACE_HTTP_SERVER_RESPONSE(const Arguments& args) {
256
#ifndef HAVE_SYSTEMTAP
257
  if (!NODE_HTTP_SERVER_RESPONSE_ENABLED())
258
    return Undefined();
259
#endif
260

    
261
  HandleScope scope;
262

    
263
  SLURP_CONNECTION(args[0], conn);
264
#ifdef HAVE_SYSTEMTAP
265
  NODE_HTTP_SERVER_RESPONSE(conn.fd, conn.remote, conn.port, conn.buffered);
266
#else
267
  NODE_HTTP_SERVER_RESPONSE(&conn);
268
#endif
269

    
270
  return Undefined();
271
}
272

    
273
Handle<Value> DTRACE_HTTP_CLIENT_REQUEST(const Arguments& args) {
274
  node_dtrace_http_client_request_t req;
275
  char *header;
276

    
277
#ifndef HAVE_SYSTEMTAP
278
  if (!NODE_HTTP_CLIENT_REQUEST_ENABLED())
279
    return Undefined();
280
#endif
281

    
282
  HandleScope scope;
283

    
284
  /*
285
   * For the method and URL, we're going to dig them out of the header.  This
286
   * is not as efficient as it could be, but we would rather not force the
287
   * caller here to retain their method and URL until the time at which
288
   * DTRACE_HTTP_CLIENT_REQUEST can be called.
289
   */
290
  Local<Object> arg0 = Local<Object>::Cast(args[0]);
291
  SLURP_STRING(arg0, _header, &header);
292

    
293
  req.method = header;
294

    
295
  while (*header != '\0' && *header != ' ')
296
    header++;
297

    
298
  if (*header != '\0')
299
    *header++ = '\0';
300

    
301
  req.url = header;
302

    
303
  while (*header != '\0' && *header != ' ')
304
    header++;
305

    
306
  *header = '\0';
307

    
308
  SLURP_CONNECTION_HTTP_CLIENT(args[1], conn);
309
#ifdef HAVE_SYSTEMTAP
310
  NODE_HTTP_CLIENT_REQUEST(&req, conn.fd, conn.remote, conn.port, \
311
                           conn.buffered);
312
#else
313
  NODE_HTTP_CLIENT_REQUEST(&req, &conn);
314
#endif
315
  return Undefined();
316
}
317

    
318
Handle<Value> DTRACE_HTTP_CLIENT_RESPONSE(const Arguments& args) {
319
#ifndef HAVE_SYSTEMTAP
320
  if (!NODE_HTTP_CLIENT_RESPONSE_ENABLED())
321
    return Undefined();
322
#endif
323
  HandleScope scope;
324

    
325
  SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(args[0], args[1], conn);
326
#ifdef HAVE_SYSTEMTAP
327
  NODE_HTTP_CLIENT_RESPONSE(conn.fd, conn.remote, conn.port, conn.buffered);
328
#else
329
  NODE_HTTP_CLIENT_RESPONSE(&conn);
330
#endif
331

    
332
  return Undefined();
333
}
334

    
335
#define NODE_PROBE(name) #name, name, Persistent<FunctionTemplate>()
336

    
337
static int dtrace_gc_start(GCType type, GCCallbackFlags flags) {
338
#ifdef HAVE_SYSTEMTAP
339
  NODE_GC_START();
340
#else
341
  NODE_GC_START(type, flags);
342
#endif
343
  /*
344
   * We avoid the tail-call elimination of the USDT probe (which screws up
345
   * args) by forcing a return of 0.
346
   */
347
  return 0;
348
}
349

    
350
static int dtrace_gc_done(GCType type, GCCallbackFlags flags) {
351
#ifdef HAVE_SYSTEMTAP
352
  NODE_GC_DONE();
353
#else
354
  NODE_GC_DONE(type, flags);
355
#endif
356
  return 0;
357
}
358

    
359
void InitDTrace(Handle<Object> target) {
360
  static struct {
361
    const char *name;
362
    Handle<Value> (*func)(const Arguments&);
363
    Persistent<FunctionTemplate> templ;
364
  } tab[] = {
365
    { NODE_PROBE(DTRACE_NET_SERVER_CONNECTION) },
366
    { NODE_PROBE(DTRACE_NET_STREAM_END) },
367
    { NODE_PROBE(DTRACE_NET_SOCKET_READ) },
368
    { NODE_PROBE(DTRACE_NET_SOCKET_WRITE) },
369
    { NODE_PROBE(DTRACE_HTTP_SERVER_REQUEST) },
370
    { NODE_PROBE(DTRACE_HTTP_SERVER_RESPONSE) },
371
    { NODE_PROBE(DTRACE_HTTP_CLIENT_REQUEST) },
372
    { NODE_PROBE(DTRACE_HTTP_CLIENT_RESPONSE) }
373
  };
374

    
375
  for (unsigned int i = 0; i < ARRAY_SIZE(tab); i++) {
376
    tab[i].templ = Persistent<FunctionTemplate>::New(
377
        FunctionTemplate::New(tab[i].func));
378
    target->Set(String::NewSymbol(tab[i].name), tab[i].templ->GetFunction());
379
  }
380

    
381
#ifdef HAVE_ETW
382
  init_etw();
383
#endif
384

    
385
#if defined HAVE_DTRACE || defined HAVE_ETW || defined HAVE_SYSTEMTAP
386
  v8::V8::AddGCPrologueCallback((GCPrologueCallback)dtrace_gc_start);
387
  v8::V8::AddGCEpilogueCallback((GCEpilogueCallback)dtrace_gc_done);
388
#endif
389
}
390

    
391
}