# SOME/IP Server Implementation
This directory contains the server/provider functionality for `simple_someip`, allowing you to **offer services** and **publish events** rather than just consuming them.
## Overview
The server implementation provides:
1. **Service Announcement** - Periodically broadcast OfferService messages via Service Discovery (SD)
2. **Event Publishing** - Send events to subscribed clients
3. **Subscription Management** - Track who's subscribed to which event groups
4. **End-to-End Protection** - Automatic E2E protection/checking per message key
5. **UDP Socket Management** - Handle unicast and multicast communication
## Architecture
```
┌──────────────────────────────────────────────────────────────┐
│ Server │
├──────────────────────────────────────────────────────────────┤
│ - ServerConfig (service ID, ports, TTL) │
│ - Unicast socket (receives subscriptions) │
│ - SD socket (sends announcements) │
│ - SubscriptionManager (tracks subscribers) │
│ - EventPublisher (sends events to subscribers) │
└──────────────────────────────────────────────────────────────┘
│ │ │
│ SD Announcements │ Events │ Subscriptions
↓ ↓ ↑
┌────────────────┐ ┌────────────────┐ ┌────────────────┐
│ 239.255.0.255 │ │ Subscriber │ │ Subscriber │
│ :30490 │ │ (unicast) │ │ (unicast) │
│ (multicast) │ └────────────────┘ └────────────────┘
└────────────────┘
```
## Usage Example
### Basic Server Setup
```rust
use simple_someip::server::{Server, ServerConfig};
use std::net::Ipv4Addr;
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Configure the server
let config = ServerConfig::new(
Ipv4Addr::new(192, 168, 1, 200), // Local interface
30500, // Local port
0x1234, // Service ID
1, // Instance ID
);
// Create the server
let mut server = Server::new(config).await?;
// Start announcing the service (sends OfferService every 1s).
// Spawn the announcement loop future on the Tokio runtime.
tokio::spawn(server.announcement_loop()?);
// Get event publisher for sending events
let publisher = server.publisher();
// Spawn the server run loop to handle subscriptions
tokio::spawn(async move {
if let Err(e) = server.run().await {
eprintln!("Server error: {:?}", e);
}
});
// Publish events to subscribers using raw bytes
publisher.publish_raw_event(
0x1234, // service_id
1, // instance_id
0x01, // event_group_id
0x8001, // event_id
0, // session_id
1, // protocol_version
1, // interface_version
&[0x01], // payload
).await?;
Ok(())
}
```
## Service Discovery (SD) Protocol
The server periodically sends **OfferService** messages to the multicast group `239.255.0.255:30490`:
```
SD Message Structure:
├─ Flags: Reboot=Recently/Continuous (per session-counter wrap), Unicast=true
├─ Entry: OfferService
│ ├─ Service ID
│ ├─ Instance ID
│ ├─ Major Version
│ ├─ Minor Version
│ └─ TTL (seconds)
└─ Option: IPv4 Endpoint
├─ IP address
├─ Port
└─ Protocol: UDP
```
Clients listening on the multicast group will discover your service and can subscribe to event groups.
## Event Publishing
Events are sent as SOME/IP notifications:
```
SOME/IP Message:
├─ Header (16 bytes)
│ ├─ Service ID
│ ├─ Method ID (event ID)
│ ├─ Length: payload length + 8
│ ├─ Session ID: incrementing counter
│ ├─ Protocol Version: 1
│ ├─ Interface Version: 1
│ ├─ Message Type: Notification (0x02)
│ └─ Return Code: OK (0x00)
└─ Payload (application-defined)
```
## Architecture Notes
### Event-Based vs Request/Response
This implementation follows the **event-based** model where:
- **Server OFFERS services** (announces availability)
- **Clients SUBSCRIBE to event groups**
- **Server PUBLISHES events** to all subscribers
This is common in automotive SOME/IP deployments where control commands are broadcast as events, allowing multiple ECUs to subscribe without request/response overhead.
## API Reference
### `ServerConfig`
Configuration for a SOME/IP service provider:
- `interface: Ipv4Addr` - Local network interface
- `local_port: u16` - Port to bind for receiving subscriptions
- `service_id: u16` - SOME/IP service ID
- `instance_id: u16` - Service instance ID
- `major_version: u8` - Service major version (default: 1)
- `minor_version: u32` - Service minor version (default: 0)
- `ttl: u32` - Service Discovery TTL in seconds (default: 3)
### `Server`
Main server struct:
- `new(config: ServerConfig) -> Result<Self, Error>` - Create new server
- `announcement_loop() -> Result<impl Future<Output = ()> + Send + 'static, Error>` - Build the SD announcement future; caller spawns on the Tokio runtime
- `publisher() -> Arc<EventPublisher>` - Get event publisher
- `run() -> Result<(), Error>` - Run event loop (handles subscriptions)
- `register_e2e(key, profile)` - Register E2E protection for a message key
- `unregister_e2e(key)` - Remove E2E protection for a message key
### `EventPublisher`
Publishes events to subscribers:
- `publish_event(service_id, instance_id, event_group_id, message) -> Result<usize>`
- Type-safe event publishing using `Message<P>`
- Automatically applies E2E protection if configured for the message key
- Returns number of subscribers that received the event
- `publish_raw_event(service_id, instance_id, event_group_id, event_id, session_id, protocol_version, interface_version, payload) -> Result<usize>`
- Low-level event publishing using raw bytes
- Returns number of subscribers that received the event
- `register_subscriber(service_id, instance_id, event_group_id, subscriber_addr) -> Result<(), SubscribeError>`
- Manually register a subscriber (advanced use; the built-in SD loop calls this for you)
- Capacity-rejects with `SubscribeError::*` so external dispatchers can emit a `SubscribeNack`
- `remove_subscriber(service_id, instance_id, event_group_id, subscriber_addr)`
- Manually remove a subscriber
- `has_subscribers(service_id, instance_id, event_group_id) -> bool`
- Check if any subscribers exist for an event group
- `subscriber_count(service_id, instance_id, event_group_id) -> usize`
- Returns the number of subscribers for an event group
### `SubscriptionManager`
Manages event group subscriptions:
- `subscribe(service_id, instance_id, event_group_id, subscriber_addr) -> Result<(), SubscribeError>` - Add subscriber (deduplicates automatically); returns `Err` when a fixed-capacity bound (`SUBSCRIBERS_PER_GROUP` or `EVENT_GROUPS_CAP`) is exhausted
- `unsubscribe(service_id, instance_id, event_group_id, subscriber_addr)` - Remove subscriber
- `get_subscribers(service_id, instance_id, event_group_id) -> Vec<Subscriber>` - Get all subscribers
External dispatchers (those calling `EventPublisher::register_subscriber` directly) must NACK on `Err(SubscribeError::*)`; the server's built-in SD loop already does this automatically.
## Troubleshooting
### No subscribers
**Problem**: Server starts but no subscribers appear
**Solution**:
- Verify clients can see SD announcements (check with Wireshark, filter `udp.port == 30490`)
- Check firewall settings (allow UDP on your service port and 30490)
- Ensure the correct network interface is selected
### Service not discovered
**Problem**: Clients don't discover your service
**Solution**:
- Verify multicast routing on your OS
- Check interface IP matches the client's subnet
- Try increasing TTL in ServerConfig
- Monitor with Wireshark for OfferService messages