반응형


#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <systemd/sd-bus.h>
#include <signal.h>

static sd_bus *bus = NULL;
static sd_bus_slot *slot = NULL;
static int running = 1;

// Add 메서드 핸들러
static int method_add(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
    int a, b, result;
    int r;
    
    // 입력 파라미터 읽기
    r = sd_bus_message_read(m, "ii", &a, &b);
    if (r < 0) {
        fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));
        return r;
    }
    
    result = a + b;
    printf("Add called: %d + %d = %d\n", a, b, result);
    
    // 결과 반환
    return sd_bus_reply_method_return(m, "i", result);
}

// Sub 메서드 핸들러
static int method_sub(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
    int a, b, result;
    int r;
    
    // 입력 파라미터 읽기
    r = sd_bus_message_read(m, "ii", &a, &b);
    if (r < 0) {
        fprintf(stderr, "Failed to parse parameters: %s\n", strerror(-r));
        return r;
    }
    
    result = a - b;
    printf("Sub called: %d - %d = %d\n", a, b, result);
    
    // 결과 반환
    return sd_bus_reply_method_return(m, "i", result);
}

// VTable 정의 (인터페이스 메서드 매핑)
static const sd_bus_vtable calculator_vtable[] = {
    SD_BUS_VTABLE_START(0),
    SD_BUS_METHOD("Add", "ii", "i", method_add, SD_BUS_VTABLE_UNPRIVILEGED),
    SD_BUS_METHOD("Sub", "ii", "i", method_sub, SD_BUS_VTABLE_UNPRIVILEGED),
    SD_BUS_VTABLE_END
};

// SIGINT 핸들러
static void signal_handler(int sig) {
    printf("\nReceived signal %d, shutting down...\n", sig);
    running = 0;
}

int main(int argc, char *argv[]) {
    int r;
    
    // SIGINT 핸들러 설정
    signal(SIGINT, signal_handler);
    signal(SIGTERM, signal_handler);
    
    // 세션 버스에 연결
    r = sd_bus_open_user(&bus);
    if (r < 0) {
        fprintf(stderr, "Failed to connect to session bus: %s\n", strerror(-r));
        goto finish;
    }
    
    printf("Connected to D-Bus\n");
    
    // 객체에 인터페이스 추가
    r = sd_bus_add_object_vtable(bus,
                                 &slot,
                                 "/org/example/Calculator",  // 객체 경로
                                 "org.example.Calculator",    // 인터페이스 이름
                                 calculator_vtable,
                                 NULL);
    if (r < 0) {
        fprintf(stderr, "Failed to issue method call: %s\n", strerror(-r));
        goto finish;
    }
    
    printf("Object registered at /org/example/Calculator\n");
    
    // 버스 이름 요청
    r = sd_bus_request_name(bus, "org.example.Calculator", 0);
    if (r < 0) {
        fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-r));
        goto finish;
    }
    
    printf("Service name acquired: org.example.Calculator\n");
    printf("Calculator server started. Press Ctrl+C to exit.\n");
    
    // 메인 루프
    while (running) {
        // 이벤트 처리 (타임아웃: 1초)
        r = sd_bus_process(bus, NULL);
        if (r < 0) {
            fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
            goto finish;
        }
        if (r > 0) {
            // 메시지를 처리했으면 계속
            continue;
        }
        
        // 다음 이벤트 대기
        r = sd_bus_wait(bus, 1000000); // 1초 타임아웃
        if (r < 0) {
            fprintf(stderr, "Failed to wait on bus: %s\n", strerror(-r));
            goto finish;
        }
    }
    
    printf("Shutting down...\n");
    
finish:
    // 슬롯 해제 (vtable 연결 해제)
    if (slot) {
        sd_bus_slot_unref(slot);
        printf("Object unregistered\n");
    }
    
    // 버스 연결 해제
    if (bus) {
        sd_bus_unref(bus);
        printf("Disconnected from D-Bus\n");
    }
    
    printf("Server stopped.\n");
    
    return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}

반응형