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 @ 35a1421e

History | View | Annotate | Download (9.75 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
#include "node_dtrace.h"
23
#include <string.h>
24

    
25
#ifdef HAVE_DTRACE
26
#include "node_provider.h"
27
#elif HAVE_ETW
28
#include "node_win32_etw_provider.h"
29
#include "node_win32_etw_provider-inl.h"
30
#else
31
#define NODE_HTTP_SERVER_REQUEST(arg0, arg1)
32
#define NODE_HTTP_SERVER_REQUEST_ENABLED() (0)
33
#define NODE_HTTP_SERVER_RESPONSE(arg0)
34
#define NODE_HTTP_SERVER_RESPONSE_ENABLED() (0)
35
#define NODE_HTTP_CLIENT_REQUEST(arg0, arg1)
36
#define NODE_HTTP_CLIENT_REQUEST_ENABLED() (0)
37
#define NODE_HTTP_CLIENT_RESPONSE(arg0)
38
#define NODE_HTTP_CLIENT_RESPONSE_ENABLED() (0)
39
#define NODE_NET_SERVER_CONNECTION(arg0)
40
#define NODE_NET_SERVER_CONNECTION_ENABLED() (0)
41
#define NODE_NET_STREAM_END(arg0)
42
#define NODE_NET_STREAM_END_ENABLED() (0)
43
#define NODE_NET_SOCKET_READ(arg0, arg1)
44
#define NODE_NET_SOCKET_READ_ENABLED() (0)
45
#define NODE_NET_SOCKET_WRITE(arg0, arg1)
46
#define NODE_NET_SOCKET_WRITE_ENABLED() (0)
47
#define NODE_GC_START(arg0, arg1)
48
#define NODE_GC_DONE(arg0, arg1)
49
#endif
50

    
51
namespace node {
52

    
53
using namespace v8;
54

    
55
#define SLURP_STRING(obj, member, valp) \
56
  if (!(obj)->IsObject()) { \
57
    return (ThrowException(Exception::Error(String::New("expected " \
58
      "object for " #obj " to contain string member " #member)))); \
59
  } \
60
  String::Utf8Value _##member(obj->Get(String::New(#member))); \
61
  if ((*(const char **)valp = *_##member) == NULL) \
62
    *(const char **)valp = "<unknown>";
63

    
64
#define SLURP_INT(obj, member, valp) \
65
  if (!(obj)->IsObject()) { \
66
    return (ThrowException(Exception::Error(String::New("expected " \
67
      "object for " #obj " to contain integer member " #member)))); \
68
  } \
69
  *valp = obj->Get(String::New(#member))->ToInteger()->Value();
70

    
71
#define SLURP_OBJECT(obj, member, valp) \
72
  if (!(obj)->IsObject()) { \
73
    return (ThrowException(Exception::Error(String::New("expected " \
74
      "object for " #obj " to contain object member " #member)))); \
75
  } \
76
  *valp = Local<Object>::Cast(obj->Get(String::New(#member)));
77

    
78
#define SLURP_CONNECTION(arg, conn) \
79
  if (!(arg)->IsObject()) { \
80
    return (ThrowException(Exception::Error(String::New("expected " \
81
      "argument " #arg " to be a connection object")))); \
82
  } \
83
  node_dtrace_connection_t conn; \
84
  Local<Object> _##conn = Local<Object>::Cast(arg); \
85
  SLURP_INT(_##conn, fd, &conn.fd); \
86
  SLURP_STRING(_##conn, remoteAddress, &conn.remote); \
87
  SLURP_INT(_##conn, remotePort, &conn.port); \
88
  SLURP_INT(_##conn, bufferSize, &conn.buffered);
89

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

    
102
#define SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(arg0, arg1, conn) \
103
  if (!(arg0)->IsObject()) { \
104
    return (ThrowException(Exception::Error(String::New("expected " \
105
      "argument " #arg0 " to be a connection object")))); \
106
  } \
107
  if (!(arg1)->IsObject()) { \
108
    return (ThrowException(Exception::Error(String::New("expected " \
109
      "argument " #arg1 " to be a connection object")))); \
110
  } \
111
  node_dtrace_connection_t conn; \
112
  Local<Object> _##conn = Local<Object>::Cast(arg0); \
113
  SLURP_INT(_##conn, fd, &conn.fd); \
114
  SLURP_INT(_##conn, bufferSize, &conn.buffered); \
115
  _##conn = Local<Object>::Cast(arg1); \
116
  SLURP_STRING(_##conn, host, &conn.remote); \
117
  SLURP_INT(_##conn, port, &conn.port);
118

    
119

    
120
Handle<Value> DTRACE_NET_SERVER_CONNECTION(const Arguments& args) {
121
  if (!NODE_NET_SERVER_CONNECTION_ENABLED())
122
    return Undefined();
123

    
124
  HandleScope scope;
125

    
126
  SLURP_CONNECTION(args[0], conn);
127
  NODE_NET_SERVER_CONNECTION(&conn);
128

    
129
  return Undefined();
130
}
131

    
132
Handle<Value> DTRACE_NET_STREAM_END(const Arguments& args) {
133
  if (!NODE_NET_STREAM_END_ENABLED())
134
    return Undefined();
135

    
136
  HandleScope scope;
137

    
138
  SLURP_CONNECTION(args[0], conn);
139
  NODE_NET_STREAM_END(&conn);
140

    
141
  return Undefined();
142
}
143

    
144
Handle<Value> DTRACE_NET_SOCKET_READ(const Arguments& args) {
145
  if (!NODE_NET_SOCKET_READ_ENABLED())
146
    return Undefined();
147

    
148
  HandleScope scope;
149
  int nbytes;
150

    
151
  SLURP_CONNECTION(args[0], conn);
152

    
153
  if (!args[1]->IsNumber()) {
154
    return (ThrowException(Exception::Error(String::New("expected " 
155
      "argument 1 to be number of bytes"))));
156
  }
157

    
158
  nbytes = args[1]->Int32Value();
159

    
160
  NODE_NET_SOCKET_READ(&conn, nbytes);
161

    
162
  return Undefined();
163
}
164

    
165
Handle<Value> DTRACE_NET_SOCKET_WRITE(const Arguments& args) {
166
  if (!NODE_NET_SOCKET_WRITE_ENABLED())
167
    return Undefined();
168

    
169
  HandleScope scope;
170
  int nbytes;
171

    
172
  SLURP_CONNECTION(args[0], conn);
173

    
174
  if (!args[1]->IsNumber()) {
175
    return (ThrowException(Exception::Error(String::New("expected " 
176
      "argument 1 to be number of bytes"))));
177
  }
178

    
179
  nbytes = args[1]->Int32Value();
180

    
181
  NODE_NET_SOCKET_WRITE(&conn, nbytes);
182

    
183
  return Undefined();
184
}
185

    
186
Handle<Value> DTRACE_HTTP_SERVER_REQUEST(const Arguments& args) {
187
  node_dtrace_http_server_request_t req;
188

    
189
  if (!NODE_HTTP_SERVER_REQUEST_ENABLED())
190
    return Undefined();
191

    
192
  HandleScope scope;
193

    
194
  Local<Object> arg0 = Local<Object>::Cast(args[0]);
195
  Local<Object> headers;
196

    
197
  memset(&req, 0, sizeof(req));
198
  req._un.version = 1;
199
  SLURP_STRING(arg0, url, &req.url);
200
  SLURP_STRING(arg0, method, &req.method);
201

    
202
  SLURP_OBJECT(arg0, headers, &headers);
203

    
204
  if (!(headers)->IsObject())
205
    return (ThrowException(Exception::Error(String::New("expected "
206
      "object for request to contain string member headers"))));
207

    
208
  Local<Value> strfwdfor = headers->Get(String::New("x-forwarded-for"));
209
  String::Utf8Value fwdfor(strfwdfor);
210

    
211
  if (!strfwdfor->IsString() || (req.forwardedFor = *fwdfor) == NULL)
212
    req.forwardedFor = const_cast<char*>("");
213

    
214
  SLURP_CONNECTION(args[1], conn);
215

    
216
  NODE_HTTP_SERVER_REQUEST(&req, &conn);
217
  return Undefined();
218
}
219

    
220
Handle<Value> DTRACE_HTTP_SERVER_RESPONSE(const Arguments& args) {
221
  if (!NODE_HTTP_SERVER_RESPONSE_ENABLED())
222
    return Undefined();
223

    
224
  HandleScope scope;
225

    
226
  SLURP_CONNECTION(args[0], conn);
227
  NODE_HTTP_SERVER_RESPONSE(&conn);
228

    
229
  return Undefined();
230
}
231

    
232
Handle<Value> DTRACE_HTTP_CLIENT_REQUEST(const Arguments& args) {
233
  node_dtrace_http_client_request_t req;
234
  char *header;
235

    
236
  if (!NODE_HTTP_CLIENT_REQUEST_ENABLED())
237
    return Undefined();
238

    
239
  HandleScope scope;
240

    
241
  /*
242
   * For the method and URL, we're going to dig them out of the header.  This
243
   * is not as efficient as it could be, but we would rather not force the
244
   * caller here to retain their method and URL until the time at which
245
   * DTRACE_HTTP_CLIENT_REQUEST can be called.
246
   */
247
  Local<Object> arg0 = Local<Object>::Cast(args[0]);
248
  SLURP_STRING(arg0, _header, &header);
249

    
250
  req.method = header;
251

    
252
  while (*header != '\0' && *header != ' ')
253
    header++;
254

    
255
  if (*header != '\0')
256
    *header++ = '\0';
257

    
258
  req.url = header;
259

    
260
  while (*header != '\0' && *header != ' ')
261
    header++;
262

    
263
  *header = '\0';
264

    
265
  SLURP_CONNECTION_HTTP_CLIENT(args[1], conn);
266
  NODE_HTTP_CLIENT_REQUEST(&req, &conn);
267
  return Undefined();
268
}
269

    
270
Handle<Value> DTRACE_HTTP_CLIENT_RESPONSE(const Arguments& args) {
271
  if (!NODE_HTTP_CLIENT_RESPONSE_ENABLED())
272
    return Undefined();
273

    
274
  HandleScope scope;
275

    
276
  SLURP_CONNECTION_HTTP_CLIENT_RESPONSE(args[0], args[1], conn);
277
  NODE_HTTP_CLIENT_RESPONSE(&conn);
278

    
279
  return Undefined();
280
}
281

    
282
#define NODE_PROBE(name) #name, name
283

    
284
static int dtrace_gc_start(GCType type, GCCallbackFlags flags) {
285
  NODE_GC_START(type, flags);
286
  /*
287
   * We avoid the tail-call elimination of the USDT probe (which screws up
288
   * args) by forcing a return of 0.
289
   */
290
  return 0;
291
}
292

    
293
static int dtrace_gc_done(GCType type, GCCallbackFlags flags) {
294
  NODE_GC_DONE(type, flags);
295
  return 0;
296
}
297

    
298
void InitDTrace(Handle<Object> target) {
299
  static struct {
300
    const char *name;
301
    Handle<Value> (*func)(const Arguments&);
302
    Persistent<FunctionTemplate> templ;
303
  } tab[] = {
304
    { NODE_PROBE(DTRACE_NET_SERVER_CONNECTION) },
305
    { NODE_PROBE(DTRACE_NET_STREAM_END) },
306
    { NODE_PROBE(DTRACE_NET_SOCKET_READ) },
307
    { NODE_PROBE(DTRACE_NET_SOCKET_WRITE) },
308
    { NODE_PROBE(DTRACE_HTTP_SERVER_REQUEST) },
309
    { NODE_PROBE(DTRACE_HTTP_SERVER_RESPONSE) },
310
    { NODE_PROBE(DTRACE_HTTP_CLIENT_REQUEST) },
311
    { NODE_PROBE(DTRACE_HTTP_CLIENT_RESPONSE) },
312
    { NULL }
313
  };
314

    
315
  for (int i = 0; tab[i].name != NULL; i++) {
316
    tab[i].templ = Persistent<FunctionTemplate>::New(
317
        FunctionTemplate::New(tab[i].func));
318
    target->Set(String::NewSymbol(tab[i].name), tab[i].templ->GetFunction());
319
  }
320

    
321
#ifdef HAVE_ETW
322
  init_etw();
323
#endif
324

    
325
#if defined HAVE_DTRACE || defined HAVE_ETW
326
  v8::V8::AddGCPrologueCallback((GCPrologueCallback)dtrace_gc_start);
327
  v8::V8::AddGCEpilogueCallback((GCEpilogueCallback)dtrace_gc_done);
328
#endif
329
}
330

    
331
}