# How webMAN MOD Implements the NETISO Protocol for Streaming PS3 Games Over Network

> Discover how webMAN MOD streams PS3 games over your network using the NETISO protocol. Learn how it intercepts SCSI commands for a seamless local disc drive experience.

- Repository: [Aldo Vargas/webman-mod](https://github.com/aldostools/webman-mod)
- Tags: how-to-guide
- Published: 2026-02-24

---

**webMAN MOD streams PS3, PS1, DVD, and Blu-ray ISOs over a LAN using a custom binary NETISO protocol that pairs a PS3 client with the PC-side ps3netsrv daemon on TCP port 38008, intercepting SCSI commands and forwarding them as network packets to simulate a locally attached disc drive.**

The **aldostools/webman-mod** repository contains the complete implementation of this protocol, enabling users to mount and play games stored on a remote PC without copying them to the console's local storage. The architecture splits functionality between a lightweight **NETISO client** embedded in the webMAN MOD plugin and the **ps3netsrv** server application that handles file-system operations on the host machine.

## NETISO Protocol Architecture

The NETISO system relies on two cooperating components that communicate via raw binary packets over TCP **port 38008**. When a user selects a network game in the webMAN MOD interface, the plugin constructs a `net://` URL (for example, `net://192.168.1.10/ISO/Game.iso`) and initiates a mount sequence.

The **PS3-side NETISO client**, defined in [`include/mount/netclient.h`](https://github.com/aldostools/webman-mod/blob/main/include/mount/netclient.h), opens a persistent TCP socket to the server and translates Cobra driver SCSI requests into protocol commands. The **PC-side NETISO server**, implemented in [`_Projects_/ps3netsrv/src/main.cpp`](https://github.com/aldostools/webman-mod/blob/main/_Projects_/ps3netsrv/src/main.cpp), listens for these commands, performs the corresponding file I/O, and streams raw bytes back to the client. From the PS3's perspective, the data appears to originate from a local BD-ROM drive.

## Protocol Command Reference

The NETISO protocol defines a fixed set of opcodes in [`cobra/netiso.h`](https://github.com/aldostools/webman-mod/blob/main/cobra/netiso.h) for file and directory operations. All multi-byte integers use **big-endian** encoding, with the PS3 client automatically converting host byte order using inline helpers `BE16`, `BE32`, and `BE64`.

| Opcode | Command | Client Sends | Server Returns |
|--------|---------|--------------|----------------|
| `NETISO_CMD_OPEN_FILE` (0x1224) | Open a read-only file | `_netiso_open_cmd` with path length | `_netiso_open_result` containing file size and mtime |
| `NETISO_CMD_READ_FILE` | Standard read request | `_netiso_read_file_cmd` with offset and byte count | `_netiso_read_file_result` followed by raw data |
| `NETISO_CMD_READ_FILE_CRITICAL` | Fast read without error recovery | `_netiso_read_file_critical_cmd` | Raw data (client aborts on failure) |
| `NETISO_CMD_READ_CD_2048_CRITICAL` | Read 2048-byte sectors for DVD/BD | `_netiso_read_cd_2048_critical_cmd` | Raw sector data |
| `NETISO_CMD_STAT_FILE` | Retrieve file metadata | `_netiso_stat_cmd` | `_netiso_stat_result` with size and timestamps |
| `NETISO_CMD_OPEN_DIR` | Open directory for listing | `_netiso_open_dir_cmd` | `_netiso_open_dir_result` |
| `NETISO_CMD_READ_DIR` | Fetch directory entries | `_netiso_read_dir_cmd` | `_netiso_read_dir_result` with entry list |
| `NETISO_CMD_CUSTOM_0` (0x2412) | Extension point for future use | — | — |

## Client-Side Implementation in webMAN MOD

The PS3 implementation integrates directly with the Cobra driver to intercept disc access requests.

### Mounting Network ISOs

When a user triggers a mount via the webMAN MOD UI, the code in [`_Projects_/netiso/main.c`](https://github.com/aldostools/webman-mod/blob/main/_Projects_/netiso/main.c) and [`netiso.c`](https://github.com/aldostools/webman-mod/blob/main/netiso.c) creates a `netiso_args` structure containing the server IP, remote path, and emulation mode. The `mount_iso()` function parses the `net://` URL and invokes the **NETISO client** API, which registers itself with Cobra using `SYS_MODULE_INFO(NETISO, …)`. Once registered, all subsequent SCSI read commands route through the NETISO client rather than the physical drive.

### Building Binary Command Packets

The client constructs packets by populating C structs and converting fields to big-endian. Below is a simplified version of the file-opening logic found in the client implementation:

```c
// Simplified from netclient.c
int netiso_open(const char *server, const char *path)
{
    int s = socket(AF_INET, SOCK_STREAM, 0);
    struct sockaddr_in addr = { .sin_family = AF_INET, .sin_port = htons(NETISO_PORT) };
    inet_pton(AF_INET, server, &addr.sin_addr);
    connect(s, (struct sockaddr *)&addr, sizeof(addr));

    // Build open command with proper byte order
    netiso_open_cmd cmd = { 
        .opcode = BE16(NETISO_CMD_OPEN_FILE), 
        .fp_len = BE16(strlen(path)) 
    };
    send(s, &cmd, sizeof(cmd), 0);
    send(s, path, strlen(path), 0);

    netiso_open_result res;
    recv(s, &res, sizeof(res), 0);
    res.file_size = (s64)BE64(res.file_size);
    return s;   // Socket handle for subsequent reads
}

```

For reading data, the client sends a `_netiso_read_file_cmd` structure specifying the byte offset and length, then receives the payload in two stages: first the result header containing the actual bytes read, then the raw ISO data.

```c
// Read request construction
netiso_read_file_cmd rcmd = {
    .opcode     = BE16(NETISO_CMD_READ_FILE),
    .pad        = 0,
    .num_bytes  = BE32(0x10000),          // 64 KB chunks
    .offset     = BE64(file_offset)
};
send(s, &rcmd, sizeof(rcmd), 0);

netiso_read_file_result rres;
recv(s, &rres, sizeof(rres), 0);
int bytes = BE32(rres.bytes_read);
recv(s, buffer, bytes, 0);   // Raw ISO sector data

```

## Server-Side Implementation (ps3netsrv)

The PC-side daemon **ps3netsrv** handles the actual file-system operations. The source in [`_Projects_/ps3netsrv/src/main.cpp`](https://github.com/aldostools/webman-mod/blob/main/_Projects_/ps3netsrv/src/main.cpp) implements a blocking TCP server that maintains per-connection state, including open file pointers.

### Command Dispatch Loop

The server enters a loop receiving 16-bit opcodes, switching on the command type, and executing the corresponding handler. For `NETISO_CMD_OPEN_FILE`, it reconstructs the filename, opens the file in binary mode, and returns the size:

```cpp
// Excerpt from _Projects_/ps3netsrv/src/main.cpp
case NETISO_CMD_OPEN_FILE:
{
    netiso_open_cmd cmd;
    recv(sock, &cmd, sizeof(cmd), 0);
    cmd.opcode = BE16(cmd.opcode);
    
    char filename[0x420];
    recv(sock, filename, BE16(cmd.fp_len), 0);
    
    FILE *fp = fopen(filename, "rb");
    netiso_open_result res = { .file_size = -1, .mtime = 0 };
    if (fp) {
        fseek(fp, 0, SEEK_END);
        res.file_size = ftell(fp);
        rewind(fp);
    }
    res.file_size = BE64(res.file_size);
    send(sock, &res, sizeof(res), 0);
    // File pointer stored in connection state for reads
}
break;

```

### Streaming File Data

For read operations, the server seeks to the requested offset, allocates a temporary buffer, and transmits the data immediately:

```cpp
case NETISO_CMD_READ_FILE:
{
    netiso_read_file_cmd cmd;
    recv(sock, &cmd, sizeof(cmd), 0);
    uint64_t off = BE64(cmd.offset);
    uint32_t nbytes = BE32(cmd.num_bytes);

    fseek(state->fp, off, SEEK_SET);
    char *buf = new char[nbytes];
    size_t got = fread(buf, 1, nbytes, state->fp);

    netiso_read_file_result res = { .bytes_read = BE32((uint32_t)got) };
    send(sock, &res, sizeof(res), 0);
    send(sock, buf, got, 0);
    delete[] buf;
}
break;

```

This zero-copy-like approach ensures minimal latency for streaming high-bandwidth Blu-ray ISOs over gigabit Ethernet.

## Summary

- **webMAN MOD** implements the **NETISO protocol** to stream disc images over TCP port 38008, enabling network gameplay without local storage.
- The **client** in [`include/mount/netclient.h`](https://github.com/aldostools/webman-mod/blob/main/include/mount/netclient.h) converts Cobra SCSI requests into binary commands using big-endian byte order helpers (`BE16`, `BE32`, `BE64`).
- The **server** in [`_Projects_/ps3netsrv/src/main.cpp`](https://github.com/aldostools/webman-mod/blob/main/_Projects_/ps3netsrv/src/main.cpp) dispatches opcodes such as `NETISO_CMD_OPEN_FILE` and `NETISO_CMD_READ_FILE` to serve file data in 64 KB chunks or 2048-byte sectors.
- Integration occurs through `net://` URL parsing in [`_Projects_/netiso/main.c`](https://github.com/aldostools/webman-mod/blob/main/_Projects_/netiso/main.c), which registers the NETISO module with the Cobra driver to intercept disc reads.

## Frequently Asked Questions

### What network port does the NETISO protocol use?

The NETISO protocol uses **TCP port 38008** for all client-server communication. The ps3netsrv daemon binds to this port by default, and the webMAN MOD client connects to it when mounting `net://` URLs.

### Can NETISO stream folder-based games or only ISO files?

NETISO supports both **ISO files** and **folder-based games**. While ISOs use `NETISO_CMD_READ_FILE` for byte-offset reads, folder-based content (JBOD format) uses `NETISO_CMD_OPEN_DIR` and `NETISO_CMD_READ_DIR` to browse directory structures, with individual files accessed via the standard file commands.

### How does webMAN MOD handle byte order in NETISO packets?

All NETISO packets use **big-endian** encoding to match the PS3's PowerPC architecture. The client and server use inline conversion macros `BE16`, `BE32`, and `BE64` defined in [`cobra/netiso.h`](https://github.com/aldostools/webman-mod/blob/main/cobra/netiso.h) to swap byte order when packing or unpacking command structures on little-endian PC hosts.

### Is the NETISO server compatible with other PS3 homebrew besides webMAN MOD?

The **ps3netsrv** implementation is specific to the NETISO protocol used by webMAN MOD and Cobra firmware. While the protocol is open-source, compatibility with other tools depends on whether they implement the same command set found in [`include/mount/netclient.h`](https://github.com/aldostools/webman-mod/blob/main/include/mount/netclient.h) and [`_Projects_/ps3netsrv/include/netiso.h`](https://github.com/aldostools/webman-mod/blob/main/_Projects_/ps3netsrv/include/netiso.h).