Coverage Report

Created: 2024-07-23 06:42

/src/moddable/xs/tools/xst.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) 2016-2024  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Tools.
5
 * 
6
 *   The Moddable SDK Tools is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Tools is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU General Public License
17
 *   along with the Moddable SDK Tools.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 */
20
21
#include "xsAll.h"
22
#include "xsScript.h"
23
#include "xs.h"
24
25
extern int fuzz(int argc, char* argv[]);
26
extern void fx_print(xsMachine* the);
27
extern void fxBuildAgent(xsMachine* the);
28
extern void fxBuildFuzz(xsMachine* the);
29
extern txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags);
30
extern void fxFulfillModuleFile(txMachine* the);
31
extern void fxRejectModuleFile(txMachine* the);
32
extern void fxRunLoop(txMachine* the);
33
extern void fxRunModuleFile(txMachine* the, txString path);
34
extern void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags);
35
extern int main262(int argc, char* argv[]);
36
37
struct sxJob {
38
  txMachine* the;
39
  txSlot self;
40
  txSlot function;
41
  txSlot argument;
42
};
43
44
struct sxSharedTimer {
45
  txSharedTimer* next;
46
  txThread thread;
47
  txNumber when;
48
  txNumber interval;
49
  txSharedTimerCallback callback;
50
  txInteger refconSize;
51
  char refcon[1];
52
};
53
54
static void fxPrintUsage();
55
56
static void fx_agent_broadcast(xsMachine* the);
57
static void fx_agent_getReport(xsMachine* the);
58
static void fx_agent_leaving(xsMachine* the);
59
static void fx_agent_monotonicNow(xsMachine* the);
60
static void fx_agent_receiveBroadcast(xsMachine* the);
61
static void fx_agent_report(xsMachine* the);
62
static void fx_agent_sleep(xsMachine* the);
63
static void fx_agent_start(xsMachine* the);
64
#if mxWindows
65
static unsigned int __stdcall fx_agent_start_aux(void* it);
66
#else
67
static void* fx_agent_start_aux(void* it);
68
#endif
69
static void fx_createRealm(xsMachine* the);
70
static void fx_detachArrayBuffer(xsMachine* the);
71
static void fx_evalScript(xsMachine* the);
72
static void fx_gc(xsMachine* the);
73
static void fx_metering(xsMachine* the);
74
static void fx_runScript(xsMachine* the);
75
76
extern void fx_clearTimer(txMachine* the);
77
static void fx_destroyTimer(void* data);
78
static void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot);
79
static void fx_setInterval(txMachine* the);
80
static void fx_setTimeout(txMachine* the);
81
static void fx_setTimer(txMachine* the, txNumber interval, txBoolean repeat);
82
83
84
char *gxAbortStrings[] = {
85
  "debugger",
86
  "memory full",
87
  "stack overflow",
88
  "fatal",
89
  "dead strip",
90
  "unhandled exception",
91
  "not enough keys",
92
  "too much computation",
93
  "unhandled rejection"
94
};
95
96
txAgentCluster gxAgentCluster;
97
98
#if OSSFUZZ
99
int omain(int argc, char* argv[]) 
100
#else
101
int main(int argc, char* argv[]) 
102
#endif
103
0
{
104
0
  txAgentCluster* agentCluster = &gxAgentCluster;
105
0
  int argi;
106
0
  int option = 0;
107
0
  int profiling = 0;
108
0
  char path[C_PATH_MAX];
109
0
  char* dot;
110
#if mxWindows
111
    char* harnessPath = "..\\harness";
112
#else
113
0
    char* harnessPath = "../harness";
114
0
#endif
115
0
  int error = 0;
116
  
117
0
  c_memset(agentCluster, 0, sizeof(txAgentCluster));
118
0
  fxCreateMutex(&(agentCluster->mainMutex));
119
0
  fxCreateCondition(&(agentCluster->countCondition));
120
0
  fxCreateMutex(&(agentCluster->countMutex));
121
0
  fxCreateCondition(&(agentCluster->dataCondition));
122
0
  fxCreateMutex(&(agentCluster->dataMutex));
123
0
  fxCreateMutex(&(agentCluster->reportMutex));
124
125
0
  if (argc == 1) {
126
0
    fxPrintUsage();
127
0
    return 1;
128
0
  }
129
0
  for (argi = 1; argi < argc; argi++) {
130
0
    if (argv[argi][0] != '-')
131
0
      continue;
132
  
133
0
    if (!strcmp(argv[argi], "-c"))
134
0
      option = 4;
135
0
    else if (!strcmp(argv[argi], "-i")) {
136
0
      argi++;
137
0
      option = 4;
138
0
    }
139
0
    else if (!strcmp(argv[argi], "-l"))
140
0
      option = 4;
141
0
    else if (!strcmp(argv[argi], "-lc"))
142
0
      option = 4;
143
0
    else if (!strcmp(argv[argi], "-o")) {
144
0
      argi++;
145
0
      option = 4;
146
0
    }
147
0
    else if (!strcmp(argv[argi], "-t"))
148
0
      option = 4;
149
150
0
    else if (!strcmp(argv[argi], "-h"))
151
0
      fxPrintUsage();
152
0
    else if (!strcmp(argv[argi], "-b"))
153
0
      option = 7;
154
0
    else if (!strcmp(argv[argi], "-e"))
155
0
      option = 1;
156
0
    else if (!strcmp(argv[argi], "-f"))
157
0
      option = 5;
158
0
    else if (!strcmp(argv[argi], "-j"))
159
0
      option = 6;
160
0
    else if (!strcmp(argv[argi], "-m"))
161
0
      option = 2;
162
0
    else if (!strcmp(argv[argi], "-p"))
163
0
      profiling = 1;
164
0
    else if (!strcmp(argv[argi], "-s"))
165
0
      option = 3;
166
0
    else if (!strcmp(argv[argi], "-v"))
167
0
      printf("XS %d.%d.%d, slot %zu bytes, ID %zu bytes\n", XS_MAJOR_VERSION, XS_MINOR_VERSION, XS_PATCH_VERSION, sizeof(txSlot), sizeof(txID));
168
0
    else {
169
0
      fxPrintUsage();
170
0
      return 1;
171
0
    }
172
0
  }
173
0
  if (option == 0) {
174
0
    if (c_realpath(harnessPath, path))
175
0
      option  = 4;
176
0
  }
177
0
  if (option == 4) {
178
0
    error = main262(argc, argv);
179
0
  }
180
0
  else if (option == 5) {
181
0
    error = fuzz(argc, argv);
182
0
  }
183
0
  else {
184
0
    xsCreation _creation = {
185
0
      16 * 1024 * 1024,   /* initialChunkSize */
186
0
      16 * 1024 * 1024,   /* incrementalChunkSize */
187
0
      1 * 1024 * 1024,  /* initialHeapCount */
188
0
      1 * 1024 * 1024,  /* incrementalHeapCount */
189
0
      256 * 1024,     /* stackCount */
190
0
      1024,         /* initialKeyCount */
191
0
      1024,       /* incrementalKeyCount */
192
0
      1993,         /* nameModulo */
193
0
      127,        /* symbolModulo */
194
0
      64 * 1024,      /* parserBufferSize */
195
0
      1993,       /* parserTableModulo */
196
0
    };
197
0
    xsCreation* creation = &_creation;
198
0
    xsMachine* machine;
199
0
        machine = xsCreateMachine(creation, "xst", NULL);
200
0
    xsBeginMetering(machine, NULL, 0);
201
0
    {
202
0
    if (profiling)
203
0
      fxStartProfiling(machine);
204
205
0
    xsBeginHost(machine);
206
0
    {
207
0
      xsVars(2);
208
0
      xsTry {
209
0
        fxBuildAgent(machine);
210
0
        fxBuildFuzz(machine);
211
212
0
        xsVar(0) = xsUndefined;
213
0
        the->rejection = &xsVar(0);
214
0
        for (argi = 1; argi < argc; argi++) {
215
0
          if (argv[argi][0] == '-')
216
0
            continue;
217
0
          if (option == 1) {
218
0
            xsVar(1) = xsGet(xsGlobal, xsID("$262"));
219
0
            xsResult = xsString(argv[argi]);
220
0
            xsCall1(xsVar(1), xsID("evalScript"), xsResult);
221
0
          }
222
0
          else {
223
0
            if (!c_realpath(argv[argi], path))
224
0
              xsURIError("file not found: %s", argv[argi]);
225
0
            dot = strrchr(path, '.');
226
0
            if ((option == 6) || (option == 7)) {
227
0
              FILE* file = C_NULL;
228
0
              char *buffer = C_NULL;
229
0
              xsTry {
230
0
                file = fopen(path, "r");
231
0
                if (!file)
232
0
                  xsUnknownError("can't open file");
233
0
                fseek(file, 0, SEEK_END);
234
0
                size_t size = ftell(file);
235
0
                fseek(file, 0, SEEK_SET);
236
0
                buffer = c_malloc(size + 1);
237
0
                if (!buffer)
238
0
                  xsUnknownError("not enough memory");
239
0
                if (size != fread(buffer, 1, size, file)) 
240
0
                  xsUnknownError("can't read file");
241
0
                buffer[size] = 0;
242
0
                fclose(file);
243
0
                file = C_NULL;
244
0
                xsResult = xsArrayBuffer(buffer, (txInteger)size);
245
0
                c_free(buffer);
246
0
                buffer = C_NULL;
247
0
                xsVar(1) = xsNew0(xsGlobal, xsID("TextDecoder"));
248
0
                xsResult = xsCall1(xsVar(1), xsID("decode"), xsResult);
249
0
                if (option == 6) {
250
0
                  xsVar(1) = xsGet(xsGlobal, xsID("JSON"));
251
0
                  xsResult = xsCall1(xsVar(1), xsID("parse"), xsResult);
252
0
                }
253
0
                else {
254
0
                  xsResult = xsCall1(xsGlobal, xsID("eval"), xsResult);
255
0
                }
256
0
              }
257
0
              xsCatch {
258
0
                if (buffer)
259
0
                  c_free(buffer);
260
0
                if (file)
261
0
                  fclose(file);
262
0
              }
263
0
            }
264
0
            else
265
0
            if (((option == 0) && dot && !c_strcmp(dot, ".mjs")) || (option == 2))
266
0
              fxRunModuleFile(the, path);
267
0
            else
268
0
              fxRunProgramFile(the, path, mxProgramFlag | mxDebugFlag);
269
0
          }
270
0
        }
271
0
        fxRunLoop(the);
272
0
        if (xsTest(xsVar(0))) 
273
0
          xsThrow(xsVar(0));
274
0
      }
275
0
      xsCatch {
276
0
        fprintf(stderr, "%s\n", xsToString(xsException));
277
0
        error = 1;
278
0
      }
279
0
    }
280
0
    fxCheckUnhandledRejections(machine, 1);
281
0
    xsEndHost(machine);
282
0
    if (profiling)
283
0
      fxStopProfiling(machine, C_NULL);
284
0
    }
285
0
    xsEndMetering(machine);
286
0
    if (machine->exitStatus) {
287
0
      char *why = (machine->exitStatus <= XS_UNHANDLED_REJECTION_EXIT) ? gxAbortStrings[machine->exitStatus] : "unknown";
288
0
      fprintf(stderr, "Error: %s\n", why);
289
0
      error = 1;
290
0
    }
291
0
    xsDeleteMachine(machine);
292
0
  }
293
0
  return error;
294
0
}
295
296
extern void modInstallTextDecoder(xsMachine *the);
297
extern void modInstallTextEncoder(xsMachine *the);
298
extern void modInstallBase64(xsMachine *the);
299
300
void fxBuildAgent(xsMachine* the) 
301
0
{
302
0
  txSlot* slot;
303
0
  txSlot* agent;
304
0
  txSlot* global;
305
306
0
  slot = fxLastProperty(the, fxNewHostObject(the, NULL));
307
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_broadcast, 2, xsID("broadcast"), XS_DONT_ENUM_FLAG); 
308
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_getReport, 0, xsID("getReport"), XS_DONT_ENUM_FLAG); 
309
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_monotonicNow, 0, xsID("monotonicNow"), XS_DONT_ENUM_FLAG); 
310
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_sleep, 1, xsID("sleep"), XS_DONT_ENUM_FLAG); 
311
0
  slot = fxNextHostFunctionProperty(the, slot, fx_agent_start, 1, xsID("start"), XS_DONT_ENUM_FLAG); 
312
0
  agent = the->stack;
313
314
0
  mxPush(mxGlobal);
315
0
  global = the->stack;
316
317
0
  mxPush(mxObjectPrototype);
318
0
  slot = fxLastProperty(the, fxNewObjectInstance(the));
319
0
  slot = fxNextSlotProperty(the, slot, agent, xsID("agent"), XS_GET_ONLY);
320
0
  slot = fxNextHostFunctionProperty(the, slot, fx_createRealm, 0, xsID("createRealm"), XS_DONT_ENUM_FLAG); 
321
0
  slot = fxNextHostFunctionProperty(the, slot, fx_detachArrayBuffer, 1, xsID("detachArrayBuffer"), XS_DONT_ENUM_FLAG); 
322
0
  slot = fxNextHostFunctionProperty(the, slot, fx_gc, 1, xsID("gc"), XS_DONT_ENUM_FLAG); 
323
0
  slot = fxNextHostFunctionProperty(the, slot, fx_evalScript, 1, xsID("evalScript"), XS_DONT_ENUM_FLAG); 
324
0
  slot = fxNextHostFunctionProperty(the, slot, fx_metering, 1, xsID("metering"), XS_DONT_ENUM_FLAG); 
325
0
  slot = fxNextSlotProperty(the, slot, global, xsID("global"), XS_GET_ONLY);
326
327
0
  slot = fxLastProperty(the, fxToInstance(the, global));
328
0
  slot = fxNextSlotProperty(the, slot, the->stack, xsID("$262"), XS_DONT_ENUM_FLAG);
329
0
  slot = fxNextHostFunctionProperty(the, slot, fx_print, 1, xsID("print"), XS_DONT_ENUM_FLAG);
330
0
  slot = fxNextHostFunctionProperty(the, slot, fx_runScript, 1, xsID("runScript"), XS_DONT_ENUM_FLAG);
331
0
  slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearInterval"), XS_DONT_ENUM_FLAG);
332
0
  slot = fxNextHostFunctionProperty(the, slot, fx_clearTimer, 1, xsID("clearTimeout"), XS_DONT_ENUM_FLAG);
333
0
  slot = fxNextHostFunctionProperty(the, slot, fx_setInterval, 1, xsID("setInterval"), XS_DONT_ENUM_FLAG);
334
0
  slot = fxNextHostFunctionProperty(the, slot, fx_setTimeout, 1, xsID("setTimeout"), XS_DONT_ENUM_FLAG);
335
  
336
0
  slot = fxNextHostFunctionProperty(the, slot, fx_harden, 1, xsID("harden"), XS_DONT_ENUM_FLAG);
337
0
  slot = fxNextHostFunctionProperty(the, slot, fx_lockdown, 0, xsID("lockdown"), XS_DONT_ENUM_FLAG);
338
  
339
0
  slot = fxNextHostFunctionProperty(the, slot, fx_unicodeCompare, 2, xsID("unicodeCompare"), XS_DONT_ENUM_FLAG);
340
341
0
  mxPop();
342
0
  mxPop();
343
  
344
0
  modInstallTextDecoder(the);
345
0
  modInstallTextEncoder(the);
346
0
  modInstallBase64(the);
347
0
}
348
349
void fxPrintUsage()
350
0
{
351
0
  printf("xst [-h] [-e] [-f] [-j] [-m] [-p] [-s] [-t] [-v] strings...\n");
352
0
  printf("\t-b: strings are paths to script buffers\n");
353
0
  printf("\t-e: eval strings\n");
354
0
  printf("\t-f: fuzz with REPRL harness\n");
355
0
  printf("\t-h: print this help message\n");
356
0
  printf("\t-j: strings are paths to JSON buffers\n");
357
0
  printf("\t-m: strings are paths to modules\n");
358
0
  printf("\t-p: profile\n");
359
0
  printf("\t-s: strings are paths to scripts\n");
360
0
  printf("\t-t: strings are paths to test262 cases or directories\n");
361
0
  printf("\t-v: print XS version\n");
362
0
  printf("without -b, -e, -f, -j, -m, -s, or -t:\n");
363
0
  printf("\tif ../harness exists, strings are paths to test262 cases or directories\n");
364
0
  printf("\telse if the extension is .mjs, strings are paths to modules\n");
365
0
  printf("\telse strings are paths to scripts\n");
366
0
}
367
368
void fx_gc(xsMachine* the)
369
0
{
370
0
  xsCollectGarbage();
371
0
}
372
373
void fx_evalScript(xsMachine* the)
374
0
{
375
0
  txSlot* realm;
376
0
  txSlot* module = mxFunctionInstanceHome(mxFunction->value.reference)->value.home.module;
377
0
  if (!module) module = mxProgram.value.reference;
378
0
  realm = mxModuleInstanceInternal(module)->value.module.realm;
379
0
  txStringStream aStream;
380
0
  aStream.slot = mxArgv(0);
381
0
  aStream.offset = 0;
382
0
  aStream.size = mxStringLength(fxToString(the, mxArgv(0)));
383
0
  fxRunScript(the, fxParseScript(the, &aStream, fxStringGetter, mxProgramFlag | mxDebugFlag), mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, module);
384
0
  mxPullSlot(mxResult);
385
0
}
386
387
void fx_metering(xsMachine* the)
388
0
{
389
0
#ifdef mxMetering
390
0
  xsResult = xsNumber(the->meterIndex);
391
0
#endif  
392
0
}
393
394
void fx_print(xsMachine* the)
395
22
{
396
22
  xsIntegerValue c = xsToInteger(xsArgc), i;
397
22
  xsStringValue string, p, q;
398
22
  xsVars(1);
399
22
  xsVar(0) = xsGet(xsGlobal, xsID("String"));
400
42
  for (i = 0; i < c; i++) {
401
20
    if (i)
402
3
      fprintf(stdout, " ");
403
20
    xsArg(i) = xsCallFunction1(xsVar(0), xsUndefined, xsArg(i));
404
20
    p = string = xsToString(xsArg(i));
405
20
  #if mxCESU8
406
21.2k
    for (;;) {
407
21.2k
      xsIntegerValue character;
408
21.2k
      q = fxUTF8Decode(p, &character);
409
21.2k
    again:
410
21.2k
      if (character == C_EOF)
411
20
        break;
412
21.2k
      if (character == 0) {
413
2.47k
        if (p > string) {
414
655
          char c = *p;
415
655
          *p = 0;
416
655
          fprintf(stdout, "%s", string);
417
655
          *p = c;
418
655
        }
419
2.47k
        string = q;
420
2.47k
      }
421
18.7k
      else if ((0x0000D800 <= character) && (character <= 0x0000DBFF)) {
422
432
        xsStringValue r = q;
423
432
        xsIntegerValue surrogate;
424
432
        q = fxUTF8Decode(r, &surrogate);
425
432
        if ((0x0000DC00 <= surrogate) && (surrogate <= 0x0000DFFF)) {
426
402
          char buffer[5];
427
402
          character = (txInteger)(0x00010000 + ((character & 0x03FF) << 10) + (surrogate & 0x03FF));
428
402
          if (p > string) {
429
305
            char c = *p;
430
305
            *p = 0;
431
305
            fprintf(stdout, "%s", string);
432
305
            *p = c;
433
305
          }
434
402
          p = fxUTF8Encode(buffer, character);
435
402
          *p = 0;
436
402
          fprintf(stdout, "%s", buffer);
437
402
          string = q;
438
402
        }
439
30
        else {
440
30
          p = r;
441
30
          character = surrogate;
442
30
          goto again;
443
30
        }
444
432
      }
445
21.2k
      p = q;
446
21.2k
    }
447
20
  #endif  
448
20
    fprintf(stdout, "%s", string);
449
20
  }
450
22
  fprintf(stdout, "\n");
451
22
}
452
453
void fx_runScript(xsMachine* the)
454
0
{
455
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
456
0
  char path[C_PATH_MAX];
457
0
  txUnsigned flags = mxProgramFlag | mxDebugFlag;
458
0
  if (!c_realpath(fxToString(the, mxArgv(0)), path))
459
0
    xsURIError("file not found");
460
0
  txScript* script = fxLoadScript(the, path, flags);
461
0
  mxModuleInstanceInternal(mxProgram.value.reference)->value.module.id = fxID(the, path);
462
0
  fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference);
463
0
  mxPullSlot(mxResult);
464
0
}
465
466
/* $262 */
467
468
void fx_agent_broadcast(xsMachine* the)
469
0
{
470
0
  txAgentCluster* agentCluster = &gxAgentCluster;
471
0
  if (xsIsInstanceOf(xsArg(0), xsTypedArrayPrototype)) {
472
0
    xsArg(0) = xsGet(xsArg(0), xsID("buffer"));
473
0
  }
474
0
    fxLockMutex(&(agentCluster->dataMutex));
475
0
  agentCluster->dataBuffer = xsMarshallAlien(xsArg(0));
476
0
  if (mxArgc > 1)
477
0
    agentCluster->dataValue = xsToInteger(xsArg(1));
478
0
  fxWakeAllCondition(&(agentCluster->dataCondition));
479
0
    fxUnlockMutex(&(agentCluster->dataMutex));
480
    
481
0
    fxLockMutex(&(agentCluster->countMutex));
482
0
    while (agentCluster->count > 0)
483
0
    fxSleepCondition(&(agentCluster->countCondition), &(agentCluster->countMutex));
484
0
    fxUnlockMutex(&(agentCluster->countMutex));
485
0
}
486
487
void fx_agent_getReport(xsMachine* the)
488
0
{
489
0
  txAgentCluster* agentCluster = &gxAgentCluster;
490
0
  txAgentReport* report = C_NULL;
491
0
    fxLockMutex(&(agentCluster->reportMutex));
492
0
  report = agentCluster->firstReport;
493
0
  if (report)
494
0
    agentCluster->firstReport = report->next;
495
0
    fxUnlockMutex(&(agentCluster->reportMutex));
496
0
    if (report) {
497
0
      xsResult = xsString(report->message);
498
0
      c_free(report);
499
0
    }
500
0
    else
501
0
      xsResult = xsNull;
502
0
}
503
504
void fx_agent_leaving(xsMachine* the)
505
0
{
506
0
}
507
508
void fx_agent_monotonicNow(xsMachine* the)
509
0
{
510
0
  xsResult = xsNumber(mxMonotonicNow());
511
0
}
512
513
void fx_agent_receiveBroadcast(xsMachine* the)
514
0
{
515
0
  txAgentCluster* agentCluster = &gxAgentCluster;
516
0
   fxLockMutex(&(agentCluster->dataMutex));
517
0
  while (agentCluster->dataBuffer == NULL)
518
0
    fxSleepCondition(&(agentCluster->dataCondition), &(agentCluster->dataMutex));
519
0
  xsResult = xsDemarshallAlien(agentCluster->dataBuffer);
520
0
    fxUnlockMutex(&(agentCluster->dataMutex));
521
  
522
0
    fxLockMutex(&(agentCluster->countMutex));
523
0
    agentCluster->count--;
524
0
    fxWakeCondition(&(agentCluster->countCondition));
525
0
    fxUnlockMutex(&(agentCluster->countMutex));
526
    
527
0
  xsCallFunction2(xsArg(0), xsGlobal, xsResult, xsInteger(agentCluster->dataValue));
528
0
}
529
530
void fx_agent_report(xsMachine* the)
531
0
{
532
0
  txAgentCluster* agentCluster = &gxAgentCluster;
533
0
  xsStringValue message = xsToString(xsArg(0));
534
0
  xsIntegerValue messageLength = mxStringLength(message);
535
0
  txAgentReport* report = c_malloc(sizeof(txAgentReport) + messageLength);
536
0
  if (!report) xsUnknownError("not enough memory");
537
0
    report->next = C_NULL;
538
0
  c_memcpy(&(report->message[0]), message, messageLength + 1);
539
0
    fxLockMutex(&(agentCluster->reportMutex));
540
0
    if (agentCluster->firstReport)
541
0
    agentCluster->lastReport->next = report;
542
0
    else
543
0
    agentCluster->firstReport = report;
544
0
  agentCluster->lastReport = report;
545
0
    fxUnlockMutex(&(agentCluster->reportMutex));
546
0
}
547
548
void fx_agent_sleep(xsMachine* the)
549
0
{
550
0
  xsIntegerValue delay = xsToInteger(xsArg(0));
551
#if mxWindows
552
  Sleep(delay);
553
#else 
554
0
  usleep(delay * 1000);
555
0
#endif
556
0
}
557
558
void fx_agent_start(xsMachine* the)
559
0
{
560
0
  xsStringValue script = xsToString(xsArg(0));
561
0
  xsIntegerValue scriptLength = mxStringLength(script);
562
0
  txAgentCluster* agentCluster = &gxAgentCluster;
563
0
  txAgent* agent = c_malloc(sizeof(txAgent) + scriptLength);
564
0
  if (!agent) xsUnknownError("not enough memory");
565
0
  c_memset(agent, 0, sizeof(txAgent));
566
0
  if (agentCluster->firstAgent)
567
0
    agentCluster->lastAgent->next = agent;
568
0
  else
569
0
    agentCluster->firstAgent = agent;
570
0
  agentCluster->lastAgent = agent;
571
0
  agentCluster->count++;
572
0
  agent->scriptLength = scriptLength;
573
0
  c_memcpy(&(agent->script[0]), script, scriptLength + 1);
574
#if mxWindows
575
  agent->thread = (HANDLE)_beginthreadex(NULL, 0, fx_agent_start_aux, agent, 0, NULL);
576
#elif mxMacOSX
577
  pthread_attr_t attr; 
578
  pthread_t self = pthread_self();
579
  size_t size = pthread_get_stacksize_np(self);
580
  pthread_attr_init(&attr);
581
  pthread_attr_setstacksize(&attr, size);
582
    pthread_create(&(agent->thread), &attr, &fx_agent_start_aux, agent);
583
#else 
584
0
    pthread_create(&(agent->thread), NULL, &fx_agent_start_aux, agent);
585
0
#endif
586
0
}
587
588
#if mxWindows
589
unsigned int __stdcall fx_agent_start_aux(void* it)
590
#else
591
void* fx_agent_start_aux(void* it)
592
#endif
593
0
{
594
0
  xsCreation creation = {
595
0
    16 * 1024 * 1024,   /* initialChunkSize */
596
0
    16 * 1024 * 1024,   /* incrementalChunkSize */
597
0
    1 * 1024 * 1024,  /* initialHeapCount */
598
0
    1 * 1024 * 1024,  /* incrementalHeapCount */
599
0
    4096,         /* stackCount */
600
0
    1024,         /* initialKeyCount */
601
0
    1024,       /* incrementalKeyCount */
602
0
    1993,         /* nameModulo */
603
0
    127,        /* symbolModulo */
604
0
    64 * 1024,      /* parserBufferSize */
605
0
    1993,       /* parserTableModulo */
606
0
  };
607
0
  txAgent* agent = it;
608
0
  xsMachine* machine = xsCreateMachine(&creation, "xst-agent", NULL);
609
0
  xsBeginHost(machine);
610
0
  {
611
0
    xsTry {
612
0
      txSlot* slot;
613
0
      txSlot* global;
614
0
      txStringCStream stream;
615
      
616
0
      mxPush(mxGlobal);
617
0
      global = the->stack;
618
      
619
0
      slot = fxLastProperty(the, fxNewHostObject(the, NULL));
620
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_leaving, 0, xsID("leaving"), XS_DONT_ENUM_FLAG); 
621
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_monotonicNow, 0, xsID("monotonicNow"), XS_DONT_ENUM_FLAG); 
622
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_receiveBroadcast, 1, xsID("receiveBroadcast"), XS_DONT_ENUM_FLAG); 
623
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_report, 1, xsID("report"), XS_DONT_ENUM_FLAG); 
624
0
      slot = fxNextHostFunctionProperty(the, slot, fx_agent_sleep, 1, xsID("sleep"), XS_DONT_ENUM_FLAG); 
625
0
      fxSetHostData(the, the->stack, agent);
626
      
627
0
      mxPush(mxObjectPrototype);
628
0
      slot = fxLastProperty(the, fxNewObjectInstance(the));
629
0
      slot = fxNextSlotProperty(the, slot, the->stack + 1, xsID("agent"), XS_GET_ONLY);
630
      
631
0
      slot = fxLastProperty(the, fxToInstance(the, global));
632
0
      slot = fxNextSlotProperty(the, slot, the->stack, xsID("$262"), XS_GET_ONLY);
633
      
634
0
      mxPop();
635
0
      mxPop();
636
0
      mxPop();
637
      
638
0
      stream.buffer = agent->script;
639
0
      stream.offset = 0;
640
0
      stream.size = agent->scriptLength;
641
0
      fxRunScript(the, fxParseScript(the, &stream, fxStringCGetter, mxProgramFlag), mxThis, C_NULL, C_NULL, C_NULL, mxProgram.value.reference);
642
0
      fxRunLoop(the);
643
0
    }
644
0
    xsCatch {
645
0
    }
646
0
  }
647
0
  xsEndHost(the);
648
0
  xsDeleteMachine(machine);
649
#if mxWindows
650
  return 0;
651
#else
652
0
  return NULL;
653
0
#endif
654
0
}
655
656
void fx_createRealm(xsMachine* the)
657
0
{
658
0
  xsResult = xsThis;
659
0
}
660
661
void fx_detachArrayBuffer(xsMachine* the)
662
0
{
663
0
  txSlot* slot = mxArgv(0);
664
0
  if (slot->kind == XS_REFERENCE_KIND) {
665
0
    txSlot* instance = slot->value.reference;
666
0
    if (((slot = instance->next)) && (slot->flag & XS_INTERNAL_FLAG) && (slot->kind == XS_ARRAY_BUFFER_KIND) && (instance != mxArrayBufferPrototype.value.reference)) {
667
0
      slot->value.arrayBuffer.address = C_NULL;
668
0
      slot->next->value.bufferInfo.length = 0;
669
0
      return;
670
0
    }
671
0
  }
672
0
  mxTypeError("this is no ArrayBuffer instance");
673
0
}
674
675
/* TIMER */
676
677
static txHostHooks gxTimerHooks = {
678
  fx_destroyTimer,
679
  fx_markTimer
680
};
681
682
void fx_callbackTimer(txSharedTimer* timer, void* refcon, txInteger refconSize)
683
0
{
684
0
  txJob* job = (txJob*)refcon;
685
0
  txMachine* the = job->the;
686
0
  fxBeginHost(the);
687
0
  mxTry(the) {
688
0
    mxPushUndefined();
689
0
    mxPush(job->function);
690
0
    mxCall();
691
0
    mxPush(job->argument);
692
0
    mxRunCount(1);
693
0
    mxPop();
694
0
  }
695
0
  mxCatch(the) {
696
0
    *((txSlot*)the->rejection) = mxException;
697
0
    timer->interval = 0;
698
0
  }
699
0
  if (timer->interval == 0) {
700
0
    fxAccess(the, &job->self);
701
0
    *mxResult = the->scratch;
702
0
    fxForget(the, &job->self);
703
0
    fxSetHostData(the, mxResult, NULL);
704
0
  }
705
0
  fxEndHost(the);
706
0
}
707
708
void fx_clearTimer(txMachine* the)
709
0
{
710
0
  if (mxIsNull(mxArgv(0)))
711
0
    return;
712
0
  txHostHooks* hooks = fxGetHostHooks(the, mxArgv(0));
713
0
  if (hooks == &gxTimerHooks) {
714
0
    txSharedTimer* timer = fxGetHostData(the, mxArgv(0));
715
0
    if (timer) {
716
0
      txJob* job = (txJob*)&(timer->refcon[0]);
717
0
      fxForget(the, &job->self);
718
0
      fxSetHostData(the, mxArgv(0), NULL);
719
0
      fxUnscheduleSharedTimer(timer);
720
0
    }
721
0
  }
722
0
  else
723
0
    mxTypeError("no timer");
724
0
}
725
726
void fx_destroyTimer(void* data)
727
0
{
728
0
}
729
730
void fx_markTimer(txMachine* the, void* it, txMarkRoot markRoot)
731
0
{
732
0
  txJob* job = it;
733
0
  if (job) {
734
0
    (*markRoot)(the, &job->function);
735
0
    (*markRoot)(the, &job->argument);
736
0
  }
737
0
}
738
739
void fx_setInterval(txMachine* the)
740
0
{
741
0
  fx_setTimer(the, fxToNumber(the, mxArgv(1)), 1);
742
0
}
743
744
void fx_setTimeout(txMachine* the)
745
0
{
746
0
  fx_setTimer(the, fxToNumber(the, mxArgv(1)), 0);
747
0
}
748
749
void fx_setTimer(txMachine* the, txNumber interval, txBoolean repeat)
750
0
{
751
0
  txJob _job;
752
0
  txJob* job;
753
0
  txSharedTimer* timer;
754
0
  if (c_isnan(interval) || (interval < 0))
755
0
    interval = 0;
756
0
  c_memset(&_job, 0, sizeof(txJob));
757
0
  timer = fxScheduleSharedTimer(interval, (repeat) ? interval : 0, fx_callbackTimer, &_job, sizeof(txJob));  
758
0
  if (!timer)
759
0
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
760
0
  job = (txJob*)&(timer->refcon[0]);
761
0
  job->the = the;
762
0
  fxNewHostObject(the, NULL);
763
0
    mxPull(job->self);
764
0
  job->function = *mxArgv(0);
765
0
  if (mxArgc > 2)
766
0
    job->argument = *mxArgv(2);
767
0
  else
768
0
    job->argument = mxUndefined;
769
0
  fxSetHostData(the, &job->self, timer);
770
0
  fxSetHostHooks(the, &job->self, &gxTimerHooks);
771
0
  fxRemember(the, &job->self);
772
0
  fxAccess(the, &job->self);
773
0
  *mxResult = the->scratch;
774
0
}
775
776
/* PLATFORM */
777
778
void fxCreateMachinePlatform(txMachine* the)
779
20.5k
{
780
20.5k
#ifdef mxDebug
781
20.5k
  the->connection = mxNoSocket;
782
20.5k
#endif
783
20.5k
}
784
785
void fxDeleteMachinePlatform(txMachine* the)
786
20.5k
{
787
20.5k
}
788
789
void fxQueuePromiseJobs(txMachine* the)
790
371k
{
791
371k
  the->promiseJobs = 1;
792
371k
}
793
794
/* SHARED TIMERS */
795
796
typedef struct sxSharedTimers txSharedTimers;
797
struct sxSharedTimers {
798
  txSharedTimer* first;
799
  txMutex mutex;
800
};
801
static txSharedTimers gxSharedTimers;
802
803
void fxInitializeSharedTimers()
804
20.5k
{
805
20.5k
  c_memset(&gxSharedTimers, 0, sizeof(txSharedTimers));
806
20.5k
  fxCreateMutex(&(gxSharedTimers.mutex));
807
20.5k
}
808
809
void fxTerminateSharedTimers()
810
20.5k
{
811
20.5k
  fxDeleteMutex(&(gxSharedTimers.mutex));
812
20.5k
  if (gxSharedTimers.first != C_NULL) {
813
0
    fprintf(stderr, "# shared timers mismatch!\n");
814
0
    exit(1);
815
0
  }
816
20.5k
}
817
818
void fxRescheduleSharedTimer(txSharedTimer* timer, txNumber timeout, txNumber interval)
819
0
{
820
0
    fxLockMutex(&(gxSharedTimers.mutex));
821
0
  timer->when = mxMonotonicNow() + timeout;
822
0
  timer->interval = interval;
823
0
    fxUnlockMutex(&(gxSharedTimers.mutex));
824
0
}
825
826
void* fxScheduleSharedTimer(txNumber timeout, txNumber interval, txSharedTimerCallback callback, void* refcon, txInteger refconSize)
827
13
{
828
13
  txSharedTimer* timer;
829
13
  txSharedTimer** address;
830
13
  txSharedTimer* link;
831
13
  timer = c_calloc(1, sizeof(txSharedTimer) + refconSize - 1);
832
13
  if (timer) {
833
13
    timer->thread = mxCurrentThread();
834
13
    timer->when = mxMonotonicNow() + timeout;
835
13
    timer->interval = interval;
836
13
    timer->callback = callback;
837
13
    timer->refconSize = refconSize;
838
13
    c_memcpy(timer->refcon, refcon, refconSize);
839
    
840
13
    fxLockMutex(&(gxSharedTimers.mutex));
841
13
    address = (txSharedTimer**)&(gxSharedTimers.first);
842
26
    while ((link = *address))
843
13
      address = &(link->next);
844
13
    *address = timer;
845
13
    fxUnlockMutex(&(gxSharedTimers.mutex));
846
13
    }
847
13
    return timer;
848
13
}
849
850
void fxUnscheduleSharedTimer(txSharedTimer* timer)
851
13
{
852
13
  txSharedTimer** address;
853
13
  txSharedTimer* link;
854
13
    fxLockMutex(&(gxSharedTimers.mutex));
855
13
    address = (txSharedTimer**)&(gxSharedTimers.first);
856
13
  while ((link = *address)) {
857
13
    if (link == timer) {
858
13
      *address = link->next;
859
13
      c_free(timer);
860
13
      break;
861
13
    }
862
0
    address = &(link->next);
863
0
  }
864
13
    fxUnlockMutex(&(gxSharedTimers.mutex));
865
13
}
866
867
void fxRunLoop(txMachine* the)
868
8.43k
{
869
8.43k
  txThread thread = mxCurrentThread();
870
8.43k
  txNumber when;
871
8.43k
  txInteger count;
872
8.43k
  txSharedTimer* timer;
873
  
874
8.43k
  for (;;) {
875
8.43k
    fxEndJob(the);
876
8.52k
    while (the->promiseJobs) {
877
371k
      while (the->promiseJobs) {
878
371k
        the->promiseJobs = 0;
879
371k
        fxRunPromiseJobs(the);
880
371k
      }
881
86
      fxEndJob(the);
882
86
    }
883
8.43k
    when = mxMonotonicNow();
884
8.43k
    fxLockMutex(&(gxSharedTimers.mutex));
885
8.43k
    count = 0;
886
8.43k
    timer = gxSharedTimers.first;
887
8.43k
    while (timer) {
888
0
      if (timer->thread == thread) {
889
0
        count++;
890
0
        if (timer->when <= when)
891
0
          break; // one timer at time to run promise jobs queued by the timer in the same "tick"
892
0
      }
893
0
      timer = timer->next;
894
0
    }
895
8.43k
    fxUnlockMutex(&(gxSharedTimers.mutex));
896
8.43k
    if (timer) {
897
0
      (timer->callback)(timer, timer->refcon, timer->refconSize);
898
0
      if (timer->interval == 0)
899
0
        fxUnscheduleSharedTimer(timer);
900
0
      else
901
0
        timer->when += timer->interval;
902
0
      continue;
903
0
    }
904
8.43k
    if (count == 0)
905
8.42k
      break;
906
8.43k
  }
907
8.43k
}
908
909
void fxFulfillModuleFile(txMachine* the)
910
0
{
911
0
}
912
913
void fxRejectModuleFile(txMachine* the)
914
0
{
915
0
  *((txSlot*)the->rejection) = xsArg(0);
916
0
}
917
918
void fxRunModuleFile(txMachine* the, txString path)
919
0
{
920
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
921
0
  mxPushStringC(path);
922
0
  fxRunImport(the, realm, XS_NO_ID);
923
0
  mxDub();
924
0
  fxGetID(the, mxID(_then));
925
0
  mxCall();
926
0
  fxNewHostFunction(the, fxFulfillModuleFile, 1, XS_NO_ID, XS_NO_ID);
927
0
  fxNewHostFunction(the, fxRejectModuleFile, 1, XS_NO_ID, XS_NO_ID);
928
0
  mxRunCount(2);
929
0
  mxPop();
930
0
}
931
932
void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags)
933
0
{
934
0
  txSlot* realm = mxProgram.value.reference->next->value.module.realm;
935
0
  txScript* script = fxLoadScript(the, path, flags);
936
0
  mxModuleInstanceInternal(mxProgram.value.reference)->value.module.id = fxID(the, path);
937
0
  fxRunScript(the, script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference);
938
0
  mxPullSlot(mxResult);
939
0
}
940
941
void fxAbort(txMachine* the, int status)
942
308
{
943
308
  if (XS_DEBUGGER_EXIT == status)
944
0
    c_exit(1);
945
308
  if (the->exitStatus) // xsEndHost calls fxAbort!
946
0
    return;
947
308
  the->exitStatus = status;
948
308
  fxExitToHost(the);
949
308
}
950
951
txID fxFindModule(txMachine* the, txSlot* realm, txID moduleID, txSlot* slot)
952
114k
{
953
114k
  char name[C_PATH_MAX];
954
114k
  char path[C_PATH_MAX];
955
114k
  txInteger dot = 0;
956
114k
  txString slash;
957
114k
  fxToStringBuffer(the, slot, name, sizeof(name));
958
114k
  if (name[0] == '.') {
959
0
    if (name[1] == '/') {
960
0
      dot = 1;
961
0
    }
962
0
    else if ((name[1] == '.') && (name[2] == '/')) {
963
0
      dot = 2;
964
0
    }
965
0
  }
966
114k
  if (dot) {
967
0
    if (moduleID == XS_NO_ID)
968
0
      return XS_NO_ID;
969
0
    c_strncpy(path, fxGetKeyName(the, moduleID), C_PATH_MAX - 1);
970
0
    path[C_PATH_MAX - 1] = 0;
971
0
    slash = c_strrchr(path, mxSeparator);
972
0
    if (!slash)
973
0
      return XS_NO_ID;
974
0
    if (dot == 2) {
975
0
      *slash = 0;
976
0
      slash = c_strrchr(path, mxSeparator);
977
0
      if (!slash)
978
0
        return XS_NO_ID;
979
0
    }
980
#if mxWindows
981
    {
982
      char c;
983
      char* s = name;
984
      while ((c = *s)) {
985
        if (c == '/')
986
          *s = '\\';
987
        s++;
988
      }
989
    }
990
#endif
991
0
  }
992
114k
  else
993
114k
    slash = path;
994
114k
  *slash = 0;
995
114k
  if ((c_strlen(path) + c_strlen(name + dot)) >= sizeof(path))
996
0
    xsRangeError("path too long");
997
114k
  c_strcat(path, name + dot);
998
114k
  return fxNewNameC(the, path);
999
114k
}
1000
1001
void fxLoadModule(txMachine* the, txSlot* module, txID moduleID)
1002
36
{
1003
36
  char path[C_PATH_MAX];
1004
36
  char real[C_PATH_MAX];
1005
36
  txScript* script;
1006
36
#ifdef mxDebug
1007
36
  txUnsigned flags = mxDebugFlag;
1008
#else
1009
  txUnsigned flags = 0;
1010
#endif
1011
36
  c_strncpy(path, fxGetKeyName(the, moduleID), C_PATH_MAX - 1);
1012
36
  path[C_PATH_MAX - 1] = 0;
1013
36
  if (c_realpath(path, real)) {
1014
#if mxWindows
1015
    DWORD attributes;
1016
    attributes = GetFileAttributes(path);
1017
    if (attributes != 0xFFFFFFFF) {
1018
      if (attributes & FILE_ATTRIBUTE_DIRECTORY)
1019
        return;
1020
    }
1021
#else
1022
0
    struct stat a_stat;
1023
0
    if (stat(path, &a_stat) == 0) {
1024
0
      if (S_ISDIR(a_stat.st_mode)) 
1025
0
        return;
1026
0
    }
1027
0
#endif  
1028
0
    script = fxLoadScript(the, real, flags);
1029
0
    if (script)
1030
0
      fxResolveModule(the, module, moduleID, script, C_NULL, C_NULL);
1031
0
  }
1032
36
}
1033
1034
txScript* fxLoadScript(txMachine* the, txString path, txUnsigned flags)
1035
0
{
1036
0
  txParser _parser;
1037
0
  txParser* parser = &_parser;
1038
0
  txParserJump jump;
1039
0
  FILE* file = NULL;
1040
0
  txString name = NULL;
1041
0
  char map[C_PATH_MAX];
1042
0
  txScript* script = NULL;
1043
0
  fxInitializeParser(parser, the, the->parserBufferSize, the->parserTableModulo);
1044
0
  parser->firstJump = &jump;
1045
0
  file = fopen(path, "r");
1046
0
  if (c_setjmp(jump.jmp_buf) == 0) {
1047
0
    mxParserThrowElse(file);
1048
0
    parser->path = fxNewParserSymbol(parser, path);
1049
0
    fxParserTree(parser, file, (txGetter)fgetc, flags, &name);
1050
0
    fclose(file);
1051
0
    file = NULL;
1052
0
    if (name) {
1053
0
      mxParserThrowElse(c_realpath(fxCombinePath(parser, path, name), map));
1054
0
      parser->path = fxNewParserSymbol(parser, map);
1055
0
      file = fopen(map, "r");
1056
0
      mxParserThrowElse(file);
1057
0
      fxParserSourceMap(parser, file, (txGetter)fgetc, flags, &name);
1058
0
      fclose(file);
1059
0
      file = NULL;
1060
0
      if ((parser->errorCount == 0) && name) {
1061
0
        mxParserThrowElse(c_realpath(fxCombinePath(parser, map, name), map));
1062
0
        parser->path = fxNewParserSymbol(parser, map);
1063
0
      }
1064
0
    }
1065
0
    fxParserHoist(parser);
1066
0
    fxParserBind(parser);
1067
0
    script = fxParserCode(parser);
1068
0
  }
1069
0
  if (file)
1070
0
    fclose(file);
1071
#ifdef mxInstrument
1072
  if (the->peakParserSize < parser->total)
1073
    the->peakParserSize = parser->total;
1074
#endif
1075
0
  fxTerminateParser(parser);
1076
0
  return script;
1077
0
}
1078
1079
/* DEBUG */
1080
1081
#ifdef mxDebug
1082
1083
void fxConnect(txMachine* the)
1084
20.5k
{
1085
20.5k
  if (!c_strcmp(the->name, "xst_fuzz"))
1086
0
    return;
1087
20.5k
  if (!c_strcmp(the->name, "xst_fuzz_oss"))
1088
20.5k
    return;
1089
#ifdef mxMultipleThreads
1090
  if (!c_strcmp(the->name, "xst262"))
1091
    return;
1092
  if (!c_strcmp(the->name, "xst-agent"))
1093
    return;
1094
#endif    
1095
0
  char name[256];
1096
0
  char* colon;
1097
0
  int port;
1098
#if mxWindows
1099
  if (GetEnvironmentVariable("XSBUG_HOST", name, sizeof(name))) {
1100
#else
1101
0
  colon = getenv("XSBUG_HOST");
1102
0
  if ((colon) && (c_strlen(colon) + 1 < sizeof(name))) {
1103
0
    c_strcpy(name, colon);
1104
0
#endif    
1105
0
    colon = strchr(name, ':');
1106
0
    if (colon == NULL)
1107
0
      port = 5002;
1108
0
    else {
1109
0
      *colon = 0;
1110
0
      colon++;
1111
0
      port = strtol(colon, NULL, 10);
1112
0
    }
1113
0
  }
1114
0
  else {
1115
0
    strcpy(name, "localhost");
1116
0
    port = 5002;
1117
0
  }
1118
#if mxWindows
1119
{   
1120
  WSADATA wsaData;
1121
  struct hostent *host;
1122
  struct sockaddr_in address;
1123
  unsigned long flag;
1124
  if (WSAStartup(0x202, &wsaData) == SOCKET_ERROR)
1125
    return;
1126
  host = gethostbyname(name);
1127
  if (!host)
1128
    goto bail;
1129
  memset(&address, 0, sizeof(address));
1130
  address.sin_family = AF_INET;
1131
  memcpy(&(address.sin_addr), host->h_addr, host->h_length);
1132
    address.sin_port = htons(port);
1133
  the->connection = socket(AF_INET, SOCK_STREAM, 0);
1134
  if (the->connection == INVALID_SOCKET)
1135
    return;
1136
    flag = 1;
1137
    ioctlsocket(the->connection, FIONBIO, &flag);
1138
  if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) == SOCKET_ERROR) {
1139
    if (WSAEWOULDBLOCK == WSAGetLastError()) {
1140
      fd_set fds;
1141
      struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds
1142
      FD_ZERO(&fds);
1143
      FD_SET(the->connection, &fds);
1144
      if (select(0, NULL, &fds, NULL, &timeout) == 0)
1145
        goto bail;
1146
      if (!FD_ISSET(the->connection, &fds))
1147
        goto bail;
1148
    }
1149
    else
1150
      goto bail;
1151
  }
1152
  flag = 0;
1153
  ioctlsocket(the->connection, FIONBIO, &flag);
1154
}
1155
#else
1156
0
{   
1157
0
  struct sockaddr_in address;
1158
0
  int flag;
1159
0
  memset(&address, 0, sizeof(address));
1160
0
    address.sin_family = AF_INET;
1161
0
  address.sin_addr.s_addr = inet_addr(name);
1162
0
  if (address.sin_addr.s_addr == INADDR_NONE) {
1163
0
    struct hostent *host = gethostbyname(name);
1164
0
    if (!host)
1165
0
      return;
1166
0
    memcpy(&(address.sin_addr), host->h_addr, host->h_length);
1167
0
  }
1168
0
    address.sin_port = htons(port);
1169
0
  the->connection = socket(AF_INET, SOCK_STREAM, 0);
1170
0
  if (the->connection <= 0)
1171
0
    goto bail;
1172
0
  c_signal(SIGPIPE, SIG_IGN);
1173
#if mxMacOSX
1174
  {
1175
    int set = 1;
1176
    setsockopt(the->connection, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));
1177
  }
1178
#endif
1179
0
  flag = fcntl(the->connection, F_GETFL, 0);
1180
0
  fcntl(the->connection, F_SETFL, flag | O_NONBLOCK);
1181
0
  if (connect(the->connection, (struct sockaddr*)&address, sizeof(address)) < 0) {
1182
0
       if (errno == EINPROGRESS) { 
1183
0
      fd_set fds;
1184
0
      struct timeval timeout = { 2, 0 }; // 2 seconds, 0 micro-seconds
1185
0
      int error = 0;
1186
0
      unsigned int length = sizeof(error);
1187
0
      FD_ZERO(&fds);
1188
0
      FD_SET(the->connection, &fds);
1189
0
      if (select(the->connection + 1, NULL, &fds, NULL, &timeout) == 0)
1190
0
        goto bail;
1191
0
      if (!FD_ISSET(the->connection, &fds))
1192
0
        goto bail;
1193
0
      if (getsockopt(the->connection, SOL_SOCKET, SO_ERROR, &error, &length) < 0)
1194
0
        goto bail;
1195
0
      if (error)
1196
0
        goto bail;
1197
0
    }
1198
0
    else
1199
0
      goto bail;
1200
0
  }
1201
0
  fcntl(the->connection, F_SETFL, flag);
1202
0
  c_signal(SIGPIPE, SIG_DFL);
1203
0
}
1204
0
#endif
1205
0
  return;
1206
0
bail:
1207
0
  fxDisconnect(the);
1208
0
}
1209
1210
void fxDisconnect(txMachine* the)
1211
0
{
1212
#if mxWindows
1213
  if (the->connection != INVALID_SOCKET) {
1214
    closesocket(the->connection);
1215
    the->connection = INVALID_SOCKET;
1216
  }
1217
  WSACleanup();
1218
#else
1219
0
  if (the->connection >= 0) {
1220
0
    close(the->connection);
1221
0
    the->connection = -1;
1222
0
  }
1223
0
#endif
1224
0
}
1225
1226
txBoolean fxIsConnected(txMachine* the)
1227
7.38M
{
1228
7.38M
  return (the->connection != mxNoSocket) ? 1 : 0;
1229
7.38M
}
1230
1231
txBoolean fxIsReadable(txMachine* the)
1232
100M
{
1233
100M
  return 0;
1234
100M
}
1235
1236
void fxReceive(txMachine* the)
1237
0
{
1238
0
  int count;
1239
0
  if (the->connection != mxNoSocket) {
1240
#if mxWindows
1241
    count = recv(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1, 0);
1242
    if (count < 0)
1243
      fxDisconnect(the);
1244
    else
1245
      the->debugOffset = count;
1246
#else
1247
0
  again:
1248
0
    count = read(the->connection, the->debugBuffer, sizeof(the->debugBuffer) - 1);
1249
0
    if (count < 0) {
1250
0
      if (errno == EINTR)
1251
0
        goto again;
1252
0
      else
1253
0
        fxDisconnect(the);
1254
0
    }
1255
0
    else
1256
0
      the->debugOffset = count;
1257
0
#endif
1258
0
  }
1259
0
  the->debugBuffer[the->debugOffset] = 0;
1260
0
}
1261
1262
void fxSend(txMachine* the, txBoolean more)
1263
0
{
1264
0
  if (the->connection != mxNoSocket) {
1265
#if mxWindows
1266
    if (send(the->connection, the->echoBuffer, the->echoOffset, 0) <= 0)
1267
      fxDisconnect(the);
1268
#else
1269
0
  again:
1270
0
    if (write(the->connection, the->echoBuffer, the->echoOffset) <= 0) {
1271
0
      if (errno == EINTR)
1272
0
        goto again;
1273
0
      else
1274
0
        fxDisconnect(the);
1275
0
    }
1276
0
#endif
1277
0
  }
1278
0
}
1279
1280
#endif /* mxDebug */
1281
1282
1283
1284
1285