@php-wasm/web-5-2 3.1.34 → 3.1.36

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
@@ -4673,6 +4673,7 @@ export function init(RuntimeName, PHPLoader) {
4673
4673
  O_NONBLOCK: 2048,
4674
4674
  POLLHUP: 16,
4675
4675
  SETFL_MASK: 3072,
4676
+ socketTimeouts: new Map,
4676
4677
  init: function () {
4677
4678
  if (PHPLoader.bindUserSpace) {
4678
4679
  addOnInit(() => {
@@ -5036,6 +5037,29 @@ export function init(RuntimeName, PHPLoader) {
5036
5037
  return [promise, cancel];
5037
5038
  },
5038
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
+ },
5039
5063
  spawnProcess: function (command, args, options) {
5040
5064
  if (Module['spawnProcess']) {
5041
5065
  const spawned = Module['spawnProcess'](command, args, {
@@ -5064,6 +5088,7 @@ export function init(RuntimeName, PHPLoader) {
5064
5088
  throw e;
5065
5089
  },
5066
5090
  shutdownSocket: function (socketd, how) {
5091
+ PHPWASM.socketTimeouts.delete(socketd);
5067
5092
  const sock = getSocketFromFD(socketd);
5068
5093
  const peer = Object.values(sock.peers)[0];
5069
5094
  if (!peer) {
@@ -5133,41 +5158,74 @@ export function init(RuntimeName, PHPLoader) {
5133
5158
  wakeUp(-ERRNO_CODES.ECONNREFUSED);
5134
5159
  return;
5135
5160
  }
5136
- 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;
5137
5165
  let resolved = false;
5138
- const timeoutId = setTimeout(() => {
5139
- if (!resolved) {
5140
- resolved = true;
5141
- wakeUp(-ERRNO_CODES.ETIMEDOUT);
5142
- }
5143
- }, timeout);
5144
- const handleOpen = () => {
5145
- if (!resolved) {
5146
- 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') {
5147
5176
  clearTimeout(timeoutId);
5148
- ws.removeEventListener('error', handleError);
5149
- ws.removeEventListener('close', handleClose);
5150
- wakeUp(0);
5151
5177
  }
5178
+ ws.removeEventListener('open', handleOpen);
5179
+ ws.removeEventListener('error', handleError);
5180
+ ws.removeEventListener('close', handleClose);
5152
5181
  };
5153
- const handleError = () => {
5154
- if (!resolved) {
5155
- resolved = true;
5156
- clearTimeout(timeoutId);
5157
- ws.removeEventListener('open', handleOpen);
5158
- ws.removeEventListener('close', handleClose);
5159
- 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.
5193
+ }
5194
+ if (peer) {
5195
+ SOCKFS.websocket_sock_ops.removePeer(sock, peer);
5160
5196
  }
5197
+ sock.connecting = false;
5198
+ sock.error = errno;
5161
5199
  };
5162
- const handleClose = () => {
5200
+
5201
+ const finishConnect = (result) => {
5163
5202
  if (!resolved) {
5164
5203
  resolved = true;
5165
- clearTimeout(timeoutId);
5166
- ws.removeEventListener('open', handleOpen);
5167
- ws.removeEventListener('error', handleError);
5168
- wakeUp(-ERRNO_CODES.ECONNREFUSED);
5204
+ cleanupConnectListeners();
5205
+ if (result < 0) {
5206
+ cleanupFailedConnect(-result);
5207
+ }
5208
+ wakeUp(result);
5169
5209
  }
5170
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
+ };
5171
5229
  ws.addEventListener('open', handleOpen);
5172
5230
  ws.addEventListener('error', handleError);
5173
5231
  ws.addEventListener('close', handleClose);
@@ -7401,21 +7459,35 @@ export function init(RuntimeName, PHPLoader) {
7401
7459
  const SO_SNDTIMEO = 67;
7402
7460
  const IPPROTO_TCP = 6;
7403
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
+ }
7404
7482
  const isForwardable =
7405
7483
  (level === SOL_SOCKET && optionName === SO_KEEPALIVE) ||
7406
7484
  (level === IPPROTO_TCP && optionName === TCP_NODELAY);
7407
- const isIgnorable =
7408
- level === SOL_SOCKET &&
7409
- (optionName === SO_RCVTIMEO || optionName === SO_SNDTIMEO);
7410
- if (!isForwardable && !isIgnorable) {
7485
+ if (!isForwardable) {
7411
7486
  console.warn(
7412
7487
  `Unsupported socket option: ${level}, ${optionName}, ${optionValue}`
7413
7488
  );
7414
7489
  return -1;
7415
7490
  }
7416
- if (isIgnorable) {
7417
- return 0;
7418
- }
7419
7491
  const ws = PHPWASM.getAllWebSockets(socketd)[0];
7420
7492
  if (!ws) {
7421
7493
  return -1;
@@ -7423,6 +7495,7 @@ export function init(RuntimeName, PHPLoader) {
7423
7495
  ws.setSocketOpt(level, optionName, optionValuePtr);
7424
7496
  return 0;
7425
7497
  }
7498
+
7426
7499
  var Asyncify = {
7427
7500
  instrumentWasmImports(imports) {
7428
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.34",
3
+ "version": "3.1.36",
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": "86daccc84fe31900eb57c4c8e1c3ba21a7ae8d13",
38
+ "gitHead": "371f4fd6f9d56af6fb35b6c2cf0267edaea83755",
39
39
  "dependencies": {
40
40
  "wasm-feature-detect": "1.8.0",
41
- "@php-wasm/universal": "3.1.34"
41
+ "@php-wasm/universal": "3.1.36"
42
42
  },
43
43
  "packageManager": "npm@10.9.2",
44
44
  "overrides": {