@php-wasm/web-5-2 3.1.33 → 3.1.35

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4716,6 +4716,7 @@ export function init(RuntimeName, PHPLoader) {
4716
4716
  O_NONBLOCK: 2048,
4717
4717
  POLLHUP: 16,
4718
4718
  SETFL_MASK: 3072,
4719
+ socketTimeouts: new Map,
4719
4720
  init: function () {
4720
4721
  if (PHPLoader.bindUserSpace) {
4721
4722
  addOnInit(() => {
@@ -5079,6 +5080,29 @@ export function init(RuntimeName, PHPLoader) {
5079
5080
  return [promise, cancel];
5080
5081
  },
5081
5082
  noop: function () {},
5083
+ parseSocketTimeout: function (optionValuePtr, optionLen) {
5084
+ if (!optionValuePtr || optionLen < 8) {
5085
+ return null;
5086
+ }
5087
+ let seconds;
5088
+ let microseconds;
5089
+ if (optionLen >= 16) {
5090
+ seconds = Number(HEAP64[optionValuePtr >> 3]);
5091
+ microseconds = Number(HEAP64[(optionValuePtr + 8) >> 3]);
5092
+ } else {
5093
+ seconds = HEAP32[optionValuePtr >> 2];
5094
+ microseconds = HEAP32[(optionValuePtr + 4) >> 2];
5095
+ }
5096
+ if (
5097
+ !Number.isFinite(seconds) ||
5098
+ !Number.isFinite(microseconds) ||
5099
+ seconds < 0 ||
5100
+ microseconds < 0
5101
+ ) {
5102
+ return null;
5103
+ }
5104
+ return seconds * 1e3 + Math.ceil(microseconds / 1e3);
5105
+ },
5082
5106
  spawnProcess: function (command, args, options) {
5083
5107
  if (Module['spawnProcess']) {
5084
5108
  const spawned = Module['spawnProcess'](command, args, {
@@ -5107,6 +5131,7 @@ export function init(RuntimeName, PHPLoader) {
5107
5131
  throw e;
5108
5132
  },
5109
5133
  shutdownSocket: function (socketd, how) {
5134
+ PHPWASM.socketTimeouts.delete(socketd);
5110
5135
  const sock = getSocketFromFD(socketd);
5111
5136
  const peer = Object.values(sock.peers)[0];
5112
5137
  if (!peer) {
@@ -5176,41 +5201,74 @@ export function init(RuntimeName, PHPLoader) {
5176
5201
  wakeUp(-ERRNO_CODES.ECONNREFUSED);
5177
5202
  return;
5178
5203
  }
5179
- const timeout = 3e4;
5204
+ // Wait for the connection to be established. A zero timeval
5205
+ // disables the timeout, matching SO_SNDTIMEO semantics.
5206
+ const sendTimeout = PHPWASM.socketTimeouts.get(sockfd)?.send;
5207
+ const timeout = sendTimeout ?? 3e4;
5180
5208
  let resolved = false;
5181
- const timeoutId = setTimeout(() => {
5182
- if (!resolved) {
5183
- resolved = true;
5184
- wakeUp(-ERRNO_CODES.ETIMEDOUT);
5185
- }
5186
- }, timeout);
5187
- const handleOpen = () => {
5188
- if (!resolved) {
5189
- resolved = true;
5209
+ let timeoutId;
5210
+ let handleOpen;
5211
+ let handleError;
5212
+ let handleClose;
5213
+ const peer = PHPWASM.getAllPeers(sock).find(
5214
+ (candidate) => candidate.socket === ws
5215
+ );
5216
+
5217
+ const cleanupConnectListeners = () => {
5218
+ if (typeof timeoutId !== 'undefined') {
5190
5219
  clearTimeout(timeoutId);
5191
- ws.removeEventListener('error', handleError);
5192
- ws.removeEventListener('close', handleClose);
5193
- wakeUp(0);
5194
5220
  }
5221
+ ws.removeEventListener('open', handleOpen);
5222
+ ws.removeEventListener('error', handleError);
5223
+ ws.removeEventListener('close', handleClose);
5195
5224
  };
5196
- const handleError = () => {
5197
- if (!resolved) {
5198
- resolved = true;
5199
- clearTimeout(timeoutId);
5200
- ws.removeEventListener('open', handleOpen);
5201
- ws.removeEventListener('close', handleClose);
5202
- wakeUp(-ERRNO_CODES.ECONNREFUSED);
5225
+
5226
+ const cleanupFailedConnect = (errno) => {
5227
+ try {
5228
+ if (
5229
+ ws.readyState !== ws.CLOSING &&
5230
+ ws.readyState !== ws.CLOSED
5231
+ ) {
5232
+ ws.close();
5233
+ }
5234
+ } catch (e) {
5235
+ // Ignore close errors on an already-failed connect.
5203
5236
  }
5237
+ if (peer) {
5238
+ SOCKFS.websocket_sock_ops.removePeer(sock, peer);
5239
+ }
5240
+ sock.connecting = false;
5241
+ sock.error = errno;
5204
5242
  };
5205
- const handleClose = () => {
5243
+
5244
+ const finishConnect = (result) => {
5206
5245
  if (!resolved) {
5207
5246
  resolved = true;
5208
- clearTimeout(timeoutId);
5209
- ws.removeEventListener('open', handleOpen);
5210
- ws.removeEventListener('error', handleError);
5211
- wakeUp(-ERRNO_CODES.ECONNREFUSED);
5247
+ cleanupConnectListeners();
5248
+ if (result < 0) {
5249
+ cleanupFailedConnect(-result);
5250
+ }
5251
+ wakeUp(result);
5212
5252
  }
5213
5253
  };
5254
+
5255
+ if (timeout > 0) {
5256
+ timeoutId = setTimeout(() => {
5257
+ finishConnect(-ERRNO_CODES.ETIMEDOUT);
5258
+ }, timeout);
5259
+ }
5260
+
5261
+ handleOpen = () => {
5262
+ finishConnect(0);
5263
+ };
5264
+
5265
+ handleError = () => {
5266
+ finishConnect(-ERRNO_CODES.ECONNREFUSED);
5267
+ };
5268
+
5269
+ handleClose = () => {
5270
+ finishConnect(-ERRNO_CODES.ECONNREFUSED);
5271
+ };
5214
5272
  ws.addEventListener('open', handleOpen);
5215
5273
  ws.addEventListener('error', handleError);
5216
5274
  ws.addEventListener('close', handleClose);
@@ -7448,21 +7506,35 @@ export function init(RuntimeName, PHPLoader) {
7448
7506
  const SO_SNDTIMEO = 67;
7449
7507
  const IPPROTO_TCP = 6;
7450
7508
  const TCP_NODELAY = 1;
7509
+ if (
7510
+ level === SOL_SOCKET &&
7511
+ (optionName === SO_RCVTIMEO || optionName === SO_SNDTIMEO)
7512
+ ) {
7513
+ const timeoutMs = PHPWASM.parseSocketTimeout(
7514
+ optionValuePtr,
7515
+ optionLen
7516
+ );
7517
+ if (timeoutMs === null) {
7518
+ return -1;
7519
+ }
7520
+ const timeouts = PHPWASM.socketTimeouts.get(socketd) || {};
7521
+ if (optionName === SO_RCVTIMEO) {
7522
+ timeouts.receive = timeoutMs;
7523
+ } else {
7524
+ timeouts.send = timeoutMs;
7525
+ }
7526
+ PHPWASM.socketTimeouts.set(socketd, timeouts);
7527
+ return 0;
7528
+ }
7451
7529
  const isForwardable =
7452
7530
  (level === SOL_SOCKET && optionName === SO_KEEPALIVE) ||
7453
7531
  (level === IPPROTO_TCP && optionName === TCP_NODELAY);
7454
- const isIgnorable =
7455
- level === SOL_SOCKET &&
7456
- (optionName === SO_RCVTIMEO || optionName === SO_SNDTIMEO);
7457
- if (!isForwardable && !isIgnorable) {
7532
+ if (!isForwardable) {
7458
7533
  console.warn(
7459
7534
  `Unsupported socket option: ${level}, ${optionName}, ${optionValue}`
7460
7535
  );
7461
7536
  return -1;
7462
7537
  }
7463
- if (isIgnorable) {
7464
- return 0;
7465
- }
7466
7538
  const ws = PHPWASM.getAllWebSockets(socketd)[0];
7467
7539
  if (!ws) {
7468
7540
  return -1;
package/jspi/php_5_2.js CHANGED
@@ -174,6 +174,9 @@ export function init(RuntimeName, PHPLoader) {
174
174
  }
175
175
  function getWasmImports() {
176
176
  Asyncify.instrumentWasmImports(wasmImports);
177
+ wasmImports['__c_longjmp'] ??= new WebAssembly.Tag({
178
+ parameters: ['i32'],
179
+ });
177
180
  var imports = {
178
181
  env: wasmImports,
179
182
  wasi_snapshot_preview1: wasmImports,
@@ -4670,6 +4673,7 @@ export function init(RuntimeName, PHPLoader) {
4670
4673
  O_NONBLOCK: 2048,
4671
4674
  POLLHUP: 16,
4672
4675
  SETFL_MASK: 3072,
4676
+ socketTimeouts: new Map,
4673
4677
  init: function () {
4674
4678
  if (PHPLoader.bindUserSpace) {
4675
4679
  addOnInit(() => {
@@ -5033,6 +5037,29 @@ export function init(RuntimeName, PHPLoader) {
5033
5037
  return [promise, cancel];
5034
5038
  },
5035
5039
  noop: function () {},
5040
+ parseSocketTimeout: function (optionValuePtr, optionLen) {
5041
+ if (!optionValuePtr || optionLen < 8) {
5042
+ return null;
5043
+ }
5044
+ let seconds;
5045
+ let microseconds;
5046
+ if (optionLen >= 16) {
5047
+ seconds = Number(HEAP64[optionValuePtr >> 3]);
5048
+ microseconds = Number(HEAP64[(optionValuePtr + 8) >> 3]);
5049
+ } else {
5050
+ seconds = HEAP32[optionValuePtr >> 2];
5051
+ microseconds = HEAP32[(optionValuePtr + 4) >> 2];
5052
+ }
5053
+ if (
5054
+ !Number.isFinite(seconds) ||
5055
+ !Number.isFinite(microseconds) ||
5056
+ seconds < 0 ||
5057
+ microseconds < 0
5058
+ ) {
5059
+ return null;
5060
+ }
5061
+ return seconds * 1e3 + Math.ceil(microseconds / 1e3);
5062
+ },
5036
5063
  spawnProcess: function (command, args, options) {
5037
5064
  if (Module['spawnProcess']) {
5038
5065
  const spawned = Module['spawnProcess'](command, args, {
@@ -5061,6 +5088,7 @@ export function init(RuntimeName, PHPLoader) {
5061
5088
  throw e;
5062
5089
  },
5063
5090
  shutdownSocket: function (socketd, how) {
5091
+ PHPWASM.socketTimeouts.delete(socketd);
5064
5092
  const sock = getSocketFromFD(socketd);
5065
5093
  const peer = Object.values(sock.peers)[0];
5066
5094
  if (!peer) {
@@ -5130,41 +5158,74 @@ export function init(RuntimeName, PHPLoader) {
5130
5158
  wakeUp(-ERRNO_CODES.ECONNREFUSED);
5131
5159
  return;
5132
5160
  }
5133
- const timeout = 3e4;
5161
+ // Wait for the connection to be established. A zero timeval
5162
+ // disables the timeout, matching SO_SNDTIMEO semantics.
5163
+ const sendTimeout = PHPWASM.socketTimeouts.get(sockfd)?.send;
5164
+ const timeout = sendTimeout ?? 3e4;
5134
5165
  let resolved = false;
5135
- const timeoutId = setTimeout(() => {
5136
- if (!resolved) {
5137
- resolved = true;
5138
- wakeUp(-ERRNO_CODES.ETIMEDOUT);
5139
- }
5140
- }, timeout);
5141
- const handleOpen = () => {
5142
- if (!resolved) {
5143
- resolved = true;
5166
+ let timeoutId;
5167
+ let handleOpen;
5168
+ let handleError;
5169
+ let handleClose;
5170
+ const peer = PHPWASM.getAllPeers(sock).find(
5171
+ (candidate) => candidate.socket === ws
5172
+ );
5173
+
5174
+ const cleanupConnectListeners = () => {
5175
+ if (typeof timeoutId !== 'undefined') {
5144
5176
  clearTimeout(timeoutId);
5145
- ws.removeEventListener('error', handleError);
5146
- ws.removeEventListener('close', handleClose);
5147
- wakeUp(0);
5148
5177
  }
5178
+ ws.removeEventListener('open', handleOpen);
5179
+ ws.removeEventListener('error', handleError);
5180
+ ws.removeEventListener('close', handleClose);
5149
5181
  };
5150
- const handleError = () => {
5151
- if (!resolved) {
5152
- resolved = true;
5153
- clearTimeout(timeoutId);
5154
- ws.removeEventListener('open', handleOpen);
5155
- ws.removeEventListener('close', handleClose);
5156
- wakeUp(-ERRNO_CODES.ECONNREFUSED);
5182
+
5183
+ const cleanupFailedConnect = (errno) => {
5184
+ try {
5185
+ if (
5186
+ ws.readyState !== ws.CLOSING &&
5187
+ ws.readyState !== ws.CLOSED
5188
+ ) {
5189
+ ws.close();
5190
+ }
5191
+ } catch (e) {
5192
+ // Ignore close errors on an already-failed connect.
5157
5193
  }
5194
+ if (peer) {
5195
+ SOCKFS.websocket_sock_ops.removePeer(sock, peer);
5196
+ }
5197
+ sock.connecting = false;
5198
+ sock.error = errno;
5158
5199
  };
5159
- const handleClose = () => {
5200
+
5201
+ const finishConnect = (result) => {
5160
5202
  if (!resolved) {
5161
5203
  resolved = true;
5162
- clearTimeout(timeoutId);
5163
- ws.removeEventListener('open', handleOpen);
5164
- ws.removeEventListener('error', handleError);
5165
- wakeUp(-ERRNO_CODES.ECONNREFUSED);
5204
+ cleanupConnectListeners();
5205
+ if (result < 0) {
5206
+ cleanupFailedConnect(-result);
5207
+ }
5208
+ wakeUp(result);
5166
5209
  }
5167
5210
  };
5211
+
5212
+ if (timeout > 0) {
5213
+ timeoutId = setTimeout(() => {
5214
+ finishConnect(-ERRNO_CODES.ETIMEDOUT);
5215
+ }, timeout);
5216
+ }
5217
+
5218
+ handleOpen = () => {
5219
+ finishConnect(0);
5220
+ };
5221
+
5222
+ handleError = () => {
5223
+ finishConnect(-ERRNO_CODES.ECONNREFUSED);
5224
+ };
5225
+
5226
+ handleClose = () => {
5227
+ finishConnect(-ERRNO_CODES.ECONNREFUSED);
5228
+ };
5168
5229
  ws.addEventListener('open', handleOpen);
5169
5230
  ws.addEventListener('error', handleError);
5170
5231
  ws.addEventListener('close', handleClose);
@@ -7398,21 +7459,35 @@ export function init(RuntimeName, PHPLoader) {
7398
7459
  const SO_SNDTIMEO = 67;
7399
7460
  const IPPROTO_TCP = 6;
7400
7461
  const TCP_NODELAY = 1;
7462
+ if (
7463
+ level === SOL_SOCKET &&
7464
+ (optionName === SO_RCVTIMEO || optionName === SO_SNDTIMEO)
7465
+ ) {
7466
+ const timeoutMs = PHPWASM.parseSocketTimeout(
7467
+ optionValuePtr,
7468
+ optionLen
7469
+ );
7470
+ if (timeoutMs === null) {
7471
+ return -1;
7472
+ }
7473
+ const timeouts = PHPWASM.socketTimeouts.get(socketd) || {};
7474
+ if (optionName === SO_RCVTIMEO) {
7475
+ timeouts.receive = timeoutMs;
7476
+ } else {
7477
+ timeouts.send = timeoutMs;
7478
+ }
7479
+ PHPWASM.socketTimeouts.set(socketd, timeouts);
7480
+ return 0;
7481
+ }
7401
7482
  const isForwardable =
7402
7483
  (level === SOL_SOCKET && optionName === SO_KEEPALIVE) ||
7403
7484
  (level === IPPROTO_TCP && optionName === TCP_NODELAY);
7404
- const isIgnorable =
7405
- level === SOL_SOCKET &&
7406
- (optionName === SO_RCVTIMEO || optionName === SO_SNDTIMEO);
7407
- if (!isForwardable && !isIgnorable) {
7485
+ if (!isForwardable) {
7408
7486
  console.warn(
7409
7487
  `Unsupported socket option: ${level}, ${optionName}, ${optionValue}`
7410
7488
  );
7411
7489
  return -1;
7412
7490
  }
7413
- if (isIgnorable) {
7414
- return 0;
7415
- }
7416
7491
  const ws = PHPWASM.getAllWebSockets(socketd)[0];
7417
7492
  if (!ws) {
7418
7493
  return -1;
@@ -7420,6 +7495,7 @@ export function init(RuntimeName, PHPLoader) {
7420
7495
  ws.setSocketOpt(level, optionName, optionValuePtr);
7421
7496
  return 0;
7422
7497
  }
7498
+
7423
7499
  var Asyncify = {
7424
7500
  instrumentWasmImports(imports) {
7425
7501
  var importPattern =
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@php-wasm/web-5-2",
3
- "version": "3.1.33",
3
+ "version": "3.1.35",
4
4
  "description": "PHP 5.2 WebAssembly binaries for web (legacy)",
5
5
  "repository": {
6
6
  "type": "git",
@@ -35,10 +35,10 @@
35
35
  "node": ">=20.10.0",
36
36
  "npm": ">=10.2.3"
37
37
  },
38
- "gitHead": "f80a40d763283d582f9b97b0d5eb59bf54d2a943",
38
+ "gitHead": "9d29b73246e12465902d8ce42c0fe747125bc69a",
39
39
  "dependencies": {
40
40
  "wasm-feature-detect": "1.8.0",
41
- "@php-wasm/universal": "3.1.33"
41
+ "@php-wasm/universal": "3.1.35"
42
42
  },
43
43
  "packageManager": "npm@10.9.2",
44
44
  "overrides": {