configured PC-DC for VirtualBOX

Online games, how to get online, and anything involving Dreamcast online can be discussed here.
User avatar
Holsten
Cracked LCD
Posts: 408

Re: configured PC-DC for VirtualBOX

Post by Holsten »

This is awesome, i hope i can figure out on how to set it up.
Holsten knallt am dollsten.

User avatar
Scrivani
Metallic
Posts: 819
Dreamcast Games you play Online: Almost all

Re: configured PC-DC for VirtualBOX

Post by Scrivani »

Hello friends,

The script below has the necessary changes for:

1 - Sega Tetris (PAP Secrets Authentication)
2 - Power Smash (to be released)
3 - Shouma TTL Update (increase lifetime of a data packet)

The content or the entire file must be added to the VM.

Destination: /usr/local/bin/dreampi

https://github.com/scrivanidc/dreampi_c ... and_TETRIS
VM.png

Code: Select all

#!/usr/bin/env python

import atexit
import serial
import socket
import os
import logging
import logging.handlers
import sys
import time
import subprocess
import sh
import signal
import re
import config_server
import urllib
import urllib2
import iptc
#import requests

from dcnow import DreamcastNowService
from port_forwarding import PortForwarding

from datetime import datetime, timedelta


DNS_FILE = "https://dreamcast.online/dreampi/dreampi_dns.conf"


logger = logging.getLogger('dreampi')


def check_internet_connection():
    """ Returns True if there's a connection """

    IP_ADDRESS_LIST = [
        "1.1.1.1",  # Cloudflare
        "1.0.0.1",
        "8.8.8.8",  # Google DNS
        "8.8.4.4",
        "208.67.222.222",  # Open DNS
        "208.67.220.220"
    ]

    port = 53
    timeout = 3

    for host in IP_ADDRESS_LIST:
        try:
            socket.setdefaulttimeout(timeout)
            socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((host, port))
            return True
        except socket.error:
            pass
    else:
        logger.exception("No internet connection")
        return False


def restart_dnsmasq():
    subprocess.call("sudo service dnsmasq restart".split())


def update_dns_file():
    """
        Download a DNS settings file for the DreamPi configuration (avoids forwarding requests to the main DNS server
        and provides a backup if that ever goes down)
    """
    try:
        response = urllib2.urlopen(DNS_FILE)
        # Stop the server
        subprocess.check_call("sudo service dnsmasq stop".split())

        # Update the configuration
        with open("/etc/dnsmasq.d/dreampi.conf", "w") as f:
            f.write(response.read())

        # Start the server again
        subprocess.check_call("sudo service dnsmasq start".split())
    except (urllib2.URLError, urllib2.HTTPError, IOError):
        logging.exception("Unable to update the DNS file for some reason, will use upstream")
        pass


##afo_patcher = None
# Increase the TTL in the IP HDR from 30 to 64
def add_increased_ttl():
    table = iptc.Table(iptc.Table.MANGLE)
    chain = iptc.Chain(table, "PREROUTING")

    rule = iptc.Rule()
    rule.in_interface = "ppp0"
    rule.create_target("TTL").ttl_set = str(64)

    chain.insert_rule(rule)

    logger.info("DC TTL increased from 30 to 64")
    return rule

def remove_increased_ttl(ttl_rule):
    if ttl_rule:
        table = iptc.Table(iptc.Table.MANGLE)
        chain = iptc.Chain(table, "PREROUTING")
        chain.delete_rule(ttl_rule)
        logger.info("DC TTL removed")

# Add additional DNAT rules
#def start_dnat_rules():
#    rules = []
#
#    def fetch_replacement_ips():
#        url = "https://shumania.ddns.net/dnat.txt"
#        try:
#            r = requests.get(url, verify=False)
#            r.raise_for_status()
#            return r.text.strip()
#        except requests.exceptions.HTTPError:
#            logging.info(
#            "HTTP error; will skip adding DNAT rules"
#            )
#            return None
#        except requests.exceptions.Timeout:
#            logging.info(
#            "Request timed out; will skip adding DNAT rules"
#            )
#            return None
#        except requests.exceptions.SSLError:
#            logging.info(
#            "SSL error; will skip adding DNAT rules"
#            )
#            return None
#
#    data = fetch_replacement_ips()
#
#    if data is None:
#        logger.info("No DNAT rules added")
#        return None
#
#    for ips in data.splitlines():
#        ip = ips.split()
#        
#        if ip[0] is None:
#            logger.info("Missing SRC in DNAT rule - SKIP")
#            return None
#
#        if ip[1] is None:
#            logger.info("Missing DST in DNAT rule - SKIP")
#            return None
# 
#        table = iptc.Table(iptc.Table.NAT)
#        chain = iptc.Chain(table, "PREROUTING")
#
#        rule = iptc.Rule()
#        rule.protocol = "tcp"
#        rule.dst = ip[0]
#        rule.create_target("DNAT")
#        rule.target.to_destination = ip[1]
#
#        chain.append_rule(rule)
#        logger.info("DNAT rule appended %s -> %s",ip[0],ip[1])
#        rules.append(rule)
#    return rules

#def remove_dnat_rule(drule):
#    if drule:
#        table = iptc.Table(iptc.Table.NAT)
#        chain = iptc.Chain(table, "PREROUTING")
#        chain.delete_rule(drule)
#        logger.info("DNAT rule removed")

#def start_afo_patching():
#
#    def fetch_replacement_ip():
#        url = "http://dreamcast.online/afo.txt"
#        try:
#            r = requests.get(url)
#            r.raise_for_status()
#            afo_IP = r.text.strip()
#            return afo_IP
#        except requests.exceptions.HTTPError:
#            return None
#
#    replacement = fetch_replacement_ip()
#
#    if replacement is None:
#        logger.warning("Not starting AFO patch as couldn't get IP from server")
#        return
#
#    table = iptc.Table(iptc.Table.NAT)
#    chain = iptc.Chain(table, "PREROUTING")
#
#    rule = iptc.Rule()
#    rule.protocol = "tcp"
#    rule.dst = "63.251.242.131"
#    rule.create_target("DNAT")
#    rule.target.to_destination = replacement
#
#    chain.append_rule(rule)
#
#    logger.info("AFO routing enabled")
#    return rule
#
#
#def stop_afo_patching(afo_patcher_rule):
#    if afo_patcher_rule:
#        table = iptc.Table(iptc.Table.NAT)
#        chain = iptc.Chain(table, "PREROUTING")
#        chain.delete_rule(afo_patcher_rule)
#        logger.info("AFO routing disabled")

afo_patcher = None
ps_patcher = None

def start_afo_patching():
    global afo_patcher

    def fetch_replacement_ip():
        url = "http://dreamcast.online/afo.txt"
        try:
            return urllib.urlopen(url).read().strip()
        except IOError:
            return None

    replacement = fetch_replacement_ip()

    if not replacement:
        logger.warning("Not starting AFO patch as couldn't get IP from server")
        return

    table = iptc.Table(iptc.Table.NAT)
    chain = iptc.Chain(table, "PREROUTING")

    rule = iptc.Rule()
    rule.protocol = "tcp"
    rule.dst = "63.251.242.131"
    rule.create_target("DNAT")
    rule.target.to_destination = replacement

    chain.append_rule(rule)

    afo_patcher = rule
    logger.info("AFO routing enabled")


def stop_afo_patching():
    global afo_patcher
    if afo_patcher:
        table = iptc.Table(iptc.Table.NAT)
        chain = iptc.Chain(table, "PREROUTING")
        chain.delete_rule(afo_patcher)
        logger.info("AFO routing disabled")

def start_ps_patching():
    global ps_patcher

    table = iptc.Table(iptc.Table.NAT)
    chain = iptc.Chain(table, "PREROUTING")

    rule = iptc.Rule()
    rule.protocol = "tcp"
    rule.dst = "172.17.18.2"
    rule.create_target("DNAT")
    rule.target.to_destination = "146.185.135.179"

    chain.append_rule(rule)

    ps_patcher = rule
    logger.info("Power Smash routing enabled")


def stop_ps_patching():
    global ps_patcher
    if ps_patcher:
        table = iptc.Table(iptc.Table.NAT)
        chain = iptc.Chain(table, "PREROUTING")
        chain.delete_rule(ps_patcher)
        logger.info("Power Smash routing disabled")

def start_service(name):
    try:
        logger.info("Starting {} process - Thanks ShuoumaDC!".format(name))
        with open(os.devnull, "wb") as devnull:
            subprocess.check_call(["sudo", "service", name, "start"], stdout=devnull)
    except (subprocess.CalledProcessError, IOError):
        logging.warning("Unable to start the {} process".format(name))


def stop_service(name):
    try:
        logger.info("Stopping {} process".format(name))
        with open(os.devnull, "wb") as devnull:
            subprocess.check_call(["sudo", "service", name, "stop"], stdout=devnull)
    except (subprocess.CalledProcessError, IOError):
        logging.warning("Unable to stop the {} process".format(name))


def get_default_iface_name_linux():
    route = "/proc/net/route"
    with open(route) as f:
        for line in f.readlines():
            try:
                iface, dest, _, flags, _, _, _, _, _, _, _, = line.strip().split()
                if dest != '00000000' or not int(flags, 16) & 2:
                    continue
                return iface
            except:
                continue


def ip_exists(ip, iface):
    command = ["arp", "-a", "-i", iface]
    output = subprocess.check_output(command).decode()
    if ("(%s)" % ip) in output:
        logger.info("IP existed at %s", ip)
        return True
    else:
        logger.info("Free IP at %s", ip)
        return False


def find_next_unused_ip(start):
    interface = get_default_iface_name_linux()

    parts = [int(x) for x in start.split(".")]
    current_check = parts[-1] - 1

    while current_check:
        test_ip = ".".join([str(x) for x in parts[:3] + [current_check]])
        if not ip_exists(test_ip, interface):
            return test_ip
        current_check -= 1

    raise Exception("Unable to find a free IP on the network")


def autoconfigure_ppp(device, speed):
    """
       Every network is different, this function runs on boot and tries
       to autoconfigure PPP as best it can by detecting the subnet and gateway
       we're running on.

       Returns the IP allocated to the Dreamcast
    """

    gateway_ip = subprocess.check_output(
        "route -n | grep 'UG[ \t]' | awk '{print $2}'", shell=True
    ).decode()
    subnet = gateway_ip.split(".")[:3]

    PEERS_TEMPLATE = "{device}\n" "{device_speed}\n" "{this_ip}:{dc_ip}\n" "auth\n"

    OPTIONS_TEMPLATE = "debug\n" "ms-dns {this_ip}\n" "proxyarp\n" "ktune\n" "noccp\n"

    PAP_SECRETS_TEMPLATE = "# Modded from dreampi.py\n" "# INBOUND connections\n" '*       *       ""      *' "\n"

    this_ip = find_next_unused_ip(".".join(subnet) + ".100")
    dreamcast_ip = find_next_unused_ip(this_ip)
    #dreamcast_ip = this_ip[0:len(this_ip)-2] + "98"

    logger.info("Dreamcast IP: {}".format(dreamcast_ip))

    peers_content = PEERS_TEMPLATE.format(
        device=device, device_speed=speed, this_ip=this_ip, dc_ip=dreamcast_ip
    )

    with open("/etc/ppp/peers/dreamcast", "w") as f:
        f.write(peers_content)

    options_content = OPTIONS_TEMPLATE.format(this_ip=this_ip)

    with open("/etc/ppp/options", "w") as f:
        f.write(options_content)

    pap_secrets_content = PAP_SECRETS_TEMPLATE

    with open("/etc/ppp/pap-secrets", "w") as f:
        f.write(pap_secrets_content)

    return dreamcast_ip


ENABLE_SPEED_DETECTION = True  # Set this to true if you want to use wvdialconf for device detection


def detect_device_and_speed():
    MAX_SPEED = 57600

    if not ENABLE_SPEED_DETECTION:
        # By default we don't detect the speed or device as it's flakey in later
        # Pi kernels. But it might be necessary for some people so that functionality
        # can be enabled by setting the flag above to True
        return ("ttyACM0", MAX_SPEED)

    command = ["wvdialconf", "/dev/null"]

    try:
        output = subprocess.check_output(command, stderr=subprocess.STDOUT)

        lines = output.split("\n")

        for line in lines:
            match = re.match("(.+)\<Info\>\:\sSpeed\s(\d+);", line.strip())
            if match:
                device = match.group(1)
                speed = match.group(2)
                logger.info("Detected device {} with speed {}".format(device, speed))

                # Many modems report speeds higher than they can handle so we cap
                # to 56k
                return device, min(speed, MAX_SPEED)
        else:
            logger.info("No device detected")

    except:
        logger.exception("Unable to detect modem. Falling back to ttyACM0")
    return ("ttyACM0", MAX_SPEED)


class Daemon(object):
    def __init__(self, pidfile, process):
        self.pidfile = pidfile
        self.process = process

    def daemonize(self):
        try:
            pid = os.fork()
            if pid > 0:
                sys.exit(0)

        except OSError:
            sys.exit(1)

        os.chdir("/")
        os.setsid()
        os.umask(0)

        try:
            pid = os.fork()
            if pid > 0:
                sys.exit(0)
        except OSError:
            sys.exit(1)

        atexit.register(self.delete_pid)
        pid = str(os.getpid())
        with open(self.pidfile, 'w+') as f:
            f.write("%s\n" % pid)

    def delete_pid(self):
        os.remove(self.pidfile)

    def _read_pid_from_pidfile(self):
        try:
            with open(self.pidfile, 'r') as pf:
                pid = int(pf.read().strip())
        except IOError:
            pid = None
        return pid

    def start(self):
        pid = self._read_pid_from_pidfile()

        if pid:
            logger.info("Daemon already running, exiting")
            sys.exit(1)

        logger.info("Starting daemon")
        self.daemonize()
        self.run()

    def stop(self):
        pid = self._read_pid_from_pidfile()

        if not pid:
            logger.info("pidfile doesn't exist, deamon must not be running")
            return

        try:
            while True:
                os.kill(pid, signal.SIGTERM)
                time.sleep(0.1)

        except OSError:
            if os.path.exists(self.pidfile):
                os.remove(self.pidfile)
            else:
                sys.exit(1)

    def restart(self):
        self.stop()
        self.start()

    def run(self):
        self.process()


class Modem(object):
    def __init__(self, device, speed, send_dial_tone=True):
        self._device, self._speed = device, speed
        self._serial = None
        self._sending_tone = False

        if send_dial_tone:
            self._dial_tone_wav = self._read_dial_tone()
        else:
            self._dial_tone_wav = None

        self._time_since_last_dial_tone = None
        self._dial_tone_counter = 0

    @property
    def device_speed(self):
        return self._speed

    @property
    def device_name(self):
        return self._device

    def _read_dial_tone(self):
        this_dir = os.path.dirname(os.path.abspath(os.path.realpath(__file__)))
        dial_tone_wav = os.path.join(this_dir, "dial-tone.wav")

        with open(dial_tone_wav, "rb") as f:
            dial_tone = f.read()  # Read the entire wav file
            dial_tone = dial_tone[44:]  # Strip the header (44 bytes)

        return dial_tone

    def connect(self):
        if self._serial:
            self.disconnect()

        logger.info("Opening serial interface to {}".format(self._device))
        self._serial = serial.Serial(
            "/dev/{}".format(self._device), self._speed, timeout=0
        )

    def disconnect(self):
        if self._serial and self._serial.isOpen():
            #self._serial.flush()        
            self._serial.close()
            self._serial = None
            logger.info("Serial interface terminated")

    def reset(self):
        self.send_command("ATZ0")  # Send reset command
        self.send_command("ATE0")  # Don't echo our responses

    def start_dial_tone(self):
        if not self._dial_tone_wav:
            return

        self.reset()
        self.send_command("AT+FCLASS=8")  # Enter voice mode
        self.send_command("AT+VLS=1")  # Go off-hook
        #self.send_command("AT+VSM=1,8000")  # 8 bit unsigned PCM
        self.send_command("AT+VTX")  # Voice transmission mode

        self._sending_tone = True

        self._time_since_last_dial_tone = (
            datetime.now() - timedelta(seconds=100)
        )

        self._dial_tone_counter = 0

    def stop_dial_tone(self):
        if not self._sending_tone:
            return

        self._serial.write("\0{}{}\r\n".format(chr(0x10), chr(0x03)))
        self.send_escape()
        self.send_command("ATH0")  # Go on-hook
        self.reset()  # Reset the modem
        self._sending_tone = False

    def answer(self):
        self.reset()
        # When we send ATA we only want to look for CONNECT. Some modems respond OK then CONNECT
        # and that messes everything up
        self.send_command("ATA", ignore_responses=["OK"])
        time.sleep(5)
        logger.info("Call answered!")
        logger.info(subprocess.check_output(["pon", "dreamcast"]))
        logger.info("Connected")

    def send_command(self, command, timeout=60, ignore_responses=None):
        ignore_responses = ignore_responses or []  # Things to completely ignore

        VALID_RESPONSES = ["OK", "ERROR", "CONNECT", "VCON"]

        for ignore in ignore_responses:
            VALID_RESPONSES.remove(ignore)

        final_command = "%s\r\n" % command
        self._serial.write(final_command)
        logger.info(final_command)

        start = datetime.now()

        line = ""
        while True:
            new_data = self._serial.readline().strip()

            if not new_data:
                continue

            line = line + new_data
            for resp in VALID_RESPONSES:
                if resp in line:
                    logger.info(line[line.find(resp):])
                    return  # We are done

            if (datetime.now() - start).total_seconds() > timeout:
                raise IOError("There was a timeout while waiting for a response from the modem")

    def send_escape(self):
        time.sleep(1.0)
        self._serial.write("+++")
        time.sleep(1.0)

    def update(self):
        now = datetime.now()
        if self._sending_tone:
            # Keep sending dial tone
            BUFFER_LENGTH = 1000
            TIME_BETWEEN_UPLOADS_MS = (1000.0 / 8000.0) * BUFFER_LENGTH

            milliseconds = (now - self._time_since_last_dial_tone).microseconds * 1000
            if not self._time_since_last_dial_tone or milliseconds >= TIME_BETWEEN_UPLOADS_MS:
                byte = self._dial_tone_wav[self._dial_tone_counter:self._dial_tone_counter+BUFFER_LENGTH]
                self._dial_tone_counter += BUFFER_LENGTH
                if self._dial_tone_counter >= len(self._dial_tone_wav):
                    self._dial_tone_counter = 0
                self._serial.write(byte)
                self._time_since_last_dial_tone = now


class GracefulKiller(object):
    def __init__(self):
        self.kill_now = False
        signal.signal(signal.SIGINT, self.exit_gracefully)
        signal.signal(signal.SIGTERM, self.exit_gracefully)

    def exit_gracefully(self, signum, frame):
        logging.warning("Received signal: %s", signum)
        self.kill_now = True


def process():
    killer = GracefulKiller()

    dial_tone_enabled = "--disable-dial-tone" not in sys.argv

    # Make sure pppd isn't running
    with open(os.devnull, 'wb') as devnull:
        subprocess.call(["sudo", "killall", "pppd"], stderr=devnull)

    device_and_speed, internet_connected = None, False

    # Startup checks, make sure that we don't do anything until
    # we have a modem and internet connection
    while True:
        logger.info("Detecting connection and modem...")
        internet_connected = check_internet_connection()
        device_and_speed = detect_device_and_speed()

        if internet_connected and device_and_speed:
            logger.info("Internet connected and device found!")
            break

        elif not internet_connected:
            logger.warn("Unable to detect an internet connection. Waiting...")
        elif not device_and_speed:
            logger.warn("Unable to find a modem device. Waiting...")

        time.sleep(5)

    modem = Modem(device_and_speed[0], device_and_speed[1], dial_tone_enabled)
    dreamcast_ip = autoconfigure_ppp(modem.device_name, modem.device_speed)

    # Get a port forwarding object, now that we know the DC IP.
    # port_forwarding = PortForwarding(dreamcast_ip, logger)

    # Disabled until we can figure out a faster way of doing this.. it takes a minute
    # on my router which is way too long to wait for the DreamPi to boot
    # port_forwarding.forward_all()

    mode = "LISTENING"

    modem.connect()
    if dial_tone_enabled:
        modem.start_dial_tone()

    time_digit_heard = None

    dcnow = DreamcastNowService()

    while True:
        if killer.kill_now:
            break

        now = datetime.now()

        if mode == "LISTENING":
            modem.update()
            char = modem._serial.read(1).strip()
            if not char:
                continue

            if ord(char) == 16:
                # DLE character
                try:
                    char = modem._serial.read(1)
                    digit = int(char)
                    logger.info("Heard: %s", digit)

                    mode = "ANSWERING"
                    modem.stop_dial_tone()
                    time_digit_heard = now
                except (TypeError, ValueError):
                    pass
        elif mode == "ANSWERING":
            if (now - time_digit_heard).total_seconds() > 8.0:
                time_digit_heard = None
                modem.answer()
                modem.disconnect()
                mode = "CONNECTED"

        elif mode == "CONNECTED":
            dcnow.go_online(dreamcast_ip)

            # We start watching /var/log/messages for the hang up message
            for line in sh.tail("-f", "/var/log/messages", "-n", "1", _iter=True):
                if "Modem hangup" in line:
                    logger.info("Detected modem hang up, going back to listening")
                    time.sleep(5)  # Give the hangup some time
                    break
                time.sleep(0.5)
            dcnow.go_offline()
            mode = "LISTENING"
            modem = Modem(device_and_speed[0], device_and_speed[1], dial_tone_enabled)
            modem.connect()
            if dial_tone_enabled:
                modem.start_dial_tone()

    # Temporarily disabled, see above
    # port_forwarding.delete_all()
    return 0


def enable_prom_mode_on_wlan0():
    """
        The Pi wifi firmware seems broken, we can only get it to work by enabling
        promiscuous mode.

        This is a hack, we just enable it for wlan0 and ignore errors
    """

    try:
        subprocess.check_call("sudo ifconfig wlan0 promisc".split())
        logging.info("Promiscuous mode set on wlan0")
    except subprocess.CalledProcessError:
        logging.info("Attempted to set promiscuous mode on wlan0 but was unsuccessful")
        logging.info("Probably no wifi connected, or using a different device name")


def main():
    afo_patcher_rule = None
    ps_patcher_rule = None
    ttl_rule = None
    dnat_rules = []
    
    try:
        # Don't do anything until there is an internet connection
        while not check_internet_connection():
            logger.info("Waiting for internet connection...")
            time.sleep(3)

        # Try to update the DNS configuration
        #update_dns_file()

        # Hack around dodgy Raspberry Pi things
        #enable_prom_mode_on_wlan0()

        # Just make sure everything is fine
        restart_dnsmasq()

        config_server.start()
        afo_patcher_rule = start_afo_patching()
        ps_patcher_rule = start_ps_patching()
        #dnat_rules = start_dnat_rules()
        ttl_rule = add_increased_ttl()        
        start_service("dcvoip")
        start_service("dcgamespy")
        start_service("dc2k2")
        start_service("dcdaytona")        
        return process()
    except:
        logger.exception("Something went wrong...")
        return 1
    finally:
        stop_service("dc2k2")
        stop_service("dcgamespy")
        stop_service("dcvoip")
        stop_service("dcdaytona")
        if afo_patcher_rule is not None:
            stop_afo_patching(afo_patcher_rule)
        if ps_patcher_rule is not None:
            stop_ps_patching(ps_patcher_rule)
        if ttl_rule is not None:
            remove_increased_ttl(ttl_rule)
        #if dnat_rules is not None:
        #    for drule in dnat_rules:
        #        remove_dnat_rule(drule)        

        config_server.stop()
        logger.info("Dreampi quit successfully")


if __name__ == '__main__':
    logger.setLevel(logging.INFO)
    handler = logging.handlers.SysLogHandler(address='/dev/log')
    logger.addHandler(handler)

    if len(sys.argv) > 1 and "--no-daemon" in sys.argv:
        logger.addHandler(logging.StreamHandler())
        sys.exit(main())

    daemon = Daemon("/tmp/dreampi.pid", main)

    if len(sys.argv) == 2:
        if sys.argv[1] == "start":
            daemon.start()
        elif sys.argv[1] == "stop":
            daemon.stop()
        elif sys.argv[1] == "restart":
            daemon.restart()
        else:
            sys.exit(2)
        sys.exit(0)
    else:
        print("Usage: %s start|stop|restart" % sys.argv[0])
        sys.exit(2)


Also my recommendation for megavolt next VM update is to add the second DNS Server 209.50.50.129
Last edited by Scrivani on Thu Jan 23, 2025 8:34 pm, edited 1 time in total.
Happy if may help:
- https://bit.ly/scrivanidc
- BBA Mode for DreamPi: https://bit.ly/3JEIuhs
- VPN Port Fowarding: https://bit.ly/3Bgw4bu
- DC Now Data Analysis: https://bit.ly/42coxXw
- DC KARA NOT DEAD AT ALL- VCD Method: https://bit.ly/3P6VePw
- Know part of BR Community: https://bit.ly/3iLXS12

User avatar
Johne
Dead House
Posts: 373
Dreamcast Games you play Online: All of the online games!!

Re: configured PC-DC for VirtualBOX

Post by Johne »

Sega Tetris Script running on VM!
Sega Tetris Script running on VM!
WhatsApp Image 2025-01-23 at 22.41.48.jpeg

User avatar
MattoBii
noob
Posts: 1

Re: configured PC-DC for VirtualBOX

Post by MattoBii »

I searched for this issue and didn't see anything, so apologies if this has been addressed before and I just missed it somehow.

I've been trying to set up the dcgmail script (as seen here: https://dreamcastlive.net/sega-swirl-guide/) on my PC-DC setup, but upon executing it, I run into this issue:
Screenshot 2025-02-01 044438.png
It just stops there without installing dovecot-core, no matter how many times I try, even when manually running 'apt-get install dovecot-core'; everything else installs fine.

Though trying to substitute it with dovecot-common makes the script complete, it doesn't actually end up working.
falsesuccess.png
dchostbusy.png
Is there a way I can fix this and get dovecot-core installed so I can get email properly working? Or is this not possible on PC-DC as is for whatever reason? In any case, thank you for any help you can provide.

KoNeko
shadow
Posts: 11
Dreamcast Games you play Online: Phantasy Star Online
4x4 Evolution
Starlancer
Maximum Pool Online

Re: configured PC-DC for VirtualBOX

Post by KoNeko »

Hello! I am trying to connect with this image, but my connection stalls at the "OK ATA" step. I'm using a Dell RD02-D400 modem (both lights are green at this point) and a Magicjack plugged into another USB port for voltage. A splitter is plugged into the Dreamcast modem, with one cable going to the modem and another cable to the Magicjack.

Oddly enough, it connected exactly once and hasn't worked since. On the Dreamcast side, using Planetweb 2.6, it stays on "Dialing Modem" for a while and eventually says "There is no answer at this telephone number."

Any thoughts on what could be going wrong here? I've been trying different USB ports and phone cables for hours to no avail...Image

User avatar
Ke1Nishimaru
noob
Posts: 1
Dreamcast Games you play Online: PSOV2, Q3A, UT, DUSA, SL.

Re: configured PC-DC for VirtualBOX

Post by Ke1Nishimaru »

Image
Using a USRobotics USB Modem USR5637 (Same type used on my other setup I ended up giving to a friend of mine), I know it is compatible with the VM. Having problems with the setup. It detects the modem, but it always fails no matter which usb port I use. Yes, even using suggested commands is giving me nothing to work with. Any suggestions?

User avatar
Scrivani
Metallic
Posts: 819
Dreamcast Games you play Online: Almost all

Re: configured PC-DC for VirtualBOX

Post by Scrivani »

Ke1Nishimaru wrote: Thu Feb 27, 2025 9:26 am Image
Using a USRobotics USB Modem USR5637 (Same type used on my other setup I ended up giving to a friend of mine), I know it is compatible with the VM. Having problems with the setup. It detects the modem, but it always fails no matter which usb port I use. Yes, even using suggested commands is giving me nothing to work with. Any suggestions?
You need firmware update to add voice feature.

>>>>>

https://www.usr.com/support/usr5637/

Firmware
Firmware Version 1.2.23 - Includes Voice‡

Windows Stand alone flasher
Download file and run to update.
USRFlash 1.2.23.EXE (427 KB 07/24/2012)

Linux Stand alone flasher
Download file, extract zip, open readme file for update instructions.
USRFlash_1.2.23.zip (281 KB 07/25/2012)
Happy if may help:
- https://bit.ly/scrivanidc
- BBA Mode for DreamPi: https://bit.ly/3JEIuhs
- VPN Port Fowarding: https://bit.ly/3Bgw4bu
- DC Now Data Analysis: https://bit.ly/42coxXw
- DC KARA NOT DEAD AT ALL- VCD Method: https://bit.ly/3P6VePw
- Know part of BR Community: https://bit.ly/3iLXS12

User avatar
KeiNishimaru
rebel
Posts: 15
Dreamcast Games you play Online: Phantasy Star Online V2
Worms World Party
Outtrigger
Quake III Arena
Alien Front Online

Re: configured PC-DC for VirtualBOX

Post by KeiNishimaru »

Now it works. Thanks!
Keep the peace in space.