Merge pull request #2 from flyinghead/fh/wince-dynarec

Merge wince branch into master
This commit is contained in:
flyinghead 2019-07-30 13:03:39 +02:00 committed by GitHub
commit f23a3d3756
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
426 changed files with 12008 additions and 70045 deletions

View File

@ -46,7 +46,6 @@ before_deploy:
- cd ../../
- mkdir -p artifacts/$GIT_BUILD/
- cp shell/android-studio/reicast/build/outputs/apk/dreamcast/debug/reicast-dreamcast-debug.apk artifacts/$GIT_BUILD/flycast-debug-$GIT_HASH.apk
- cp shell/android-studio/reicast/build/outputs/apk/naomi/debug/reicast-naomi-debug.apk artifacts/$GIT_BUILD/flycast-naomi-debug-$GIT_HASH.apk
deploy:
provider: s3
access_key_id: AKIAJOZQS4H2PHQWYFCA

View File

@ -1,397 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset=utf-8 http-equiv="Content-Language" content="en"/>
<title>Minimal Websocket test app</title>
<style type="text/css">
div.title { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#000000; }
.browser { font-size:18pt; font: Arial; font-weight:normal; text-align:center; color:#ffff00; vertical-align:middle; text-align:center; background:#d0b070; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px;}
.group2 { width:600px; vertical-align:middle; text-align:center; background:#f0f0e0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
.explain { vertical-align:middle; text-align:center; background:#f0f0c0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; color:#404000; }
.content { vertical-align:top; text-align:center; background:#fffff0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
.canvas { vertical-align:top; text-align:center; background:#efefd0; padding:12px; -webkit-border-radius:10px; -moz-border-radius:10px; border-radius:10px; }
</style>
</head>
<body>
<header></header>
<article>
<table><tr><td>
<table width="100%"><tr><td valign=middle align=center><a href="http://libwebsockets.org"><img src="/libwebsockets.org-logo.png"></a></td><td>
<section class="browser">Detected Browser: <div id=brow>...</div></section></td></tr></table>
</td></tr><tr><td>
<section id="increment" class="group2">
<div class="title">libwebsockets "dumb-increment-protocol"</div>
<table><tr><td>
<table class="content" width="200px">
<tr><td align=center><input type=button id=offset value="Reset counter" onclick="reset();" ></td></tr>
<tr><td width=200px align=center><div id=number> </div></td></tr>
<tr><td id=wsdi_statustd align=center class="explain"><div id=wsdi_status>Not initialized</div></td></tr>
</tr>
</table>
</td><td class="explain">
The incrementing number is coming from the server and is individual for
each connection to the server... try opening a second browser window.
<br/><br/>
The button zeros just this connection's number.
<br/><br/>
</td></tr></table>
</section>
<br>
<section id="mirror" class="group2">
<div class="title">libwebsockets "lws-mirror-protocol"</div>
<div class="explain">
Use the mouse to draw on the canvas below -- all other browser windows open
on this page see your drawing in realtime and you can see any of theirs as
well.
<br/><br/>
The lws-mirror protocol doesn't interpret what is being sent to it, it just
re-sends it to every other websocket it has a connection with using that
protocol, including the guy who sent the packet.
<br/><br/>
<b>libwebsockets-test-client</b> joins in by spamming circles on to this shared canvas when
run.
</div>
<table class="content">
<tr>
<td>Drawing color:
<select id="color" onchange="update_color();">
<option value=#000000>Black</option>
<option value=#0000ff>Blue</option>
<option value=#20ff20>Green</option>
<option value=#802020>Dark Red</option>
</select>
</td>
<td id=wslm_statustd align=center class="explain"><div id=wslm_status>Not initialized</div></td>
</tr>
<tr>
<td colspan=2 width=500 class="content">
<div id="wslm_drawing">
</div></td>
</tr>
</table>
</section>
</td></tr><tr><td>
Looking for support? <a href="http://libwebsockets.org">http://libwebsockets.org</a><br/>
Join the mailing list: <a href="http://ml.libwebsockets.org/mailman/listinfo/libwebsockets">http://ml.libwebsockets.org/mailman/listinfo/libwebsockets</a>
</td></tr></table>
</article>
<script>
/* BrowserDetect came from http://www.quirksmode.org/js/detect.html */
var BrowserDetect = {
init: function () {
this.browser = this.searchString(this.dataBrowser) || "An unknown browser";
this.version = this.searchVersion(navigator.userAgent)
|| this.searchVersion(navigator.appVersion)
|| "an unknown version";
this.OS = this.searchString(this.dataOS) || "an unknown OS";
},
searchString: function (data) {
for (var i=0;i<data.length;i++) {
var dataString = data[i].string;
var dataProp = data[i].prop;
this.versionSearchString = data[i].versionSearch || data[i].identity;
if (dataString) {
if (dataString.indexOf(data[i].subString) != -1)
return data[i].identity;
}
else if (dataProp)
return data[i].identity;
}
},
searchVersion: function (dataString) {
var index = dataString.indexOf(this.versionSearchString);
if (index == -1) return;
return parseFloat(dataString.substring(index+this.versionSearchString.length+1));
},
dataBrowser: [
{
string: navigator.userAgent,
subString: "Chrome",
identity: "Chrome"
},
{ string: navigator.userAgent,
subString: "OmniWeb",
versionSearch: "OmniWeb/",
identity: "OmniWeb"
},
{
string: navigator.vendor,
subString: "Apple",
identity: "Safari",
versionSearch: "Version"
},
{
prop: window.opera,
identity: "Opera",
versionSearch: "Version"
},
{
string: navigator.vendor,
subString: "iCab",
identity: "iCab"
},
{
string: navigator.vendor,
subString: "KDE",
identity: "Konqueror"
},
{
string: navigator.userAgent,
subString: "Firefox",
identity: "Firefox"
},
{
string: navigator.vendor,
subString: "Camino",
identity: "Camino"
},
{ // for newer Netscapes (6+)
string: navigator.userAgent,
subString: "Netscape",
identity: "Netscape"
},
{
string: navigator.userAgent,
subString: "MSIE",
identity: "Explorer",
versionSearch: "MSIE"
},
{
string: navigator.userAgent,
subString: "Gecko",
identity: "Mozilla",
versionSearch: "rv"
},
{ // for older Netscapes (4-)
string: navigator.userAgent,
subString: "Mozilla",
identity: "Netscape",
versionSearch: "Mozilla"
}
],
dataOS : [
{
string: navigator.platform,
subString: "Win",
identity: "Windows"
},
{
string: navigator.platform,
subString: "Mac",
identity: "Mac"
},
{
string: navigator.userAgent,
subString: "iPhone",
identity: "iPhone/iPod"
},
{
string: navigator.platform,
subString: "Linux",
identity: "Linux"
}
]
};
BrowserDetect.init();
document.getElementById("brow").textContent = " " + BrowserDetect.browser + " "
+ BrowserDetect.version +" " + BrowserDetect.OS +" ";
var pos = 0;
function get_appropriate_ws_url()
{
var pcol;
var u = document.URL;
/*
* We open the websocket encrypted if this page came on an
* https:// url itself, otherwise unencrypted
*/
if (u.substring(0, 5) == "https") {
pcol = "wss://";
u = u.substr(8);
} else {
pcol = "ws://";
if (u.substring(0, 4) == "http")
u = u.substr(7);
}
u = u.split('/');
/* + "/xxx" bit is for IE10 workaround */
return pcol + u[0] + "/xxx";
}
document.getElementById("number").textContent = get_appropriate_ws_url();
/* dumb increment protocol */
var socket_di;
if (typeof MozWebSocket != "undefined") {
socket_di = new MozWebSocket(get_appropriate_ws_url(),
"dumb-increment-protocol");
} else {
socket_di = new WebSocket(get_appropriate_ws_url(),
"dumb-increment-protocol");
}
try {
socket_di.onopen = function() {
document.getElementById("wsdi_statustd").style.backgroundColor = "#40ff40";
document.getElementById("wsdi_status").textContent = " websocket connection opened ";
}
socket_di.onmessage =function got_packet(msg) {
document.getElementById("number").textContent = msg.data + "\n";
}
socket_di.onclose = function(){
document.getElementById("wsdi_statustd").style.backgroundColor = "#ff4040";
document.getElementById("wsdi_status").textContent = " websocket connection CLOSED ";
}
} catch(exception) {
alert('<p>Error' + exception);
}
function reset() {
socket_di.send("reset\n");
}
/* lws-mirror protocol */
var down = 0;
var no_last = 1;
var last_x = 0, last_y = 0;
var ctx;
var socket_lm;
var color = "#000000";
if (typeof MozWebSocket != "undefined") {
socket_lm = new MozWebSocket(get_appropriate_ws_url(),
"lws-mirror-protocol");
} else {
socket_lm = new WebSocket(get_appropriate_ws_url(),
"lws-mirror-protocol");
}
try {
socket_lm.onopen = function() {
document.getElementById("wslm_statustd").style.backgroundColor = "#40ff40";
document.getElementById("wslm_status").textContent = " websocket connection opened ";
}
socket_lm.onmessage =function got_packet(msg) {
var j = msg.data.split(';'), f = 0;
while (f < j.length - 1) {
var i = j[f].split(' ');
if (i[0] == 'd') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.moveTo(+(i[2]), +(i[3]));
ctx.lineTo(+(i[4]), +(i[5]));
ctx.stroke();
}
if (i[0] == 'c') {
ctx.strokeStyle = i[1];
ctx.beginPath();
ctx.arc(+(i[2]), +(i[3]), +(i[4]), 0, Math.PI*2, true);
ctx.stroke();
}
f++;
}
}
socket_lm.onclose = function(){
document.getElementById("wslm_statustd").style.backgroundColor = "#ff4040";
document.getElementById("wslm_status").textContent = " websocket connection CLOSED ";
}
} catch(exception) {
alert('<p>Error' + exception);
}
var canvas = document.createElement('canvas');
canvas.height = 300;
canvas.width = 480;
ctx = canvas.getContext("2d");
document.getElementById('wslm_drawing').appendChild(canvas);
canvas.addEventListener('mousemove', ev_mousemove, false);
canvas.addEventListener('mousedown', ev_mousedown, false);
canvas.addEventListener('mouseup', ev_mouseup, false);
offsetX = offsetY = 0;
element = canvas;
if (element.offsetParent) {
do {
offsetX += element.offsetLeft;
offsetY += element.offsetTop;
} while ((element = element.offsetParent));
}
function update_color() {
color = document.getElementById("color").value;
}
function ev_mousedown (ev) {
down = 1;
}
function ev_mouseup(ev) {
down = 0;
no_last = 1;
}
function ev_mousemove (ev) {
var x, y;
if (ev.offsetX) {
x = ev.offsetX;
y = ev.offsetY;
} else {
x = ev.layerX - offsetX;
y = ev.layerY - offsetY;
}
if (!down)
return;
if (no_last) {
no_last = 0;
last_x = x;
last_y = y;
return;
}
socket_lm.send("d " + color + " " + last_x + " " + last_y + " " + x + ' ' + y + ';');
last_x = x;
last_y = y;
}
</script>
</body>
</html>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -3,7 +3,6 @@ image: Visual Studio 2017
configuration:
- fast
- naomi
platform:
- x64
@ -24,14 +23,10 @@ build_script:
- cmd: >-
if "%CONFIGURATION%"=="fast" (mingw32-make platform=win32)
if "%CONFIGURATION%"=="naomi" (mingw32-make platform=win32 NAOMI=1)
after_build:
- cmd: >-
if "%CONFIGURATION%"=="fast" (cd ..\.. && set EXE_PATH=shell\linux\nosym-reicast.exe)
if "%CONFIGURATION%"=="naomi" (cd ..\.. && set EXE_PATH=shell\linux\nosym-reicast.exe)
mkdir artifacts
move %EXE_PATH% artifacts\flycast-win_%PLATFORM%-%CONFIGURATION%-%APPVEYOR_REPO_COMMIT%.exe

View File

@ -8,33 +8,6 @@ trigger_map:
- pull_request_source_branch: "*"
workflow: deploy
workflows:
deploy-naomi:
envs:
- opts:
is_expand: false
BITRISE_SCHEME: reicast-osx-naomi
steps:
- activate-ssh-key@4.0.3:
run_if: '{{getenv "SSH_RSA_PRIVATE_KEY" | ne ""}}'
- git-clone@4.0.14: {}
- cache-pull@2.0.1: {}
- certificate-and-profile-installer@1.10.1: {}
- recreate-user-schemes@1.0.2:
inputs:
- project_path: "$BITRISE_PROJECT_PATH"
- xcode-archive-mac@1.6.2:
inputs:
- project_path: "$BITRISE_PROJECT_PATH"
- scheme: "$BITRISE_SCHEME"
- export_method: "$BITRISE_EXPORT_METHOD"
- amazon-s3-uploader@1.0.1:
inputs:
- aws_access_key: AKIAJOZQS4H2PHQWYFCA
- aws_secret_key: "$S3_SECRET_KEY"
- bucket_name: flycast-builds
- path_in_bucket: osx/$GIT_BUILD
- file_path: "$BITRISE_EXPORTED_FILE_PATH"
- cache-push@2.1.1: {}
deploy:
envs:
- opts:
@ -69,8 +42,6 @@ workflows:
- path_in_bucket: osx/$GIT_BUILD
- file_path: "$BITRISE_EXPORTED_FILE_PATH"
- cache-push@2.1.1: {}
after_run:
- deploy-naomi
app:
envs:
- opts:

View File

@ -591,6 +591,19 @@ ADD.SP.REG 0x008D0000
EMIT_I;
}
EAPI SBFX(eReg Rd, eReg Rm, u8 lsb, u8 width, ConditionCode CC=AL)
{
DECL_Id(0x07A00050);
verify(lsb+width<=32);
SET_CC;
I |= (Rd&15)<<12;
I |= (Rm&15);
I |= (lsb&31)<<7;
I |= ((width-1)&31)<<16;
EMIT_I;
}
EAPI MOV(eReg Rd, eReg Rm, ConditionCode CC=AL)
{
DECL_Id(0x01A00000);
@ -844,4 +857,4 @@ ADD.SP.REG 0x008D0000
};
};

View File

@ -242,6 +242,8 @@ EAPI LDRH(eReg Rt, eReg Rn, s32 sImm8, ConditionCode CC=AL) { DECL_Id(0x005000B0
EAPI STRH(eReg Rt, eReg Rn, s32 sImm8, ConditionCode CC=AL) { DECL_Id(0x004000B0); SET_CC; SET_Rtn; SET_P; SET_sImm8; EMIT_I; }
EAPI LDRD(eReg Rt, eReg Rn, s32 sImm8, ConditionCode CC=AL) { DECL_Id(0x004000D0); SET_CC; SET_Rtn; SET_P; SET_sImm8; EMIT_I; }
EAPI STRD(eReg Rt, eReg Rn, s32 sImm8, ConditionCode CC=AL) { DECL_Id(0x004000F0); SET_CC; SET_Rtn; SET_P; SET_sImm8; EMIT_I; }
EAPI LDRSB(eReg Rt, eReg Rn, s32 sImm8 = 0, ConditionCode CC = AL) { DECL_Id(0x005000D0); SET_CC; SET_Rtn; SET_P; SET_sImm8; EMIT_I; }
EAPI LDRSH(eReg Rt, eReg Rn, s32 sImm8 = 0, ConditionCode CC = AL) { DECL_Id(0x005000F0); SET_CC; SET_Rtn; SET_P; SET_sImm8; EMIT_I; }
EAPI LDRH(eReg Rt, eReg Rn, eReg Rm, bool Add=true,ConditionCode CC=AL) { DECL_Id(0x001000B0); SET_CC; SET_Rtnm; SET_P; if (Add) {SET_U;} EMIT_I; }
EAPI STRH(eReg Rt, eReg Rn, eReg Rm, bool Add=true,ConditionCode CC=AL) { DECL_Id(0x000000B0); SET_CC; SET_Rtnm; SET_P; if (Add) {SET_U;} EMIT_I; }
@ -307,4 +309,4 @@ EAPI POP(u32 RegList, ConditionCode CC=AL)
};
};

View File

@ -627,7 +627,7 @@ namespace ARM
eFSReg SnS=(eFSReg)(Sn*2);
eFSReg SmS=(eFSReg)(Sm*2);
verify(Sd<32 && Sn<32 && Sm<32);
verify((int)Sd < 32 && (int)Sn < 32 && (int)Sm < 32);
VDIV_VFP(SdS,SnS,SmS);
}

View File

@ -27,13 +27,13 @@ namespace ARM
snat lit = Literal(FnAddr);
if(0==lit) {
printf("Error, Compiler caught NULL literal, CALL(%08X)\n", FnAddr);
printf("Error, Compiler caught NULL literal, CALL(%08zX)\n", FnAddr);
verify(false);
return;
}
if( (lit<-33554432) || (lit>33554428) ) // ..28 for BL ..30 for BLX
{
printf("Warning, CALL(%08X) is out of range for literal(%08X)\n", FnAddr, lit);
printf("Warning, CALL(%08zX) is out of range for literal(%08zX)\n", FnAddr, lit);
// verify(false);
MOV32(IP, FnAddr, CC);
@ -66,7 +66,7 @@ namespace ARM
}*/
if( (lit<-33554432) || (lit>33554428) ) // ..28 for BL ..30 for BLX
{
printf("Warning, %X is out of range for imm jump! \n", FnAddr);
printf("Warning, %zX is out of range for imm jump! \n", FnAddr);
//verify(false);
MOV32(IP, FnAddr, CC);

View File

@ -115,7 +115,9 @@
*/
#define NO_MMU
//#define NO_MMU
#define FAST_MMU
#define USE_WINCE_HACK
#define DC_PLATFORM_MASK 7
#define DC_PLATFORM_DREAMCAST 0 /* Works, for the most part */
@ -209,7 +211,7 @@
#elif defined(TARGET_GCW0)
#define HOST_OS OS_LINUX
#define HOST_CPU CPU_MIPS
#elif defined(TARGET_NACL32) || defined(TARGET_EMSCRIPTEN)
#elif defined(TARGET_EMSCRIPTEN)
#define HOST_OS OS_LINUX
#define HOST_CPU CPU_GENERIC
#elif defined(TARGET_IPHONE)
@ -225,11 +227,6 @@
#error Invalid Target: TARGET_* not defined
#endif
#if defined(TARGET_NAOMI)
#define DC_PLATFORM DC_PLATFORM_NAOMI
#undef TARGET_NAOMI
#endif
#if defined(TARGET_NO_REC)
#define FEAT_SHREC DYNAREC_NONE
#define FEAT_AREC DYNAREC_NONE
@ -265,10 +262,6 @@
//defaults
#ifndef DC_PLATFORM
#define DC_PLATFORM DC_PLATFORM_DREAMCAST
#endif
#ifndef FEAT_SHREC
#define FEAT_SHREC DYNAREC_JIT
#endif
@ -303,6 +296,10 @@
#define FEAT_HAS_SOFTREND BUILD_COMPILER == COMPILER_VC //GCC wants us to enable sse4 globaly to enable intrins
#endif
#if HOST_CPU == CPU_X64 || HOST_CPU == CPU_ARM64
#define HOST_64BIT_CPU
#endif
//Depricated build configs
#ifdef HOST_NO_REC
#error Dont use HOST_NO_REC
@ -339,94 +336,7 @@
#define RAM_SIZE_MAX (32*1024*1024)
#define VRAM_SIZE_MAX (16*1024*1024)
#define ARAM_SIZE_MAX (8*1024*1024)
#if (DC_PLATFORM==DC_PLATFORM_DREAMCAST)
#define BUILD_DREAMCAST 1
//DC : 16 mb ram, 8 mb vram, 2 mb aram, 2 mb bios, 128k flash
#define RAM_SIZE (16*1024*1024)
#define VRAM_SIZE (8*1024*1024)
#define ARAM_SIZE (2*1024*1024)
#define BIOS_SIZE (2*1024*1024)
#define FLASH_SIZE (128*1024)
#define ROM_PREFIX "dc_"
#define ROM_NAMES
#define NVR_OPTIONAL 0
#elif (DC_PLATFORM==DC_PLATFORM_DEV_UNIT)
#define BUILD_DEV_UNIT 1
//Devkit : 32 mb ram, 8? mb vram, 2? mb aram, 2? mb bios, ? flash
#define RAM_SIZE (32*1024*1024)
#define VRAM_SIZE (8*1024*1024)
#define ARAM_SIZE (2*1024*1024)
#define BIOS_SIZE (2*1024*1024)
#define FLASH_SIZE (128*1024)
#define ROM_PREFIX "hkt_"
#define ROM_NAMES
#define NVR_OPTIONAL 0
#elif (DC_PLATFORM==DC_PLATFORM_NAOMI)
//Naomi : 32 mb ram, 16 mb vram, 8 mb aram, 2 mb bios, ? flash
#define RAM_SIZE (32*1024*1024)
#define VRAM_SIZE (16*1024*1024)
#define ARAM_SIZE (8*1024*1024)
#define BIOS_SIZE (2*1024*1024)
#define BBSRAM_SIZE (32*1024)
#define ROM_PREFIX "naomi_"
#define ROM_NAMES ";epr-21576d.bin"
#define NVR_OPTIONAL 1
#elif (DC_PLATFORM==DC_PLATFORM_NAOMI2)
//Naomi2 : 32 mb ram, 16 mb vram, 8 mb aram, 2 mb bios, ? flash
#define RAM_SIZE (32*1024*1024)
#define VRAM_SIZE (16*1024*1024)
#define ARAM_SIZE (8*1024*1024)
#define BIOS_SIZE (2*1024*1024)
#define BBSRAM_SIZE (32*1024)
#define ROM_PREFIX "n2_"
#define ROM_NAMES
#define NVR_OPTIONAL 1
#elif (DC_PLATFORM==DC_PLATFORM_ATOMISWAVE)
#define BUILD_ATOMISWAVE 1
//Atomiswave : 16 mb ram, 8 mb vram, 8 mb aram, 128kb bios on flash, 128kb battery-backed ram
#define RAM_SIZE (16*1024*1024)
#define VRAM_SIZE (8*1024*1024)
#define ARAM_SIZE (8*1024*1024)
#define BIOS_SIZE (128*1024)
#define BBSRAM_SIZE (128*1024)
#define ROM_PREFIX "aw_"
#define ROM_NAMES ";bios.ic23_l"
#define NVR_OPTIONAL 1
#else
#error invalid build config
#endif
#define RAM_MASK (RAM_SIZE-1)
#define VRAM_MASK (VRAM_SIZE-1)
#define ARAM_MASK (ARAM_SIZE-1)
#define BIOS_MASK (BIOS_SIZE-1)
#ifdef FLASH_SIZE
#define FLASH_MASK (FLASH_SIZE-1)
#endif
#ifdef BBSRAM_SIZE
#define BBSRAM_MASK (BBSRAM_SIZE-1)
#endif
#define BUILD_DREAMCAST 1
#define GD_CLOCK 33868800 //GDROM XTAL -- 768fs

View File

@ -21,7 +21,7 @@ void savecfgf()
FILE* cfgfile = fopen(cfgPath.c_str(),"wt");
if (!cfgfile)
{
printf("Error: Unable to open file '%s' for saving\n", cfgPath.c_str());
WARN_LOG(COMMON, "Error: Unable to open file '%s' for saving", cfgPath.c_str());
}
else
{
@ -93,11 +93,11 @@ bool cfgOpen()
{
// Config file can't be opened
int error_code = errno;
printf("Warning: Unable to open the config file '%s' for reading (%s)\n", config_path_read.c_str(), strerror(error_code));
WARN_LOG(COMMON, "Warning: Unable to open the config file '%s' for reading (%s)", config_path_read.c_str(), strerror(error_code));
if (error_code == ENOENT || cfgPath != config_path_read)
{
// Config file didn't exist
printf("Creating new empty config file at '%s'\n", cfgPath.c_str());
INFO_LOG(COMMON, "Creating new empty config file at '%s'", cfgPath.c_str());
savecfgf();
}
else

View File

@ -49,19 +49,19 @@ int setconfig(wchar** arg,int cl)
{
if (cl<1)
{
printf("-config : invalid number of parameters, format is section:key=value\n");
WARN_LOG(COMMON, "-config : invalid number of parameters, format is section:key=value");
return rv;
}
wchar* sep=strstr(arg[1],":");
if (sep==0)
{
printf("-config : invalid parameter %s, format is section:key=value\n",arg[1]);
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", arg[1]);
return rv;
}
wchar* value=strstr(sep+1,"=");
if (value==0)
{
printf("-config : invalid parameter %s, format is section:key=value\n",arg[1]);
WARN_LOG(COMMON, "-config : invalid parameter %s, format is section:key=value", arg[1]);
return rv;
}
@ -74,14 +74,14 @@ int setconfig(wchar** arg,int cl)
if (sect==0 || key==0)
{
printf("-config : invalid parameter, format is section:key=value\n");
WARN_LOG(COMMON, "-config : invalid parameter, format is section:key=value");
return rv;
}
const wchar* constval = value;
if (constval==0)
constval="";
printf("Virtual cfg %s:%s=%s\n",sect,key,value);
INFO_LOG(COMMON, "Virtual cfg %s:%s=%s", sect, key, value);
cfgSetVirtual(sect,key,value);
rv++;
@ -101,10 +101,10 @@ int setconfig(wchar** arg,int cl)
int showhelp(wchar** arg,int cl)
{
printf("\nAvailable commands :\n");
NOTICE_LOG(COMMON, "Available commands:");
printf("-config section:key=value [, ..]: add a virtual config value\n Virtual config values won't be saved to the .cfg file\n unless a different value is written to em\nNote :\n You can specify many settings in the xx:yy=zz , gg:hh=jj , ...\n format.The spaces between the values and ',' are needed.\n");
printf("\n-help: show help info\n");
NOTICE_LOG(COMMON, "-config section:key=value [, ..]: add a virtual config value\n Virtual config values won't be saved to the .cfg file\n unless a different value is written to em\nNote :\n You can specify many settings in the xx:yy=zz , gg:hh=jj , ...\n format.The spaces between the values and ',' are needed.");
NOTICE_LOG(COMMON, "-help: show help info");
return 0;
}
@ -133,31 +133,25 @@ bool ParseCommandLine(int argc,wchar* argv[])
if (extension
&& (stricmp(extension, ".cdi") == 0 || stricmp(extension, ".chd") == 0
|| stricmp(extension, ".gdi") == 0 || stricmp(extension, ".lst") == 0
|| stricmp(extension, ".cue") == 0))
|| stricmp(extension, ".gdi") == 0 || stricmp(extension, ".cue") == 0))
{
printf("Using '%s' as cd image\n", *arg);
INFO_LOG(COMMON, "Using '%s' as cd image", *arg);
cfgSetVirtual("config", "image", *arg);
}
else if (extension && stricmp(extension, ".elf") == 0)
{
printf("Using '%s' as reios elf file\n", *arg);
INFO_LOG(COMMON, "Using '%s' as reios elf file", *arg);
cfgSetVirtual("config", "reios.enabled", "1");
cfgSetVirtual("reios", "ElfFile", *arg);
}
else
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
printf("Using '%s' as rom\n", *arg);
INFO_LOG(COMMON, "Using '%s' as rom", *arg);
cfgSetVirtual("config", "image", *arg);
#else
printf("wtf %s is supposed to do ?\n",*arg);
#endif
}
}
arg++;
cl--;
}
printf("\n");
return false;
}

View File

@ -246,7 +246,7 @@ void ConfigFile::parse(FILE* file)
if (!separator)
{
printf("Malformed entry on config - ignoring @ %d(%s)\n",cline, tl);
WARN_LOG(COMMON, "Malformed entry on config - ignoring @ %d(%s)", cline, tl);
continue;
}

View File

@ -11,16 +11,7 @@ RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ \
hw/mem/ hw/pvr/ hw/sh4/ hw/sh4/interpr/ hw/sh4/modules/ plugins/ profiler/ oslib/ \
hw/extdev/ hw/arm/ hw/naomi/ imgread/ ./ deps/coreio/ deps/zlib/ deps/chdr/ deps/crypto/ \
deps/libelf/ deps/chdpsr/ arm_emitter/ rend/ reios/ deps/libpng/ deps/xbrz/ \
deps/xxhash/ deps/libzip/ deps/imgui/ archive/ input/
ifdef WEBUI
RZDCY_MODULES += webui/
RZDCY_MODULES += deps/libwebsocket/
ifdef FOR_ANDROID
RZDCY_MODULES += deps/ifaddrs/
endif
endif
deps/xxhash/ deps/libzip/ deps/imgui/ archive/ input/ log/
ifndef NOT_ARM
RZDCY_MODULES += rec-ARM/
@ -135,7 +126,7 @@ endif
ifdef CHD5_FLAC
RZDCY_CFLAGS += -DCHD5_FLAC -I$(RZDCY_SRC_DIR)/deps/flac/src/libFLAC/include/ -I$(RZDCY_SRC_DIR)/deps/flac/include
RZDCY_CFLAGS += -DPACKAGE_VERSION=\"1.3.2\" -DFLAC__HAS_OGG=0 -DFLAC__NO_DLL -DHAVE_LROUND -DHAVE_STDINT_H -DHAVE_STDLIB_H -DHAVE_SYS_PARAM_H
RZDCY_CFLAGS += -DHAVE_CONFIG_H
RZDCY_MODULES += deps/flac/src/libFLAC/
endif

View File

@ -148,7 +148,7 @@ size_t HTTP_GET(string host, int port,string path, size_t offs, size_t len, void
string CL = "Content-Length:";
if (ln.substr(0, CL.size()) == CL) {
sscanf(ln.substr(CL.size(), ln.npos).c_str(),"%d", &content_length);
sscanf(ln.substr(CL.size(), ln.npos).c_str(),"%zd", &content_length);
}
break;

View File

@ -0,0 +1,10 @@
#define PACKAGE_VERSION "1.3.2"
#define FLAC__HAS_OGG 0
#define FLAC__NO_DLL 1
#define HAVE_LROUND 1
#define HAVE_STDINT_H 1
#define HAVE_STDLIB_H 1
#ifndef _MSC_VER
#define HAVE_SYS_PARAM_H 1
#endif

View File

@ -1,6 +0,0 @@
android-ifaddrs
===============
An implementation of getifaddrs() for Android, since the NDK does not natively support it.
Works just like you would expect on regular Linux. License information is present in each file (BSD license).

View File

@ -1,658 +0,0 @@
/*
Copyright (c) 2013, Kenneth MacKay
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "ifaddrs.h"
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/socket.h>
#include <net/if_arp.h>
#include <netinet/in.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
typedef struct NetlinkList
{
struct NetlinkList *m_next;
struct nlmsghdr *m_data;
unsigned int m_size;
} NetlinkList;
static int netlink_socket(void)
{
int l_socket = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if(l_socket < 0)
{
return -1;
}
struct sockaddr_nl l_addr;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
if(bind(l_socket, (struct sockaddr *)&l_addr, sizeof(l_addr)) < 0)
{
close(l_socket);
return -1;
}
return l_socket;
}
static int netlink_send(int p_socket, int p_request)
{
char l_buffer[NLMSG_ALIGN(sizeof(struct nlmsghdr)) + NLMSG_ALIGN(sizeof(struct rtgenmsg))];
memset(l_buffer, 0, sizeof(l_buffer));
struct nlmsghdr *l_hdr = (struct nlmsghdr *)l_buffer;
struct rtgenmsg *l_msg = (struct rtgenmsg *)NLMSG_DATA(l_hdr);
l_hdr->nlmsg_len = NLMSG_LENGTH(sizeof(*l_msg));
l_hdr->nlmsg_type = p_request;
l_hdr->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
l_hdr->nlmsg_pid = 0;
l_hdr->nlmsg_seq = p_socket;
l_msg->rtgen_family = AF_UNSPEC;
struct sockaddr_nl l_addr;
memset(&l_addr, 0, sizeof(l_addr));
l_addr.nl_family = AF_NETLINK;
return (sendto(p_socket, l_hdr, l_hdr->nlmsg_len, 0, (struct sockaddr *)&l_addr, sizeof(l_addr)));
}
static int netlink_recv(int p_socket, void *p_buffer, size_t p_len)
{
struct msghdr l_msg;
struct iovec l_iov = { p_buffer, p_len };
struct sockaddr_nl l_addr;
int l_result;
for(;;)
{
l_msg.msg_name = (void *)&l_addr;
l_msg.msg_namelen = sizeof(l_addr);
l_msg.msg_iov = &l_iov;
l_msg.msg_iovlen = 1;
l_msg.msg_control = NULL;
l_msg.msg_controllen = 0;
l_msg.msg_flags = 0;
int l_result = recvmsg(p_socket, &l_msg, 0);
if(l_result < 0)
{
if(errno == EINTR)
{
continue;
}
return -2;
}
if(l_msg.msg_flags & MSG_TRUNC)
{ // buffer was too small
return -1;
}
return l_result;
}
}
static struct nlmsghdr *getNetlinkResponse(int p_socket, int *p_size, int *p_done)
{
size_t l_size = 4096;
void *l_buffer = NULL;
for(;;)
{
free(l_buffer);
l_buffer = malloc(l_size);
if (l_buffer == NULL)
{
return NULL;
}
int l_read = netlink_recv(p_socket, l_buffer, l_size);
*p_size = l_read;
if(l_read == -2)
{
free(l_buffer);
return NULL;
}
if(l_read >= 0)
{
pid_t l_pid = getpid();
struct nlmsghdr *l_hdr;
for(l_hdr = (struct nlmsghdr *)l_buffer; NLMSG_OK(l_hdr, (unsigned int)l_read); l_hdr = (struct nlmsghdr *)NLMSG_NEXT(l_hdr, l_read))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
*p_done = 1;
break;
}
if(l_hdr->nlmsg_type == NLMSG_ERROR)
{
free(l_buffer);
return NULL;
}
}
return l_buffer;
}
l_size *= 2;
}
}
static NetlinkList *newListItem(struct nlmsghdr *p_data, unsigned int p_size)
{
NetlinkList *l_item = malloc(sizeof(NetlinkList));
if (l_item == NULL)
{
return NULL;
}
l_item->m_next = NULL;
l_item->m_data = p_data;
l_item->m_size = p_size;
return l_item;
}
static void freeResultList(NetlinkList *p_list)
{
NetlinkList *l_cur;
while(p_list)
{
l_cur = p_list;
p_list = p_list->m_next;
free(l_cur->m_data);
free(l_cur);
}
}
static NetlinkList *getResultList(int p_socket, int p_request)
{
if(netlink_send(p_socket, p_request) < 0)
{
return NULL;
}
NetlinkList *l_list = NULL;
NetlinkList *l_end = NULL;
int l_size;
int l_done = 0;
while(!l_done)
{
struct nlmsghdr *l_hdr = getNetlinkResponse(p_socket, &l_size, &l_done);
if(!l_hdr)
{ // error
freeResultList(l_list);
return NULL;
}
NetlinkList *l_item = newListItem(l_hdr, l_size);
if (!l_item)
{
freeResultList(l_list);
return NULL;
}
if(!l_list)
{
l_list = l_item;
}
else
{
l_end->m_next = l_item;
}
l_end = l_item;
}
return l_list;
}
static size_t maxSize(size_t a, size_t b)
{
return (a > b ? a : b);
}
static size_t calcAddrLen(sa_family_t p_family, int p_dataSize)
{
switch(p_family)
{
case AF_INET:
return sizeof(struct sockaddr_in);
case AF_INET6:
return sizeof(struct sockaddr_in6);
case AF_PACKET:
return maxSize(sizeof(struct sockaddr_ll), offsetof(struct sockaddr_ll, sll_addr) + p_dataSize);
default:
return maxSize(sizeof(struct sockaddr), offsetof(struct sockaddr, sa_data) + p_dataSize);
}
}
static void makeSockaddr(sa_family_t p_family, struct sockaddr *p_dest, void *p_data, size_t p_size)
{
switch(p_family)
{
case AF_INET:
memcpy(&((struct sockaddr_in*)p_dest)->sin_addr, p_data, p_size);
break;
case AF_INET6:
memcpy(&((struct sockaddr_in6*)p_dest)->sin6_addr, p_data, p_size);
break;
case AF_PACKET:
memcpy(((struct sockaddr_ll*)p_dest)->sll_addr, p_data, p_size);
((struct sockaddr_ll*)p_dest)->sll_halen = p_size;
break;
default:
memcpy(p_dest->sa_data, p_data, p_size);
break;
}
p_dest->sa_family = p_family;
}
static void addToEnd(struct ifaddrs **p_resultList, struct ifaddrs *p_entry)
{
if(!*p_resultList)
{
*p_resultList = p_entry;
}
else
{
struct ifaddrs *l_cur = *p_resultList;
while(l_cur->ifa_next)
{
l_cur = l_cur->ifa_next;
}
l_cur->ifa_next = p_entry;
}
}
static int interpretLink(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList)
{
struct ifinfomsg *l_info = (struct ifinfomsg *)NLMSG_DATA(p_hdr);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
size_t l_dataSize = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
struct rtattr *l_rta;
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
case IFLA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(AF_PACKET, l_rtaDataSize));
break;
case IFLA_IFNAME:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
case IFLA_STATS:
l_dataSize += NLMSG_ALIGN(l_rtaSize);
break;
default:
break;
}
}
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + sizeof(int) + l_nameSize + l_addrSize + l_dataSize);
if (l_entry == NULL)
{
return -1;
}
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = "";
char *l_index = ((char *)l_entry) + sizeof(struct ifaddrs);
char *l_name = l_index + sizeof(int);
char *l_addr = l_name + l_nameSize;
char *l_data = l_addr + l_addrSize;
// save the interface index so we can look it up when handling the addresses.
memcpy(l_index, &l_info->ifi_index, sizeof(int));
l_entry->ifa_flags = l_info->ifi_flags;
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifinfomsg));
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFLA_ADDRESS:
case IFLA_BROADCAST:
{
size_t l_addrLen = calcAddrLen(AF_PACKET, l_rtaDataSize);
makeSockaddr(AF_PACKET, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
((struct sockaddr_ll *)l_addr)->sll_ifindex = l_info->ifi_index;
((struct sockaddr_ll *)l_addr)->sll_hatype = l_info->ifi_type;
if(l_rta->rta_type == IFLA_ADDRESS)
{
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFLA_IFNAME:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
case IFLA_STATS:
memcpy(l_data, l_rtaData, l_rtaDataSize);
l_entry->ifa_data = l_data;
break;
default:
break;
}
}
addToEnd(p_resultList, l_entry);
return 0;
}
static struct ifaddrs *findInterface(int p_index, struct ifaddrs **p_links, int p_numLinks)
{
int l_num = 0;
struct ifaddrs *l_cur = *p_links;
while(l_cur && l_num < p_numLinks)
{
char *l_indexPtr = ((char *)l_cur) + sizeof(struct ifaddrs);
int l_index;
memcpy(&l_index, l_indexPtr, sizeof(int));
if(l_index == p_index)
{
return l_cur;
}
l_cur = l_cur->ifa_next;
++l_num;
}
return NULL;
}
static int interpretAddr(struct nlmsghdr *p_hdr, struct ifaddrs **p_resultList, int p_numLinks)
{
struct ifaddrmsg *l_info = (struct ifaddrmsg *)NLMSG_DATA(p_hdr);
struct ifaddrs *l_interface = findInterface(l_info->ifa_index, p_resultList, p_numLinks);
size_t l_nameSize = 0;
size_t l_addrSize = 0;
int l_addedNetmask = 0;
size_t l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
struct rtattr *l_rta;
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
if(l_info->ifa_family == AF_PACKET)
{
continue;
}
switch(l_rta->rta_type)
{
case IFA_ADDRESS:
case IFA_LOCAL:
if((l_info->ifa_family == AF_INET || l_info->ifa_family == AF_INET6) && !l_addedNetmask)
{ // make room for netmask
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
l_addedNetmask = 1;
}
case IFA_BROADCAST:
l_addrSize += NLMSG_ALIGN(calcAddrLen(l_info->ifa_family, l_rtaDataSize));
break;
case IFA_LABEL:
l_nameSize += NLMSG_ALIGN(l_rtaSize + 1);
break;
default:
break;
}
}
struct ifaddrs *l_entry = malloc(sizeof(struct ifaddrs) + l_nameSize + l_addrSize);
if (l_entry == NULL)
{
return -1;
}
memset(l_entry, 0, sizeof(struct ifaddrs));
l_entry->ifa_name = (l_interface ? l_interface->ifa_name : "");
char *l_name = ((char *)l_entry) + sizeof(struct ifaddrs);
char *l_addr = l_name + l_nameSize;
l_entry->ifa_flags = l_info->ifa_flags;
if(l_interface)
{
l_entry->ifa_flags |= l_interface->ifa_flags;
}
l_rtaSize = NLMSG_PAYLOAD(p_hdr, sizeof(struct ifaddrmsg));
for(l_rta = IFLA_RTA(l_info); RTA_OK(l_rta, l_rtaSize); l_rta = RTA_NEXT(l_rta, l_rtaSize))
{
void *l_rtaData = RTA_DATA(l_rta);
size_t l_rtaDataSize = RTA_PAYLOAD(l_rta);
switch(l_rta->rta_type)
{
case IFA_ADDRESS:
case IFA_BROADCAST:
case IFA_LOCAL:
{
size_t l_addrLen = calcAddrLen(l_info->ifa_family, l_rtaDataSize);
makeSockaddr(l_info->ifa_family, (struct sockaddr *)l_addr, l_rtaData, l_rtaDataSize);
if(l_info->ifa_family == AF_INET6)
{
if(IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)l_rtaData) || IN6_IS_ADDR_MC_LINKLOCAL((struct in6_addr *)l_rtaData))
{
((struct sockaddr_in6 *)l_addr)->sin6_scope_id = l_info->ifa_index;
}
}
if(l_rta->rta_type == IFA_ADDRESS)
{ // apparently in a point-to-point network IFA_ADDRESS contains the dest address and IFA_LOCAL contains the local address
if(l_entry->ifa_addr)
{
l_entry->ifa_dstaddr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
}
else if(l_rta->rta_type == IFA_LOCAL)
{
if(l_entry->ifa_addr)
{
l_entry->ifa_dstaddr = l_entry->ifa_addr;
}
l_entry->ifa_addr = (struct sockaddr *)l_addr;
}
else
{
l_entry->ifa_broadaddr = (struct sockaddr *)l_addr;
}
l_addr += NLMSG_ALIGN(l_addrLen);
break;
}
case IFA_LABEL:
strncpy(l_name, l_rtaData, l_rtaDataSize);
l_name[l_rtaDataSize] = '\0';
l_entry->ifa_name = l_name;
break;
default:
break;
}
}
if(l_entry->ifa_addr && (l_entry->ifa_addr->sa_family == AF_INET || l_entry->ifa_addr->sa_family == AF_INET6))
{
unsigned l_maxPrefix = (l_entry->ifa_addr->sa_family == AF_INET ? 32 : 128);
unsigned l_prefix = (l_info->ifa_prefixlen > l_maxPrefix ? l_maxPrefix : l_info->ifa_prefixlen);
char l_mask[16] = {0};
unsigned i;
for(i=0; i<(l_prefix/8); ++i)
{
l_mask[i] = 0xff;
}
if(l_prefix % 8)
{
l_mask[i] = 0xff << (8 - (l_prefix % 8));
}
makeSockaddr(l_entry->ifa_addr->sa_family, (struct sockaddr *)l_addr, l_mask, l_maxPrefix / 8);
l_entry->ifa_netmask = (struct sockaddr *)l_addr;
}
addToEnd(p_resultList, l_entry);
return 0;
}
static int interpretLinks(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList)
{
int l_numLinks = 0;
pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
break;
}
if(l_hdr->nlmsg_type == RTM_NEWLINK)
{
if(interpretLink(l_hdr, p_resultList) == -1)
{
return -1;
}
++l_numLinks;
}
}
}
return l_numLinks;
}
static int interpretAddrs(int p_socket, NetlinkList *p_netlinkList, struct ifaddrs **p_resultList, int p_numLinks)
{
pid_t l_pid = getpid();
for(; p_netlinkList; p_netlinkList = p_netlinkList->m_next)
{
unsigned int l_nlsize = p_netlinkList->m_size;
struct nlmsghdr *l_hdr;
for(l_hdr = p_netlinkList->m_data; NLMSG_OK(l_hdr, l_nlsize); l_hdr = NLMSG_NEXT(l_hdr, l_nlsize))
{
if((pid_t)l_hdr->nlmsg_pid != l_pid || (int)l_hdr->nlmsg_seq != p_socket)
{
continue;
}
if(l_hdr->nlmsg_type == NLMSG_DONE)
{
break;
}
if(l_hdr->nlmsg_type == RTM_NEWADDR)
{
if (interpretAddr(l_hdr, p_resultList, p_numLinks) == -1)
{
return -1;
}
}
}
}
return 0;
}
int getifaddrs(struct ifaddrs **ifap)
{
if(!ifap)
{
return -1;
}
*ifap = NULL;
int l_socket = netlink_socket();
if(l_socket < 0)
{
return -1;
}
NetlinkList *l_linkResults = getResultList(l_socket, RTM_GETLINK);
if(!l_linkResults)
{
close(l_socket);
return -1;
}
NetlinkList *l_addrResults = getResultList(l_socket, RTM_GETADDR);
if(!l_addrResults)
{
close(l_socket);
freeResultList(l_linkResults);
return -1;
}
int l_result = 0;
int l_numLinks = interpretLinks(l_socket, l_linkResults, ifap);
if(l_numLinks == -1 || interpretAddrs(l_socket, l_addrResults, ifap, l_numLinks) == -1)
{
l_result = -1;
}
freeResultList(l_linkResults);
freeResultList(l_addrResults);
close(l_socket);
return l_result;
}
void freeifaddrs(struct ifaddrs *ifa)
{
struct ifaddrs *l_cur;
while(ifa)
{
l_cur = ifa;
ifa = ifa->ifa_next;
free(l_cur);
}
}

View File

@ -1,56 +0,0 @@
/*
* Copyright (c) 1995, 1999
* Berkeley Software Design, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* BSDI ifaddrs.h,v 2.5 2000/02/23 14:51:59 dab Exp
*/
#ifndef _IFADDRS_H_
#define _IFADDRS_H_
struct ifaddrs {
struct ifaddrs *ifa_next;
char *ifa_name;
unsigned int ifa_flags;
struct sockaddr *ifa_addr;
struct sockaddr *ifa_netmask;
struct sockaddr *ifa_dstaddr;
void *ifa_data;
};
/*
* This may have been defined in <net/if.h>. Note that if <net/if.h> is
* to be included it must be included before this header file.
*/
#ifndef ifa_broadaddr
#define ifa_broadaddr ifa_dstaddr /* broadcast address interface */
#endif
#ifdef _cplusplus
extern "C" {
#endif
extern int getifaddrs(struct ifaddrs **ifap);
extern void freeifaddrs(struct ifaddrs *ifa);
#ifdef _cplusplus
}
#endif
#endif

View File

@ -63,7 +63,7 @@ Index of this file:
#include <assert.h>
#define IM_ASSERT(_EXPR) assert(_EXPR) // You can override the default assert handler by editing imconfig.h
#endif
#if defined(__clang__) || defined(__GNUC__)
#if (defined(__clang__) || defined(__GNUC__)) && !defined(_ANDROID)
#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to user functions.
#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0)))
#else

View File

@ -1,526 +0,0 @@
Libwebsockets and included programs are provided under the terms of the GNU
Library General Public License (LGPL) 2.1, with the following exceptions:
1) Static linking of programs with the libwebsockets library does not
constitute a derivative work and does not require the author to provide
source code for the program, use the shared libwebsockets libraries, or
link their program against a user-supplied version of libwebsockets.
If you link the program to a modified version of libwebsockets, then the
changes to libwebsockets must be provided under the terms of the LGPL in
sections 1, 2, and 4.
2) You do not have to provide a copy of the libwebsockets license with
programs that are linked to the libwebsockets library, nor do you have to
identify the libwebsockets license in your program or documentation as
required by section 6 of the LGPL.
However, programs must still identify their use of libwebsockets. The
following example statement can be included in user documentation to
satisfy this requirement:
"[program] is based in part on the work of the libwebsockets project
(http://libwebsockets.org)"
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@ -1,20 +0,0 @@
This is the libwebsockets C library for lightweight websocket clients and
servers. For support, visit
http://libwebsockets.org
and consider joining the project mailing list at
http://ml.libwebsockets.org/mailman/listinfo/libwebsockets
You can get the latest version of the library from git
http://git.libwebsockets.org
https://github.com/warmcat/libwebsockets
for more information:
README.build - information on building the library
README.coding - information for writing code using the library
README.test-apps - information about the test apps built with the library

View File

@ -1,93 +0,0 @@
/*
* This code originally came from here
*
* http://base64.sourceforge.net/b64.c
*
* with the following license:
*
* LICENCE: Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the
* Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall
* be included in all copies or substantial portions of the
* Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
* KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
* WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
* OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* VERSION HISTORY:
* Bob Trower 08/04/01 -- Create Version 0.00.00B
*
* I cleaned it up quite a bit to match the (linux kernel) style of the rest
* of libwebsockets; this version is under LGPL2 like the rest of libwebsockets
* since he explictly allows sublicensing, but I give the URL above so you can
* get the original with Bob's super-liberal terms directly if you prefer.
*/
#include <stdio.h>
#include <string.h>
#include "private-libwebsockets.h"
static const char encode[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz0123456789+/";
static const char decode[] = "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW"
"$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
LWS_VISIBLE int
lws_b64_encode_string(const char *in, int in_len, char *out, int out_size)
{
unsigned char triple[3];
int i;
int len;
int line = 0;
int done = 0;
while (in_len) {
len = 0;
for (i = 0; i < 3; i++) {
if (in_len) {
triple[i] = *in++;
len++;
in_len--;
} else
triple[i] = 0;
}
if (!len)
continue;
if (done + 4 >= out_size)
return -1;
*out++ = encode[triple[0] >> 2];
*out++ = encode[((triple[0] & 0x03) << 4) |
((triple[1] & 0xf0) >> 4)];
*out++ = (len > 1 ? encode[((triple[1] & 0x0f) << 2) |
((triple[2] & 0xc0) >> 6)] : '=');
*out++ = (len > 2 ? encode[triple[2] & 0x3f] : '=');
done += 4;
line += 4;
}
if (done + 1 >= out_size)
return -1;
*out++ = '\0';
return done;
}

View File

@ -1,441 +0,0 @@
#include "private-libwebsockets.h"
struct libwebsocket *libwebsocket_client_connect_2(
struct libwebsocket_context *context,
struct libwebsocket *wsi
) {
struct libwebsocket_pollfd pfd;
#ifdef LWS_USE_IPV6
struct sockaddr_in6 server_addr6;
struct sockaddr_in6 client_addr6;
struct addrinfo hints, *result;
#endif
struct sockaddr_in server_addr4;
struct sockaddr_in client_addr4;
struct hostent *server_hostent;
struct sockaddr *v;
int n;
int plen = 0;
const char *ads;
lwsl_client("libwebsocket_client_connect_2\n");
/*
* proxy?
*/
if (context->http_proxy_port) {
plen = sprintf((char *)context->service_buffer,
"CONNECT %s:%u HTTP/1.0\x0d\x0a"
"User-agent: libwebsockets\x0d\x0a"
/*Proxy-authorization: basic aGVsbG86d29ybGQ= */
"\x0d\x0a",
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
wsi->u.hdr.ah->c_port);
ads = context->http_proxy_address;
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context))
server_addr6.sin6_port = htons(context->http_proxy_port);
else
#endif
server_addr4.sin_port = htons(context->http_proxy_port);
} else {
ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context))
server_addr6.sin6_port = htons(wsi->u.hdr.ah->c_port);
else
#endif
server_addr4.sin_port = htons(wsi->u.hdr.ah->c_port);
}
/*
* prepare the actual connection (to the proxy, if any)
*/
lwsl_client("libwebsocket_client_connect_2: address %s\n", ads);
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context)) {
memset(&hints, 0, sizeof(struct addrinfo));
n = getaddrinfo(ads, NULL, &hints, &result);
if (n) {
#ifdef _WIN32
lwsl_err("getaddrinfo: %ls\n", gai_strerrorW(n));
#else
lwsl_err("getaddrinfo: %s\n", gai_strerror(n));
#endif
goto oom4;
}
server_addr6.sin6_family = AF_INET6;
switch (result->ai_family) {
case AF_INET:
/* map IPv4 to IPv6 */
bzero((char *)&server_addr6.sin6_addr,
sizeof(struct in6_addr));
server_addr6.sin6_addr.s6_addr[10] = 0xff;
server_addr6.sin6_addr.s6_addr[11] = 0xff;
memcpy(&server_addr6.sin6_addr.s6_addr[12],
&((struct sockaddr_in *)result->ai_addr)->sin_addr,
sizeof(struct in_addr));
break;
case AF_INET6:
memcpy(&server_addr6.sin6_addr,
&((struct sockaddr_in6 *)result->ai_addr)->sin6_addr,
sizeof(struct in6_addr));
break;
default:
lwsl_err("Unknown address family\n");
freeaddrinfo(result);
goto oom4;
}
freeaddrinfo(result);
} else
#endif
{
server_hostent = gethostbyname(ads);
if (!server_hostent) {
lwsl_err("Unable to get host name from %s\n", ads);
goto oom4;
}
server_addr4.sin_family = AF_INET;
server_addr4.sin_addr =
*((struct in_addr *)server_hostent->h_addr);
bzero(&server_addr4.sin_zero, 8);
}
if (wsi->sock < 0) {
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context))
wsi->sock = socket(AF_INET6, SOCK_STREAM, 0);
else
#endif
wsi->sock = socket(AF_INET, SOCK_STREAM, 0);
if (wsi->sock < 0) {
lwsl_warn("Unable to open socket\n");
goto oom4;
}
if (lws_plat_set_socket_options(context, wsi->sock)) {
lwsl_err("Failed to set wsi socket options\n");
compatible_close(wsi->sock);
goto oom4;
}
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT;
insert_wsi_socket_into_fds(context, wsi);
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_AWAITING_CONNECT_RESPONSE,
AWAITING_TIMEOUT);
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context)) {
v = (struct sockaddr *)&client_addr6;
n = sizeof(client_addr6);
bzero((char *)v, n);
client_addr6.sin6_family = AF_INET6;
} else
#endif
{
v = (struct sockaddr *)&client_addr4;
n = sizeof(client_addr4);
bzero((char *)v, n);
client_addr4.sin_family = AF_INET;
}
if (context->iface) {
if (interface_to_sa(context, context->iface,
(struct sockaddr_in *)v, n) < 0) {
lwsl_err("Unable to find interface %s\n",
context->iface);
compatible_close(wsi->sock);
goto failed;
}
if (bind(wsi->sock, v, n) < 0) {
lwsl_err("Error binding to interface %s",
context->iface);
compatible_close(wsi->sock);
goto failed;
}
}
}
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context)) {
v = (struct sockaddr *)&server_addr6;
n = sizeof(struct sockaddr_in6);
} else
#endif
{
v = (struct sockaddr *)&server_addr4;
n = sizeof(struct sockaddr);
}
if (connect(wsi->sock, v, n) == -1 || LWS_ERRNO == LWS_EISCONN) {
if (LWS_ERRNO == LWS_EALREADY || LWS_ERRNO == LWS_EINPROGRESS
|| LWS_ERRNO == LWS_EWOULDBLOCK) {
lwsl_client("nonblocking connect retry\n");
/*
* must do specifically a POLLOUT poll to hear
* about the connect completion
*/
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
goto oom4;
return wsi;
}
if (LWS_ERRNO != LWS_EISCONN) {
lwsl_debug("Connect failed errno=%d\n", LWS_ERRNO);
goto failed;
}
}
lwsl_client("connected\n");
/* we are connected to server, or proxy */
if (context->http_proxy_port) {
/* OK from now on we talk via the proxy, so connect to that */
/*
* (will overwrite existing pointer,
* leaving old string/frag there but unreferenced)
*/
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS,
context->http_proxy_address))
goto failed;
wsi->u.hdr.ah->c_port = context->http_proxy_port;
n = send(wsi->sock, context->service_buffer, plen, MSG_NOSIGNAL);
if (n < 0) {
lwsl_debug("ERROR writing to proxy socket\n");
goto failed;
}
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_AWAITING_PROXY_RESPONSE,
AWAITING_TIMEOUT);
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY;
return wsi;
}
/*
* provoke service to issue the handshake directly
* we need to do it this way because in the proxy case, this is the
* next state and executed only if and when we get a good proxy
* response inside the state machine... but notice in SSL case this
* may not have sent anything yet with 0 return, and won't until some
* many retries from main loop. To stop that becoming endless,
* cover with a timeout.
*/
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE, AWAITING_TIMEOUT);
wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE;
pfd.fd = wsi->sock;
pfd.revents = LWS_POLLIN;
n = libwebsocket_service_fd(context, &pfd);
if (n < 0)
goto failed;
if (n) /* returns 1 on failure after closing wsi */
return NULL;
return wsi;
oom4:
free(wsi->u.hdr.ah);
free(wsi);
return NULL;
failed:
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return NULL;
}
/**
* libwebsocket_client_connect() - Connect to another websocket server
* @context: Websocket context
* @address: Remote server address, eg, "myserver.com"
* @port: Port to connect to on the remote server, eg, 80
* @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
* signed certs
* @path: Websocket path on server
* @host: Hostname on server
* @origin: Socket origin name
* @protocol: Comma-separated list of protocols being asked for from
* the server, or just one. The server will pick the one it
* likes best.
* @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
* protocol supported, or the specific protocol ordinal
*
* This function creates a connection to a remote server
*/
LWS_VISIBLE struct libwebsocket *
libwebsocket_client_connect(struct libwebsocket_context *context,
const char *address,
int port,
int ssl_connection,
const char *path,
const char *host,
const char *origin,
const char *protocol,
int ietf_version_or_minus_one)
{
struct libwebsocket *wsi;
wsi = (struct libwebsocket *) malloc(sizeof(struct libwebsocket));
if (wsi == NULL)
goto bail;
memset(wsi, 0, sizeof(*wsi));
wsi->sock = -1;
/* -1 means just use latest supported */
if (ietf_version_or_minus_one == -1)
ietf_version_or_minus_one = SPEC_LATEST_SUPPORTED;
wsi->ietf_spec_revision = ietf_version_or_minus_one;
wsi->user_space = NULL;
wsi->state = WSI_STATE_CLIENT_UNCONNECTED;
wsi->protocol = NULL;
wsi->pending_timeout = NO_PENDING_TIMEOUT;
#ifdef LWS_OPENSSL_SUPPORT
wsi->use_ssl = ssl_connection;
#else
if (ssl_connection) {
lwsl_err("libwebsockets not configured for ssl\n");
goto bail;
}
#endif
if (lws_allocate_header_table(wsi))
goto bail;
/*
* we're not necessarily in a position to action these right away,
* stash them... we only need during connect phase so u.hdr is fine
*/
wsi->u.hdr.ah->c_port = port;
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
goto bail1;
/* these only need u.hdr lifetime as well */
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
goto bail1;
if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
goto bail1;
if (origin)
if (lws_hdr_simple_create(wsi,
_WSI_TOKEN_CLIENT_ORIGIN, origin))
goto bail1;
/*
* this is a list of protocols we tell the server we're okay with
* stash it for later when we compare server response with it
*/
if (protocol)
if (lws_hdr_simple_create(wsi,
_WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol))
goto bail1;
wsi->protocol = &context->protocols[0];
/*
* Check with each extension if it is able to route and proxy this
* connection for us. For example, an extension like x-google-mux
* can handle this and then we don't need an actual socket for this
* connection.
*/
if (lws_ext_callback_for_each_extension_type(context, wsi,
LWS_EXT_CALLBACK_CAN_PROXY_CLIENT_CONNECTION,
(void *)address, port) > 0) {
lwsl_client("libwebsocket_client_connect: ext handling conn\n");
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_AWAITING_EXTENSION_CONNECT_RESPONSE,
AWAITING_TIMEOUT);
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT;
return wsi;
}
lwsl_client("libwebsocket_client_connect: direct conn\n");
return libwebsocket_client_connect_2(context, wsi);
bail1:
free(wsi->u.hdr.ah);
bail:
free(wsi);
return NULL;
}
/**
* libwebsocket_client_connect_extended() - Connect to another websocket server
* @context: Websocket context
* @address: Remote server address, eg, "myserver.com"
* @port: Port to connect to on the remote server, eg, 80
* @ssl_connection: 0 = ws://, 1 = wss:// encrypted, 2 = wss:// allow self
* signed certs
* @path: Websocket path on server
* @host: Hostname on server
* @origin: Socket origin name
* @protocol: Comma-separated list of protocols being asked for from
* the server, or just one. The server will pick the one it
* likes best.
* @ietf_version_or_minus_one: -1 to ask to connect using the default, latest
* protocol supported, or the specific protocol ordinal
* @userdata: Pre-allocated user data
*
* This function creates a connection to a remote server
*/
LWS_VISIBLE struct libwebsocket *
libwebsocket_client_connect_extended(struct libwebsocket_context *context,
const char *address,
int port,
int ssl_connection,
const char *path,
const char *host,
const char *origin,
const char *protocol,
int ietf_version_or_minus_one,
void *userdata)
{
struct libwebsocket *ws =
libwebsocket_client_connect(context, address, port,
ssl_connection, path, host, origin, protocol,
ietf_version_or_minus_one);
if (ws && !ws->user_space && userdata)
ws->user_space = userdata ;
return ws ;
}

View File

@ -1,402 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
int libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c)
{
int callback_action = LWS_CALLBACK_CLIENT_RECEIVE;
int handled;
struct lws_tokens eff_buf;
int m;
switch (wsi->lws_rx_parse_state) {
case LWS_RXPS_NEW:
switch (wsi->ietf_spec_revision) {
case 13:
wsi->u.ws.opcode = c & 0xf;
wsi->u.ws.rsv = (c & 0x70);
wsi->u.ws.final = !!((c >> 7) & 1);
switch (wsi->u.ws.opcode) {
case LWS_WS_OPCODE_07__TEXT_FRAME:
case LWS_WS_OPCODE_07__BINARY_FRAME:
wsi->u.ws.frame_is_binary = wsi->u.ws.opcode ==
LWS_WS_OPCODE_07__BINARY_FRAME;
break;
}
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
break;
default:
lwsl_err("unknown spec version %02d\n",
wsi->ietf_spec_revision);
break;
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN:
wsi->u.ws.this_frame_masked = !!(c & 0x80);
switch (c & 0x7f) {
case 126:
/* control frames are not allowed to have big lengths */
if (wsi->u.ws.opcode & 8)
goto illegal_ctl_length;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
break;
case 127:
/* control frames are not allowed to have big lengths */
if (wsi->u.ws.opcode & 8)
goto illegal_ctl_length;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
break;
default:
wsi->u.ws.rx_packet_length = c;
if (wsi->u.ws.this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (c)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_2:
wsi->u.ws.rx_packet_length = c << 8;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_1:
wsi->u.ws.rx_packet_length |= c;
if (wsi->u.ws.this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (wsi->u.ws.rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_8:
if (c & 0x80) {
lwsl_warn("b63 of length must be zero\n");
/* kill the connection */
return -1;
}
#if defined __LP64__
wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
#else
wsi->u.ws.rx_packet_length = 0;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_7:
#if defined __LP64__
wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_6:
#if defined __LP64__
wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_5:
#if defined __LP64__
wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_4:
wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_3:
wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_2:
wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_1:
wsi->u.ws.rx_packet_length |= (size_t)c;
if (wsi->u.ws.this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else {
if (wsi->u.ws.rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
}
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
wsi->u.ws.frame_masking_nonce_04[0] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
wsi->u.ws.frame_masking_nonce_04[1] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
wsi->u.ws.frame_masking_nonce_04[2] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
wsi->u.ws.frame_masking_nonce_04[3] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
if (wsi->u.ws.rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
break;
case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
if (!wsi->u.ws.rx_user_buffer)
lwsl_err("NULL client rx_user_buffer\n");
if ((!wsi->u.ws.this_frame_masked) || wsi->u.ws.all_zero_nonce)
wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->u.ws.rx_user_buffer_head++)] = c;
else
wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->u.ws.rx_user_buffer_head++)] =
c ^ wsi->u.ws.frame_masking_nonce_04[
(wsi->u.ws.frame_mask_index++) & 3];
if (--wsi->u.ws.rx_packet_length == 0) {
/* spill because we have the whole frame */
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
/*
* if there's no protocol max frame size given, we are
* supposed to default to LWS_MAX_SOCKET_IO_BUF
*/
if (!wsi->protocol->rx_buffer_size &&
wsi->u.ws.rx_user_buffer_head !=
LWS_MAX_SOCKET_IO_BUF)
break;
else
if (wsi->protocol->rx_buffer_size &&
wsi->u.ws.rx_user_buffer_head !=
wsi->protocol->rx_buffer_size)
break;
/* spill because we filled our rx buffer */
spill:
handled = 0;
/*
* is this frame a control packet we should take care of at this
* layer? If so service it and hide it from the user callback
*/
switch (wsi->u.ws.opcode) {
case LWS_WS_OPCODE_07__CLOSE:
/* is this an acknowledgement of our close? */
if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
/*
* fine he has told us he is closing too, let's
* finish our close
*/
lwsl_parser("seen server's close ack\n");
return -1;
}
lwsl_parser("client sees server close len = %d\n",
wsi->u.ws.rx_user_buffer_head);
/*
* parrot the close packet payload back
* we do not care about how it went, we are closing
* immediately afterwards
*/
libwebsocket_write(wsi, (unsigned char *)
&wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING],
wsi->u.ws.rx_user_buffer_head, LWS_WRITE_CLOSE);
wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
/* close the connection */
return -1;
case LWS_WS_OPCODE_07__PING:
lwsl_info("client received ping, doing pong\n");
/*
* parrot the ping packet payload back as a pong
* !!! this may block or have partial write or fail
* !!! very unlikely if the ping size is small
*/
libwebsocket_write(wsi, (unsigned char *)
&wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING],
wsi->u.ws.rx_user_buffer_head,
LWS_WRITE_PONG);
handled = 1;
break;
case LWS_WS_OPCODE_07__PONG:
lwsl_info("client receied pong\n");
lwsl_hexdump(&wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING],
wsi->u.ws.rx_user_buffer_head);
/* issue it */
callback_action = LWS_CALLBACK_CLIENT_RECEIVE_PONG;
break;
case LWS_WS_OPCODE_07__CONTINUATION:
case LWS_WS_OPCODE_07__TEXT_FRAME:
case LWS_WS_OPCODE_07__BINARY_FRAME:
break;
default:
lwsl_parser("Reserved opc 0x%2X\n", wsi->u.ws.opcode);
/*
* It's something special we can't understand here.
* Pass the payload up to the extension's parsing
* state machine.
*/
eff_buf.token = &wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING];
eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
if (lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
&eff_buf, 0) <= 0) { /* not handle or fail */
lwsl_ext("Unhandled ext opc 0x%x\n",
wsi->u.ws.opcode);
wsi->u.ws.rx_user_buffer_head = 0;
return 0;
}
handled = 1;
break;
}
/*
* No it's real payload, pass it up to the user callback.
* It's nicely buffered with the pre-padding taken care of
* so it can be sent straight out again using libwebsocket_write
*/
if (handled)
goto already_done;
eff_buf.token = &wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING];
eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
if (lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_PAYLOAD_RX,
&eff_buf, 0) < 0) /* fail */
return -1;
if (eff_buf.token_len <= 0 &&
callback_action != LWS_CALLBACK_CLIENT_RECEIVE_PONG)
goto already_done;
eff_buf.token[eff_buf.token_len] = '\0';
if (!wsi->protocol->callback)
goto already_done;
if (callback_action == LWS_CALLBACK_CLIENT_RECEIVE_PONG)
lwsl_info("Client doing pong callback\n");
m = wsi->protocol->callback(
wsi->protocol->owning_server,
wsi,
(enum libwebsocket_callback_reasons)callback_action,
wsi->user_space,
eff_buf.token,
eff_buf.token_len);
/* if user code wants to close, let caller know */
if (m)
return 1;
already_done:
wsi->u.ws.rx_user_buffer_head = 0;
break;
default:
lwsl_err("client rx illegal state\n");
return 1;
}
return 0;
illegal_ctl_length:
lwsl_warn("Control frame asking for extended length is illegal\n");
/* kill the connection */
return -1;
}

View File

@ -1,953 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
int lws_handshake_client(struct libwebsocket *wsi, unsigned char **buf, size_t len)
{
int n;
switch (wsi->mode) {
case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
case LWS_CONNMODE_WS_CLIENT:
for (n = 0; n < len; n++)
if (libwebsocket_client_rx_sm(wsi, *(*buf)++)) {
lwsl_debug("client_rx_sm failed\n");
return 1;
}
return 0;
default:
break;
}
return 0;
}
int lws_client_socket_service(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
{
int n;
char *p = (char *)&context->service_buffer[0];
int len;
unsigned char c;
switch (wsi->mode) {
case LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT:
/*
* we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
* timeout protection set in client-handshake.c
*/
if (libwebsocket_client_connect_2(context, wsi) == NULL) {
/* closed */
lwsl_client("closed\n");
return -1;
}
/* either still pending connection, or changed mode */
return 0;
case LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY:
/* handle proxy hung up on us */
if (pollfd->revents & LWS_POLLHUP) {
lwsl_warn("Proxy connection %p (fd=%d) dead\n",
(void *)wsi, pollfd->fd);
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return 0;
}
n = recv(wsi->sock, context->service_buffer,
sizeof(context->service_buffer), 0);
if (n < 0) {
if (LWS_ERRNO == LWS_EAGAIN) {
lwsl_debug(
"Proxy read returned EAGAIN... retrying\n");
return 0;
}
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
lwsl_err("ERROR reading from proxy socket\n");
return 0;
}
context->service_buffer[13] = '\0';
if (strcmp((char *)context->service_buffer, "HTTP/1.0 200 ")) {
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
lwsl_err("ERROR proxy: %s\n", context->service_buffer);
return 0;
}
/* clear his proxy connection timeout */
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
/* fallthru */
case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE:
/*
* we are under PENDING_TIMEOUT_SENT_CLIENT_HANDSHAKE
* timeout protection set in client-handshake.c
*/
/*
* take care of our libwebsocket_callback_on_writable
* happening at a time when there's no real connection yet
*/
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
return -1;
#ifdef LWS_OPENSSL_SUPPORT
/* we can retry this... just cook the SSL BIO the first time */
if (wsi->use_ssl && !wsi->ssl) {
const char *hostname = lws_hdr_simple_ptr(wsi,
_WSI_TOKEN_CLIENT_PEER_ADDRESS);
wsi->ssl = SSL_new(context->ssl_client_ctx);
#ifndef USE_CYASSL
SSL_set_mode(wsi->ssl,
SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
#endif
/*
* use server name indication (SNI), if supported,
* when establishing connection
*/
#ifdef USE_CYASSL
#ifdef CYASSL_SNI_HOST_NAME
CyaSSL_UseSNI(wsi->ssl, CYASSL_SNI_HOST_NAME,
hostname, strlen(hostname));
#endif
#else
SSL_set_tlsext_host_name(wsi->ssl, hostname);
#endif
#ifdef USE_CYASSL
/*
* CyaSSL does certificate verification differently
* from OpenSSL.
* If we should ignore the certificate, we need to set
* this before SSL_new and SSL_connect is called.
* Otherwise the connect will simply fail with error
* code -155
*/
if (wsi->use_ssl == 2)
CyaSSL_set_verify(wsi->ssl,
SSL_VERIFY_NONE, NULL);
#endif /* USE_CYASSL */
wsi->client_bio =
BIO_new_socket(wsi->sock, BIO_NOCLOSE);
SSL_set_bio(wsi->ssl, wsi->client_bio, wsi->client_bio);
#ifdef USE_CYASSL
CyaSSL_set_using_nonblock(wsi->ssl, 1);
#else
BIO_set_nbio(wsi->client_bio, 1); /* nonblocking */
#endif
SSL_set_ex_data(wsi->ssl,
openssl_websocket_private_data_index,
context);
}
if (wsi->use_ssl) {
lws_latency_pre(context, wsi);
n = SSL_connect(wsi->ssl);
lws_latency(context, wsi,
"SSL_connect LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE",
n, n > 0);
if (n < 0) {
n = SSL_get_error(wsi->ssl, n);
if (n == SSL_ERROR_WANT_READ ||
n == SSL_ERROR_WANT_WRITE) {
/*
* wants us to retry connect due to
* state of the underlying ssl layer...
* but since it may be stalled on
* blocked write, no incoming data may
* arrive to trigger the retry.
* Force (possibly many times if the SSL
* state persists in returning the
* condition code, but other sockets
* are getting serviced inbetweentimes)
* us to get called back when writable.
*/
lwsl_info(
"SSL_connect WANT_... retrying\n");
libwebsocket_callback_on_writable(
context, wsi);
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SSL;
return 0; /* no error */
}
n = -1;
}
if (n <= 0) {
/*
* retry if new data comes until we
* run into the connection timeout or win
*/
n = ERR_get_error();
if (n != SSL_ERROR_NONE) {
lwsl_err("SSL connect error %lu: %s\n",
n,
ERR_error_string(n,
(char *)context->service_buffer));
return 0;
}
}
} else
wsi->ssl = NULL;
/* fallthru */
case LWS_CONNMODE_WS_CLIENT_WAITING_SSL:
if (wsi->use_ssl) {
if (wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_SSL) {
lws_latency_pre(context, wsi);
n = SSL_connect(wsi->ssl);
lws_latency(context, wsi,
"SSL_connect LWS_CONNMODE_WS_CLIENT_WAITING_SSL",
n, n > 0);
if (n < 0) {
n = SSL_get_error(wsi->ssl, n);
if (n == SSL_ERROR_WANT_READ ||
n == SSL_ERROR_WANT_WRITE) {
/*
* wants us to retry connect due to
* state of the underlying ssl layer...
* but since it may be stalled on
* blocked write, no incoming data may
* arrive to trigger the retry.
* Force (possibly many times if the SSL
* state persists in returning the
* condition code, but other sockets
* are getting serviced inbetweentimes)
* us to get called back when writable.
*/
lwsl_info(
"SSL_connect WANT_... retrying\n");
libwebsocket_callback_on_writable(
context, wsi);
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SSL;
return 0; /* no error */
}
n = -1;
}
if (n <= 0) {
/*
* retry if new data comes until we
* run into the connection timeout or win
*/
n = ERR_get_error();
if (n != SSL_ERROR_NONE) {
lwsl_err("SSL connect error %lu: %s\n",
n,
ERR_error_string(n,
(char *)context->service_buffer));
return 0;
}
}
}
#ifndef USE_CYASSL
/*
* See comment above about CyaSSL certificate
* verification
*/
lws_latency_pre(context, wsi);
n = SSL_get_verify_result(wsi->ssl);
lws_latency(context, wsi,
"SSL_get_verify_result LWS_CONNMODE..HANDSHAKE",
n, n > 0);
if ((n != X509_V_OK) && (
n != X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT ||
wsi->use_ssl != 2)) {
lwsl_err(
"server's cert didn't look good %d\n", n);
libwebsocket_close_and_free_session(context,
wsi, LWS_CLOSE_STATUS_NOSTATUS);
return 0;
}
#endif /* USE_CYASSL */
} else
wsi->ssl = NULL;
#endif
wsi->mode = LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE2;
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_AWAITING_CLIENT_HS_SEND,
AWAITING_TIMEOUT);
/* fallthru */
case LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE2:
p = libwebsockets_generate_client_handshake(context, wsi, p);
if (p == NULL) {
lwsl_err("Failed to generate handshake for client\n");
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return 0;
}
/* send our request to the server */
lws_latency_pre(context, wsi);
n = lws_ssl_capable_write(wsi, context->service_buffer, p - (char *)context->service_buffer);
lws_latency(context, wsi, "send lws_issue_raw", n, n == p - (char *)context->service_buffer);
switch (n) {
case LWS_SSL_CAPABLE_ERROR:
lwsl_debug("ERROR writing to client socket\n");
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return 0;
case LWS_SSL_CAPABLE_MORE_SERVICE:
libwebsocket_callback_on_writable(context, wsi);
break;
}
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
wsi->u.hdr.lextable_pos = 0;
wsi->mode = LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY;
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_AWAITING_SERVER_RESPONSE,
AWAITING_TIMEOUT);
break;
case LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY:
/* handle server hung up on us */
if (pollfd->revents & LWS_POLLHUP) {
lwsl_debug("Server connection %p (fd=%d) dead\n",
(void *)wsi, pollfd->fd);
goto bail3;
}
if (!(pollfd->revents & LWS_POLLIN))
break;
/* interpret the server response */
/*
* HTTP/1.1 101 Switching Protocols
* Upgrade: websocket
* Connection: Upgrade
* Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
* Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
* Sec-WebSocket-Protocol: chat
*/
/*
* we have to take some care here to only take from the
* socket bytewise. The browser may (and has been seen to
* in the case that onopen() performs websocket traffic)
* coalesce both handshake response and websocket traffic
* in one packet, since at that point the connection is
* definitively ready from browser pov.
*/
len = 1;
while (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE) {
n = lws_ssl_capable_read(wsi, &c, 1);
lws_latency(context, wsi, "send lws_issue_raw", n, n == 1);
switch (n) {
case LWS_SSL_CAPABLE_ERROR:
goto bail3;
case LWS_SSL_CAPABLE_MORE_SERVICE:
return 0;
}
if (libwebsocket_parse(wsi, c)) {
lwsl_warn("problems parsing header\n");
goto bail3;
}
}
/*
* hs may also be coming in multiple packets, there is a 5-sec
* libwebsocket timeout still active here too, so if parsing did
* not complete just wait for next packet coming in this state
*/
if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
break;
/*
* otherwise deal with the handshake. If there's any
* packet traffic already arrived we'll trigger poll() again
* right away and deal with it that way
*/
return lws_client_interpret_server_handshake(context, wsi);
bail3:
lwsl_info(
"closing connection at LWS_CONNMODE...SERVER_REPLY\n");
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return -1;
case LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT:
lwsl_ext("LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT\n");
break;
case LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD:
lwsl_ext("LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD\n");
break;
default:
break;
}
return 0;
}
/*
* In-place str to lower case
*/
static void
strtolower(char *s)
{
while (*s) {
*s = tolower((int)*s);
s++;
}
}
int
lws_client_interpret_server_handshake(struct libwebsocket_context *context,
struct libwebsocket *wsi)
{
const char *pc;
int okay = 0;
char *p;
int len;
#ifndef LWS_NO_EXTENSIONS
char ext_name[128];
struct libwebsocket_extension *ext;
void *v;
int more = 1;
const char *c;
#endif
int n;
int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
/*
* well, what the server sent looked reasonable for syntax.
* Now let's confirm it sent all the necessary headers
*/
if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) {
lwsl_info("no ACCEPT\n");
goto bail3;
}
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP);
if (!p) {
lwsl_info("no URI\n");
goto bail3;
}
if (p && strncmp(p, "101", 3)) {
lwsl_warn(
"lws_client_handshake: got bad HTTP response '%s'\n", p);
goto bail3;
}
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_UPGRADE);
if (!p) {
lwsl_info("no UPGRADE\n");
goto bail3;
}
strtolower(p);
if (strcmp(p, "websocket")) {
lwsl_warn(
"lws_client_handshake: got bad Upgrade header '%s'\n", p);
goto bail3;
}
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_CONNECTION);
if (!p) {
lwsl_info("no Connection hdr\n");
goto bail3;
}
strtolower(p);
if (strcmp(p, "upgrade")) {
lwsl_warn("lws_client_int_s_hs: bad header %s\n", p);
goto bail3;
}
pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
if (pc == NULL)
lwsl_parser("lws_client_int_s_hs: no protocol list\n");
else
lwsl_parser("lws_client_int_s_hs: protocol list '%s'\n", pc);
/*
* confirm the protocol the server wants to talk was in the list
* of protocols we offered
*/
len = lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL);
if (!len) {
lwsl_info("lws_client_int_s_hs: WSI_TOKEN_PROTOCOL is null\n");
/*
* no protocol name to work from,
* default to first protocol
*/
wsi->protocol = &context->protocols[0];
goto check_extensions;
}
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL);
len = strlen(p);
while (*pc && !okay) {
if (!strncmp(pc, p, len) &&
(pc[len] == ',' || pc[len] == '\0')) {
okay = 1;
continue;
}
while (*pc && *pc != ',')
pc++;
while (*pc && *pc != ' ')
pc++;
}
if (!okay) {
lwsl_err("lws_client_int_s_hs: got bad protocol %s\n", p);
goto bail2;
}
/*
* identify the selected protocol struct and set it
*/
n = 0;
wsi->protocol = NULL;
while (context->protocols[n].callback && !wsi->protocol) {
if (strcmp(p, context->protocols[n].name) == 0) {
wsi->protocol = &context->protocols[n];
break;
}
n++;
}
if (wsi->protocol == NULL) {
lwsl_err("lws_client_int_s_hs: fail protocol %s\n", p);
goto bail2;
}
check_extensions:
#ifndef LWS_NO_EXTENSIONS
/* instantiate the accepted extensions */
if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS)) {
lwsl_ext("no client extenstions allowed by server\n");
goto check_accept;
}
/*
* break down the list of server accepted extensions
* and go through matching them or identifying bogons
*/
if (lws_hdr_copy(wsi, (char *)context->service_buffer,
sizeof(context->service_buffer), WSI_TOKEN_EXTENSIONS) < 0) {
lwsl_warn("ext list from server failed to copy\n");
goto bail2;
}
c = (char *)context->service_buffer;
n = 0;
while (more) {
if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
ext_name[n] = *c++;
if (n < sizeof(ext_name) - 1)
n++;
continue;
}
ext_name[n] = '\0';
if (!*c)
more = 0;
else {
c++;
if (!n)
continue;
}
/* check we actually support it */
lwsl_ext("checking client ext %s\n", ext_name);
n = 0;
ext = wsi->protocol->owning_server->extensions;
while (ext && ext->callback) {
if (strcmp(ext_name, ext->name)) {
ext++;
continue;
}
n = 1;
lwsl_ext("instantiating client ext %s\n", ext_name);
/* instantiate the extension on this conn */
wsi->active_extensions_user[
wsi->count_active_extensions] =
malloc(ext->per_session_data_size);
if (wsi->active_extensions_user[
wsi->count_active_extensions] == NULL) {
lwsl_err("Out of mem\n");
goto bail2;
}
memset(wsi->active_extensions_user[
wsi->count_active_extensions], 0,
ext->per_session_data_size);
wsi->active_extensions[
wsi->count_active_extensions] = ext;
/* allow him to construct his context */
ext->callback(wsi->protocol->owning_server,
ext, wsi,
LWS_EXT_CALLBACK_CLIENT_CONSTRUCT,
wsi->active_extensions_user[
wsi->count_active_extensions],
NULL, 0);
wsi->count_active_extensions++;
ext++;
}
if (n == 0) {
lwsl_warn("Unknown ext '%s'!\n", ext_name);
goto bail2;
}
n = 0;
}
check_accept:
#endif
/*
* Confirm his accept token is the one we precomputed
*/
p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_ACCEPT);
if (strcmp(p, wsi->u.hdr.ah->initial_handshake_hash_base64)) {
lwsl_warn("lws_client_int_s_hs: accept %s wrong vs %s\n", p,
wsi->u.hdr.ah->initial_handshake_hash_base64);
goto bail2;
}
/* allocate the per-connection user memory (if any) */
if (libwebsocket_ensure_user_space(wsi)) {
lwsl_err("Problem allocating wsi user mem\n");
goto bail2;
}
/*
* we seem to be good to go, give client last chance to check
* headers and OK it
*/
wsi->protocol->callback(context, wsi,
LWS_CALLBACK_CLIENT_FILTER_PRE_ESTABLISH,
wsi->user_space, NULL, 0);
/* clear his proxy connection timeout */
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
/* free up his parsing allocations */
if (wsi->u.hdr.ah)
free(wsi->u.hdr.ah);
/* mark him as being alive */
wsi->state = WSI_STATE_ESTABLISHED;
wsi->mode = LWS_CONNMODE_WS_CLIENT;
/* union transition */
memset(&wsi->u, 0, sizeof(wsi->u));
wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW;
/*
* create the frame buffer for this connection according to the
* size mentioned in the protocol definition. If 0 there, then
* use a big default for compatibility
*/
n = wsi->protocol->rx_buffer_size;
if (!n)
n = LWS_MAX_SOCKET_IO_BUF;
n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
wsi->u.ws.rx_user_buffer = malloc(n);
if (!wsi->u.ws.rx_user_buffer) {
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
goto bail2;
}
lwsl_info("Allocating client RX buffer %d\n", n);
if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) {
lwsl_warn("Failed to set SNDBUF to %d", n);
goto bail3;
}
lwsl_debug("handshake OK for protocol %s\n", wsi->protocol->name);
/* call him back to inform him he is up */
wsi->protocol->callback(context, wsi,
LWS_CALLBACK_CLIENT_ESTABLISHED,
wsi->user_space, NULL, 0);
#ifndef LWS_NO_EXTENSIONS
/*
* inform all extensions, not just active ones since they
* already know
*/
ext = context->extensions;
while (ext && ext->callback) {
v = NULL;
for (n = 0; n < wsi->count_active_extensions; n++)
if (wsi->active_extensions[n] == ext)
v = wsi->active_extensions_user[n];
ext->callback(context, ext, wsi,
LWS_EXT_CALLBACK_ANY_WSI_ESTABLISHED, v, NULL, 0);
ext++;
}
#endif
return 0;
bail3:
free(wsi->u.ws.rx_user_buffer);
wsi->u.ws.rx_user_buffer = NULL;
close_reason = LWS_CLOSE_STATUS_NOSTATUS;
bail2:
if (wsi->protocol)
wsi->protocol->callback(context, wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
wsi->user_space, NULL, 0);
lwsl_info("closing connection due to bail2 connection error\n");
/* free up his parsing allocations */
if (wsi->u.hdr.ah)
free(wsi->u.hdr.ah);
libwebsocket_close_and_free_session(context, wsi, close_reason);
return 1;
}
char *
libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
struct libwebsocket *wsi, char *pkt)
{
char buf[128];
char hash[20];
char key_b64[40];
char *p = pkt;
int n;
#ifndef LWS_NO_EXTENSIONS
struct libwebsocket_extension *ext;
int ext_count = 0;
#endif
/*
* create the random key
*/
n = libwebsockets_get_random(context, hash, 16);
if (n != 16) {
lwsl_err("Unable to read from random dev %s\n",
SYSTEM_RANDOM_FILEPATH);
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return NULL;
}
lws_b64_encode_string(hash, 16, key_b64, sizeof(key_b64));
/*
* 00 example client handshake
*
* GET /socket.io/websocket HTTP/1.1
* Upgrade: WebSocket
* Connection: Upgrade
* Host: 127.0.0.1:9999
* Origin: http://127.0.0.1
* Sec-WebSocket-Key1: 1 0 2#0W 9 89 7 92 ^
* Sec-WebSocket-Key2: 7 7Y 4328 B2v[8(z1
* Cookie: socketio=websocket
*
* (稀0
*
* 04 example client handshake
*
* GET /chat HTTP/1.1
* Host: server.example.com
* Upgrade: websocket
* Connection: Upgrade
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
* Sec-WebSocket-Origin: http://example.com
* Sec-WebSocket-Protocol: chat, superchat
* Sec-WebSocket-Version: 4
*/
p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a",
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
p += sprintf(p,
"Pragma: no-cache\x0d\x0a""Cache-Control: no-cache\x0d\x0a");
p += sprintf(p, "Host: %s\x0d\x0a",
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
p += sprintf(p,
"Upgrade: websocket\x0d\x0a""Connection: Upgrade\x0d\x0a""Sec-WebSocket-Key: ");
strcpy(p, key_b64);
p += strlen(key_b64);
p += sprintf(p, "\x0d\x0a");
if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN))
p += sprintf(p, "Origin: http://%s\x0d\x0a",
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));
if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));
/* tell the server what extensions we could support */
p += sprintf(p, "Sec-WebSocket-Extensions: ");
#ifndef LWS_NO_EXTENSIONS
ext = context->extensions;
while (ext && ext->callback) {
n = lws_ext_callback_for_each_extension_type(context, wsi,
LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION,
(char *)ext->name, 0);
if (n) { /* an extension vetos us */
lwsl_ext("ext %s vetoed\n", (char *)ext->name);
ext++;
continue;
}
n = context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLIENT_CONFIRM_EXTENSION_SUPPORTED,
wsi->user_space, (char *)ext->name, 0);
/*
* zero return from callback means
* go ahead and allow the extension,
* it's what we get if the callback is
* unhandled
*/
if (n) {
ext++;
continue;
}
/* apply it */
if (ext_count)
*p++ = ',';
p += sprintf(p, "%s", ext->name);
ext_count++;
ext++;
}
#endif
p += sprintf(p, "\x0d\x0a");
if (wsi->ietf_spec_revision)
p += sprintf(p, "Sec-WebSocket-Version: %d\x0d\x0a",
wsi->ietf_spec_revision);
/* give userland a chance to append, eg, cookies */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLIENT_APPEND_HANDSHAKE_HEADER,
NULL, &p, (pkt + sizeof(context->service_buffer)) - p - 12);
p += sprintf(p, "\x0d\x0a");
/* prepare the expected server accept response */
key_b64[39] = '\0'; /* enforce composed length below buf sizeof */
n = sprintf(buf, "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", key_b64);
SHA1((unsigned char *)buf, n, (unsigned char *)hash);
lws_b64_encode_string(hash, 20,
wsi->u.hdr.ah->initial_handshake_hash_base64,
sizeof(wsi->u.hdr.ah->initial_handshake_hash_base64));
return p;
}

View File

@ -1,4 +0,0 @@
#include "build.h"
#define LWS_BUILTIN_GETIFADDRS
#define LWS_NO_DAEMONIZE

View File

@ -1,348 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
#ifndef LWS_BUILD_HASH
#define LWS_BUILD_HASH "unknown-build-hash"
#endif
#ifdef WIN32
#define getdtablesize() 30000
#endif
static const char *library_version = LWS_LIBRARY_VERSION " " LWS_BUILD_HASH;
/**
* lws_get_library_version: get version and git hash library built from
*
* returns a const char * to a string like "1.1 178d78c"
* representing the library version followed by the git head hash it
* was built from
*/
LWS_VISIBLE const char *
lws_get_library_version(void)
{
return library_version;
}
/**
* libwebsocket_create_context() - Create the websocket handler
* @info: pointer to struct with parameters
*
* This function creates the listening socket (if serving) and takes care
* of all initialization in one step.
*
* After initialization, it returns a struct libwebsocket_context * that
* represents this server. After calling, user code needs to take care
* of calling libwebsocket_service() with the context pointer to get the
* server's sockets serviced. This must be done in the same process
* context as the initialization call.
*
* The protocol callback functions are called for a handful of events
* including http requests coming in, websocket connections becoming
* established, and data arriving; it's also called periodically to allow
* async transmission.
*
* HTTP requests are sent always to the FIRST protocol in @protocol, since
* at that time websocket protocol has not been negotiated. Other
* protocols after the first one never see any HTTP callack activity.
*
* The server created is a simple http server by default; part of the
* websocket standard is upgrading this http connection to a websocket one.
*
* This allows the same server to provide files like scripts and favicon /
* images or whatever over http and dynamic data over websockets all in
* one place; they're all handled in the user callback.
*/
LWS_VISIBLE struct libwebsocket_context *
libwebsocket_create_context(struct lws_context_creation_info *info)
{
struct libwebsocket_context *context = NULL;
char *p;
int pid_daemon = get_daemonize_pid();
lwsl_notice("Initial logging level %d\n", log_level);
lwsl_notice("Library version: %s\n", library_version);
#ifdef LWS_USE_IPV6
if (!(info->options & LWS_SERVER_OPTION_DISABLE_IPV6))
lwsl_notice("IPV6 compiled in and enabled\n");
else
lwsl_notice("IPV6 compiled in but disabled\n");
#else
lwsl_notice("IPV6 not compiled in\n");
#endif
lws_feature_status_libev(info);
lwsl_info(" LWS_MAX_HEADER_LEN: %u\n", LWS_MAX_HEADER_LEN);
lwsl_info(" LWS_MAX_PROTOCOLS: %u\n", LWS_MAX_PROTOCOLS);
lwsl_info(" SPEC_LATEST_SUPPORTED: %u\n", SPEC_LATEST_SUPPORTED);
lwsl_info(" AWAITING_TIMEOUT: %u\n", AWAITING_TIMEOUT);
lwsl_info(" SYSTEM_RANDOM_FILEPATH: '%s'\n", SYSTEM_RANDOM_FILEPATH);
lwsl_info(" LWS_MAX_ZLIB_CONN_BUFFER: %u\n", LWS_MAX_ZLIB_CONN_BUFFER);
if (lws_plat_context_early_init())
return NULL;
context = (struct libwebsocket_context *)
malloc(sizeof(struct libwebsocket_context));
if (!context) {
lwsl_err("No memory for websocket context\n");
return NULL;
}
memset(context, 0, sizeof(*context));
if (pid_daemon) {
context->started_with_parent = pid_daemon;
lwsl_notice(" Started with daemon pid %d\n", pid_daemon);
}
context->listen_service_extraseen = 0;
context->protocols = info->protocols;
context->listen_port = info->port;
context->http_proxy_port = 0;
context->http_proxy_address[0] = '\0';
context->options = info->options;
context->iface = info->iface;
/* to reduce this allocation, */
#ifdef WIN32
context->max_fds = getdtablesize ();
#else
context->max_fds = sysconf(_SC_OPEN_MAX);
#endif
lwsl_notice(" static allocation: %u + (%u x %u fds) = %u bytes\n",
sizeof(struct libwebsocket_context),
sizeof(struct libwebsocket_pollfd) +
sizeof(struct libwebsocket *),
context->max_fds,
sizeof(struct libwebsocket_context) +
((sizeof(struct libwebsocket_pollfd) +
sizeof(struct libwebsocket *)) *
context->max_fds));
context->fds = (struct libwebsocket_pollfd *)
malloc(sizeof(struct libwebsocket_pollfd) *
context->max_fds);
if (context->fds == NULL) {
lwsl_err("Unable to allocate fds array for %d connections\n",
context->max_fds);
free(context);
return NULL;
}
context->lws_lookup = (struct libwebsocket **)
malloc(sizeof(struct libwebsocket *) * context->max_fds);
if (context->lws_lookup == NULL) {
lwsl_err(
"Unable to allocate lws_lookup array for %d connections\n",
context->max_fds);
free(context->fds);
free(context);
return NULL;
}
memset(context->lws_lookup, 0, sizeof(struct libwebsocket *) *
context->max_fds);
if (lws_plat_init_fd_tables(context)) {
free(context->lws_lookup);
free(context->fds);
free(context);
return NULL;
}
lws_context_init_extensions(info, context);
context->user_space = info->user;
strcpy(context->canonical_hostname, "unknown");
lws_server_get_canonical_hostname(context, info);
/* split the proxy ads:port if given */
if (info->http_proxy_address) {
strncpy(context->http_proxy_address, info->http_proxy_address,
sizeof(context->http_proxy_address) - 1);
context->http_proxy_address[
sizeof(context->http_proxy_address) - 1] = '\0';
context->http_proxy_port = info->http_proxy_port;
} else {
#ifdef HAVE_GETENV
p = getenv("http_proxy");
if (p) {
strncpy(context->http_proxy_address, p,
sizeof(context->http_proxy_address) - 1);
context->http_proxy_address[
sizeof(context->http_proxy_address) - 1] = '\0';
p = strchr(context->http_proxy_address, ':');
if (p == NULL) {
lwsl_err("http_proxy needs to be ads:port\n");
goto bail;
}
*p = '\0';
context->http_proxy_port = atoi(p + 1);
}
#endif
}
if (context->http_proxy_address[0])
lwsl_notice(" Proxy %s:%u\n",
context->http_proxy_address,
context->http_proxy_port);
lwsl_notice(
" per-conn mem: %u + %u headers + protocol rx buf\n",
sizeof(struct libwebsocket),
sizeof(struct allocated_headers));
if (lws_context_init_server_ssl(info, context))
goto bail;
if (lws_context_init_client_ssl(info, context))
goto bail;
if (lws_context_init_server(info, context))
goto bail;
/*
* drop any root privs for this process
* to listen on port < 1023 we would have needed root, but now we are
* listening, we don't want the power for anything else
*/
lws_plat_drop_app_privileges(info);
/* initialize supported protocols */
for (context->count_protocols = 0;
info->protocols[context->count_protocols].callback;
context->count_protocols++) {
lwsl_parser(" Protocol: %s\n",
info->protocols[context->count_protocols].name);
info->protocols[context->count_protocols].owning_server =
context;
info->protocols[context->count_protocols].protocol_index =
context->count_protocols;
/*
* inform all the protocols that they are doing their one-time
* initialization if they want to
*/
info->protocols[context->count_protocols].callback(context,
NULL, LWS_CALLBACK_PROTOCOL_INIT, NULL, NULL, 0);
}
/*
* give all extensions a chance to create any per-context
* allocations they need
*/
if (info->port != CONTEXT_PORT_NO_LISTEN) {
if (lws_ext_callback_for_each_extension_type(context, NULL,
LWS_EXT_CALLBACK_SERVER_CONTEXT_CONSTRUCT,
NULL, 0) < 0)
goto bail;
} else
if (lws_ext_callback_for_each_extension_type(context, NULL,
LWS_EXT_CALLBACK_CLIENT_CONTEXT_CONSTRUCT,
NULL, 0) < 0)
goto bail;
return context;
bail:
libwebsocket_context_destroy(context);
return NULL;
}
/**
* libwebsocket_context_destroy() - Destroy the websocket context
* @context: Websocket context
*
* This function closes any active connections and then frees the
* context. After calling this, any further use of the context is
* undefined.
*/
LWS_VISIBLE void
libwebsocket_context_destroy(struct libwebsocket_context *context)
{
int n;
struct libwebsocket_protocols *protocol = context->protocols;
lwsl_notice("%s\n", __func__);
#ifdef LWS_LATENCY
if (context->worst_latency_info[0])
lwsl_notice("Worst latency: %s\n", context->worst_latency_info);
#endif
for (n = 0; n < context->fds_count; n++) {
struct libwebsocket *wsi =
context->lws_lookup[context->fds[n].fd];
if (!wsi)
continue;
libwebsocket_close_and_free_session(context,
wsi, LWS_CLOSE_STATUS_NOSTATUS /* no protocol close */);
n--;
}
/*
* give all extensions a chance to clean up any per-context
* allocations they might have made
*/
if (context->listen_port) {
if (lws_ext_callback_for_each_extension_type(context, NULL,
LWS_EXT_CALLBACK_SERVER_CONTEXT_DESTRUCT, NULL, 0) < 0)
return;
} else
if (lws_ext_callback_for_each_extension_type(context, NULL,
LWS_EXT_CALLBACK_CLIENT_CONTEXT_DESTRUCT, NULL, 0) < 0)
return;
/*
* inform all the protocols that they are done and will have no more
* callbacks
*/
while (protocol->callback) {
protocol->callback(context, NULL, LWS_CALLBACK_PROTOCOL_DESTROY,
NULL, NULL, 0);
protocol++;
}
lws_plat_context_early_destroy(context);
lws_ssl_context_destroy(context);
if (context->fds)
free(context->fds);
if (context->lws_lookup)
free(context->lws_lookup);
lws_plat_context_late_destroy(context);
free(context);
}

View File

@ -1,294 +0,0 @@
#include "private-libwebsockets.h"
#include "extension-deflate-frame.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define LWS_ZLIB_WINDOW_BITS 15
#define LWS_ZLIB_MEMLEVEL 8
int lws_extension_callback_deflate_frame(
struct libwebsocket_context *context,
struct libwebsocket_extension *ext,
struct libwebsocket *wsi,
enum libwebsocket_extension_callback_reasons reason,
void *user, void *in, size_t len)
{
struct lws_ext_deflate_frame_conn *conn =
(struct lws_ext_deflate_frame_conn *)user;
struct lws_tokens *eff_buf = (struct lws_tokens *)in;
size_t current_payload, remaining_payload, total_payload;
int n;
size_t len_so_far;
switch (reason) {
/*
* for deflate-frame, both client and server sides act the same
*/
case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT:
case LWS_EXT_CALLBACK_CONSTRUCT:
conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL;
conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL;
conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL;
n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS);
if (n != Z_OK) {
lwsl_ext("deflateInit returned %d\n", n);
return 1;
}
n = deflateInit2(&conn->zs_out,
(context->listen_port ?
DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER :
DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT),
Z_DEFLATED,
-LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL,
Z_DEFAULT_STRATEGY);
if (n != Z_OK) {
lwsl_ext("deflateInit2 returned %d\n", n);
return 1;
}
conn->buf_pre_used = 0;
conn->buf_pre_length = 0;
conn->buf_in_length = sizeof(conn->buf_in);
conn->buf_out_length = sizeof(conn->buf_out);
conn->compressed_out = 0;
conn->buf_pre = NULL;
conn->buf_in = (unsigned char *)
malloc(LWS_SEND_BUFFER_PRE_PADDING +
conn->buf_in_length +
LWS_SEND_BUFFER_POST_PADDING);
if (!conn->buf_in)
goto bail;
conn->buf_out = (unsigned char *)
malloc(LWS_SEND_BUFFER_PRE_PADDING +
conn->buf_out_length +
LWS_SEND_BUFFER_POST_PADDING);
if (!conn->buf_out)
goto bail;
lwsl_ext("zlibs constructed\n");
break;
bail:
lwsl_err("Out of mem\n");
(void)inflateEnd(&conn->zs_in);
(void)deflateEnd(&conn->zs_out);
return -1;
case LWS_EXT_CALLBACK_DESTROY:
if (conn->buf_pre)
free(conn->buf_pre);
free(conn->buf_in);
free(conn->buf_out);
conn->buf_pre_used = 0;
conn->buf_pre_length = 0;
conn->buf_in_length = 0;
conn->buf_out_length = 0;
conn->compressed_out = 0;
(void)inflateEnd(&conn->zs_in);
(void)deflateEnd(&conn->zs_out);
lwsl_ext("zlibs destructed\n");
break;
case LWS_EXT_CALLBACK_PAYLOAD_RX:
if (!(wsi->u.ws.rsv & 0x40))
return 0;
/*
* inflate the incoming payload
*/
current_payload = eff_buf->token_len;
remaining_payload = wsi->u.ws.rx_packet_length;
if (remaining_payload) {
total_payload = conn->buf_pre_used +
current_payload +
remaining_payload;
if (conn->buf_pre_length < total_payload) {
conn->buf_pre_length = total_payload;
if (conn->buf_pre)
free(conn->buf_pre);
conn->buf_pre =
(unsigned char *)malloc(total_payload + 4);
if (!conn->buf_pre) {
lwsl_err("Out of memory\n");
return -1;
}
}
memcpy(conn->buf_pre + conn->buf_pre_used,
eff_buf->token, current_payload);
conn->buf_pre_used += current_payload;
eff_buf->token = NULL;
eff_buf->token_len = 0;
return 0;
}
if (conn->buf_pre_used) {
total_payload = conn->buf_pre_used +
current_payload;
memcpy(conn->buf_pre + conn->buf_pre_used,
eff_buf->token, current_payload);
conn->buf_pre_used = 0;
conn->zs_in.next_in = conn->buf_pre;
} else {
total_payload = current_payload;
conn->zs_in.next_in = (unsigned char *)eff_buf->token;
}
conn->zs_in.next_in[total_payload + 0] = 0;
conn->zs_in.next_in[total_payload + 1] = 0;
conn->zs_in.next_in[total_payload + 2] = 0xff;
conn->zs_in.next_in[total_payload + 3] = 0xff;
conn->zs_in.avail_in = total_payload + 4;
conn->zs_in.next_out =
conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING;
conn->zs_in.avail_out = conn->buf_in_length;
while (1) {
n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
switch (n) {
case Z_NEED_DICT:
case Z_STREAM_ERROR:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
/*
* screwed.. close the connection...
* we will get a destroy callback to take care
* of closing nicely
*/
lwsl_info("zlib error inflate %d: %s\n",
n, conn->zs_in.msg);
return -1;
}
if (conn->zs_in.avail_out)
break;
len_so_far = conn->zs_in.next_out -
(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
conn->buf_in_length *= 2;
if (conn->buf_in_length > LWS_MAX_ZLIB_CONN_BUFFER) {
lwsl_ext("zlib in buffer hit limit %u\n",
LWS_MAX_ZLIB_CONN_BUFFER);
return -1;
}
conn->buf_in = (unsigned char *)realloc(conn->buf_in,
LWS_SEND_BUFFER_PRE_PADDING +
conn->buf_in_length +
LWS_SEND_BUFFER_POST_PADDING);
if (!conn->buf_in) {
lwsl_err("Out of memory\n");
return -1;
}
lwsl_debug(
"deflate-frame ext RX did realloc to %ld\n",
conn->buf_in_length);
conn->zs_in.next_out = conn->buf_in +
LWS_SEND_BUFFER_PRE_PADDING + len_so_far;
conn->zs_in.avail_out =
conn->buf_in_length - len_so_far;
}
/* rewrite the buffer pointers and length */
eff_buf->token =
(char *)(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING);
eff_buf->token_len = (int)(conn->zs_in.next_out -
(conn->buf_in + LWS_SEND_BUFFER_PRE_PADDING));
return 0;
case LWS_EXT_CALLBACK_PAYLOAD_TX:
/*
* deflate the outgoing payload
*/
current_payload = eff_buf->token_len;
conn->zs_out.next_in = (unsigned char *)eff_buf->token;
conn->zs_out.avail_in = current_payload;
conn->zs_out.next_out =
conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING;
conn->zs_out.avail_out = conn->buf_out_length;
while (1) {
n = deflate(&conn->zs_out, Z_SYNC_FLUSH);
if (n == Z_STREAM_ERROR) {
/*
* screwed.. close the connection... we will
* get a destroy callback to take care of
* closing nicely
*/
lwsl_ext("zlib error deflate\n");
return -1;
}
if (conn->zs_out.avail_out)
break;
len_so_far = (conn->zs_out.next_out -
(conn->buf_out +
LWS_SEND_BUFFER_PRE_PADDING));
conn->buf_out_length *= 2;
if (conn->buf_out_length > LWS_MAX_ZLIB_CONN_BUFFER) {
lwsl_ext("zlib out hit limit %u\n",
LWS_MAX_ZLIB_CONN_BUFFER);
return -1;
}
conn->buf_out = (unsigned char *)realloc(
conn->buf_out,
LWS_SEND_BUFFER_PRE_PADDING +
conn->buf_out_length +
LWS_SEND_BUFFER_POST_PADDING);
if (!conn->buf_out) {
lwsl_err("Out of memory\n");
return -1;
}
lwsl_debug(
"deflate-frame ext TX did realloc to %ld\n",
conn->buf_in_length);
conn->zs_out.next_out = (conn->buf_out +
LWS_SEND_BUFFER_PRE_PADDING + len_so_far);
conn->zs_out.avail_out =
(conn->buf_out_length - len_so_far);
}
conn->compressed_out = 1;
/* rewrite the buffer pointers and length */
eff_buf->token = (char *)(conn->buf_out +
LWS_SEND_BUFFER_PRE_PADDING);
eff_buf->token_len = (int)(conn->zs_out.next_out -
(conn->buf_out + LWS_SEND_BUFFER_PRE_PADDING)) - 4;
return 0;
case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
if (conn->compressed_out) {
conn->compressed_out = 0;
*((unsigned char *)eff_buf->token) |= 0x40;
}
break;
case LWS_EXT_CALLBACK_CHECK_OK_TO_PROPOSE_EXTENSION:
/* Avoid x-webkit-deflate-frame extension on client */
if (!strcmp((char *)in, "x-webkit-deflate-frame"))
return 1;
break;
default:
break;
}
return 0;
}

View File

@ -1,25 +0,0 @@
#pragma once
#include "deps/zlib/zlib.h"
#define DEFLATE_FRAME_COMPRESSION_LEVEL_SERVER 1
#define DEFLATE_FRAME_COMPRESSION_LEVEL_CLIENT Z_DEFAULT_COMPRESSION
struct lws_ext_deflate_frame_conn {
z_stream zs_in;
z_stream zs_out;
size_t buf_pre_used;
size_t buf_pre_length;
size_t buf_in_length;
size_t buf_out_length;
int compressed_out;
unsigned char *buf_pre;
unsigned char *buf_in;
unsigned char *buf_out;
};
extern int lws_extension_callback_deflate_frame(
struct libwebsocket_context *context,
struct libwebsocket_extension *ext,
struct libwebsocket *wsi,
enum libwebsocket_extension_callback_reasons reason,
void *user, void *in, size_t len);

View File

@ -1,166 +0,0 @@
#include "private-libwebsockets.h"
#include "extension-deflate-stream.h"
#include <stdio.h>
#include <string.h>
#include <assert.h>
#define LWS_ZLIB_WINDOW_BITS 15
#define LWS_ZLIB_MEMLEVEL 8
int lws_extension_callback_deflate_stream(
struct libwebsocket_context *context,
struct libwebsocket_extension *ext,
struct libwebsocket *wsi,
enum libwebsocket_extension_callback_reasons reason,
void *user, void *in, size_t len)
{
struct lws_ext_deflate_stream_conn *conn =
(struct lws_ext_deflate_stream_conn *)user;
int n;
struct lws_tokens *eff_buf = (struct lws_tokens *)in;
switch (reason) {
/*
* for deflate-stream, both client and server sides act the same
*/
case LWS_EXT_CALLBACK_CLIENT_CONSTRUCT:
case LWS_EXT_CALLBACK_CONSTRUCT:
conn->zs_in.zalloc = conn->zs_out.zalloc = Z_NULL;
conn->zs_in.zfree = conn->zs_out.zfree = Z_NULL;
conn->zs_in.opaque = conn->zs_out.opaque = Z_NULL;
n = inflateInit2(&conn->zs_in, -LWS_ZLIB_WINDOW_BITS);
if (n != Z_OK) {
lwsl_err("deflateInit returned %d\n", n);
return 1;
}
n = deflateInit2(&conn->zs_out,
DEFLATE_STREAM_COMPRESSION_LEVEL, Z_DEFLATED,
-LWS_ZLIB_WINDOW_BITS, LWS_ZLIB_MEMLEVEL,
Z_DEFAULT_STRATEGY);
if (n != Z_OK) {
lwsl_err("deflateInit returned %d\n", n);
return 1;
}
lwsl_ext("zlibs constructed\n");
conn->remaining_in = 0;
break;
case LWS_EXT_CALLBACK_DESTROY:
(void)inflateEnd(&conn->zs_in);
(void)deflateEnd(&conn->zs_out);
lwsl_ext("zlibs destructed\n");
break;
case LWS_EXT_CALLBACK_PACKET_RX_PREPARSE:
/*
* inflate the incoming compressed data
* Notice, length may be 0 and pointer NULL
* in the case we are flushing with nothing new coming in
*/
if (conn->remaining_in) {
conn->zs_in.next_in = conn->buf_in;
conn->zs_in.avail_in = conn->remaining_in;
conn->remaining_in = 0;
} else {
conn->zs_in.next_in = (unsigned char *)eff_buf->token;
conn->zs_in.avail_in = eff_buf->token_len;
}
conn->zs_in.next_out = conn->buf_out;
conn->zs_in.avail_out = sizeof(conn->buf_out);
n = inflate(&conn->zs_in, Z_SYNC_FLUSH);
switch (n) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
/*
* screwed.. close the connection... we will get a
* destroy callback to take care of closing nicely
*/
lwsl_err("zlib error inflate %d\n", n);
return -1;
}
/* rewrite the buffer pointers and length */
eff_buf->token = (char *)conn->buf_out;
eff_buf->token_len =
sizeof(conn->buf_out) - conn->zs_in.avail_out;
/* copy avail data if not consumed */
if (conn->zs_in.avail_in > 0) {
conn->remaining_in = conn->zs_in.avail_in;
memcpy(conn->buf_in, conn->zs_in.next_in,
conn->zs_in.avail_in);
return 1;
}
/*
* if we filled the output buffer, signal that we likely have
* more and need to be called again
*/
if (eff_buf->token_len == sizeof(conn->buf_out))
return 1;
/* we don't need calling again until new input data comes */
return 0;
case LWS_EXT_CALLBACK_FLUSH_PENDING_TX:
case LWS_EXT_CALLBACK_PACKET_TX_PRESEND:
/*
* deflate the outgoing compressed data
*/
conn->zs_out.next_in = (unsigned char *)eff_buf->token;
conn->zs_out.avail_in = eff_buf->token_len;
conn->zs_out.next_out = conn->buf_out;
conn->zs_out.avail_out = sizeof(conn->buf_out);
n = Z_PARTIAL_FLUSH;
if (reason == LWS_EXT_CALLBACK_FLUSH_PENDING_TX)
n = Z_FULL_FLUSH;
n = deflate(&conn->zs_out, n);
if (n == Z_STREAM_ERROR) {
/*
* screwed.. close the connection... we will get a
* destroy callback to take care of closing nicely
*/
lwsl_ext("zlib error deflate\n");
return -1;
}
/* rewrite the buffer pointers and length */
eff_buf->token = (char *)conn->buf_out;
eff_buf->token_len =
sizeof(conn->buf_out) - conn->zs_out.avail_out;
/*
* if we filled the output buffer, signal that we likely have
* more and need to be called again... even in deflate case
* we might sometimes need to spill more than came in
*/
if (eff_buf->token_len == sizeof(conn->buf_out))
return 1;
/* we don't need calling again until new input data comes */
return 0;
default:
break;
}
return 0;
}

View File

@ -1,20 +0,0 @@
#include "deps/zlib/zlib.h"
#define DEFLATE_STREAM_CHUNK 128
#define DEFLATE_STREAM_COMPRESSION_LEVEL 1
struct lws_ext_deflate_stream_conn {
z_stream zs_in;
z_stream zs_out;
int remaining_in;
unsigned char buf_in[LWS_MAX_SOCKET_IO_BUF];
unsigned char buf_out[LWS_MAX_SOCKET_IO_BUF];
};
extern int lws_extension_callback_deflate_stream(
struct libwebsocket_context *context,
struct libwebsocket_extension *ext,
struct libwebsocket *wsi,
enum libwebsocket_extension_callback_reasons reason,
void *user, void *in, size_t len);

View File

@ -1,206 +0,0 @@
#include "private-libwebsockets.h"
#include "extension-deflate-frame.h"
#include "extension-deflate-stream.h"
struct libwebsocket_extension libwebsocket_internal_extensions[] = {
#ifdef LWS_EXT_DEFLATE_STREAM
{
"deflate-stream",
lws_extension_callback_deflate_stream,
sizeof(struct lws_ext_deflate_stream_conn)
},
#else
{
"x-webkit-deflate-frame",
lws_extension_callback_deflate_frame,
sizeof(struct lws_ext_deflate_frame_conn)
},
{
"deflate-frame",
lws_extension_callback_deflate_frame,
sizeof(struct lws_ext_deflate_frame_conn)
},
#endif
{ /* terminator */
NULL, NULL, 0
}
};
LWS_VISIBLE void
lws_context_init_extensions(struct lws_context_creation_info *info,
struct libwebsocket_context *context)
{
context->extensions = info->extensions;
lwsl_info(" LWS_MAX_EXTENSIONS_ACTIVE: %u\n", LWS_MAX_EXTENSIONS_ACTIVE);
}
LWS_VISIBLE struct libwebsocket_extension *libwebsocket_get_internal_extensions()
{
return libwebsocket_internal_extensions;
}
/* 0 = nobody had nonzero return, 1 = somebody had positive return, -1 = fail */
int lws_ext_callback_for_each_active(struct libwebsocket *wsi, int reason,
void *arg, int len)
{
int n, m, handled = 0;
for (n = 0; n < wsi->count_active_extensions; n++) {
m = wsi->active_extensions[n]->callback(
wsi->protocol->owning_server,
wsi->active_extensions[n], wsi,
reason,
wsi->active_extensions_user[n],
arg, len);
if (m < 0) {
lwsl_ext(
"Extension '%s' failed to handle callback %d!\n",
wsi->active_extensions[n]->name, reason);
return -1;
}
if (m > handled)
handled = m;
}
return handled;
}
int lws_ext_callback_for_each_extension_type(
struct libwebsocket_context *context, struct libwebsocket *wsi,
int reason, void *arg, int len)
{
int n = 0, m, handled = 0;
struct libwebsocket_extension *ext = context->extensions;
while (ext && ext->callback && !handled) {
m = ext->callback(context, ext, wsi, reason,
(void *)(long)n, arg, len);
if (m < 0) {
lwsl_ext(
"Extension '%s' failed to handle callback %d!\n",
wsi->active_extensions[n]->name, reason);
return -1;
}
if (m)
handled = 1;
ext++;
n++;
}
return 0;
}
int
lws_issue_raw_ext_access(struct libwebsocket *wsi,
unsigned char *buf, size_t len)
{
int ret;
struct lws_tokens eff_buf;
int m;
int n;
eff_buf.token = (char *)buf;
eff_buf.token_len = len;
/*
* while we have original buf to spill ourselves, or extensions report
* more in their pipeline
*/
ret = 1;
while (ret == 1) {
/* default to nobody has more to spill */
ret = 0;
/* show every extension the new incoming data */
m = lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_PACKET_TX_PRESEND, &eff_buf, 0);
if (m < 0)
return -1;
if (m) /* handled */
ret = 1;
if ((char *)buf != eff_buf.token)
/*
* extension recreated it:
* need to buffer this if not all sent
*/
wsi->u.ws.clean_buffer = 0;
/* assuming they left us something to send, send it */
if (eff_buf.token_len) {
n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
eff_buf.token_len);
if (n < 0) {
lwsl_info("closing from ext access\n");
return -1;
}
/* always either sent it all or privately buffered */
}
lwsl_parser("written %d bytes to client\n", eff_buf.token_len);
/* no extension has more to spill? Then we can go */
if (!ret)
break;
/* we used up what we had */
eff_buf.token = NULL;
eff_buf.token_len = 0;
/*
* Did that leave the pipe choked?
* Or we had to hold on to some of it?
*/
if (!lws_send_pipe_choked(wsi) && !wsi->truncated_send_len)
/* no we could add more, lets's do that */
continue;
lwsl_debug("choked\n");
/*
* Yes, he's choked. Don't spill the rest now get a callback
* when he is ready to send and take care of it there
*/
libwebsocket_callback_on_writable(
wsi->protocol->owning_server, wsi);
wsi->extension_data_pending = 1;
ret = 0;
}
return len;
}
int
lws_any_extension_handled(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_extension_callback_reasons r,
void *v, size_t len)
{
int n;
int handled = 0;
/* maybe an extension will take care of it for us */
for (n = 0; n < wsi->count_active_extensions && !handled; n++) {
if (!wsi->active_extensions[n]->callback)
continue;
handled |= wsi->active_extensions[n]->callback(context,
wsi->active_extensions[n], wsi,
r, wsi->active_extensions_user[n], v, len);
}
return handled;
}

View File

@ -1,171 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
/*
* -04 of the protocol (actually the 80th version) has a radically different
* handshake. The 04 spec gives the following idea
*
* The handshake from the client looks as follows:
*
* GET /chat HTTP/1.1
* Host: server.example.com
* Upgrade: websocket
* Connection: Upgrade
* Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
* Sec-WebSocket-Origin: http://example.com
* Sec-WebSocket-Protocol: chat, superchat
* Sec-WebSocket-Version: 4
*
* The handshake from the server looks as follows:
*
* HTTP/1.1 101 Switching Protocols
* Upgrade: websocket
* Connection: Upgrade
* Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
* Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
* Sec-WebSocket-Protocol: chat
*/
/*
* We have to take care about parsing because the headers may be split
* into multiple fragments. They may contain unknown headers with arbitrary
* argument lengths. So, we parse using a single-character at a time state
* machine that is completely independent of packet size.
*/
LWS_VISIBLE int
libwebsocket_read(struct libwebsocket_context *context,
struct libwebsocket *wsi, unsigned char *buf, size_t len)
{
size_t n;
switch (wsi->state) {
case WSI_STATE_HTTP_BODY:
http_postbody:
while (len--) {
if (wsi->u.http.content_length_seen >= wsi->u.http.content_length)
break;
wsi->u.http.post_buffer[wsi->u.http.body_index++] = *buf++;
wsi->u.http.content_length_seen++;
n = wsi->protocol->rx_buffer_size;
if (!n)
n = LWS_MAX_SOCKET_IO_BUF;
if (wsi->u.http.body_index != n &&
wsi->u.http.content_length_seen != wsi->u.http.content_length)
continue;
if (wsi->protocol->callback) {
n = wsi->protocol->callback(
wsi->protocol->owning_server, wsi,
LWS_CALLBACK_HTTP_BODY,
wsi->user_space, wsi->u.http.post_buffer,
wsi->u.http.body_index);
wsi->u.http.body_index = 0;
if (n)
goto bail;
}
if (wsi->u.http.content_length_seen == wsi->u.http.content_length) {
/* he sent the content in time */
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
n = wsi->protocol->callback(
wsi->protocol->owning_server, wsi,
LWS_CALLBACK_HTTP_BODY_COMPLETION,
wsi->user_space, NULL, 0);
wsi->u.http.body_index = 0;
if (n)
goto bail;
}
}
/*
* we need to spill here so everything is seen in the case
* there is no content-length
*/
if (wsi->u.http.body_index && wsi->protocol->callback) {
n = wsi->protocol->callback(
wsi->protocol->owning_server, wsi,
LWS_CALLBACK_HTTP_BODY,
wsi->user_space, wsi->u.http.post_buffer,
wsi->u.http.body_index);
wsi->u.http.body_index = 0;
if (n)
goto bail;
}
break;
case WSI_STATE_HTTP_ISSUING_FILE:
case WSI_STATE_HTTP:
wsi->state = WSI_STATE_HTTP_HEADERS;
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
wsi->u.hdr.lextable_pos = 0;
/* fallthru */
case WSI_STATE_HTTP_HEADERS:
lwsl_parser("issuing %d bytes to parser\n", (int)len);
if (lws_handshake_client(wsi, &buf, len))
goto bail;
switch (lws_handshake_server(context, wsi, &buf, len)) {
case 1:
goto bail;
case 2:
goto http_postbody;
}
break;
case WSI_STATE_AWAITING_CLOSE_ACK:
case WSI_STATE_ESTABLISHED:
if (lws_handshake_client(wsi, &buf, len))
goto bail;
switch (wsi->mode) {
case LWS_CONNMODE_WS_SERVING:
if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0) {
lwsl_info("interpret_incoming_packet has bailed\n");
goto bail;
}
break;
}
break;
default:
lwsl_err("libwebsocket_read: Unhandled state\n");
break;
}
return 0;
bail:
lwsl_debug("closing connection at libwebsocket_read bail:\n");
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return -1;
}

View File

@ -1,287 +0,0 @@
/* pos 0000: 0 */ 0x67 /* 'g' */, 0x25, 0x00 /* (to 0x0025 state 1) */,
0x70 /* 'p' */, 0x27, 0x00 /* (to 0x002A state 5) */,
0x68 /* 'h' */, 0x30, 0x00 /* (to 0x0036 state 10) */,
0x63 /* 'c' */, 0x39, 0x00 /* (to 0x0042 state 15) */,
0x73 /* 's' */, 0x54, 0x00 /* (to 0x0060 state 26) */,
0x75 /* 'u' */, 0x93, 0x00 /* (to 0x00A2 state 56) */,
0x6F /* 'o' */, 0x99, 0x00 /* (to 0x00AB state 64) */,
0x0D /* '.' */, 0xA5, 0x00 /* (to 0x00BA state 77) */,
0x61 /* 'a' */, 0xDC, 0x00 /* (to 0x00F4 state 127) */,
0x69 /* 'i' */, 0xED, 0x00 /* (to 0x0108 state 134) */,
0x64 /* 'd' */, 0x5A, 0x01 /* (to 0x0178 state 225) */,
0x72 /* 'r' */, 0x5D, 0x01 /* (to 0x017E state 230) */,
0x08, /* fail */
/* pos 0025: 1 */ 0xE5 /* 'e' -> */,
/* pos 0026: 2 */ 0xF4 /* 't' -> */,
/* pos 0027: 3 */ 0xA0 /* ' ' -> */,
/* pos 0028: 4 */ 0x00, 0x00 /* - terminal marker 0 - */,
/* pos 002a: 5 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0031 state 6) */,
0x72 /* 'r' */, 0x09, 0x01 /* (to 0x0136 state 171) */,
0x08, /* fail */
/* pos 0031: 6 */ 0xF3 /* 's' -> */,
/* pos 0032: 7 */ 0xF4 /* 't' -> */,
/* pos 0033: 8 */ 0xA0 /* ' ' -> */,
/* pos 0034: 9 */ 0x00, 0x01 /* - terminal marker 1 - */,
/* pos 0036: 10 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x003D state 11) */,
0x74 /* 't' */, 0xB2, 0x00 /* (to 0x00EB state 119) */,
0x08, /* fail */
/* pos 003d: 11 */ 0xF3 /* 's' -> */,
/* pos 003e: 12 */ 0xF4 /* 't' -> */,
/* pos 003f: 13 */ 0xBA /* ':' -> */,
/* pos 0040: 14 */ 0x00, 0x02 /* - terminal marker 2 - */,
/* pos 0042: 15 */ 0x6F /* 'o' */, 0x07, 0x00 /* (to 0x0049 state 16) */,
0x61 /* 'a' */, 0xF8, 0x00 /* (to 0x013D state 177) */,
0x08, /* fail */
/* pos 0049: 16 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0050 state 17) */,
0x6F /* 'o' */, 0x0D, 0x01 /* (to 0x0159 state 203) */,
0x08, /* fail */
/* pos 0050: 17 */ 0x6E /* 'n' */, 0x07, 0x00 /* (to 0x0057 state 18) */,
0x74 /* 't' */, 0x0C, 0x01 /* (to 0x015F state 208) */,
0x08, /* fail */
/* pos 0057: 18 */ 0xE5 /* 'e' -> */,
/* pos 0058: 19 */ 0xE3 /* 'c' -> */,
/* pos 0059: 20 */ 0xF4 /* 't' -> */,
/* pos 005a: 21 */ 0xE9 /* 'i' -> */,
/* pos 005b: 22 */ 0xEF /* 'o' -> */,
/* pos 005c: 23 */ 0xEE /* 'n' -> */,
/* pos 005d: 24 */ 0xBA /* ':' -> */,
/* pos 005e: 25 */ 0x00, 0x03 /* - terminal marker 3 - */,
/* pos 0060: 26 */ 0xE5 /* 'e' -> */,
/* pos 0061: 27 */ 0xE3 /* 'c' -> */,
/* pos 0062: 28 */ 0xAD /* '-' -> */,
/* pos 0063: 29 */ 0xF7 /* 'w' -> */,
/* pos 0064: 30 */ 0xE5 /* 'e' -> */,
/* pos 0065: 31 */ 0xE2 /* 'b' -> */,
/* pos 0066: 32 */ 0xF3 /* 's' -> */,
/* pos 0067: 33 */ 0xEF /* 'o' -> */,
/* pos 0068: 34 */ 0xE3 /* 'c' -> */,
/* pos 0069: 35 */ 0xEB /* 'k' -> */,
/* pos 006a: 36 */ 0xE5 /* 'e' -> */,
/* pos 006b: 37 */ 0xF4 /* 't' -> */,
/* pos 006c: 38 */ 0xAD /* '-' -> */,
/* pos 006d: 39 */ 0x6B /* 'k' */, 0x19, 0x00 /* (to 0x0086 state 40) */,
0x70 /* 'p' */, 0x28, 0x00 /* (to 0x0098 state 47) */,
0x64 /* 'd' */, 0x40, 0x00 /* (to 0x00B3 state 71) */,
0x76 /* 'v' */, 0x49, 0x00 /* (to 0x00BF state 80) */,
0x6F /* 'o' */, 0x4F, 0x00 /* (to 0x00C8 state 88) */,
0x65 /* 'e' */, 0x54, 0x00 /* (to 0x00D0 state 95) */,
0x61 /* 'a' */, 0x5D, 0x00 /* (to 0x00DC state 106) */,
0x6E /* 'n' */, 0x62, 0x00 /* (to 0x00E4 state 113) */,
0x08, /* fail */
/* pos 0086: 40 */ 0xE5 /* 'e' -> */,
/* pos 0087: 41 */ 0xF9 /* 'y' -> */,
/* pos 0088: 42 */ 0x31 /* '1' */, 0x0A, 0x00 /* (to 0x0092 state 43) */,
0x32 /* '2' */, 0x0A, 0x00 /* (to 0x0095 state 45) */,
0x3A /* ':' */, 0x2F, 0x00 /* (to 0x00BD state 79) */,
0x08, /* fail */
/* pos 0092: 43 */ 0xBA /* ':' -> */,
/* pos 0093: 44 */ 0x00, 0x04 /* - terminal marker 4 - */,
/* pos 0095: 45 */ 0xBA /* ':' -> */,
/* pos 0096: 46 */ 0x00, 0x05 /* - terminal marker 5 - */,
/* pos 0098: 47 */ 0xF2 /* 'r' -> */,
/* pos 0099: 48 */ 0xEF /* 'o' -> */,
/* pos 009a: 49 */ 0xF4 /* 't' -> */,
/* pos 009b: 50 */ 0xEF /* 'o' -> */,
/* pos 009c: 51 */ 0xE3 /* 'c' -> */,
/* pos 009d: 52 */ 0xEF /* 'o' -> */,
/* pos 009e: 53 */ 0xEC /* 'l' -> */,
/* pos 009f: 54 */ 0xBA /* ':' -> */,
/* pos 00a0: 55 */ 0x00, 0x06 /* - terminal marker 6 - */,
/* pos 00a2: 56 */ 0xF0 /* 'p' -> */,
/* pos 00a3: 57 */ 0xE7 /* 'g' -> */,
/* pos 00a4: 58 */ 0xF2 /* 'r' -> */,
/* pos 00a5: 59 */ 0xE1 /* 'a' -> */,
/* pos 00a6: 60 */ 0xE4 /* 'd' -> */,
/* pos 00a7: 61 */ 0xE5 /* 'e' -> */,
/* pos 00a8: 62 */ 0xBA /* ':' -> */,
/* pos 00a9: 63 */ 0x00, 0x07 /* - terminal marker 7 - */,
/* pos 00ab: 64 */ 0xF2 /* 'r' -> */,
/* pos 00ac: 65 */ 0xE9 /* 'i' -> */,
/* pos 00ad: 66 */ 0xE7 /* 'g' -> */,
/* pos 00ae: 67 */ 0xE9 /* 'i' -> */,
/* pos 00af: 68 */ 0xEE /* 'n' -> */,
/* pos 00b0: 69 */ 0xBA /* ':' -> */,
/* pos 00b1: 70 */ 0x00, 0x08 /* - terminal marker 8 - */,
/* pos 00b3: 71 */ 0xF2 /* 'r' -> */,
/* pos 00b4: 72 */ 0xE1 /* 'a' -> */,
/* pos 00b5: 73 */ 0xE6 /* 'f' -> */,
/* pos 00b6: 74 */ 0xF4 /* 't' -> */,
/* pos 00b7: 75 */ 0xBA /* ':' -> */,
/* pos 00b8: 76 */ 0x00, 0x09 /* - terminal marker 9 - */,
/* pos 00ba: 77 */ 0x8A /* '.' -> */,
/* pos 00bb: 78 */ 0x00, 0x0A /* - terminal marker 10 - */,
/* pos 00bd: 79 */ 0x00, 0x0B /* - terminal marker 11 - */,
/* pos 00bf: 80 */ 0xE5 /* 'e' -> */,
/* pos 00c0: 81 */ 0xF2 /* 'r' -> */,
/* pos 00c1: 82 */ 0xF3 /* 's' -> */,
/* pos 00c2: 83 */ 0xE9 /* 'i' -> */,
/* pos 00c3: 84 */ 0xEF /* 'o' -> */,
/* pos 00c4: 85 */ 0xEE /* 'n' -> */,
/* pos 00c5: 86 */ 0xBA /* ':' -> */,
/* pos 00c6: 87 */ 0x00, 0x0C /* - terminal marker 12 - */,
/* pos 00c8: 88 */ 0xF2 /* 'r' -> */,
/* pos 00c9: 89 */ 0xE9 /* 'i' -> */,
/* pos 00ca: 90 */ 0xE7 /* 'g' -> */,
/* pos 00cb: 91 */ 0xE9 /* 'i' -> */,
/* pos 00cc: 92 */ 0xEE /* 'n' -> */,
/* pos 00cd: 93 */ 0xBA /* ':' -> */,
/* pos 00ce: 94 */ 0x00, 0x0D /* - terminal marker 13 - */,
/* pos 00d0: 95 */ 0xF8 /* 'x' -> */,
/* pos 00d1: 96 */ 0xF4 /* 't' -> */,
/* pos 00d2: 97 */ 0xE5 /* 'e' -> */,
/* pos 00d3: 98 */ 0xEE /* 'n' -> */,
/* pos 00d4: 99 */ 0xF3 /* 's' -> */,
/* pos 00d5: 100 */ 0xE9 /* 'i' -> */,
/* pos 00d6: 101 */ 0xEF /* 'o' -> */,
/* pos 00d7: 102 */ 0xEE /* 'n' -> */,
/* pos 00d8: 103 */ 0xF3 /* 's' -> */,
/* pos 00d9: 104 */ 0xBA /* ':' -> */,
/* pos 00da: 105 */ 0x00, 0x0E /* - terminal marker 14 - */,
/* pos 00dc: 106 */ 0xE3 /* 'c' -> */,
/* pos 00dd: 107 */ 0xE3 /* 'c' -> */,
/* pos 00de: 108 */ 0xE5 /* 'e' -> */,
/* pos 00df: 109 */ 0xF0 /* 'p' -> */,
/* pos 00e0: 110 */ 0xF4 /* 't' -> */,
/* pos 00e1: 111 */ 0xBA /* ':' -> */,
/* pos 00e2: 112 */ 0x00, 0x0F /* - terminal marker 15 - */,
/* pos 00e4: 113 */ 0xEF /* 'o' -> */,
/* pos 00e5: 114 */ 0xEE /* 'n' -> */,
/* pos 00e6: 115 */ 0xE3 /* 'c' -> */,
/* pos 00e7: 116 */ 0xE5 /* 'e' -> */,
/* pos 00e8: 117 */ 0xBA /* ':' -> */,
/* pos 00e9: 118 */ 0x00, 0x10 /* - terminal marker 16 - */,
/* pos 00eb: 119 */ 0xF4 /* 't' -> */,
/* pos 00ec: 120 */ 0xF0 /* 'p' -> */,
/* pos 00ed: 121 */ 0xAF /* '/' -> */,
/* pos 00ee: 122 */ 0xB1 /* '1' -> */,
/* pos 00ef: 123 */ 0xAE /* '.' -> */,
/* pos 00f0: 124 */ 0xB1 /* '1' -> */,
/* pos 00f1: 125 */ 0xA0 /* ' ' -> */,
/* pos 00f2: 126 */ 0x00, 0x11 /* - terminal marker 17 - */,
/* pos 00f4: 127 */ 0x63 /* 'c' */, 0x07, 0x00 /* (to 0x00FB state 128) */,
0x75 /* 'u' */, 0x54, 0x00 /* (to 0x014B state 190) */,
0x08, /* fail */
/* pos 00fb: 128 */ 0xE3 /* 'c' -> */,
/* pos 00fc: 129 */ 0xE5 /* 'e' -> */,
/* pos 00fd: 130 */ 0xF0 /* 'p' -> */,
/* pos 00fe: 131 */ 0xF4 /* 't' -> */,
/* pos 00ff: 132 */ 0x3A /* ':' */, 0x07, 0x00 /* (to 0x0106 state 133) */,
0x2D /* '-' */, 0x19, 0x00 /* (to 0x011B state 152) */,
0x08, /* fail */
/* pos 0106: 133 */ 0x00, 0x12 /* - terminal marker 18 - */,
/* pos 0108: 134 */ 0xE6 /* 'f' -> */,
/* pos 0109: 135 */ 0xAD /* '-' -> */,
/* pos 010a: 136 */ 0xED /* 'm' -> */,
/* pos 010b: 137 */ 0xEF /* 'o' -> */,
/* pos 010c: 138 */ 0xE4 /* 'd' -> */,
/* pos 010d: 139 */ 0xE9 /* 'i' -> */,
/* pos 010e: 140 */ 0xE6 /* 'f' -> */,
/* pos 010f: 141 */ 0xE9 /* 'i' -> */,
/* pos 0110: 142 */ 0xE5 /* 'e' -> */,
/* pos 0111: 143 */ 0xE4 /* 'd' -> */,
/* pos 0112: 144 */ 0xAD /* '-' -> */,
/* pos 0113: 145 */ 0xF3 /* 's' -> */,
/* pos 0114: 146 */ 0xE9 /* 'i' -> */,
/* pos 0115: 147 */ 0xEE /* 'n' -> */,
/* pos 0116: 148 */ 0xE3 /* 'c' -> */,
/* pos 0117: 149 */ 0xE5 /* 'e' -> */,
/* pos 0118: 150 */ 0xBA /* ':' -> */,
/* pos 0119: 151 */ 0x00, 0x13 /* - terminal marker 19 - */,
/* pos 011b: 152 */ 0x65 /* 'e' */, 0x07, 0x00 /* (to 0x0122 state 153) */,
0x6C /* 'l' */, 0x0E, 0x00 /* (to 0x012C state 162) */,
0x08, /* fail */
/* pos 0122: 153 */ 0xEE /* 'n' -> */,
/* pos 0123: 154 */ 0xE3 /* 'c' -> */,
/* pos 0124: 155 */ 0xEF /* 'o' -> */,
/* pos 0125: 156 */ 0xE4 /* 'd' -> */,
/* pos 0126: 157 */ 0xE9 /* 'i' -> */,
/* pos 0127: 158 */ 0xEE /* 'n' -> */,
/* pos 0128: 159 */ 0xE7 /* 'g' -> */,
/* pos 0129: 160 */ 0xBA /* ':' -> */,
/* pos 012a: 161 */ 0x00, 0x14 /* - terminal marker 20 - */,
/* pos 012c: 162 */ 0xE1 /* 'a' -> */,
/* pos 012d: 163 */ 0xEE /* 'n' -> */,
/* pos 012e: 164 */ 0xE7 /* 'g' -> */,
/* pos 012f: 165 */ 0xF5 /* 'u' -> */,
/* pos 0130: 166 */ 0xE1 /* 'a' -> */,
/* pos 0131: 167 */ 0xE7 /* 'g' -> */,
/* pos 0132: 168 */ 0xE5 /* 'e' -> */,
/* pos 0133: 169 */ 0xBA /* ':' -> */,
/* pos 0134: 170 */ 0x00, 0x15 /* - terminal marker 21 - */,
/* pos 0136: 171 */ 0xE1 /* 'a' -> */,
/* pos 0137: 172 */ 0xE7 /* 'g' -> */,
/* pos 0138: 173 */ 0xED /* 'm' -> */,
/* pos 0139: 174 */ 0xE1 /* 'a' -> */,
/* pos 013a: 175 */ 0xBA /* ':' -> */,
/* pos 013b: 176 */ 0x00, 0x16 /* - terminal marker 22 - */,
/* pos 013d: 177 */ 0xE3 /* 'c' -> */,
/* pos 013e: 178 */ 0xE8 /* 'h' -> */,
/* pos 013f: 179 */ 0xE5 /* 'e' -> */,
/* pos 0140: 180 */ 0xAD /* '-' -> */,
/* pos 0141: 181 */ 0xE3 /* 'c' -> */,
/* pos 0142: 182 */ 0xEF /* 'o' -> */,
/* pos 0143: 183 */ 0xEE /* 'n' -> */,
/* pos 0144: 184 */ 0xF4 /* 't' -> */,
/* pos 0145: 185 */ 0xF2 /* 'r' -> */,
/* pos 0146: 186 */ 0xEF /* 'o' -> */,
/* pos 0147: 187 */ 0xEC /* 'l' -> */,
/* pos 0148: 188 */ 0xBA /* ':' -> */,
/* pos 0149: 189 */ 0x00, 0x17 /* - terminal marker 23 - */,
/* pos 014b: 190 */ 0xF4 /* 't' -> */,
/* pos 014c: 191 */ 0xE8 /* 'h' -> */,
/* pos 014d: 192 */ 0xEF /* 'o' -> */,
/* pos 014e: 193 */ 0xF2 /* 'r' -> */,
/* pos 014f: 194 */ 0xE9 /* 'i' -> */,
/* pos 0150: 195 */ 0xFA /* 'z' -> */,
/* pos 0151: 196 */ 0xE1 /* 'a' -> */,
/* pos 0152: 197 */ 0xF4 /* 't' -> */,
/* pos 0153: 198 */ 0xE9 /* 'i' -> */,
/* pos 0154: 199 */ 0xEF /* 'o' -> */,
/* pos 0155: 200 */ 0xEE /* 'n' -> */,
/* pos 0156: 201 */ 0xBA /* ':' -> */,
/* pos 0157: 202 */ 0x00, 0x18 /* - terminal marker 24 - */,
/* pos 0159: 203 */ 0xEB /* 'k' -> */,
/* pos 015a: 204 */ 0xE9 /* 'i' -> */,
/* pos 015b: 205 */ 0xE5 /* 'e' -> */,
/* pos 015c: 206 */ 0xBA /* ':' -> */,
/* pos 015d: 207 */ 0x00, 0x19 /* - terminal marker 25 - */,
/* pos 015f: 208 */ 0xE5 /* 'e' -> */,
/* pos 0160: 209 */ 0xEE /* 'n' -> */,
/* pos 0161: 210 */ 0xF4 /* 't' -> */,
/* pos 0162: 211 */ 0xAD /* '-' -> */,
/* pos 0163: 212 */ 0x6C /* 'l' */, 0x07, 0x00 /* (to 0x016A state 213) */,
0x74 /* 't' */, 0x0C, 0x00 /* (to 0x0172 state 220) */,
0x08, /* fail */
/* pos 016a: 213 */ 0xE5 /* 'e' -> */,
/* pos 016b: 214 */ 0xEE /* 'n' -> */,
/* pos 016c: 215 */ 0xE7 /* 'g' -> */,
/* pos 016d: 216 */ 0xF4 /* 't' -> */,
/* pos 016e: 217 */ 0xE8 /* 'h' -> */,
/* pos 016f: 218 */ 0xBA /* ':' -> */,
/* pos 0170: 219 */ 0x00, 0x1A /* - terminal marker 26 - */,
/* pos 0172: 220 */ 0xF9 /* 'y' -> */,
/* pos 0173: 221 */ 0xF0 /* 'p' -> */,
/* pos 0174: 222 */ 0xE5 /* 'e' -> */,
/* pos 0175: 223 */ 0xBA /* ':' -> */,
/* pos 0176: 224 */ 0x00, 0x1B /* - terminal marker 27 - */,
/* pos 0178: 225 */ 0xE1 /* 'a' -> */,
/* pos 0179: 226 */ 0xF4 /* 't' -> */,
/* pos 017a: 227 */ 0xE5 /* 'e' -> */,
/* pos 017b: 228 */ 0xBA /* ':' -> */,
/* pos 017c: 229 */ 0x00, 0x1C /* - terminal marker 28 - */,
/* pos 017e: 230 */ 0x61 /* 'a' */, 0x07, 0x00 /* (to 0x0185 state 231) */,
0x65 /* 'e' */, 0x0A, 0x00 /* (to 0x018B state 236) */,
0x08, /* fail */
/* pos 0185: 231 */ 0xEE /* 'n' -> */,
/* pos 0186: 232 */ 0xE7 /* 'g' -> */,
/* pos 0187: 233 */ 0xE5 /* 'e' -> */,
/* pos 0188: 234 */ 0xBA /* ':' -> */,
/* pos 0189: 235 */ 0x00, 0x1D /* - terminal marker 29 - */,
/* pos 018b: 236 */ 0xE6 /* 'f' -> */,
/* pos 018c: 237 */ 0xE5 /* 'e' -> */,
/* pos 018d: 238 */ 0xF2 /* 'r' -> */,
/* pos 018e: 239 */ 0xE5 /* 'e' -> */,
/* pos 018f: 240 */ 0xF2 /* 'r' -> */,
/* pos 0190: 241 */ 0xBA /* ':' -> */,
/* pos 0191: 242 */ 0x00, 0x1E /* - terminal marker 30 - */,
/* total size 403 bytes */

View File

@ -1,766 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
#if HOST_OS == OS_WINDOWS
#pragma comment(lib, "Ws2_32.lib")
#endif
int log_level = LLL_ERR | LLL_WARN | LLL_NOTICE;
static void (*lwsl_emit)(int level, const char *line) = lwsl_emit_stderr;
static const char * const log_level_names[] = {
"ERR",
"WARN",
"NOTICE",
"INFO",
"DEBUG",
"PARSER",
"HEADER",
"EXTENSION",
"CLIENT",
"LATENCY",
};
void
libwebsocket_close_and_free_session(struct libwebsocket_context *context,
struct libwebsocket *wsi, enum lws_close_status reason)
{
int n, m, ret;
int old_state;
unsigned char buf[LWS_SEND_BUFFER_PRE_PADDING + 2 +
LWS_SEND_BUFFER_POST_PADDING];
struct lws_tokens eff_buf;
if (!wsi)
return;
old_state = wsi->state;
switch (old_state) {
case WSI_STATE_DEAD_SOCKET:
return;
/* we tried the polite way... */
case WSI_STATE_AWAITING_CLOSE_ACK:
goto just_kill_connection;
case WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE:
if (wsi->truncated_send_len) {
libwebsocket_callback_on_writable(context, wsi);
return;
}
lwsl_info("wsi %p completed WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi);
goto just_kill_connection;
default:
if (wsi->truncated_send_len) {
lwsl_info("wsi %p entering WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE\n", wsi);
wsi->state = WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE;
return;
}
break;
}
wsi->u.ws.close_reason = reason;
if (wsi->mode == LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT ||
wsi->mode == LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE) {
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLIENT_CONNECTION_ERROR, NULL, NULL, 0);
free(wsi->u.hdr.ah);
goto just_kill_connection;
}
if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED) {
if (wsi->u.http.post_buffer) {
free(wsi->u.http.post_buffer);
wsi->u.http.post_buffer = NULL;
}
if (wsi->u.http.fd != LWS_INVALID_FILE) {
lwsl_debug("closing http file\n");
compatible_file_close(wsi->u.http.fd);
wsi->u.http.fd = LWS_INVALID_FILE;
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0);
}
}
/*
* are his extensions okay with him closing? Eg he might be a mux
* parent and just his ch1 aspect is closing?
*/
if (lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_CHECK_OK_TO_REALLY_CLOSE, NULL, 0) > 0) {
lwsl_ext("extension vetoed close\n");
return;
}
/*
* flush any tx pending from extensions, since we may send close packet
* if there are problems with send, just nuke the connection
*/
do {
ret = 0;
eff_buf.token = NULL;
eff_buf.token_len = 0;
/* show every extension the new incoming data */
m = lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_FLUSH_PENDING_TX, &eff_buf, 0);
if (m < 0) {
lwsl_ext("Extension reports fatal error\n");
goto just_kill_connection;
}
if (m)
/*
* at least one extension told us he has more
* to spill, so we will go around again after
*/
ret = 1;
/* assuming they left us something to send, send it */
if (eff_buf.token_len)
if (lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
eff_buf.token_len) != eff_buf.token_len) {
lwsl_debug("close: ext spill failed\n");
goto just_kill_connection;
}
} while (ret);
/*
* signal we are closing, libsocket_write will
* add any necessary version-specific stuff. If the write fails,
* no worries we are closing anyway. If we didn't initiate this
* close, then our state has been changed to
* WSI_STATE_RETURNED_CLOSE_ALREADY and we will skip this.
*
* Likewise if it's a second call to close this connection after we
* sent the close indication to the peer already, we are in state
* WSI_STATE_AWAITING_CLOSE_ACK and will skip doing this a second time.
*/
if (old_state == WSI_STATE_ESTABLISHED &&
reason != LWS_CLOSE_STATUS_NOSTATUS) {
lwsl_debug("sending close indication...\n");
/* make valgrind happy */
memset(buf, 0, sizeof(buf));
n = libwebsocket_write(wsi,
&buf[LWS_SEND_BUFFER_PRE_PADDING + 2],
0, LWS_WRITE_CLOSE);
if (n >= 0) {
/*
* we have sent a nice protocol level indication we
* now wish to close, we should not send anything more
*/
wsi->state = WSI_STATE_AWAITING_CLOSE_ACK;
/*
* ...and we should wait for a reply for a bit
* out of politeness
*/
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_CLOSE_ACK, 1);
lwsl_debug("sent close indication, awaiting ack\n");
return;
}
lwsl_info("close: sending close packet failed, hanging up\n");
/* else, the send failed and we should just hang up */
}
just_kill_connection:
lwsl_debug("close: just_kill_connection\n");
/*
* we won't be servicing or receiving anything further from this guy
* delete socket from the internal poll list if still present
*/
remove_wsi_socket_from_fds(context, wsi);
wsi->state = WSI_STATE_DEAD_SOCKET;
if ((old_state == WSI_STATE_ESTABLISHED ||
wsi->mode == LWS_CONNMODE_WS_SERVING ||
wsi->mode == LWS_CONNMODE_WS_CLIENT)) {
if (wsi->u.ws.rx_user_buffer) {
free(wsi->u.ws.rx_user_buffer);
wsi->u.ws.rx_user_buffer = NULL;
}
if (wsi->u.ws.rxflow_buffer) {
free(wsi->u.ws.rxflow_buffer);
wsi->u.ws.rxflow_buffer = NULL;
}
if (wsi->truncated_send_malloc) {
/* not going to be completed... nuke it */
free(wsi->truncated_send_malloc);
wsi->truncated_send_malloc = NULL;
wsi->truncated_send_len = 0;
}
}
/* tell the user it's all over for this guy */
if (wsi->protocol && wsi->protocol->callback &&
((old_state == WSI_STATE_ESTABLISHED) ||
(old_state == WSI_STATE_RETURNED_CLOSE_ALREADY) ||
(old_state == WSI_STATE_AWAITING_CLOSE_ACK))) {
lwsl_debug("calling back CLOSED\n");
wsi->protocol->callback(context, wsi, LWS_CALLBACK_CLOSED,
wsi->user_space, NULL, 0);
} else if (wsi->mode == LWS_CONNMODE_HTTP_SERVING_ACCEPTED) {
lwsl_debug("calling back CLOSED_HTTP\n");
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CLOSED_HTTP, wsi->user_space, NULL, 0 );
} else
lwsl_debug("not calling back closed\n");
/* deallocate any active extension contexts */
if (lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_DESTROY, NULL, 0) < 0)
lwsl_warn("extension destruction failed\n");
#ifndef LWS_NO_EXTENSIONS
for (n = 0; n < wsi->count_active_extensions; n++)
free(wsi->active_extensions_user[n]);
#endif
/*
* inform all extensions in case they tracked this guy out of band
* even though not active on him specifically
*/
if (lws_ext_callback_for_each_extension_type(context, wsi,
LWS_EXT_CALLBACK_DESTROY_ANY_WSI_CLOSING, NULL, 0) < 0)
lwsl_warn("ext destroy wsi failed\n");
/* lwsl_info("closing fd=%d\n", wsi->sock); */
if (!lws_ssl_close(wsi) && wsi->sock >= 0) {
n = shutdown(wsi->sock, SHUT_RDWR);
if (n)
lwsl_debug("closing: shutdown ret %d\n", LWS_ERRNO);
n = compatible_close(wsi->sock);
if (n)
lwsl_debug("closing: close ret %d\n", LWS_ERRNO);
}
/* outermost destroy notification for wsi (user_space still intact) */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_WSI_DESTROY, wsi->user_space, NULL, 0);
if (wsi->protocol && wsi->protocol->per_session_data_size &&
wsi->user_space) /* user code may own */
free(wsi->user_space);
free(wsi);
}
/**
* libwebsockets_get_peer_addresses() - Get client address information
* @context: Libwebsockets context
* @wsi: Local struct libwebsocket associated with
* @fd: Connection socket descriptor
* @name: Buffer to take client address name
* @name_len: Length of client address name buffer
* @rip: Buffer to take client address IP qotted quad
* @rip_len: Length of client address IP buffer
*
* This function fills in @name and @rip with the name and IP of
* the client connected with socket descriptor @fd. Names may be
* truncated if there is not enough room. If either cannot be
* determined, they will be returned as valid zero-length strings.
*/
LWS_VISIBLE void
libwebsockets_get_peer_addresses(struct libwebsocket_context *context,
struct libwebsocket *wsi, int fd, char *name, int name_len,
char *rip, int rip_len)
{
socklen_t len;
#ifdef LWS_USE_IPV6
struct sockaddr_in6 sin6;
#endif
struct sockaddr_in sin4;
struct hostent *host;
struct hostent *host1;
char ip[128];
unsigned char *p;
int n;
#ifdef AF_LOCAL
struct sockaddr_un *un;
#endif
int ret = -1;
rip[0] = '\0';
name[0] = '\0';
lws_latency_pre(context, wsi);
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context)) {
len = sizeof(sin6);
if (getpeername(fd, (struct sockaddr *) &sin6, &len) < 0) {
lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
goto bail;
}
if (!lws_plat_inet_ntop(AF_INET6, &sin6.sin6_addr, rip, rip_len)) {
lwsl_err("inet_ntop", strerror(LWS_ERRNO));
goto bail;
}
// Strip off the IPv4 to IPv6 header if one exists
if (strncmp(rip, "::ffff:", 7) == 0)
memmove(rip, rip + 7, strlen(rip) - 6);
getnameinfo((struct sockaddr *)&sin6,
sizeof(struct sockaddr_in6), name,
name_len, NULL, 0, 0);
} else
#endif
{
len = sizeof(sin4);
if (getpeername(fd, (struct sockaddr *) &sin4, &len) < 0) {
lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
goto bail;
}
host = gethostbyaddr((char *) &sin4.sin_addr,
sizeof(sin4.sin_addr), AF_INET);
if (host == NULL) {
lwsl_warn("gethostbyaddr: %s\n", strerror(LWS_ERRNO));
goto bail;
}
strncpy(name, host->h_name, name_len);
name[name_len - 1] = '\0';
host1 = gethostbyname(host->h_name);
if (host1 == NULL)
goto bail;
p = (unsigned char *)host1;
n = 0;
while (p != NULL) {
p = (unsigned char *)host1->h_addr_list[n++];
if (p == NULL)
continue;
if ((host1->h_addrtype != AF_INET)
#ifdef AF_LOCAL
&& (host1->h_addrtype != AF_LOCAL)
#endif
)
continue;
if (host1->h_addrtype == AF_INET)
sprintf(ip, "%u.%u.%u.%u",
p[0], p[1], p[2], p[3]);
#ifdef AF_LOCAL
else {
un = (struct sockaddr_un *)p;
strncpy(ip, un->sun_path, sizeof(ip) - 1);
ip[sizeof(ip) - 1] = '\0';
}
#endif
p = NULL;
strncpy(rip, ip, rip_len);
rip[rip_len - 1] = '\0';
}
}
ret = 0;
bail:
lws_latency(context, wsi, "libwebsockets_get_peer_addresses", ret, 1);
}
/**
* libwebsocket_context_user() - get the user data associated with the context
* @context: Websocket context
*
* This returns the optional user allocation that can be attached to
* the context the sockets live in at context_create time. It's a way
* to let all sockets serviced in the same context share data without
* using globals statics in the user code.
*/
LWS_EXTERN void *
libwebsocket_context_user(struct libwebsocket_context *context)
{
return context->user_space;
}
/**
* libwebsocket_callback_all_protocol() - Callback all connections using
* the given protocol with the given reason
*
* @protocol: Protocol whose connections will get callbacks
* @reason: Callback reason index
*/
LWS_VISIBLE int
libwebsocket_callback_all_protocol(
const struct libwebsocket_protocols *protocol, int reason)
{
struct libwebsocket_context *context = protocol->owning_server;
int n;
struct libwebsocket *wsi;
for (n = 0; n < context->fds_count; n++) {
wsi = context->lws_lookup[context->fds[n].fd];
if (!wsi)
continue;
if (wsi->protocol == protocol)
protocol->callback(context, wsi,
reason, wsi->user_space, NULL, 0);
}
return 0;
}
/**
* libwebsocket_set_timeout() - marks the wsi as subject to a timeout
*
* You will not need this unless you are doing something special
*
* @wsi: Websocket connection instance
* @reason: timeout reason
* @secs: how many seconds
*/
LWS_VISIBLE void
libwebsocket_set_timeout(struct libwebsocket *wsi,
enum pending_timeout reason, int secs)
{
time_t now;
time(&now);
wsi->pending_timeout_limit = now + secs;
wsi->pending_timeout = reason;
}
/**
* libwebsocket_get_socket_fd() - returns the socket file descriptor
*
* You will not need this unless you are doing something special
*
* @wsi: Websocket connection instance
*/
LWS_VISIBLE int
libwebsocket_get_socket_fd(struct libwebsocket *wsi)
{
return wsi->sock;
}
#ifdef LWS_LATENCY
void
lws_latency(struct libwebsocket_context *context, struct libwebsocket *wsi,
const char *action, int ret, int completed)
{
unsigned long long u;
char buf[256];
u = time_in_microseconds();
if (!action) {
wsi->latency_start = u;
if (!wsi->action_start)
wsi->action_start = u;
return;
}
if (completed) {
if (wsi->action_start == wsi->latency_start)
sprintf(buf,
"Completion first try lat %luus: %p: ret %d: %s\n",
u - wsi->latency_start,
(void *)wsi, ret, action);
else
sprintf(buf,
"Completion %luus: lat %luus: %p: ret %d: %s\n",
u - wsi->action_start,
u - wsi->latency_start,
(void *)wsi, ret, action);
wsi->action_start = 0;
} else
sprintf(buf, "lat %luus: %p: ret %d: %s\n",
u - wsi->latency_start, (void *)wsi, ret, action);
if (u - wsi->latency_start > context->worst_latency) {
context->worst_latency = u - wsi->latency_start;
strcpy(context->worst_latency_info, buf);
}
lwsl_latency("%s", buf);
}
#endif
/**
* libwebsocket_rx_flow_control() - Enable and disable socket servicing for
* receieved packets.
*
* If the output side of a server process becomes choked, this allows flow
* control for the input side.
*
* @wsi: Websocket connection instance to get callback for
* @enable: 0 = disable read servicing for this connection, 1 = enable
*/
LWS_VISIBLE int
libwebsocket_rx_flow_control(struct libwebsocket *wsi, int enable)
{
if (enable == (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW))
return 0;
lwsl_info("libwebsocket_rx_flow_control(0x%p, %d)\n", wsi, enable);
wsi->u.ws.rxflow_change_to = LWS_RXFLOW_PENDING_CHANGE | !!enable;
return 0;
}
/**
* libwebsocket_rx_flow_allow_all_protocol() - Allow all connections with this protocol to receive
*
* When the user server code realizes it can accept more input, it can
* call this to have the RX flow restriction removed from all connections using
* the given protocol.
*
* @protocol: all connections using this protocol will be allowed to receive
*/
LWS_VISIBLE void
libwebsocket_rx_flow_allow_all_protocol(
const struct libwebsocket_protocols *protocol)
{
struct libwebsocket_context *context = protocol->owning_server;
int n;
struct libwebsocket *wsi;
for (n = 0; n < context->fds_count; n++) {
wsi = context->lws_lookup[context->fds[n].fd];
if (!wsi)
continue;
if (wsi->protocol == protocol)
libwebsocket_rx_flow_control(wsi, LWS_RXFLOW_ALLOW);
}
}
/**
* libwebsocket_canonical_hostname() - returns this host's hostname
*
* This is typically used by client code to fill in the host parameter
* when making a client connection. You can only call it after the context
* has been created.
*
* @context: Websocket context
*/
LWS_VISIBLE extern const char *
libwebsocket_canonical_hostname(struct libwebsocket_context *context)
{
return (const char *)context->canonical_hostname;
}
int user_callback_handle_rxflow(callback_function callback_function,
struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len)
{
int n;
n = callback_function(context, wsi, reason, user, in, len);
if (!n)
n = _libwebsocket_rx_flow_control(wsi);
return n;
}
/**
* libwebsocket_set_proxy() - Setups proxy to libwebsocket_context.
* @context: pointer to struct libwebsocket_context you want set proxy to
* @proxy: pointer to c string containing proxy in format address:port
*
* Returns 0 if proxy string was parsed and proxy was setup.
* Returns -1 if @proxy is NULL or has incorrect format.
*
* This is only required if your OS does not provide the http_proxy
* enviroment variable (eg, OSX)
*
* IMPORTANT! You should call this function right after creation of the
* libwebsocket_context and before call to connect. If you call this
* function after connect behavior is undefined.
* This function will override proxy settings made on libwebsocket_context
* creation with genenv() call.
*/
LWS_VISIBLE int
libwebsocket_set_proxy(struct libwebsocket_context *context, const char *proxy)
{
char *p;
if (!proxy)
return -1;
strncpy(context->http_proxy_address, proxy,
sizeof(context->http_proxy_address) - 1);
context->http_proxy_address[
sizeof(context->http_proxy_address) - 1] = '\0';
p = strchr(context->http_proxy_address, ':');
if (!p) {
lwsl_err("http_proxy needs to be ads:port\n");
return -1;
}
*p = '\0';
context->http_proxy_port = atoi(p + 1);
lwsl_notice(" Proxy %s:%u\n", context->http_proxy_address,
context->http_proxy_port);
return 0;
}
/**
* libwebsockets_get_protocol() - Returns a protocol pointer from a websocket
* connection.
* @wsi: pointer to struct websocket you want to know the protocol of
*
*
* Some apis can act on all live connections of a given protocol,
* this is how you can get a pointer to the active protocol if needed.
*/
LWS_VISIBLE const struct libwebsocket_protocols *
libwebsockets_get_protocol(struct libwebsocket *wsi)
{
return wsi->protocol;
}
LWS_VISIBLE int
libwebsocket_is_final_fragment(struct libwebsocket *wsi)
{
return wsi->u.ws.final;
}
LWS_VISIBLE unsigned char
libwebsocket_get_reserved_bits(struct libwebsocket *wsi)
{
return wsi->u.ws.rsv;
}
int
libwebsocket_ensure_user_space(struct libwebsocket *wsi)
{
if (!wsi->protocol)
return 1;
/* allocate the per-connection user memory (if any) */
if (wsi->protocol->per_session_data_size && !wsi->user_space) {
wsi->user_space = malloc(
wsi->protocol->per_session_data_size);
if (wsi->user_space == NULL) {
lwsl_err("Out of memory for conn user space\n");
return 1;
}
memset(wsi->user_space, 0,
wsi->protocol->per_session_data_size);
}
return 0;
}
LWS_VISIBLE void lwsl_emit_stderr(int level, const char *line)
{
char buf[300];
unsigned long long now;
int n;
buf[0] = '\0';
for (n = 0; n < LLL_COUNT; n++)
if (level == (1 << n)) {
now = time_in_microseconds() / 100;
sprintf(buf, "[%lu:%04d] %s: ", (unsigned long) now / 10000,
(int)(now % 10000), log_level_names[n]);
break;
}
fprintf(stderr, "%s%s", buf, line);
}
LWS_VISIBLE void _lws_log(int filter, const char *format, ...)
{
char buf[256];
va_list ap;
if (!(log_level & filter))
return;
va_start(ap, format);
vsnprintf(buf, sizeof(buf), format, ap);
buf[sizeof(buf) - 1] = '\0';
va_end(ap);
lwsl_emit(filter, buf);
}
/**
* lws_set_log_level() - Set the logging bitfield
* @level: OR together the LLL_ debug contexts you want output from
* @log_emit_function: NULL to leave it as it is, or a user-supplied
* function to perform log string emission instead of
* the default stderr one.
*
* log level defaults to "err", "warn" and "notice" contexts enabled and
* emission on stderr.
*/
LWS_VISIBLE void lws_set_log_level(int level, void (*log_emit_function)(int level,
const char *line))
{
log_level = level;
if (log_emit_function)
lwsl_emit = log_emit_function;
}

File diff suppressed because it is too large Load Diff

View File

@ -1,396 +0,0 @@
#include "private-libwebsockets.h"
#include "build.h"
#if HOST_OS != OS_WINDOWS
/*
* included from libwebsockets.c for unix builds
*/
unsigned long long time_in_microseconds(void)
{
struct timeval tv;
gettimeofday(&tv, NULL);
return (tv.tv_sec * 1000000) + tv.tv_usec;
}
LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
void *buf, int len)
{
return read(context->fd_random, (char *)buf, len);
}
LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi)
{
struct libwebsocket_pollfd fds;
/* treat the fact we got a truncated send pending as if we're choked */
if (wsi->truncated_send_len)
return 1;
fds.fd = wsi->sock;
fds.events = POLLOUT;
fds.revents = 0;
if (poll(&fds, 1, 0) != 1)
return 1;
if ((fds.revents & POLLOUT) == 0)
return 1;
/* okay to send another packet without blocking */
return 0;
}
LWS_VISIBLE int
lws_poll_listen_fd(struct libwebsocket_pollfd *fd)
{
return poll(fd, 1, 0);
}
/*
* This is just used to interrupt poll waiting
* we don't have to do anything with it.
*/
static void lws_sigusr2(int sig)
{
}
/**
* libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
* @context: Websocket context
*
* This function let a call to libwebsocket_service() waiting for a timeout
* immediately return.
*/
LWS_VISIBLE void
libwebsocket_cancel_service(struct libwebsocket_context *context)
{
char buf = 0;
if (write(context->dummy_pipe_fds[1], &buf, sizeof(buf)) != 1)
lwsl_err("Cannot write to dummy pipe");
}
LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
{
/*
int syslog_level = LOG_DEBUG;
switch (level) {
case LLL_ERR:
syslog_level = LOG_ERR;
break;
case LLL_WARN:
syslog_level = LOG_WARNING;
break;
case LLL_NOTICE:
syslog_level = LOG_NOTICE;
break;
case LLL_INFO:
syslog_level = LOG_INFO;
break;
}
*/
printf("%s", line);
}
LWS_VISIBLE int
lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
{
int n;
int m;
char buf;
/* stay dead once we are dead */
if (!context)
return 1;
lws_libev_run(context);
context->service_tid = context->protocols[0].callback(context, NULL,
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
n = poll(context->fds, context->fds_count, timeout_ms);
context->service_tid = 0;
if (n == 0) /* poll timeout */ {
libwebsocket_service_fd(context, NULL);
return 0;
}
if (n < 0) {
if (LWS_ERRNO != LWS_EINTR)
return -1;
return 0;
}
/* any socket with events to service? */
for (n = 0; n < context->fds_count; n++) {
if (!context->fds[n].revents)
continue;
if (context->fds[n].fd == context->dummy_pipe_fds[0]) {
if (read(context->fds[n].fd, &buf, 1) != 1)
lwsl_err("Cannot read from dummy pipe.");
continue;
}
m = libwebsocket_service_fd(context, &context->fds[n]);
if (m < 0)
return -1;
/* if something closed, retry this slot */
if (m)
n--;
}
return 0;
}
LWS_VISIBLE int
lws_plat_set_socket_options(struct libwebsocket_context *context, int fd)
{
int optval = 1;
socklen_t optlen = sizeof(optval);
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__)
struct protoent *tcp_proto;
#endif
if (context->ka_time) {
/* enable keepalive on this socket */
optval = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
(const void *)&optval, optlen) < 0)
return 1;
#if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__CYGWIN__)
/*
* didn't find a way to set these per-socket, need to
* tune kernel systemwide values
*/
#else
/* set the keepalive conditions we want on it too */
optval = context->ka_time;
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPIDLE,
(const void *)&optval, optlen) < 0)
return 1;
optval = context->ka_interval;
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPINTVL,
(const void *)&optval, optlen) < 0)
return 1;
optval = context->ka_probes;
if (setsockopt(fd, IPPROTO_IP, TCP_KEEPCNT,
(const void *)&optval, optlen) < 0)
return 1;
#endif
}
/* Disable Nagle */
optval = 1;
#if !defined(__APPLE__) && !defined(__FreeBSD__) && !defined(__NetBSD__)
setsockopt(fd, SOL_TCP, TCP_NODELAY, (const void *)&optval, optlen);
#else
tcp_proto = getprotobyname("TCP");
setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, &optval, optlen);
#endif
/* We are nonblocking... */
fcntl(fd, F_SETFL, O_NONBLOCK);
return 0;
}
LWS_VISIBLE void
lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
{
if (info->gid != -1)
if (setgid(info->gid))
lwsl_warn("setgid: %s\n", strerror(LWS_ERRNO));
if (info->uid != -1)
if (setuid(info->uid))
lwsl_warn("setuid: %s\n", strerror(LWS_ERRNO));
}
LWS_VISIBLE int
lws_plat_init_fd_tables(struct libwebsocket_context *context)
{
if (lws_libev_init_fd_table(context))
/* libev handled it instead */
return 0;
if (pipe(context->dummy_pipe_fds)) {
lwsl_err("Unable to create pipe\n");
return 1;
}
/* use the read end of pipe as first item */
context->fds[0].fd = context->dummy_pipe_fds[0];
context->fds[0].events = LWS_POLLIN;
context->fds[0].revents = 0;
context->fds_count = 1;
context->fd_random = open(SYSTEM_RANDOM_FILEPATH, O_RDONLY);
if (context->fd_random < 0) {
lwsl_err("Unable to open random device %s %d\n",
SYSTEM_RANDOM_FILEPATH, context->fd_random);
return 1;
}
return 0;
}
static void sigpipe_handler(int x)
{
}
LWS_VISIBLE int
lws_plat_context_early_init(void)
{
sigset_t mask;
signal(SIGUSR2, lws_sigusr2);
sigemptyset(&mask);
sigaddset(&mask, SIGUSR2);
sigprocmask(SIG_BLOCK, &mask, NULL);
signal(SIGPIPE, sigpipe_handler);
return 0;
}
LWS_VISIBLE void
lws_plat_context_early_destroy(struct libwebsocket_context *context)
{
}
LWS_VISIBLE void
lws_plat_context_late_destroy(struct libwebsocket_context *context)
{
close(context->dummy_pipe_fds[0]);
close(context->dummy_pipe_fds[1]);
close(context->fd_random);
}
/* cast a struct sockaddr_in6 * into addr for ipv6 */
LWS_VISIBLE int
interface_to_sa(struct libwebsocket_context *context,
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
{
int rc = -1;
struct ifaddrs *ifr;
struct ifaddrs *ifc;
#ifdef LWS_USE_IPV6
struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr;
#endif
getifaddrs(&ifr);
for (ifc = ifr; ifc != NULL && rc; ifc = ifc->ifa_next) {
if (!ifc->ifa_addr)
continue;
lwsl_info(" interface %s vs %s\n", ifc->ifa_name, ifname);
if (strcmp(ifc->ifa_name, ifname))
continue;
switch (ifc->ifa_addr->sa_family) {
case AF_INET:
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context)) {
/* map IPv4 to IPv6 */
bzero((char *)&addr6->sin6_addr,
sizeof(struct in6_addr));
addr6->sin6_addr.s6_addr[10] = 0xff;
addr6->sin6_addr.s6_addr[11] = 0xff;
memcpy(&addr6->sin6_addr.s6_addr[12],
&((struct sockaddr_in *)ifc->ifa_addr)->sin_addr,
sizeof(struct in_addr));
} else
#endif
memcpy(addr,
(struct sockaddr_in *)ifc->ifa_addr,
sizeof(struct sockaddr_in));
break;
#ifdef LWS_USE_IPV6
case AF_INET6:
if (rc >= 0)
break;
memcpy(&addr6->sin6_addr,
&((struct sockaddr_in6 *)ifc->ifa_addr)->sin6_addr,
sizeof(struct in6_addr));
break;
#endif
default:
continue;
}
rc = 0;
}
freeifaddrs(ifr);
return rc;
}
LWS_VISIBLE void
lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi)
{
lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_READ);
context->fds[context->fds_count++].revents = 0;
}
LWS_VISIBLE void
lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi, int m)
{
}
LWS_VISIBLE void
lws_plat_service_periodic(struct libwebsocket_context *context)
{
/* if our parent went down, don't linger around */
if (context->started_with_parent &&
kill(context->started_with_parent, 0) < 0)
kill(getpid(), SIGTERM);
}
LWS_VISIBLE int
lws_plat_change_pollfd(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd)
{
return 0;
}
LWS_VISIBLE int
lws_plat_open_file(const char* filename, unsigned long* filelen)
{
struct stat stat_buf;
int ret = open(filename, O_RDONLY);
if (ret < 0)
return LWS_INVALID_FILE;
fstat(ret, &stat_buf);
*filelen = stat_buf.st_size;
return ret;
}
#ifdef LWS_USE_IPV6
LWS_VISIBLE const char *
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
{
return inet_ntop(af, src, dst, cnt);
}
#endif
#endif

View File

@ -1,365 +0,0 @@
#include "private-libwebsockets.h"
#include "build.h"
#if HOST_OS == OS_WINDOWS
unsigned long long
time_in_microseconds()
{
#define DELTA_EPOCH_IN_MICROSECS 11644473600000000ULL
FILETIME filetime;
ULARGE_INTEGER datetime;
#ifdef _WIN32_WCE
GetCurrentFT(&filetime);
#else
GetSystemTimeAsFileTime(&filetime);
#endif
/*
* As per Windows documentation for FILETIME, copy the resulting FILETIME structure to a
* ULARGE_INTEGER structure using memcpy (using memcpy instead of direct assignment can
* prevent alignment faults on 64-bit Windows).
*/
memcpy(&datetime, &filetime, sizeof(datetime));
/* Windows file times are in 100s of nanoseconds. */
return (datetime.QuadPart - DELTA_EPOCH_IN_MICROSECS) / 10;
}
#ifdef _WIN32_WCE
time_t time(time_t *t)
{
time_t ret = time_in_microseconds() / 1000000;
*t = ret;
return ret;
}
#endif
LWS_VISIBLE int libwebsockets_get_random(struct libwebsocket_context *context,
void *buf, int len)
{
int n;
char *p = (char *)buf;
for (n = 0; n < len; n++)
p[n] = (unsigned char)rand();
return n;
}
LWS_VISIBLE int lws_send_pipe_choked(struct libwebsocket *wsi)
{
return wsi->sock_send_blocking;
}
LWS_VISIBLE int lws_poll_listen_fd(struct libwebsocket_pollfd *fd)
{
fd_set readfds;
struct timeval tv = { 0, 0 };
assert(fd->events == LWS_POLLIN);
FD_ZERO(&readfds);
FD_SET(fd->fd, &readfds);
return select(fd->fd + 1, &readfds, NULL, NULL, &tv);
}
/**
* libwebsocket_cancel_service() - Cancel servicing of pending websocket activity
* @context: Websocket context
*
* This function let a call to libwebsocket_service() waiting for a timeout
* immediately return.
*/
LWS_VISIBLE void
libwebsocket_cancel_service(struct libwebsocket_context *context)
{
WSASetEvent(context->events[0]);
}
LWS_VISIBLE void lwsl_emit_syslog(int level, const char *line)
{
lwsl_emit_stderr(level, line);
}
LWS_VISIBLE int
lws_plat_service(struct libwebsocket_context *context, int timeout_ms)
{
int n;
int i;
DWORD ev;
WSANETWORKEVENTS networkevents;
struct libwebsocket_pollfd *pfd;
/* stay dead once we are dead */
if (context == NULL)
return 1;
context->service_tid = context->protocols[0].callback(context, NULL,
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
for (i = 0; i < context->fds_count; ++i) {
pfd = &context->fds[i];
if (pfd->fd == context->listen_service_fd)
continue;
if (pfd->events & LWS_POLLOUT) {
if (context->lws_lookup[pfd->fd]->sock_send_blocking)
continue;
pfd->revents = LWS_POLLOUT;
n = libwebsocket_service_fd(context, pfd);
if (n < 0)
return n;
}
}
ev = WSAWaitForMultipleEvents(context->fds_count + 1,
context->events, FALSE, timeout_ms, FALSE);
context->service_tid = 0;
if (ev == WSA_WAIT_TIMEOUT) {
libwebsocket_service_fd(context, NULL);
return 0;
}
if (ev == WSA_WAIT_EVENT_0) {
WSAResetEvent(context->events[0]);
return 0;
}
if (ev < WSA_WAIT_EVENT_0 || ev > WSA_WAIT_EVENT_0 + context->fds_count)
return -1;
pfd = &context->fds[ev - WSA_WAIT_EVENT_0 - 1];
if (WSAEnumNetworkEvents(pfd->fd,
context->events[ev - WSA_WAIT_EVENT_0],
&networkevents) == SOCKET_ERROR) {
lwsl_err("WSAEnumNetworkEvents() failed with error %d\n",
LWS_ERRNO);
return -1;
}
pfd->revents = networkevents.lNetworkEvents;
if (pfd->revents & LWS_POLLOUT)
context->lws_lookup[pfd->fd]->sock_send_blocking = FALSE;
return libwebsocket_service_fd(context, pfd);
}
LWS_VISIBLE int
lws_plat_set_socket_options(struct libwebsocket_context *context, int fd)
{
int optval = 1;
int optlen = sizeof(optval);
u_long optl = 1;
DWORD dwBytesRet;
struct tcp_keepalive alive;
struct protoent *tcp_proto;
if (context->ka_time) {
/* enable keepalive on this socket */
optval = 1;
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE,
(const char *)&optval, optlen) < 0)
return 1;
alive.onoff = TRUE;
alive.keepalivetime = context->ka_time;
alive.keepaliveinterval = context->ka_interval;
if (WSAIoctl(fd, SIO_KEEPALIVE_VALS, &alive, sizeof(alive),
NULL, 0, &dwBytesRet, NULL, NULL))
return 1;
}
/* Disable Nagle */
optval = 1;
tcp_proto = getprotobyname("TCP");
setsockopt(fd, tcp_proto->p_proto, TCP_NODELAY, (const char *)&optval, optlen);
/* We are nonblocking... */
ioctlsocket(fd, FIONBIO, &optl);
return 0;
}
LWS_VISIBLE void
lws_plat_drop_app_privileges(struct lws_context_creation_info *info)
{
}
LWS_VISIBLE int
lws_plat_init_fd_tables(struct libwebsocket_context *context)
{
context->events = (WSAEVENT *)malloc(sizeof(WSAEVENT) *
(context->max_fds + 1));
if (context->events == NULL) {
lwsl_err("Unable to allocate events array for %d connections\n",
context->max_fds);
return 1;
}
context->fds_count = 0;
context->events[0] = WSACreateEvent();
context->fd_random = 0;
return 0;
}
LWS_VISIBLE int
lws_plat_context_early_init(void)
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
/* Use the MAKEWORD(lowbyte, highbyte) macro from Windef.h */
wVersionRequested = MAKEWORD(2, 2);
err = WSAStartup(wVersionRequested, &wsaData);
if (!err)
return 0;
/*
* Tell the user that we could not find a usable
* Winsock DLL
*/
lwsl_err("WSAStartup failed with error: %d\n", err);
return 1;
}
LWS_VISIBLE void
lws_plat_context_early_destroy(struct libwebsocket_context *context)
{
if (context->events) {
WSACloseEvent(context->events[0]);
free(context->events);
}
}
LWS_VISIBLE void
lws_plat_context_late_destroy(struct libwebsocket_context *context)
{
WSACleanup();
}
LWS_VISIBLE int
interface_to_sa(struct libwebsocket_context *context,
const char *ifname, struct sockaddr_in *addr, size_t addrlen)
{
return -1;
}
LWS_VISIBLE void
lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi)
{
context->fds[context->fds_count++].revents = 0;
context->events[context->fds_count] = WSACreateEvent();
WSAEventSelect(wsi->sock, context->events[context->fds_count], LWS_POLLIN);
}
LWS_VISIBLE void
lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi, int m)
{
WSACloseEvent(context->events[m + 1]);
context->events[m + 1] = context->events[context->fds_count + 1];
}
LWS_VISIBLE void
lws_plat_service_periodic(struct libwebsocket_context *context)
{
}
LWS_VISIBLE int
lws_plat_change_pollfd(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd)
{
long networkevents = LWS_POLLOUT | LWS_POLLHUP;
if ((pfd->events & LWS_POLLIN))
networkevents |= LWS_POLLIN;
if (WSAEventSelect(wsi->sock,
context->events[wsi->position_in_fds_table + 1],
networkevents) != SOCKET_ERROR)
return 0;
lwsl_err("WSAEventSelect() failed with error %d\n", LWS_ERRNO);
return 1;
}
LWS_VISIBLE HANDLE
lws_plat_open_file(const char* filename, unsigned long* filelen)
{
HANDLE ret;
WCHAR buffer[MAX_PATH];
MultiByteToWideChar(CP_UTF8, 0, filename, -1, buffer,
sizeof(buffer) / sizeof(buffer[0]));
ret = CreateFileW(buffer, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (ret != LWS_INVALID_FILE)
*filelen = GetFileSize(ret, NULL);
return ret;
}
LWS_VISIBLE const char *
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt)
{
WCHAR *buffer;
DWORD bufferlen = cnt;
BOOL ok = FALSE;
buffer = malloc(bufferlen);
if (!buffer) {
lwsl_err("Out of memory\n");
return NULL;
}
if (af == AF_INET) {
struct sockaddr_in srcaddr;
bzero(&srcaddr, sizeof(srcaddr));
srcaddr.sin_family = AF_INET;
memcpy(&(srcaddr.sin_addr), src, sizeof(srcaddr.sin_addr));
if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
ok = TRUE;
#ifdef LWS_USE_IPV6
} else if (af == AF_INET6) {
struct sockaddr_in6 srcaddr;
bzero(&srcaddr, sizeof(srcaddr));
srcaddr.sin6_family = AF_INET6;
memcpy(&(srcaddr.sin6_addr), src, sizeof(srcaddr.sin6_addr));
if (!WSAAddressToStringW((struct sockaddr*)&srcaddr, sizeof(srcaddr), 0, buffer, &bufferlen))
ok = TRUE;
#endif
} else
lwsl_err("Unsupported type\n");
if (!ok) {
int rv = WSAGetLastError();
lwsl_err("WSAAddressToString() : %d\n", rv);
} else {
if (WideCharToMultiByte(CP_ACP, 0, buffer, bufferlen, dst, cnt, 0, NULL) <= 0)
ok = FALSE;
}
free(buffer);
return ok ? dst : NULL;
}
#endif

View File

@ -1,174 +0,0 @@
/* config.h.in. Generated from configure.ac by autoheader. */
#ifndef WIN32
#define _DEBUG
#endif
/* Define to 1 to use CyaSSL as a replacement for OpenSSL.
* LWS_OPENSSL_SUPPORT needs to be set also for this to work. */
/* #undef USE_CYASSL */
/* The Libwebsocket version */
#define LWS_LIBRARY_VERSION "1.3"
/* The current git commit hash that we're building from */
#define LWS_BUILD_HASH "c11b847"
/* Build with OpenSSL support */
/* #undef LWS_OPENSSL_SUPPORT */
/* The client should load and trust CA root certs it finds in the OS */
/* #undef LWS_SSL_CLIENT_USE_OS_CA_CERTS */
/* Sets the path where the client certs should be installed. */
#define LWS_OPENSSL_CLIENT_CERTS "../share"
/* Turn off websocket extensions */
/* #undef LWS_NO_EXTENSIONS */
/* Enable libev io loop */
/* #undef LWS_USE_LIBEV */
/* Build with support for ipv6 */
/* #undef LWS_USE_IPV6 */
/* Build with support for HTTP2 */
/* #undef LWS_USE_HTTP2 */
/* Turn on latency measuring code */
/* #undef LWS_LATENCY */
/* Don't build the daemonizeation api */
#define LWS_NO_DAEMONIZE
/* Build without server support */
/* #undef LWS_NO_SERVER */
/* Build without client support */
/* #undef LWS_NO_CLIENT */
/* If we should compile with MinGW support */
/* #undef LWS_MINGW_SUPPORT */
/* Use the BSD getifaddrs that comes with libwebsocket, for uclibc support */
#define LWS_BUILTIN_GETIFADDRS
/* Define to 1 if you have the `bzero' function. */
/* #undef HAVE_BZERO */
/* Define to 1 if you have the <dlfcn.h> header file. */
/* #undef HAVE_DLFCN_H */
/* Define to 1 if you have the <fcntl.h> header file. */
#define HAVE_FCNTL_H
/* Define to 1 if you have the `fork' function. */
/* #undef HAVE_FORK */
/* Define to 1 if you have the `getenv function. */
#define HAVE_GETENV
/* Define to 1 if you have the <in6addr.h> header file. */
/* #undef HAVE_IN6ADDR_H */
/* Define to 1 if you have the <inttypes.h> header file. */
/* #undef HAVE_INTTYPES_H */
/* Define to 1 if you have the `ssl' library (-lssl). */
/* #undef HAVE_LIBSSL */
/* Define to 1 if your system has a GNU libc compatible `malloc' function, and
to 0 otherwise. */
#define HAVE_MALLOC
/* Define to 1 if you have the <memory.h> header file. */
#define HAVE_MEMORY_H
/* Define to 1 if you have the `memset' function. */
#define HAVE_MEMSET
/* Define to 1 if you have the <netinet/in.h> header file. */
/* #undef HAVE_NETINET_IN_H */
/* Define to 1 if your system has a GNU libc compatible `realloc' function,
and to 0 otherwise. */
#define HAVE_REALLOC
/* Define to 1 if you have the `socket' function. */
/* #undef HAVE_SOCKET */
/* Define to 1 if you have the <stdint.h> header file. */
#define HAVE_STDINT_H
/* Define to 1 if you have the <stdlib.h> header file. */
#define HAVE_STDLIB_H
/* Define to 1 if you have the `strerror' function. */
#define HAVE_STRERROR
/* Define to 1 if you have the <strings.h> header file. */
/* #undef HAVE_STRINGS_H */
/* Define to 1 if you have the <string.h> header file. */
#define HAVE_STRING_H
/* Define to 1 if you have the <sys/prctl.h> header file. */
/* #undef HAVE_SYS_PRCTL_H */
/* Define to 1 if you have the <sys/socket.h> header file. */
/* #undef HAVE_SYS_SOCKET_H */
/* Define to 1 if you have the <sys/stat.h> header file. */
#define HAVE_SYS_STAT_H
/* Define to 1 if you have the <sys/types.h> header file. */
#define HAVE_SYS_TYPES_H
/* Define to 1 if you have the <unistd.h> header file. */
/* #undef HAVE_UNISTD_H */
/* Define to 1 if you have the `vfork' function. */
/* #undef HAVE_VFORK */
/* Define to 1 if you have the <vfork.h> header file. */
/* #undef HAVE_VFORK_H */
/* Define to 1 if `fork' works. */
#define HAVE_WORKING_FORK
/* Define to 1 if `vfork' works. */
#define HAVE_WORKING_VFORK
/* Define to 1 if you have the <zlib.h> header file. */
/* #undef HAVE_ZLIB_H */
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR // We're not using libtool
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS
/* Version number of package */
#define VERSION
/* Define to rpl_malloc if the replacement function should be used. */
/* #undef malloc */
/* Define to `int' if <sys/types.h> does not define. */
#define pid_t
/* Define to rpl_realloc if the replacement function should be used. */
/* #undef realloc */
/* Define to `unsigned int' if <sys/types.h> does not define. */
/* #undef size_t */
/* Define to 1 if we have getifaddrs */
/* #undef HAVE_GETIFADDRS */
/* Define as `fork' if `vfork' does not work. */
/* #undef vfork */
/* Define if the inline keyword doesn't exist. */
#define inline

View File

@ -1,571 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
static int
libwebsocket_0405_frame_mask_generate(struct libwebsocket *wsi)
{
int n;
/* fetch the per-frame nonce */
n = libwebsockets_get_random(wsi->protocol->owning_server,
wsi->u.ws.frame_masking_nonce_04, 4);
if (n != 4) {
lwsl_parser("Unable to read from random device %s %d\n",
SYSTEM_RANDOM_FILEPATH, n);
return 1;
}
/* start masking from first byte of masking key buffer */
wsi->u.ws.frame_mask_index = 0;
return 0;
}
#ifdef _DEBUG
LWS_VISIBLE void lwsl_hexdump(void *vbuf, size_t len)
{
int n;
int m;
int start;
unsigned char *buf = (unsigned char *)vbuf;
char line[80];
char *p;
lwsl_parser("\n");
for (n = 0; n < len;) {
start = n;
p = line;
p += sprintf(p, "%04X: ", start);
for (m = 0; m < 16 && n < len; m++)
p += sprintf(p, "%02X ", buf[n++]);
while (m++ < 16)
p += sprintf(p, " ");
p += sprintf(p, " ");
for (m = 0; m < 16 && (start + m) < len; m++) {
if (buf[start + m] >= ' ' && buf[start + m] < 127)
*p++ = buf[start + m];
else
*p++ = '.';
}
while (m++ < 16)
*p++ = ' ';
*p++ = '\n';
*p = '\0';
lwsl_debug("%s", line);
}
lwsl_debug("\n");
}
#endif
/*
* notice this returns number of bytes consumed, or -1
*/
int lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len)
{
struct libwebsocket_context *context = wsi->protocol->owning_server;
int n;
size_t real_len = len;
int m;
if (!len)
return 0;
/* just ignore sends after we cleared the truncation buffer */
if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE &&
!wsi->truncated_send_len)
return len;
if (wsi->truncated_send_len && (buf < wsi->truncated_send_malloc ||
buf > (wsi->truncated_send_malloc +
wsi->truncated_send_len +
wsi->truncated_send_offset))) {
lwsl_err("****** %x Sending new, pending truncated ...\n", wsi);
assert(0);
}
m = lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_PACKET_TX_DO_SEND, &buf, len);
if (m < 0)
return -1;
if (m) /* handled */ {
n = m;
goto handle_truncated_send;
}
if (wsi->sock < 0)
lwsl_warn("** error invalid sock but expected to send\n");
/*
* nope, send it on the socket directly
*/
lws_latency_pre(context, wsi);
n = lws_ssl_capable_write(wsi, buf, len);
lws_latency(context, wsi, "send lws_issue_raw", n, n == len);
switch (n) {
case LWS_SSL_CAPABLE_ERROR:
return -1;
case LWS_SSL_CAPABLE_MORE_SERVICE:
/* nothing got sent, not fatal, retry the whole thing later */
n = 0;
break;
}
handle_truncated_send:
/*
* we were already handling a truncated send?
*/
if (wsi->truncated_send_len) {
lwsl_info("***** %x partial send moved on by %d (vs %d)\n",
wsi, n, real_len);
wsi->truncated_send_offset += n;
wsi->truncated_send_len -= n;
if (!wsi->truncated_send_len) {
lwsl_info("***** %x partial send completed\n", wsi);
/* done with it, but don't free it */
n = real_len;
if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
lwsl_info("***** %x signalling to close now\n", wsi);
return -1; /* retry closing now */
}
}
/* always callback on writeable */
libwebsocket_callback_on_writable(
wsi->protocol->owning_server, wsi);
return n;
}
if (n == real_len)
/* what we just sent went out cleanly */
return n;
if (n && wsi->u.ws.clean_buffer)
/*
* This buffer unaffected by extension rewriting.
* It means the user code is expected to deal with
* partial sends. (lws knows the header was already
* sent, so on next send will just resume sending
* payload)
*/
return n;
/*
* Newly truncated send. Buffer the remainder (it will get
* first priority next time the socket is writable)
*/
lwsl_info("***** %x new partial sent %d from %d total\n",
wsi, n, real_len);
/*
* - if we still have a suitable malloc lying around, use it
* - or, if too small, reallocate it
* - or, if no buffer, create it
*/
if (!wsi->truncated_send_malloc ||
real_len - n > wsi->truncated_send_allocation) {
if (wsi->truncated_send_malloc)
free(wsi->truncated_send_malloc);
wsi->truncated_send_allocation = real_len - n;
wsi->truncated_send_malloc = malloc(real_len - n);
if (!wsi->truncated_send_malloc) {
lwsl_err("truncated send: unable to malloc %d\n",
real_len - n);
return -1;
}
}
wsi->truncated_send_offset = 0;
wsi->truncated_send_len = real_len - n;
memcpy(wsi->truncated_send_malloc, buf + n, real_len - n);
/* since something buffered, force it to get another chance to send */
libwebsocket_callback_on_writable(wsi->protocol->owning_server, wsi);
return real_len;
}
/**
* libwebsocket_write() - Apply protocol then write data to client
* @wsi: Websocket instance (available from user callback)
* @buf: The data to send. For data being sent on a websocket
* connection (ie, not default http), this buffer MUST have
* LWS_SEND_BUFFER_PRE_PADDING bytes valid BEFORE the pointer
* and an additional LWS_SEND_BUFFER_POST_PADDING bytes valid
* in the buffer after (buf + len). This is so the protocol
* header and trailer data can be added in-situ.
* @len: Count of the data bytes in the payload starting from buf
* @protocol: Use LWS_WRITE_HTTP to reply to an http connection, and one
* of LWS_WRITE_BINARY or LWS_WRITE_TEXT to send appropriate
* data on a websockets connection. Remember to allow the extra
* bytes before and after buf if LWS_WRITE_BINARY or LWS_WRITE_TEXT
* are used.
*
* This function provides the way to issue data back to the client
* for both http and websocket protocols.
*
* In the case of sending using websocket protocol, be sure to allocate
* valid storage before and after buf as explained above. This scheme
* allows maximum efficiency of sending data and protocol in a single
* packet while not burdening the user code with any protocol knowledge.
*
* Return may be -1 for a fatal error needing connection close, or a
* positive number reflecting the amount of bytes actually sent. This
* can be less than the requested number of bytes due to OS memory
* pressure at any given time.
*/
LWS_VISIBLE int libwebsocket_write(struct libwebsocket *wsi, unsigned char *buf,
size_t len, enum libwebsocket_write_protocol protocol)
{
int n;
int pre = 0;
int post = 0;
int masked7 = wsi->mode == LWS_CONNMODE_WS_CLIENT;
unsigned char *dropmask = NULL;
unsigned char is_masked_bit = 0;
size_t orig_len = len;
struct lws_tokens eff_buf;
if (len == 0 && protocol != LWS_WRITE_CLOSE &&
protocol != LWS_WRITE_PING && protocol != LWS_WRITE_PONG) {
lwsl_warn("zero length libwebsocket_write attempt\n");
return 0;
}
if (protocol == LWS_WRITE_HTTP)
goto send_raw;
/* websocket protocol, either binary or text */
if (wsi->state != WSI_STATE_ESTABLISHED)
return -1;
/* if we are continuing a frame that already had its header done */
if (wsi->u.ws.inside_frame)
goto do_more_inside_frame;
/* if he wants all partials buffered, never have a clean_buffer */
wsi->u.ws.clean_buffer = !wsi->protocol->no_buffer_all_partial_tx;
/*
* give a chance to the extensions to modify payload
* pre-TX mangling is not allowed to truncate
*/
eff_buf.token = (char *)buf;
eff_buf.token_len = len;
switch (protocol) {
case LWS_WRITE_PING:
case LWS_WRITE_PONG:
case LWS_WRITE_CLOSE:
break;
default:
if (lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_PAYLOAD_TX, &eff_buf, 0) < 0)
return -1;
}
/*
* an extension did something we need to keep... for example, if
* compression extension, it has already updated its state according
* to this being issued
*/
if ((char *)buf != eff_buf.token)
/*
* extension recreated it:
* need to buffer this if not all sent
*/
wsi->u.ws.clean_buffer = 0;
buf = (unsigned char *)eff_buf.token;
len = eff_buf.token_len;
switch (wsi->ietf_spec_revision) {
case 13:
if (masked7) {
pre += 4;
dropmask = &buf[0 - pre];
is_masked_bit = 0x80;
}
switch (protocol & 0xf) {
case LWS_WRITE_TEXT:
n = LWS_WS_OPCODE_07__TEXT_FRAME;
break;
case LWS_WRITE_BINARY:
n = LWS_WS_OPCODE_07__BINARY_FRAME;
break;
case LWS_WRITE_CONTINUATION:
n = LWS_WS_OPCODE_07__CONTINUATION;
break;
case LWS_WRITE_CLOSE:
n = LWS_WS_OPCODE_07__CLOSE;
/*
* 06+ has a 2-byte status code in network order
* we can do this because we demand post-buf
*/
if (wsi->u.ws.close_reason) {
/* reason codes count as data bytes */
buf -= 2;
buf[0] = wsi->u.ws.close_reason >> 8;
buf[1] = wsi->u.ws.close_reason;
len += 2;
}
break;
case LWS_WRITE_PING:
n = LWS_WS_OPCODE_07__PING;
break;
case LWS_WRITE_PONG:
n = LWS_WS_OPCODE_07__PONG;
break;
default:
lwsl_warn("lws_write: unknown write opc / protocol\n");
return -1;
}
if (!(protocol & LWS_WRITE_NO_FIN))
n |= 1 << 7;
if (len < 126) {
pre += 2;
buf[-pre] = n;
buf[-pre + 1] = len | is_masked_bit;
} else {
if (len < 65536) {
pre += 4;
buf[-pre] = n;
buf[-pre + 1] = 126 | is_masked_bit;
buf[-pre + 2] = len >> 8;
buf[-pre + 3] = len;
} else {
pre += 10;
buf[-pre] = n;
buf[-pre + 1] = 127 | is_masked_bit;
#if defined __LP64__
buf[-pre + 2] = (len >> 56) & 0x7f;
buf[-pre + 3] = len >> 48;
buf[-pre + 4] = len >> 40;
buf[-pre + 5] = len >> 32;
#else
buf[-pre + 2] = 0;
buf[-pre + 3] = 0;
buf[-pre + 4] = 0;
buf[-pre + 5] = 0;
#endif
buf[-pre + 6] = len >> 24;
buf[-pre + 7] = len >> 16;
buf[-pre + 8] = len >> 8;
buf[-pre + 9] = len;
}
}
break;
}
do_more_inside_frame:
/*
* Deal with masking if we are in client -> server direction and
* the protocol demands it
*/
if (wsi->mode == LWS_CONNMODE_WS_CLIENT) {
if (!wsi->u.ws.inside_frame)
if (libwebsocket_0405_frame_mask_generate(wsi)) {
lwsl_err("frame mask generation failed\n");
return -1;
}
/*
* in v7, just mask the payload
*/
if (dropmask) { /* never set if already inside frame */
for (n = 4; n < (int)len + 4; n++)
dropmask[n] = dropmask[n] ^
wsi->u.ws.frame_masking_nonce_04[
(wsi->u.ws.frame_mask_index++) & 3];
/* copy the frame nonce into place */
memcpy(dropmask, wsi->u.ws.frame_masking_nonce_04, 4);
}
}
send_raw:
switch (protocol) {
case LWS_WRITE_CLOSE:
/* lwsl_hexdump(&buf[-pre], len + post); */
case LWS_WRITE_HTTP:
case LWS_WRITE_PONG:
case LWS_WRITE_PING:
return lws_issue_raw(wsi, (unsigned char *)buf - pre,
len + pre + post);
default:
break;
}
wsi->u.ws.inside_frame = 1;
/*
* give any active extensions a chance to munge the buffer
* before send. We pass in a pointer to an lws_tokens struct
* prepared with the default buffer and content length that's in
* there. Rather than rewrite the default buffer, extensions
* that expect to grow the buffer can adapt .token to
* point to their own per-connection buffer in the extension
* user allocation. By default with no extensions or no
* extension callback handling, just the normal input buffer is
* used then so it is efficient.
*
* callback returns 1 in case it wants to spill more buffers
*
* This takes care of holding the buffer if send is incomplete, ie,
* if wsi->u.ws.clean_buffer is 0 (meaning an extension meddled with
* the buffer). If wsi->u.ws.clean_buffer is 1, it will instead
* return to the user code how much OF THE USER BUFFER was consumed.
*/
n = lws_issue_raw_ext_access(wsi, buf - pre, len + pre + post);
if (n <= 0)
return n;
if (n == len + pre + post) {
/* everything in the buffer was handled (or rebuffered...) */
wsi->u.ws.inside_frame = 0;
return orig_len;
}
/*
* it is how many bytes of user buffer got sent... may be < orig_len
* in which case callback when writable has already been arranged
* and user code can call libwebsocket_write() again with the rest
* later.
*/
return n - (pre + post);
}
LWS_VISIBLE int libwebsockets_serve_http_file_fragment(
struct libwebsocket_context *context, struct libwebsocket *wsi)
{
int n;
int m;
while (!lws_send_pipe_choked(wsi)) {
if (wsi->truncated_send_len) {
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
wsi->truncated_send_offset,
wsi->truncated_send_len) < 0) {
lwsl_info("closing from libwebsockets_serve_http_file_fragment\n");
return -1;
}
continue;
}
if (wsi->u.http.filepos == wsi->u.http.filelen)
goto all_sent;
compatible_file_read(n, wsi->u.http.fd, context->service_buffer,
sizeof(context->service_buffer));
if (n < 0)
return -1; /* caller will close */
if (n) {
m = libwebsocket_write(wsi, context->service_buffer, n,
LWS_WRITE_HTTP);
if (m < 0)
return -1;
wsi->u.http.filepos += m;
if (m != n)
/* adjust for what was not sent */
compatible_file_seek_cur(wsi->u.http.fd, m - n);
}
all_sent:
if (!wsi->truncated_send_len &&
wsi->u.http.filepos == wsi->u.http.filelen) {
wsi->state = WSI_STATE_HTTP;
if (wsi->protocol->callback)
/* ignore callback returned value */
user_callback_handle_rxflow(
wsi->protocol->callback, context, wsi,
LWS_CALLBACK_HTTP_FILE_COMPLETION,
wsi->user_space, NULL, 0);
return 1; /* >0 indicates completed */
}
}
lwsl_info("choked before able to send whole file (post)\n");
libwebsocket_callback_on_writable(context, wsi);
return 0; /* indicates further processing must be done */
}
LWS_VISIBLE int
lws_ssl_capable_read_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len)
{
int n;
n = recv(wsi->sock, buf, len, 0);
if (n >= 0)
return n;
lwsl_warn("error on reading from skt\n");
return LWS_SSL_CAPABLE_ERROR;
}
LWS_VISIBLE int
lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len)
{
int n;
n = send(wsi->sock, buf, len, 0);
if (n >= 0)
return n;
if (LWS_ERRNO == LWS_EAGAIN ||
LWS_ERRNO == LWS_EWOULDBLOCK ||
LWS_ERRNO == LWS_EINTR) {
if (LWS_ERRNO == LWS_EWOULDBLOCK)
lws_set_blocking_send(wsi);
return LWS_SSL_CAPABLE_MORE_SERVICE;
}
lwsl_debug("ERROR writing len %d to skt %d\n", len, n);
return LWS_SSL_CAPABLE_ERROR;
}

View File

@ -1,973 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
unsigned char lextable[] = {
#include "lextable.h"
};
#define FAIL_CHAR 0x08
int lextable_decode(int pos, char c)
{
c = tolower(c);
while (1) {
if (lextable[pos] & (1 << 7)) { /* 1-byte, fail on mismatch */
if ((lextable[pos] & 0x7f) != c)
return -1;
/* fall thru */
pos++;
if (lextable[pos] == FAIL_CHAR)
return -1;
return pos;
}
/* b7 = 0, end or 3-byte */
if (lextable[pos] < FAIL_CHAR) /* terminal marker */
return pos;
if (lextable[pos] == c) /* goto */
return pos + (lextable[pos + 1]) +
(lextable[pos + 2] << 8);
/* fall thru goto */
pos += 3;
/* continue */
}
}
int lws_allocate_header_table(struct libwebsocket *wsi)
{
wsi->u.hdr.ah = malloc(sizeof(*wsi->u.hdr.ah));
if (wsi->u.hdr.ah == NULL) {
lwsl_err("Out of memory\n");
return -1;
}
memset(wsi->u.hdr.ah->frag_index, 0, sizeof(wsi->u.hdr.ah->frag_index));
wsi->u.hdr.ah->next_frag_index = 0;
wsi->u.hdr.ah->pos = 0;
return 0;
}
LWS_VISIBLE int lws_hdr_total_length(struct libwebsocket *wsi, enum lws_token_indexes h)
{
int n;
int len = 0;
n = wsi->u.hdr.ah->frag_index[h];
if (!n)
return 0;
do {
len += wsi->u.hdr.ah->frags[n].len;
n = wsi->u.hdr.ah->frags[n].next_frag_index;
} while (n);
return len;
}
LWS_VISIBLE int lws_hdr_copy(struct libwebsocket *wsi, char *dest, int len,
enum lws_token_indexes h)
{
int toklen = lws_hdr_total_length(wsi, h);
int n;
if (toklen >= len)
return -1;
n = wsi->u.hdr.ah->frag_index[h];
if (!n)
return 0;
do {
strcpy(dest,
&wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset]);
dest += wsi->u.hdr.ah->frags[n].len;
n = wsi->u.hdr.ah->frags[n].next_frag_index;
} while (n);
return toklen;
}
char *lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h)
{
int n;
n = wsi->u.hdr.ah->frag_index[h];
if (!n)
return NULL;
return &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset];
}
int lws_hdr_simple_create(struct libwebsocket *wsi,
enum lws_token_indexes h, const char *s)
{
wsi->u.hdr.ah->next_frag_index++;
if (wsi->u.hdr.ah->next_frag_index ==
sizeof(wsi->u.hdr.ah->frags) / sizeof(wsi->u.hdr.ah->frags[0])) {
lwsl_warn("More hdr frags than we can deal with, dropping\n");
return -1;
}
wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->next_frag_index;
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
wsi->u.hdr.ah->pos;
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].next_frag_index =
0;
do {
if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
lwsl_err("Ran out of header data space\n");
return -1;
}
wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s;
if (*s)
wsi->u.hdr.ah->frags[
wsi->u.hdr.ah->next_frag_index].len++;
} while (*s++);
return 0;
}
static char char_to_hex(const char c)
{
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
if (c >= 'A' && c <= 'F')
return c - 'A' + 10;
return -1;
}
static int issue_char(struct libwebsocket *wsi, unsigned char c)
{
if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
lwsl_warn("excessive header content\n");
return -1;
}
wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = c;
if (c)
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
return 0;
}
int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
{
int n;
switch (wsi->u.hdr.parser_state) {
case WSI_TOKEN_GET_URI:
case WSI_TOKEN_POST_URI:
case WSI_TOKEN_HOST:
case WSI_TOKEN_CONNECTION:
case WSI_TOKEN_KEY1:
case WSI_TOKEN_KEY2:
case WSI_TOKEN_PROTOCOL:
case WSI_TOKEN_UPGRADE:
case WSI_TOKEN_ORIGIN:
case WSI_TOKEN_SWORIGIN:
case WSI_TOKEN_DRAFT:
case WSI_TOKEN_CHALLENGE:
case WSI_TOKEN_KEY:
case WSI_TOKEN_VERSION:
case WSI_TOKEN_ACCEPT:
case WSI_TOKEN_NONCE:
case WSI_TOKEN_EXTENSIONS:
case WSI_TOKEN_HTTP:
case WSI_TOKEN_HTTP_ACCEPT:
case WSI_TOKEN_HTTP_IF_MODIFIED_SINCE:
case WSI_TOKEN_HTTP_ACCEPT_ENCODING:
case WSI_TOKEN_HTTP_ACCEPT_LANGUAGE:
case WSI_TOKEN_HTTP_PRAGMA:
case WSI_TOKEN_HTTP_CACHE_CONTROL:
case WSI_TOKEN_HTTP_AUTHORIZATION:
case WSI_TOKEN_HTTP_COOKIE:
case WSI_TOKEN_HTTP_CONTENT_LENGTH:
case WSI_TOKEN_HTTP_CONTENT_TYPE:
case WSI_TOKEN_HTTP_DATE:
case WSI_TOKEN_HTTP_RANGE:
case WSI_TOKEN_HTTP_REFERER:
lwsl_parser("WSI_TOK_(%d) '%c'\n", wsi->u.hdr.parser_state, c);
/* collect into malloc'd buffers */
/* optional initial space swallow */
if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->frag_index[
wsi->u.hdr.parser_state]].len && c == ' ')
break;
if ((wsi->u.hdr.parser_state != WSI_TOKEN_GET_URI) && (wsi->u.hdr.parser_state != WSI_TOKEN_POST_URI))
goto check_eol;
/* special URI processing... end at space */
if (c == ' ') {
/* enforce starting with / */
if (!wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len)
if (issue_char(wsi, '/') < 0)
return -1;
c = '\0';
wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
goto spill;
}
/* special URI processing... convert %xx */
switch (wsi->u.hdr.ues) {
case URIES_IDLE:
if (c == '%') {
wsi->u.hdr.ues = URIES_SEEN_PERCENT;
goto swallow;
}
break;
case URIES_SEEN_PERCENT:
if (char_to_hex(c) < 0) {
/* regurgitate */
if (issue_char(wsi, '%') < 0)
return -1;
wsi->u.hdr.ues = URIES_IDLE;
/* continue on to assess c */
break;
}
wsi->u.hdr.esc_stash = c;
wsi->u.hdr.ues = URIES_SEEN_PERCENT_H1;
goto swallow;
case URIES_SEEN_PERCENT_H1:
if (char_to_hex(c) < 0) {
/* regurgitate */
issue_char(wsi, '%');
wsi->u.hdr.ues = URIES_IDLE;
/* regurgitate + assess */
if (libwebsocket_parse(wsi, wsi->u.hdr.esc_stash) < 0)
return -1;
/* continue on to assess c */
break;
}
c = (char_to_hex(wsi->u.hdr.esc_stash) << 4) |
char_to_hex(c);
wsi->u.hdr.ues = URIES_IDLE;
break;
}
/*
* special URI processing...
* convert /.. or /... or /../ etc to /
* convert /./ to /
* convert // or /// etc to /
* leave /.dir or whatever alone
*/
switch (wsi->u.hdr.ups) {
case URIPS_IDLE:
/* issue the first / always */
if (c == '/')
wsi->u.hdr.ups = URIPS_SEEN_SLASH;
break;
case URIPS_SEEN_SLASH:
/* swallow subsequent slashes */
if (c == '/')
goto swallow;
/* track and swallow the first . after / */
if (c == '.') {
wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT;
goto swallow;
} else
wsi->u.hdr.ups = URIPS_IDLE;
break;
case URIPS_SEEN_SLASH_DOT:
/* swallow second . */
if (c == '.') {
/*
* back up one dir level if possible
* safe against header fragmentation because
* the method URI can only be in 1 fragment
*/
if (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 2) {
wsi->u.hdr.ah->pos--;
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
do {
wsi->u.hdr.ah->pos--;
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len--;
} while (wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len > 1 &&
wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos] != '/');
}
wsi->u.hdr.ups = URIPS_SEEN_SLASH_DOT_DOT;
goto swallow;
}
/* change /./ to / */
if (c == '/') {
wsi->u.hdr.ups = URIPS_SEEN_SLASH;
goto swallow;
}
/* it was like /.dir ... regurgitate the . */
wsi->u.hdr.ups = URIPS_IDLE;
issue_char(wsi, '.');
break;
case URIPS_SEEN_SLASH_DOT_DOT:
/* swallow prior .. chars and any subsequent . */
if (c == '.')
goto swallow;
/* last issued was /, so another / == // */
if (c == '/')
goto swallow;
else /* last we issued was / so SEEN_SLASH */
wsi->u.hdr.ups = URIPS_SEEN_SLASH;
break;
case URIPS_ARGUMENTS:
/* leave them alone */
break;
}
check_eol:
/* bail at EOL */
if (wsi->u.hdr.parser_state != WSI_TOKEN_CHALLENGE &&
c == '\x0d') {
c = '\0';
wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
lwsl_parser("*\n");
}
if (c == '?') { /* start of URI arguments */
/* seal off uri header */
wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = '\0';
/* move to using WSI_TOKEN_HTTP_URI_ARGS */
wsi->u.hdr.ah->next_frag_index++;
wsi->u.hdr.ah->frags[
wsi->u.hdr.ah->next_frag_index].offset =
wsi->u.hdr.ah->pos;
wsi->u.hdr.ah->frags[
wsi->u.hdr.ah->next_frag_index].len = 0;
wsi->u.hdr.ah->frags[
wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP_URI_ARGS] =
wsi->u.hdr.ah->next_frag_index;
/* defeat normal uri path processing */
wsi->u.hdr.ups = URIPS_ARGUMENTS;
goto swallow;
}
spill:
if (issue_char(wsi, c) < 0)
return -1;
swallow:
/* per-protocol end of headers management */
if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
goto set_parsing_complete;
break;
/* collecting and checking a name part */
case WSI_TOKEN_NAME_PART:
lwsl_parser("WSI_TOKEN_NAME_PART '%c'\n", c);
wsi->u.hdr.lextable_pos =
lextable_decode(wsi->u.hdr.lextable_pos, c);
if (wsi->u.hdr.lextable_pos < 0) {
/* this is not a header we know about */
if (wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI] || wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI] ||
wsi->u.hdr.ah->frag_index[WSI_TOKEN_HTTP]) {
/*
* altready had the method, no idea what
* this crap is, ignore
*/
wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
break;
}
/*
* hm it's an unknown http method in fact,
* treat as dangerous
*/
lwsl_info("Unknown method - dropping\n");
return -1;
}
if (lextable[wsi->u.hdr.lextable_pos] < FAIL_CHAR) {
/* terminal state */
n = (lextable[wsi->u.hdr.lextable_pos] << 8) | lextable[wsi->u.hdr.lextable_pos + 1];
lwsl_parser("known hdr %d\n", n);
if (n == WSI_TOKEN_GET_URI &&
wsi->u.hdr.ah->frag_index[WSI_TOKEN_GET_URI]) {
lwsl_warn("Duplicated GET\n");
return -1;
} else if (n == WSI_TOKEN_POST_URI &&
wsi->u.hdr.ah->frag_index[WSI_TOKEN_POST_URI]) {
lwsl_warn("Duplicated POST\n");
return -1;
}
/*
* WSORIGIN is protocol equiv to ORIGIN,
* JWebSocket likes to send it, map to ORIGIN
*/
if (n == WSI_TOKEN_SWORIGIN)
n = WSI_TOKEN_ORIGIN;
wsi->u.hdr.parser_state = (enum lws_token_indexes)
(WSI_TOKEN_GET_URI + n);
if (wsi->u.hdr.parser_state == WSI_TOKEN_CHALLENGE)
goto set_parsing_complete;
goto start_fragment;
}
break;
start_fragment:
wsi->u.hdr.ah->next_frag_index++;
if (wsi->u.hdr.ah->next_frag_index ==
sizeof(wsi->u.hdr.ah->frags) /
sizeof(wsi->u.hdr.ah->frags[0])) {
lwsl_warn("More hdr frags than we can deal with\n");
return -1;
}
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset =
wsi->u.hdr.ah->pos;
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
wsi->u.hdr.ah->frags[
wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
n = wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state];
if (!n) { /* first fragment */
wsi->u.hdr.ah->frag_index[wsi->u.hdr.parser_state] =
wsi->u.hdr.ah->next_frag_index;
break;
}
/* continuation */
while (wsi->u.hdr.ah->frags[n].next_frag_index)
n = wsi->u.hdr.ah->frags[n].next_frag_index;
wsi->u.hdr.ah->frags[n].next_frag_index =
wsi->u.hdr.ah->next_frag_index;
if (wsi->u.hdr.ah->pos == sizeof(wsi->u.hdr.ah->data)) {
lwsl_warn("excessive header content\n");
return -1;
}
wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = ' ';
wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
break;
/* skipping arg part of a name we didn't recognize */
case WSI_TOKEN_SKIPPING:
lwsl_parser("WSI_TOKEN_SKIPPING '%c'\n", c);
if (c == '\x0d')
wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING_SAW_CR;
break;
case WSI_TOKEN_SKIPPING_SAW_CR:
lwsl_parser("WSI_TOKEN_SKIPPING_SAW_CR '%c'\n", c);
if (c == '\x0a') {
wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
wsi->u.hdr.lextable_pos = 0;
} else
wsi->u.hdr.parser_state = WSI_TOKEN_SKIPPING;
break;
/* we're done, ignore anything else */
case WSI_PARSING_COMPLETE:
lwsl_parser("WSI_PARSING_COMPLETE '%c'\n", c);
break;
default: /* keep gcc happy */
break;
}
return 0;
set_parsing_complete:
if (lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE)) {
if (lws_hdr_total_length(wsi, WSI_TOKEN_VERSION))
wsi->ietf_spec_revision =
atoi(lws_hdr_simple_ptr(wsi, WSI_TOKEN_VERSION));
lwsl_parser("v%02d hdrs completed\n", wsi->ietf_spec_revision);
}
wsi->u.hdr.parser_state = WSI_PARSING_COMPLETE;
wsi->hdr_parsing_completed = 1;
return 0;
}
/**
* lws_frame_is_binary: true if the current frame was sent in binary mode
*
* @wsi: the connection we are inquiring about
*
* This is intended to be called from the LWS_CALLBACK_RECEIVE callback if
* it's interested to see if the frame it's dealing with was sent in binary
* mode.
*/
LWS_VISIBLE int lws_frame_is_binary(struct libwebsocket *wsi)
{
return wsi->u.ws.frame_is_binary;
}
int
libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c)
{
int n;
struct lws_tokens eff_buf;
int ret = 0;
switch (wsi->lws_rx_parse_state) {
case LWS_RXPS_NEW:
switch (wsi->ietf_spec_revision) {
case 13:
/*
* no prepended frame key any more
*/
wsi->u.ws.all_zero_nonce = 1;
goto handle_first;
default:
lwsl_warn("lws_rx_sm: unknown spec version %d\n",
wsi->ietf_spec_revision);
break;
}
break;
case LWS_RXPS_04_MASK_NONCE_1:
wsi->u.ws.frame_masking_nonce_04[1] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_2;
break;
case LWS_RXPS_04_MASK_NONCE_2:
wsi->u.ws.frame_masking_nonce_04[2] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_04_MASK_NONCE_3;
break;
case LWS_RXPS_04_MASK_NONCE_3:
wsi->u.ws.frame_masking_nonce_04[3] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
/*
* start from the zero'th byte in the XOR key buffer since
* this is the start of a frame with a new key
*/
wsi->u.ws.frame_mask_index = 0;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_1;
break;
/*
* 04 logical framing from the spec (all this is masked when incoming
* and has to be unmasked)
*
* We ignore the possibility of extension data because we don't
* negotiate any extensions at the moment.
*
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-------+-+-------------+-------------------------------+
* |F|R|R|R| opcode|R| Payload len | Extended payload length |
* |I|S|S|S| (4) |S| (7) | (16/63) |
* |N|V|V|V| |V| | (if payload len==126/127) |
* | |1|2|3| |4| | |
* +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
* | Extended payload length continued, if payload len == 127 |
* + - - - - - - - - - - - - - - - +-------------------------------+
* | | Extension data |
* +-------------------------------+ - - - - - - - - - - - - - - - +
* : :
* +---------------------------------------------------------------+
* : Application data :
* +---------------------------------------------------------------+
*
* We pass payload through to userland as soon as we get it, ignoring
* FIN. It's up to userland to buffer it up if it wants to see a
* whole unfragmented block of the original size (which may be up to
* 2^63 long!)
*/
case LWS_RXPS_04_FRAME_HDR_1:
handle_first:
wsi->u.ws.opcode = c & 0xf;
wsi->u.ws.rsv = c & 0x70;
wsi->u.ws.final = !!((c >> 7) & 1);
switch (wsi->u.ws.opcode) {
case LWS_WS_OPCODE_07__TEXT_FRAME:
case LWS_WS_OPCODE_07__BINARY_FRAME:
wsi->u.ws.frame_is_binary =
wsi->u.ws.opcode == LWS_WS_OPCODE_07__BINARY_FRAME;
break;
}
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN;
break;
case LWS_RXPS_04_FRAME_HDR_LEN:
wsi->u.ws.this_frame_masked = !!(c & 0x80);
switch (c & 0x7f) {
case 126:
/* control frames are not allowed to have big lengths */
if (wsi->u.ws.opcode & 8)
goto illegal_ctl_length;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_2;
break;
case 127:
/* control frames are not allowed to have big lengths */
if (wsi->u.ws.opcode & 8)
goto illegal_ctl_length;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_8;
break;
default:
wsi->u.ws.rx_packet_length = c & 0x7f;
if (wsi->u.ws.this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else
if (wsi->u.ws.rx_packet_length)
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
else {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
break;
}
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_2:
wsi->u.ws.rx_packet_length = c << 8;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN16_1;
break;
case LWS_RXPS_04_FRAME_HDR_LEN16_1:
wsi->u.ws.rx_packet_length |= c;
if (wsi->u.ws.this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_8:
if (c & 0x80) {
lwsl_warn("b63 of length must be zero\n");
/* kill the connection */
return -1;
}
#if defined __LP64__
wsi->u.ws.rx_packet_length = ((size_t)c) << 56;
#else
wsi->u.ws.rx_packet_length = 0;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_7;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_7:
#if defined __LP64__
wsi->u.ws.rx_packet_length |= ((size_t)c) << 48;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_6;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_6:
#if defined __LP64__
wsi->u.ws.rx_packet_length |= ((size_t)c) << 40;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_5;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_5:
#if defined __LP64__
wsi->u.ws.rx_packet_length |= ((size_t)c) << 32;
#endif
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_4;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_4:
wsi->u.ws.rx_packet_length |= ((size_t)c) << 24;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_3;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_3:
wsi->u.ws.rx_packet_length |= ((size_t)c) << 16;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_2;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_2:
wsi->u.ws.rx_packet_length |= ((size_t)c) << 8;
wsi->lws_rx_parse_state = LWS_RXPS_04_FRAME_HDR_LEN64_1;
break;
case LWS_RXPS_04_FRAME_HDR_LEN64_1:
wsi->u.ws.rx_packet_length |= ((size_t)c);
if (wsi->u.ws.this_frame_masked)
wsi->lws_rx_parse_state =
LWS_RXPS_07_COLLECT_FRAME_KEY_1;
else
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_1:
wsi->u.ws.frame_masking_nonce_04[0] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_2;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_2:
wsi->u.ws.frame_masking_nonce_04[1] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_3;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_3:
wsi->u.ws.frame_masking_nonce_04[2] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state = LWS_RXPS_07_COLLECT_FRAME_KEY_4;
break;
case LWS_RXPS_07_COLLECT_FRAME_KEY_4:
wsi->u.ws.frame_masking_nonce_04[3] = c;
if (c)
wsi->u.ws.all_zero_nonce = 0;
wsi->lws_rx_parse_state =
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED;
wsi->u.ws.frame_mask_index = 0;
if (wsi->u.ws.rx_packet_length == 0) {
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
break;
case LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED:
if (!wsi->u.ws.rx_user_buffer)
lwsl_err("NULL user buffer...\n");
if (wsi->u.ws.all_zero_nonce)
wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->u.ws.rx_user_buffer_head++)] = c;
else
wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING +
(wsi->u.ws.rx_user_buffer_head++)] =
c ^ wsi->u.ws.frame_masking_nonce_04[
(wsi->u.ws.frame_mask_index++) & 3];
if (--wsi->u.ws.rx_packet_length == 0) {
/* spill because we have the whole frame */
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
goto spill;
}
/*
* if there's no protocol max frame size given, we are
* supposed to default to LWS_MAX_SOCKET_IO_BUF
*/
if (!wsi->protocol->rx_buffer_size &&
wsi->u.ws.rx_user_buffer_head !=
LWS_MAX_SOCKET_IO_BUF)
break;
else
if (wsi->protocol->rx_buffer_size &&
wsi->u.ws.rx_user_buffer_head !=
wsi->protocol->rx_buffer_size)
break;
/* spill because we filled our rx buffer */
spill:
/*
* is this frame a control packet we should take care of at this
* layer? If so service it and hide it from the user callback
*/
lwsl_parser("spill on %s\n", wsi->protocol->name);
switch (wsi->u.ws.opcode) {
case LWS_WS_OPCODE_07__CLOSE:
/* is this an acknowledgement of our close? */
if (wsi->state == WSI_STATE_AWAITING_CLOSE_ACK) {
/*
* fine he has told us he is closing too, let's
* finish our close
*/
lwsl_parser("seen client close ack\n");
return -1;
}
lwsl_parser("server sees client close packet\n");
/* parrot the close packet payload back */
n = libwebsocket_write(wsi, (unsigned char *)
&wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING],
wsi->u.ws.rx_user_buffer_head,
LWS_WRITE_CLOSE);
if (n < 0)
lwsl_info("write of close ack failed %d\n", n);
wsi->state = WSI_STATE_RETURNED_CLOSE_ALREADY;
/* close the connection */
return -1;
case LWS_WS_OPCODE_07__PING:
lwsl_info("received %d byte ping, sending pong\n",
wsi->u.ws.rx_user_buffer_head);
lwsl_hexdump(&wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING],
wsi->u.ws.rx_user_buffer_head);
/* parrot the ping packet payload back as a pong */
n = libwebsocket_write(wsi, (unsigned char *)
&wsi->u.ws.rx_user_buffer[LWS_SEND_BUFFER_PRE_PADDING],
wsi->u.ws.rx_user_buffer_head, LWS_WRITE_PONG);
if (n < 0)
return -1;
/* ... then just drop it */
wsi->u.ws.rx_user_buffer_head = 0;
return 0;
case LWS_WS_OPCODE_07__PONG:
/* ... then just drop it */
wsi->u.ws.rx_user_buffer_head = 0;
return 0;
case LWS_WS_OPCODE_07__TEXT_FRAME:
case LWS_WS_OPCODE_07__BINARY_FRAME:
case LWS_WS_OPCODE_07__CONTINUATION:
break;
default:
lwsl_parser("passing opc %x up to exts\n",
wsi->u.ws.opcode);
/*
* It's something special we can't understand here.
* Pass the payload up to the extension's parsing
* state machine.
*/
eff_buf.token = &wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING];
eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
if (lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_EXTENDED_PAYLOAD_RX,
&eff_buf, 0) <= 0) /* not handle or fail */
lwsl_ext("ext opc opcode 0x%x unknown\n",
wsi->u.ws.opcode);
wsi->u.ws.rx_user_buffer_head = 0;
return 0;
}
/*
* No it's real payload, pass it up to the user callback.
* It's nicely buffered with the pre-padding taken care of
* so it can be sent straight out again using libwebsocket_write
*/
eff_buf.token = &wsi->u.ws.rx_user_buffer[
LWS_SEND_BUFFER_PRE_PADDING];
eff_buf.token_len = wsi->u.ws.rx_user_buffer_head;
if (lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_PAYLOAD_RX, &eff_buf, 0) < 0)
return -1;
if (eff_buf.token_len > 0) {
eff_buf.token[eff_buf.token_len] = '\0';
if (wsi->protocol->callback)
ret = user_callback_handle_rxflow(
wsi->protocol->callback,
wsi->protocol->owning_server,
wsi, LWS_CALLBACK_RECEIVE,
wsi->user_space,
eff_buf.token,
eff_buf.token_len);
else
lwsl_err("No callback on payload spill!\n");
}
wsi->u.ws.rx_user_buffer_head = 0;
break;
}
return ret;
illegal_ctl_length:
lwsl_warn("Control frame with xtended length is illegal\n");
/* kill the connection */
return -1;
}
/**
* libwebsockets_remaining_packet_payload() - Bytes to come before "overall"
* rx packet is complete
* @wsi: Websocket instance (available from user callback)
*
* This function is intended to be called from the callback if the
* user code is interested in "complete packets" from the client.
* libwebsockets just passes through payload as it comes and issues a buffer
* additionally when it hits a built-in limit. The LWS_CALLBACK_RECEIVE
* callback handler can use this API to find out if the buffer it has just
* been given is the last piece of a "complete packet" from the client --
* when that is the case libwebsockets_remaining_packet_payload() will return
* 0.
*
* Many protocols won't care becuse their packets are always small.
*/
LWS_VISIBLE size_t
libwebsockets_remaining_packet_payload(struct libwebsocket *wsi)
{
return wsi->u.ws.rx_packet_length;
}

View File

@ -1,239 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
int
insert_wsi_socket_into_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi)
{
struct libwebsocket_pollargs pa = { wsi->sock, LWS_POLLIN, 0 };
if (context->fds_count >= context->max_fds) {
lwsl_err("Too many fds (%d)\n", context->max_fds);
return 1;
}
if (wsi->sock >= context->max_fds) {
lwsl_err("Socket fd %d is too high (%d)\n",
wsi->sock, context->max_fds);
return 1;
}
assert(wsi);
assert(wsi->sock >= 0);
lwsl_info("insert_wsi_socket_into_fds: wsi=%p, sock=%d, fds pos=%d\n",
wsi, wsi->sock, context->fds_count);
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_LOCK_POLL,
wsi->user_space, (void *) &pa, 0);
context->lws_lookup[wsi->sock] = wsi;
wsi->position_in_fds_table = context->fds_count;
context->fds[context->fds_count].fd = wsi->sock;
context->fds[context->fds_count].events = LWS_POLLIN;
lws_plat_insert_socket_into_fds(context, wsi);
/* external POLL support via protocol 0 */
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_ADD_POLL_FD,
wsi->user_space, (void *) &pa, 0);
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_UNLOCK_POLL,
wsi->user_space, (void *)&pa, 0);
return 0;
}
int
remove_wsi_socket_from_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi)
{
int m;
struct libwebsocket_pollargs pa = { wsi->sock, 0, 0 };
lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_READ | LWS_EV_WRITE);
if (!--context->fds_count) {
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_LOCK_POLL,
wsi->user_space, (void *) &pa, 0);
goto do_ext;
}
if (wsi->sock > context->max_fds) {
lwsl_err("Socket fd %d too high (%d)\n",
wsi->sock, context->max_fds);
return 1;
}
lwsl_info("%s: wsi=%p, sock=%d, fds pos=%d\n", __func__,
wsi, wsi->sock, wsi->position_in_fds_table);
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_LOCK_POLL,
wsi->user_space, (void *)&pa, 0);
m = wsi->position_in_fds_table; /* replace the contents for this */
/* have the last guy take up the vacant slot */
context->fds[m] = context->fds[context->fds_count];
lws_plat_delete_socket_from_fds(context, wsi, m);
/*
* end guy's fds_lookup entry remains unchanged
* (still same fd pointing to same wsi)
*/
/* end guy's "position in fds table" changed */
context->lws_lookup[context->fds[context->fds_count].fd]->
position_in_fds_table = m;
/* deletion guy's lws_lookup entry needs nuking */
context->lws_lookup[wsi->sock] = NULL;
/* removed wsi has no position any more */
wsi->position_in_fds_table = -1;
do_ext:
/* remove also from external POLL support via protocol 0 */
if (wsi->sock) {
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_DEL_POLL_FD, wsi->user_space,
(void *) &pa, 0);
}
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_UNLOCK_POLL,
wsi->user_space, (void *) &pa, 0);
return 0;
}
int
lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or)
{
struct libwebsocket_context *context = wsi->protocol->owning_server;
int tid;
int sampled_tid;
struct libwebsocket_pollfd *pfd;
struct libwebsocket_pollargs pa;
pfd = &context->fds[wsi->position_in_fds_table];
pa.fd = wsi->sock;
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_LOCK_POLL, wsi->user_space, (void *) &pa, 0);
pa.prev_events = pfd->events;
pa.events = pfd->events = (pfd->events & ~_and) | _or;
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_CHANGE_MODE_POLL_FD,
wsi->user_space, (void *) &pa, 0);
/*
* if we changed something in this pollfd...
* ... and we're running in a different thread context
* than the service thread...
* ... and the service thread is waiting ...
* then cancel it to force a restart with our changed events
*/
if (pa.prev_events != pa.events) {
if (lws_plat_change_pollfd(context, wsi, pfd)) {
lwsl_info("%s failed\n", __func__);
return 1;
}
sampled_tid = context->service_tid;
if (sampled_tid) {
tid = context->protocols[0].callback(context, NULL,
LWS_CALLBACK_GET_THREAD_ID, NULL, NULL, 0);
if (tid != sampled_tid)
libwebsocket_cancel_service(context);
}
}
context->protocols[0].callback(context, wsi,
LWS_CALLBACK_UNLOCK_POLL, wsi->user_space, (void *) &pa, 0);
return 0;
}
/**
* libwebsocket_callback_on_writable() - Request a callback when this socket
* becomes able to be written to without
* blocking
*
* @context: libwebsockets context
* @wsi: Websocket connection instance to get callback for
*/
LWS_VISIBLE int
libwebsocket_callback_on_writable(struct libwebsocket_context *context,
struct libwebsocket *wsi)
{
if (lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_REQUEST_ON_WRITEABLE, NULL, 0))
return 1;
if (wsi->position_in_fds_table < 0) {
lwsl_err("%s: failed to find socket %d\n", __func__, wsi->sock);
return -1;
}
if (lws_change_pollfd(wsi, 0, LWS_POLLOUT))
return -1;
lws_libev_io(context, wsi, LWS_EV_START | LWS_EV_WRITE);
return 1;
}
/**
* libwebsocket_callback_on_writable_all_protocol() - Request a callback for
* all connections using the given protocol when it
* becomes possible to write to each socket without
* blocking in turn.
*
* @protocol: Protocol whose connections will get callbacks
*/
LWS_VISIBLE int
libwebsocket_callback_on_writable_all_protocol(
const struct libwebsocket_protocols *protocol)
{
struct libwebsocket_context *context = protocol->owning_server;
int n;
struct libwebsocket *wsi;
for (n = 0; n < context->fds_count; n++) {
wsi = context->lws_lookup[context->fds[n].fd];
if (!wsi)
continue;
if (wsi->protocol == protocol)
libwebsocket_callback_on_writable(context, wsi);
}
return 0;
}

View File

@ -1,916 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010 - 2013 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#pragma once
#include "build.h"
/* The Libwebsocket version */
#define LWS_LIBRARY_VERSION "1.3"
/* The current git commit hash that we're building from */
#define LWS_BUILD_HASH "c11b847"
/* System introspection configs */
#ifdef CMAKE_BUILD
#include "lws_config.h"
#else
#if HOST_OS == OS_WINDOWS
#define inline __inline
#else /* not WIN32 */
#include "config.h"
#endif /* not WIN32 */
#endif /* not CMAKE */
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <limits.h>
#include <stdarg.h>
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#if defined(WIN32) || defined(_WIN32)
#define LWS_NO_DAEMONIZE
#define LWS_ERRNO WSAGetLastError()
#define LWS_EAGAIN WSAEWOULDBLOCK
#define LWS_EALREADY WSAEALREADY
#define LWS_EINPROGRESS WSAEINPROGRESS
#define LWS_EINTR WSAEINTR
#define LWS_EISCONN WSAEISCONN
#define LWS_EWOULDBLOCK WSAEWOULDBLOCK
#define LWS_POLLHUP (FD_CLOSE)
#define LWS_POLLIN (FD_READ | FD_ACCEPT)
#define LWS_POLLOUT (FD_WRITE)
#define MSG_NOSIGNAL 0
#define SHUT_RDWR SD_BOTH
#define SOL_TCP IPPROTO_TCP
#define compatible_close(fd) closesocket(fd)
#define compatible_file_close(fd) CloseHandle(fd)
#define compatible_file_seek_cur(fd, offset) SetFilePointer(fd, offset, NULL, FILE_CURRENT)
#define compatible_file_read(amount, fd, buf, len) {\
DWORD _amount; \
if (!ReadFile(fd, buf, len, &_amount, NULL)) \
amount = -1; \
else \
amount = _amount; \
}
#define lws_set_blocking_send(wsi) wsi->sock_send_blocking = TRUE
#include <winsock2.h>
#include <windows.h>
#include <tchar.h>
#ifdef HAVE_IN6ADDR_H
#include <in6addr.h>
#endif
#include <mstcpip.h>
#ifndef __func__
#define __func__ __FUNCTION__
#endif
#ifdef _WIN32_WCE
#define vsnprintf _vsnprintf
#endif
#define LWS_INVALID_FILE INVALID_HANDLE_VALUE
#else /* not windows --> */
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <signal.h>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#ifdef LWS_BUILTIN_GETIFADDRS
#include "deps/ifaddrs/ifaddrs.h"
#else
#include <ifaddrs.h>
#endif
//#include <sys/syslog.h>
#include <sys/un.h>
#include <sys/socket.h>
#include <netdb.h>
#ifndef LWS_NO_FORK
#ifdef HAVE_SYS_PRCTL_H
#include <sys/prctl.h>
#endif
#endif
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <poll.h>
#ifdef LWS_USE_LIBEV
#include <ev.h>
#endif /* LWS_USE_LIBEV */
#include <sys/mman.h>
#include <sys/time.h>
#define LWS_ERRNO errno
#define LWS_EAGAIN EAGAIN
#define LWS_EALREADY EALREADY
#define LWS_EINPROGRESS EINPROGRESS
#define LWS_EINTR EINTR
#define LWS_EISCONN EISCONN
#define LWS_EWOULDBLOCK EWOULDBLOCK
#define LWS_INVALID_FILE -1
#define LWS_POLLHUP (POLLHUP|POLLERR)
#define LWS_POLLIN (POLLIN)
#define LWS_POLLOUT (POLLOUT)
#define compatible_close(fd) close(fd)
#define compatible_file_close(fd) close(fd)
#define compatible_file_seek_cur(fd, offset) lseek(fd, offset, SEEK_CUR)
#define compatible_file_read(amount, fd, buf, len) \
amount = read(fd, buf, len);
#define lws_set_blocking_send(wsi)
#endif
#ifndef HAVE_BZERO
#define bzero(b, len) (memset((b), '\0', (len)), (void) 0)
#endif
#ifndef HAVE_STRERROR
#define strerror(x) ""
#endif
#ifdef LWS_OPENSSL_SUPPORT
#ifdef USE_CYASSL
#include <cyassl/openssl/ssl.h>
#include <cyassl/error.h>
unsigned char *
SHA1(const unsigned char *d, size_t n, unsigned char *md);
#else
#include <openssl/ssl.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
#endif /* not USE_CYASSL */
#endif
#include "libwebsockets.h"
#if defined(WIN32) || defined(_WIN32)
#ifndef BIG_ENDIAN
#define BIG_ENDIAN 4321 /* to show byte order (taken from gcc) */
#endif
#ifndef LITTLE_ENDIAN
#define LITTLE_ENDIAN 1234
#endif
#ifndef BYTE_ORDER
#define BYTE_ORDER LITTLE_ENDIAN
#endif
typedef unsigned __int64 u_int64_t;
#undef __P
#ifndef __P
#if __STDC__
#define __P(protos) protos
#else
#define __P(protos) ()
#endif
#endif
#else
#include <sys/stat.h>
#include <sys/time.h>
#if defined(__APPLE__)
#include <machine/endian.h>
#elif defined(__FreeBSD__)
#include <sys/endian.h>
#elif defined(__linux__)
#include <endian.h>
#endif
#if !defined(BYTE_ORDER)
# define BYTE_ORDER __BYTE_ORDER
#endif
#if !defined(LITTLE_ENDIAN)
# define LITTLE_ENDIAN __LITTLE_ENDIAN
#endif
#if !defined(BIG_ENDIAN)
# define BIG_ENDIAN __BIG_ENDIAN
#endif
#endif
/*
* Mac OSX as well as iOS do not define the MSG_NOSIGNAL flag,
* but happily have something equivalent in the SO_NOSIGPIPE flag.
*/
#ifdef __APPLE__
#define MSG_NOSIGNAL SO_NOSIGPIPE
#endif
#ifndef LWS_MAX_HEADER_LEN
#define LWS_MAX_HEADER_LEN 1024
#endif
#ifndef LWS_MAX_PROTOCOLS
#define LWS_MAX_PROTOCOLS 5
#endif
#ifndef LWS_MAX_EXTENSIONS_ACTIVE
#define LWS_MAX_EXTENSIONS_ACTIVE 3
#endif
#ifndef SPEC_LATEST_SUPPORTED
#define SPEC_LATEST_SUPPORTED 13
#endif
#ifndef AWAITING_TIMEOUT
#define AWAITING_TIMEOUT 5
#endif
#ifndef CIPHERS_LIST_STRING
#define CIPHERS_LIST_STRING "DEFAULT"
#endif
#ifndef LWS_SOMAXCONN
#define LWS_SOMAXCONN SOMAXCONN
#endif
#define MAX_WEBSOCKET_04_KEY_LEN 128
#define LWS_MAX_SOCKET_IO_BUF 4096
#ifndef SYSTEM_RANDOM_FILEPATH
#define SYSTEM_RANDOM_FILEPATH "/dev/urandom"
#endif
#ifndef LWS_MAX_ZLIB_CONN_BUFFER
#define LWS_MAX_ZLIB_CONN_BUFFER (64 * 1024)
#endif
/*
* if not in a connection storm, check for incoming
* connections this many normal connection services
*/
#define LWS_LISTEN_SERVICE_MODULO 10
enum lws_websocket_opcodes_07 {
LWS_WS_OPCODE_07__CONTINUATION = 0,
LWS_WS_OPCODE_07__TEXT_FRAME = 1,
LWS_WS_OPCODE_07__BINARY_FRAME = 2,
LWS_WS_OPCODE_07__NOSPEC__MUX = 7,
/* control extensions 8+ */
LWS_WS_OPCODE_07__CLOSE = 8,
LWS_WS_OPCODE_07__PING = 9,
LWS_WS_OPCODE_07__PONG = 0xa,
};
enum lws_connection_states {
WSI_STATE_HTTP,
WSI_STATE_HTTP_ISSUING_FILE,
WSI_STATE_HTTP_HEADERS,
WSI_STATE_HTTP_BODY,
WSI_STATE_DEAD_SOCKET,
WSI_STATE_ESTABLISHED,
WSI_STATE_CLIENT_UNCONNECTED,
WSI_STATE_RETURNED_CLOSE_ALREADY,
WSI_STATE_AWAITING_CLOSE_ACK,
WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE,
};
enum lws_rx_parse_state {
LWS_RXPS_NEW,
LWS_RXPS_04_MASK_NONCE_1,
LWS_RXPS_04_MASK_NONCE_2,
LWS_RXPS_04_MASK_NONCE_3,
LWS_RXPS_04_FRAME_HDR_1,
LWS_RXPS_04_FRAME_HDR_LEN,
LWS_RXPS_04_FRAME_HDR_LEN16_2,
LWS_RXPS_04_FRAME_HDR_LEN16_1,
LWS_RXPS_04_FRAME_HDR_LEN64_8,
LWS_RXPS_04_FRAME_HDR_LEN64_7,
LWS_RXPS_04_FRAME_HDR_LEN64_6,
LWS_RXPS_04_FRAME_HDR_LEN64_5,
LWS_RXPS_04_FRAME_HDR_LEN64_4,
LWS_RXPS_04_FRAME_HDR_LEN64_3,
LWS_RXPS_04_FRAME_HDR_LEN64_2,
LWS_RXPS_04_FRAME_HDR_LEN64_1,
LWS_RXPS_07_COLLECT_FRAME_KEY_1,
LWS_RXPS_07_COLLECT_FRAME_KEY_2,
LWS_RXPS_07_COLLECT_FRAME_KEY_3,
LWS_RXPS_07_COLLECT_FRAME_KEY_4,
LWS_RXPS_PAYLOAD_UNTIL_LENGTH_EXHAUSTED
};
enum connection_mode {
LWS_CONNMODE_HTTP_SERVING,
LWS_CONNMODE_HTTP_SERVING_ACCEPTED, /* actual HTTP service going on */
LWS_CONNMODE_PRE_WS_SERVING_ACCEPT,
LWS_CONNMODE_WS_SERVING,
LWS_CONNMODE_WS_CLIENT,
/* transient, ssl delay hiding */
LWS_CONNMODE_SSL_ACK_PENDING,
/* transient modes */
LWS_CONNMODE_WS_CLIENT_WAITING_CONNECT,
LWS_CONNMODE_WS_CLIENT_WAITING_PROXY_REPLY,
LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE,
LWS_CONNMODE_WS_CLIENT_ISSUE_HANDSHAKE2,
LWS_CONNMODE_WS_CLIENT_WAITING_SSL,
LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY,
LWS_CONNMODE_WS_CLIENT_WAITING_EXTENSION_CONNECT,
LWS_CONNMODE_WS_CLIENT_PENDING_CANDIDATE_CHILD,
/* special internal types */
LWS_CONNMODE_SERVER_LISTENER,
};
enum {
LWS_RXFLOW_ALLOW = (1 << 0),
LWS_RXFLOW_PENDING_CHANGE = (1 << 1),
};
struct libwebsocket_protocols;
struct libwebsocket;
#ifdef LWS_USE_LIBEV
struct lws_io_watcher {
struct ev_io watcher;
struct libwebsocket_context* context;
};
struct lws_signal_watcher {
struct ev_signal watcher;
struct libwebsocket_context* context;
};
#endif /* LWS_USE_LIBEV */
struct libwebsocket_context {
#ifdef _WIN32
WSAEVENT *events;
#endif
struct libwebsocket_pollfd *fds;
struct libwebsocket **lws_lookup; /* fd to wsi */
int fds_count;
#ifdef LWS_USE_LIBEV
struct ev_loop* io_loop;
struct lws_io_watcher w_accept;
struct lws_signal_watcher w_sigint;
#endif /* LWS_USE_LIBEV */
int max_fds;
int listen_port;
const char *iface;
char http_proxy_address[128];
char canonical_hostname[128];
unsigned int http_proxy_port;
unsigned int options;
time_t last_timeout_check_s;
/*
* usable by anything in the service code, but only if the scope
* does not last longer than the service action (since next service
* of any socket can likewise use it and overwrite)
*/
unsigned char service_buffer[LWS_MAX_SOCKET_IO_BUF];
int started_with_parent;
int fd_random;
int listen_service_modulo;
int listen_service_count;
int listen_service_fd;
int listen_service_extraseen;
/*
* set to the Thread ID that's doing the service loop just before entry
* to poll indicates service thread likely idling in poll()
* volatile because other threads may check it as part of processing
* for pollfd event change.
*/
volatile int service_tid;
#ifndef _WIN32
int dummy_pipe_fds[2];
#endif
int ka_time;
int ka_probes;
int ka_interval;
#ifdef LWS_LATENCY
unsigned long worst_latency;
char worst_latency_info[256];
#endif
#ifdef LWS_OPENSSL_SUPPORT
int use_ssl;
int allow_non_ssl_on_ssl_port;
SSL_CTX *ssl_ctx;
SSL_CTX *ssl_client_ctx;
#endif
struct libwebsocket_protocols *protocols;
int count_protocols;
#ifndef LWS_NO_EXTENSIONS
struct libwebsocket_extension *extensions;
#endif
void *user_space;
};
enum {
LWS_EV_READ = (1 << 0),
LWS_EV_WRITE = (1 << 1),
LWS_EV_START = (1 << 2),
LWS_EV_STOP = (1 << 3),
};
#ifdef LWS_USE_LIBEV
#define LWS_LIBEV_ENABLED(context) (context->options & LWS_SERVER_OPTION_LIBEV)
LWS_EXTERN void lws_feature_status_libev(struct lws_context_creation_info *info);
LWS_EXTERN void
lws_libev_accept(struct libwebsocket_context *context,
struct libwebsocket *new_wsi, int accept_fd);
LWS_EXTERN void
lws_libev_io(struct libwebsocket_context *context,
struct libwebsocket *wsi, int flags);
LWS_EXTERN int
lws_libev_init_fd_table(struct libwebsocket_context *context);
LWS_EXTERN void
lws_libev_run(struct libwebsocket_context *context);
#else
#define LWS_LIBEV_ENABLED(context) (0)
#define lws_feature_status_libev(_a) \
lwsl_notice("libev support not compiled in\n")
#define lws_libev_accept(_a, _b, _c) (0)
#define lws_libev_io(_a, _b, _c) (0)
#define lws_libev_init_fd_table(_a) (0)
#define lws_libev_run(_a) (0)
#endif
#ifdef LWS_USE_IPV6
#define LWS_IPV6_ENABLED(context) (!(context->options & LWS_SERVER_OPTION_DISABLE_IPV6))
#else
#define LWS_IPV6_ENABLED(context) (0)
#endif
enum uri_path_states {
URIPS_IDLE,
URIPS_SEEN_SLASH,
URIPS_SEEN_SLASH_DOT,
URIPS_SEEN_SLASH_DOT_DOT,
URIPS_ARGUMENTS,
};
enum uri_esc_states {
URIES_IDLE,
URIES_SEEN_PERCENT,
URIES_SEEN_PERCENT_H1,
};
/*
* This is totally opaque to code using the library. It's exported as a
* forward-reference pointer-only declaration; the user can use the pointer with
* other APIs to get information out of it.
*/
struct lws_fragments {
unsigned short offset;
unsigned short len;
unsigned char next_frag_index;
};
struct allocated_headers {
unsigned short next_frag_index;
unsigned short pos;
unsigned char frag_index[WSI_TOKEN_COUNT];
struct lws_fragments frags[WSI_TOKEN_COUNT * 2];
char data[LWS_MAX_HEADER_LEN];
#ifndef LWS_NO_CLIENT
char initial_handshake_hash_base64[30];
unsigned short c_port;
#endif
};
struct _lws_http_mode_related {
struct allocated_headers *ah; /* mirroring _lws_header_related */
#if defined(WIN32) || defined(_WIN32)
HANDLE fd;
#else
int fd;
#endif
unsigned long filepos;
unsigned long filelen;
int content_length;
int content_length_seen;
int body_index;
unsigned char *post_buffer;
};
struct _lws_header_related {
struct allocated_headers *ah;
short lextable_pos;
unsigned char parser_state; /* enum lws_token_indexes */
enum uri_path_states ups;
enum uri_esc_states ues;
char esc_stash;
};
struct _lws_websocket_related {
char *rx_user_buffer;
int rx_user_buffer_head;
unsigned char frame_masking_nonce_04[4];
unsigned char frame_mask_index;
size_t rx_packet_length;
unsigned char opcode;
unsigned int final:1;
unsigned char rsv;
unsigned int frame_is_binary:1;
unsigned int all_zero_nonce:1;
short close_reason; /* enum lws_close_status */
unsigned char *rxflow_buffer;
int rxflow_len;
int rxflow_pos;
unsigned int rxflow_change_to:2;
unsigned int this_frame_masked:1;
unsigned int inside_frame:1; /* next write will be more of frame */
unsigned int clean_buffer:1; /* buffer not rewritten by extension */
};
struct libwebsocket {
/* lifetime members */
#ifdef LWS_USE_LIBEV
struct lws_io_watcher w_read;
struct lws_io_watcher w_write;
#endif /* LWS_USE_LIBEV */
const struct libwebsocket_protocols *protocol;
#ifndef LWS_NO_EXTENSIONS
struct libwebsocket_extension *
active_extensions[LWS_MAX_EXTENSIONS_ACTIVE];
void *active_extensions_user[LWS_MAX_EXTENSIONS_ACTIVE];
unsigned char count_active_extensions;
unsigned int extension_data_pending:1;
#endif
unsigned char ietf_spec_revision;
char mode; /* enum connection_mode */
char state; /* enum lws_connection_states */
char lws_rx_parse_state; /* enum lws_rx_parse_state */
char rx_frame_type; /* enum libwebsocket_write_protocol */
unsigned int hdr_parsing_completed:1;
char pending_timeout; /* enum pending_timeout */
time_t pending_timeout_limit;
int sock;
int position_in_fds_table;
#ifdef LWS_LATENCY
unsigned long action_start;
unsigned long latency_start;
#endif
/* truncated send handling */
unsigned char *truncated_send_malloc; /* non-NULL means buffering in progress */
unsigned int truncated_send_allocation; /* size of malloc */
unsigned int truncated_send_offset; /* where we are in terms of spilling */
unsigned int truncated_send_len; /* how much is buffered */
void *user_space;
/* members with mutually exclusive lifetimes are unionized */
union u {
struct _lws_http_mode_related http;
struct _lws_header_related hdr;
struct _lws_websocket_related ws;
} u;
#ifdef LWS_OPENSSL_SUPPORT
SSL *ssl;
BIO *client_bio;
unsigned int use_ssl:2;
#endif
#ifdef _WIN32
BOOL sock_send_blocking;
#endif
};
LWS_EXTERN int log_level;
LWS_EXTERN void
libwebsocket_close_and_free_session(struct libwebsocket_context *context,
struct libwebsocket *wsi, enum lws_close_status);
LWS_EXTERN int
remove_wsi_socket_from_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi);
#ifndef LWS_LATENCY
static inline void lws_latency(struct libwebsocket_context *context,
struct libwebsocket *wsi, const char *action,
int ret, int completion) { while (0); }
static inline void lws_latency_pre(struct libwebsocket_context *context,
struct libwebsocket *wsi) { while (0); }
#else
#define lws_latency_pre(_context, _wsi) lws_latency(_context, _wsi, NULL, 0, 0)
extern void
lws_latency(struct libwebsocket_context *context,
struct libwebsocket *wsi, const char *action,
int ret, int completion);
#endif
LWS_EXTERN int
libwebsocket_client_rx_sm(struct libwebsocket *wsi, unsigned char c);
LWS_EXTERN int
libwebsocket_parse(struct libwebsocket *wsi, unsigned char c);
LWS_EXTERN int
lws_b64_selftest(void);
LWS_EXTERN struct libwebsocket *
wsi_from_fd(struct libwebsocket_context *context, int fd);
LWS_EXTERN int
insert_wsi_socket_into_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi);
LWS_EXTERN int
lws_issue_raw(struct libwebsocket *wsi, unsigned char *buf, size_t len);
LWS_EXTERN int
libwebsocket_service_timeout_check(struct libwebsocket_context *context,
struct libwebsocket *wsi, unsigned int sec);
LWS_EXTERN struct libwebsocket *
libwebsocket_client_connect_2(struct libwebsocket_context *context,
struct libwebsocket *wsi);
LWS_EXTERN struct libwebsocket *
libwebsocket_create_new_server_wsi(struct libwebsocket_context *context);
LWS_EXTERN char *
libwebsockets_generate_client_handshake(struct libwebsocket_context *context,
struct libwebsocket *wsi, char *pkt);
LWS_EXTERN int
lws_handle_POLLOUT_event(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
/*
* EXTENSIONS
*/
#ifndef LWS_NO_EXTENSIONS
LWS_VISIBLE void
lws_context_init_extensions(struct lws_context_creation_info *info,
struct libwebsocket_context *context);
LWS_EXTERN int
lws_any_extension_handled(struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_extension_callback_reasons r,
void *v, size_t len);
LWS_EXTERN int
lws_ext_callback_for_each_active(struct libwebsocket *wsi, int reason,
void *buf, int len);
LWS_EXTERN int
lws_ext_callback_for_each_extension_type(
struct libwebsocket_context *context, struct libwebsocket *wsi,
int reason, void *arg, int len);
#else
#define lws_any_extension_handled(_a, _b, _c, _d, _e) (0)
#define lws_ext_callback_for_each_active(_a, _b, _c, _d) (0)
#define lws_ext_callback_for_each_extension_type(_a, _b, _c, _d, _e) (0)
#define lws_issue_raw_ext_access lws_issue_raw
#define lws_context_init_extensions(_a, _b)
#endif
LWS_EXTERN int
lws_client_interpret_server_handshake(struct libwebsocket_context *context,
struct libwebsocket *wsi);
LWS_EXTERN int
libwebsocket_rx_sm(struct libwebsocket *wsi, unsigned char c);
LWS_EXTERN int
lws_issue_raw_ext_access(struct libwebsocket *wsi,
unsigned char *buf, size_t len);
LWS_EXTERN int
_libwebsocket_rx_flow_control(struct libwebsocket *wsi);
LWS_EXTERN int
user_callback_handle_rxflow(callback_function,
struct libwebsocket_context *context,
struct libwebsocket *wsi,
enum libwebsocket_callback_reasons reason, void *user,
void *in, size_t len);
LWS_EXTERN int
lws_plat_set_socket_options(struct libwebsocket_context *context, int fd);
LWS_EXTERN int
lws_allocate_header_table(struct libwebsocket *wsi);
LWS_EXTERN char *
lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h);
LWS_EXTERN int
lws_hdr_simple_create(struct libwebsocket *wsi,
enum lws_token_indexes h, const char *s);
LWS_EXTERN int
libwebsocket_ensure_user_space(struct libwebsocket *wsi);
LWS_EXTERN int
lws_change_pollfd(struct libwebsocket *wsi, int _and, int _or);
#ifndef LWS_NO_SERVER
int lws_context_init_server(struct lws_context_creation_info *info,
struct libwebsocket_context *context);
LWS_EXTERN int handshake_0405(struct libwebsocket_context *context,
struct libwebsocket *wsi);
LWS_EXTERN int
libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
unsigned char *buf, size_t len);
LWS_EXTERN void
lws_server_get_canonical_hostname(struct libwebsocket_context *context,
struct lws_context_creation_info *info);
#else
#define lws_context_init_server(_a, _b) (0)
#define libwebsocket_interpret_incoming_packet(_a, _b, _c) (0)
#define lws_server_get_canonical_hostname(_a, _b)
#endif
#ifndef LWS_NO_DAEMONIZE
LWS_EXTERN int get_daemonize_pid();
#else
#define get_daemonize_pid() (0)
#endif
LWS_EXTERN int interface_to_sa(struct libwebsocket_context *context,
const char *ifname, struct sockaddr_in *addr, size_t addrlen);
LWS_EXTERN void lwsl_emit_stderr(int level, const char *line);
#ifdef _WIN32
LWS_EXTERN HANDLE lws_plat_open_file(const char* filename, unsigned long* filelen);
#else
LWS_EXTERN int lws_plat_open_file(const char* filename, unsigned long* filelen);
#endif
enum lws_ssl_capable_status {
LWS_SSL_CAPABLE_ERROR = -1,
LWS_SSL_CAPABLE_MORE_SERVICE = -2,
};
#ifndef LWS_OPENSSL_SUPPORT
#define LWS_SSL_ENABLED(context) (0)
unsigned char *
SHA1(const unsigned char *d, size_t n, unsigned char *md);
#define lws_context_init_server_ssl(_a, _b) (0)
#define lws_ssl_destroy(_a)
#define lws_context_init_http2_ssl(_a)
#define lws_ssl_pending(_a) (0)
#define lws_ssl_capable_read lws_ssl_capable_read_no_ssl
#define lws_ssl_capable_write lws_ssl_capable_write_no_ssl
#define lws_server_socket_service_ssl(_a, _b, _c, _d, _e) (0)
#define lws_ssl_close(_a) (0)
#define lws_ssl_context_destroy(_a)
#else
#define LWS_SSL_ENABLED(context) (context->use_ssl)
LWS_EXTERN int lws_ssl_pending(struct libwebsocket *wsi);
LWS_EXTERN int openssl_websocket_private_data_index;
LWS_EXTERN int
lws_ssl_capable_read(struct libwebsocket *wsi, unsigned char *buf, int len);
LWS_EXTERN int
lws_ssl_capable_write(struct libwebsocket *wsi, unsigned char *buf, int len);
LWS_EXTERN int
lws_server_socket_service_ssl(struct libwebsocket_context *context,
struct libwebsocket **wsi, struct libwebsocket *new_wsi,
int accept_fd, struct libwebsocket_pollfd *pollfd);
LWS_EXTERN int
lws_ssl_close(struct libwebsocket *wsi);
LWS_EXTERN void
lws_ssl_context_destroy(struct libwebsocket_context *context);
#ifndef LWS_NO_SERVER
LWS_EXTERN int
lws_context_init_server_ssl(struct lws_context_creation_info *info,
struct libwebsocket_context *context);
#else
#define lws_context_init_server_ssl(_a, _b) (0)
#endif
LWS_EXTERN void
lws_ssl_destroy(struct libwebsocket_context *context);
/* HTTP2-related */
#ifdef LWS_USE_HTTP2
LWS_EXTERN void
lws_context_init_http2_ssl(struct libwebsocket_context *context);
#else
#define lws_context_init_http2_ssl(_a)
#endif
#endif
LWS_EXTERN int
lws_ssl_capable_read_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len);
LWS_EXTERN int
lws_ssl_capable_write_no_ssl(struct libwebsocket *wsi, unsigned char *buf, int len);
#ifndef LWS_NO_CLIENT
LWS_EXTERN int lws_client_socket_service(
struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
#ifdef LWS_OPENSSL_SUPPORT
LWS_EXTERN int lws_context_init_client_ssl(struct lws_context_creation_info *info,
struct libwebsocket_context *context);
#else
#define lws_context_init_client_ssl(_a, _b) (0)
#endif
LWS_EXTERN int lws_handshake_client(struct libwebsocket *wsi, unsigned char **buf, size_t len);
LWS_EXTERN void
libwebsockets_decode_ssl_error(void);
#else
#define lws_context_init_client_ssl(_a, _b) (0)
#define lws_handshake_client(_a, _b, _c) (0)
#endif
#ifndef LWS_NO_SERVER
LWS_EXTERN int lws_server_socket_service(
struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd);
LWS_EXTERN int _libwebsocket_rx_flow_control(struct libwebsocket *wsi);
LWS_EXTERN int lws_handshake_server(struct libwebsocket_context *context,
struct libwebsocket *wsi, unsigned char **buf, size_t len);
#else
#define lws_server_socket_service(_a, _b, _c) (0)
#define _libwebsocket_rx_flow_control(_a) (0)
#define lws_handshake_server(_a, _b, _c, _d) (0)
#endif
/*
* lws_plat_
*/
LWS_EXTERN void
lws_plat_delete_socket_from_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi, int m);
LWS_EXTERN void
lws_plat_insert_socket_into_fds(struct libwebsocket_context *context,
struct libwebsocket *wsi);
LWS_EXTERN void
lws_plat_service_periodic(struct libwebsocket_context *context);
LWS_EXTERN int
lws_plat_change_pollfd(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pfd);
LWS_EXTERN int
lws_plat_context_early_init(void);
LWS_EXTERN void
lws_plat_context_early_destroy(struct libwebsocket_context *context);
LWS_EXTERN void
lws_plat_context_late_destroy(struct libwebsocket_context *context);
LWS_EXTERN int
lws_poll_listen_fd(struct libwebsocket_pollfd *fd);
LWS_EXTERN int
lws_plat_service(struct libwebsocket_context *context, int timeout_ms);
LWS_EXTERN int
lws_plat_init_fd_tables(struct libwebsocket_context *context);
LWS_EXTERN void
lws_plat_drop_app_privileges(struct lws_context_creation_info *info);
LWS_EXTERN unsigned long long
time_in_microseconds(void);
LWS_EXTERN const char *
lws_plat_inet_ntop(int af, const void *src, char *dst, int cnt);

View File

@ -1,280 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
#define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
#ifndef LWS_NO_EXTENSIONS
LWS_VISIBLE int
lws_extension_server_handshake(struct libwebsocket_context *context,
struct libwebsocket *wsi, char **p)
{
int n;
char *c;
char ext_name[128];
struct libwebsocket_extension *ext;
int ext_count = 0;
int more = 1;
/*
* Figure out which extensions the client has that we want to
* enable on this connection, and give him back the list
*/
if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS))
return 0;
/*
* break down the list of client extensions
* and go through them
*/
if (lws_hdr_copy(wsi, (char *)context->service_buffer,
sizeof(context->service_buffer),
WSI_TOKEN_EXTENSIONS) < 0)
return 1;
c = (char *)context->service_buffer;
lwsl_parser("WSI_TOKEN_EXTENSIONS = '%s'\n", c);
wsi->count_active_extensions = 0;
n = 0;
while (more) {
if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
ext_name[n] = *c++;
if (n < sizeof(ext_name) - 1)
n++;
continue;
}
ext_name[n] = '\0';
if (!*c)
more = 0;
else {
c++;
if (!n)
continue;
}
/* check a client's extension against our support */
ext = wsi->protocol->owning_server->extensions;
while (ext && ext->callback) {
if (strcmp(ext_name, ext->name)) {
ext++;
continue;
}
/*
* oh, we do support this one he
* asked for... but let's ask user
* code if it's OK to apply it on this
* particular connection + protocol
*/
n = wsi->protocol->owning_server->
protocols[0].callback(
wsi->protocol->owning_server,
wsi,
LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
wsi->user_space, ext_name, 0);
/*
* zero return from callback means
* go ahead and allow the extension,
* it's what we get if the callback is
* unhandled
*/
if (n) {
ext++;
continue;
}
/* apply it */
if (ext_count)
*(*p)++ = ',';
else
LWS_CPYAPP(*p,
"\x0d\x0aSec-WebSocket-Extensions: ");
*p += sprintf(*p, "%s", ext_name);
ext_count++;
/* instantiate the extension on this conn */
wsi->active_extensions_user[
wsi->count_active_extensions] =
malloc(ext->per_session_data_size);
if (wsi->active_extensions_user[
wsi->count_active_extensions] == NULL) {
lwsl_err("Out of mem\n");
return 1;
}
memset(wsi->active_extensions_user[
wsi->count_active_extensions], 0,
ext->per_session_data_size);
wsi->active_extensions[
wsi->count_active_extensions] = ext;
/* allow him to construct his context */
ext->callback(wsi->protocol->owning_server,
ext, wsi,
LWS_EXT_CALLBACK_CONSTRUCT,
wsi->active_extensions_user[
wsi->count_active_extensions], NULL, 0);
wsi->count_active_extensions++;
lwsl_parser("count_active_extensions <- %d\n",
wsi->count_active_extensions);
ext++;
}
n = 0;
}
return 0;
}
#endif
int
handshake_0405(struct libwebsocket_context *context, struct libwebsocket *wsi)
{
unsigned char hash[20];
int n;
char *response;
char *p;
int accept_len;
if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) ||
!lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) {
lwsl_parser("handshake_04 missing pieces\n");
/* completed header processing, but missing some bits */
goto bail;
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_KEY) >=
MAX_WEBSOCKET_04_KEY_LEN) {
lwsl_warn("Client key too long %d\n", MAX_WEBSOCKET_04_KEY_LEN);
goto bail;
}
/*
* since key length is restricted above (currently 128), cannot
* overflow
*/
n = sprintf((char *)context->service_buffer,
"%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY));
SHA1(context->service_buffer, n, hash);
accept_len = lws_b64_encode_string((char *)hash, 20,
(char *)context->service_buffer,
sizeof(context->service_buffer));
if (accept_len < 0) {
lwsl_warn("Base64 encoded hash too long\n");
goto bail;
}
/* allocate the per-connection user memory (if any) */
if (libwebsocket_ensure_user_space(wsi))
goto bail;
/* create the response packet */
/* make a buffer big enough for everything */
response = (char *)context->service_buffer + MAX_WEBSOCKET_04_KEY_LEN;
p = response;
LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
"Upgrade: WebSocket\x0d\x0a"
"Connection: Upgrade\x0d\x0a"
"Sec-WebSocket-Accept: ");
strcpy(p, (char *)context->service_buffer);
p += accept_len;
if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
n = lws_hdr_copy(wsi, p, 128, WSI_TOKEN_PROTOCOL);
if (n < 0)
goto bail;
p += n;
}
#ifndef LWS_NO_EXTENSIONS
/*
* Figure out which extensions the client has that we want to
* enable on this connection, and give him back the list
*/
if (lws_extension_server_handshake(context, wsi, &p))
goto bail;
#endif
/* end of response packet */
LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
if (!lws_any_extension_handled(context, wsi,
LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
response, p - response)) {
/* okay send the handshake response accepting the connection */
lwsl_parser("issuing resp pkt %d len\n", (int)(p - response));
#ifdef DEBUG
fwrite(response, 1, p - response, stderr);
#endif
n = libwebsocket_write(wsi, (unsigned char *)response,
p - response, LWS_WRITE_HTTP);
if (n != (p - response)) {
lwsl_debug("handshake_0405: ERROR writing to socket\n");
goto bail;
}
}
/* alright clean up and set ourselves into established state */
wsi->state = WSI_STATE_ESTABLISHED;
wsi->lws_rx_parse_state = LWS_RXPS_NEW;
/* notify user code that we're ready to roll */
if (wsi->protocol->callback)
wsi->protocol->callback(wsi->protocol->owning_server,
wsi, LWS_CALLBACK_ESTABLISHED,
wsi->user_space, NULL, 0);
return 0;
bail:
/* free up his parsing allocations */
if (wsi->u.hdr.ah)
free(wsi->u.hdr.ah);
return -1;
}

View File

@ -1,868 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
int lws_context_init_server(struct lws_context_creation_info *info,
struct libwebsocket_context *context)
{
int n;
int sockfd;
struct sockaddr_in sin;
socklen_t len = sizeof(sin);
int opt = 1;
struct libwebsocket *wsi;
#ifdef LWS_USE_IPV6
struct sockaddr_in6 serv_addr6;
#endif
struct sockaddr_in serv_addr4;
struct sockaddr *v;
/* set up our external listening socket we serve on */
if (info->port == CONTEXT_PORT_NO_LISTEN)
return 0;
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context))
sockfd = socket(AF_INET6, SOCK_STREAM, 0);
else
#endif
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
lwsl_err("ERROR opening socket\n");
return 1;
}
/*
* allow us to restart even if old sockets in TIME_WAIT
*/
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR,
(const void *)&opt, sizeof(opt));
lws_plat_set_socket_options(context, sockfd);
#ifdef LWS_USE_IPV6
if (LWS_IPV6_ENABLED(context)) {
v = (struct sockaddr *)&serv_addr6;
n = sizeof(struct sockaddr_in6);
bzero((char *) &serv_addr6, sizeof(serv_addr6));
serv_addr6.sin6_addr = in6addr_any;
serv_addr6.sin6_family = AF_INET6;
serv_addr6.sin6_port = htons(info->port);
} else
#endif
{
v = (struct sockaddr *)&serv_addr4;
n = sizeof(serv_addr4);
bzero((char *) &serv_addr4, sizeof(serv_addr4));
serv_addr4.sin_addr.s_addr = INADDR_ANY;
serv_addr4.sin_family = AF_INET;
serv_addr4.sin_port = htons(info->port);
if (info->iface) {
if (interface_to_sa(context, info->iface,
(struct sockaddr_in *)v, n) < 0) {
lwsl_err("Unable to find interface %s\n",
info->iface);
compatible_close(sockfd);
return 1;
}
}
} /* ipv4 */
n = bind(sockfd, v, n);
if (n < 0) {
lwsl_err("ERROR on binding to port %d (%d %d)\n",
info->port, n, LWS_ERRNO);
compatible_close(sockfd);
return 1;
}
if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
else
info->port = ntohs(sin.sin_port);
context->listen_port = info->port;
wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
if (wsi == NULL) {
lwsl_err("Out of mem\n");
compatible_close(sockfd);
return 1;
}
memset(wsi, 0, sizeof(struct libwebsocket));
wsi->sock = sockfd;
wsi->mode = LWS_CONNMODE_SERVER_LISTENER;
insert_wsi_socket_into_fds(context, wsi);
context->listen_service_modulo = LWS_LISTEN_SERVICE_MODULO;
context->listen_service_count = 0;
context->listen_service_fd = sockfd;
listen(sockfd, LWS_SOMAXCONN);
lwsl_notice(" Listening on port %d\n", info->port);
return 0;
}
int
_libwebsocket_rx_flow_control(struct libwebsocket *wsi)
{
struct libwebsocket_context *context = wsi->protocol->owning_server;
/* there is no pending change */
if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_PENDING_CHANGE))
return 0;
/* stuff is still buffered, not ready to really accept new input */
if (wsi->u.ws.rxflow_buffer) {
/* get ourselves called back to deal with stashed buffer */
libwebsocket_callback_on_writable(context, wsi);
return 0;
}
/* pending is cleared, we can change rxflow state */
wsi->u.ws.rxflow_change_to &= ~LWS_RXFLOW_PENDING_CHANGE;
lwsl_info("rxflow: wsi %p change_to %d\n", wsi,
wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW);
/* adjust the pollfd for this wsi */
if (wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW) {
if (lws_change_pollfd(wsi, 0, LWS_POLLIN)) {
lwsl_info("%s: fail\n", __func__);
return -1;
}
} else
if (lws_change_pollfd(wsi, LWS_POLLIN, 0))
return -1;
return 0;
}
int lws_handshake_server(struct libwebsocket_context *context,
struct libwebsocket *wsi, unsigned char **buf, size_t len)
{
struct allocated_headers *ah;
char *uri_ptr = NULL;
int uri_len = 0;
char content_length_str[32];
int n;
/* LWS_CONNMODE_WS_SERVING */
while (len--) {
if (libwebsocket_parse(wsi, *(*buf)++)) {
lwsl_info("libwebsocket_parse failed\n");
goto bail_nuke_ah;
}
if (wsi->u.hdr.parser_state != WSI_PARSING_COMPLETE)
continue;
lwsl_parser("libwebsocket_parse sees parsing complete\n");
wsi->mode = LWS_CONNMODE_PRE_WS_SERVING_ACCEPT;
libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
/* is this websocket protocol or normal http 1.0? */
if (!lws_hdr_total_length(wsi, WSI_TOKEN_UPGRADE) ||
!lws_hdr_total_length(wsi, WSI_TOKEN_CONNECTION)) {
/* it's not websocket.... shall we accept it as http? */
if (!lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
!lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
lwsl_warn("Missing URI in HTTP request\n");
goto bail_nuke_ah;
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI) &&
lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
lwsl_warn("GET and POST methods?\n");
goto bail_nuke_ah;
}
if (libwebsocket_ensure_user_space(wsi))
goto bail_nuke_ah;
if (lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI)) {
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI);
uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_GET_URI);
lwsl_info("HTTP GET request for '%s'\n",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_GET_URI));
}
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI)) {
lwsl_info("HTTP POST request for '%s'\n",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI));
uri_ptr = lws_hdr_simple_ptr(wsi, WSI_TOKEN_POST_URI);
uri_len = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI);
}
/*
* Hm we still need the headers so the
* callback can look at leaders like the URI, but we
* need to transition to http union state.... hold a
* copy of u.hdr.ah and deallocate afterwards
*/
ah = wsi->u.hdr.ah;
/* union transition */
memset(&wsi->u, 0, sizeof(wsi->u));
wsi->mode = LWS_CONNMODE_HTTP_SERVING_ACCEPTED;
wsi->state = WSI_STATE_HTTP;
wsi->u.http.fd = LWS_INVALID_FILE;
/* expose it at the same offset as u.hdr */
wsi->u.http.ah = ah;
/* HTTP header had a content length? */
wsi->u.http.content_length = 0;
if (lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI))
wsi->u.http.content_length = 100 * 1024 * 1024;
if (lws_hdr_total_length(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH)) {
lws_hdr_copy(wsi, content_length_str,
sizeof(content_length_str) - 1,
WSI_TOKEN_HTTP_CONTENT_LENGTH);
wsi->u.http.content_length = atoi(content_length_str);
}
if (wsi->u.http.content_length > 0) {
wsi->u.http.body_index = 0;
n = wsi->protocol->rx_buffer_size;
if (!n)
n = LWS_MAX_SOCKET_IO_BUF;
wsi->u.http.post_buffer = malloc(n);
if (!wsi->u.http.post_buffer) {
lwsl_err("Unable to allocate post buffer\n");
n = -1;
goto cleanup;
}
}
n = 0;
if (wsi->protocol->callback)
n = wsi->protocol->callback(context, wsi,
LWS_CALLBACK_FILTER_HTTP_CONNECTION,
wsi->user_space, uri_ptr, uri_len);
if (!n) {
/*
* if there is content supposed to be coming,
* put a timeout on it having arrived
*/
libwebsocket_set_timeout(wsi,
PENDING_TIMEOUT_HTTP_CONTENT,
AWAITING_TIMEOUT);
if (wsi->protocol->callback)
n = wsi->protocol->callback(context, wsi,
LWS_CALLBACK_HTTP,
wsi->user_space, uri_ptr, uri_len);
}
cleanup:
/* now drop the header info we kept a pointer to */
if (ah)
free(ah);
/* not possible to continue to use past here */
wsi->u.http.ah = NULL;
if (n) {
lwsl_info("LWS_CALLBACK_HTTP closing\n");
return 1; /* struct ah ptr already nuked */
}
/*
* (if callback didn't start sending a file)
* deal with anything else as body, whether
* there was a content-length or not
*/
if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE)
wsi->state = WSI_STATE_HTTP_BODY;
return 2; /* goto http_postbody; */
}
if (!wsi->protocol)
lwsl_err("NULL protocol at libwebsocket_read\n");
/*
* It's websocket
*
* Make sure user side is happy about protocol
*/
while (wsi->protocol->callback) {
if (!lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
if (wsi->protocol->name == NULL)
break;
} else
if (wsi->protocol->name && strcmp(
lws_hdr_simple_ptr(wsi,
WSI_TOKEN_PROTOCOL),
wsi->protocol->name) == 0)
break;
wsi->protocol++;
}
/* we didn't find a protocol he wanted? */
if (wsi->protocol->callback == NULL) {
if (lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL) ==
NULL) {
lwsl_info("no protocol -> prot 0 handler\n");
wsi->protocol = &context->protocols[0];
} else {
lwsl_err("Req protocol %s not supported\n",
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL));
goto bail_nuke_ah;
}
}
/* allocate wsi->user storage */
if (libwebsocket_ensure_user_space(wsi))
goto bail_nuke_ah;
/*
* Give the user code a chance to study the request and
* have the opportunity to deny it
*/
if ((wsi->protocol->callback)(wsi->protocol->owning_server, wsi,
LWS_CALLBACK_FILTER_PROTOCOL_CONNECTION,
wsi->user_space,
lws_hdr_simple_ptr(wsi, WSI_TOKEN_PROTOCOL), 0)) {
lwsl_warn("User code denied connection\n");
goto bail_nuke_ah;
}
/*
* Perform the handshake according to the protocol version the
* client announced
*/
switch (wsi->ietf_spec_revision) {
case 13:
lwsl_parser("lws_parse calling handshake_04\n");
if (handshake_0405(context, wsi)) {
lwsl_info("hs0405 has failed the connection\n");
goto bail_nuke_ah;
}
break;
default:
lwsl_warn("Unknown client spec version %d\n",
wsi->ietf_spec_revision);
goto bail_nuke_ah;
}
/* drop the header info -- no bail_nuke_ah after this */
if (wsi->u.hdr.ah)
free(wsi->u.hdr.ah);
wsi->mode = LWS_CONNMODE_WS_SERVING;
/* union transition */
memset(&wsi->u, 0, sizeof(wsi->u));
wsi->u.ws.rxflow_change_to = LWS_RXFLOW_ALLOW;
/*
* create the frame buffer for this connection according to the
* size mentioned in the protocol definition. If 0 there, use
* a big default for compatibility
*/
n = wsi->protocol->rx_buffer_size;
if (!n)
n = LWS_MAX_SOCKET_IO_BUF;
n += LWS_SEND_BUFFER_PRE_PADDING + LWS_SEND_BUFFER_POST_PADDING;
wsi->u.ws.rx_user_buffer = malloc(n);
if (!wsi->u.ws.rx_user_buffer) {
lwsl_err("Out of Mem allocating rx buffer %d\n", n);
return 1;
}
lwsl_info("Allocating RX buffer %d\n", n);
if (setsockopt(wsi->sock, SOL_SOCKET, SO_SNDBUF, (const char *)&n, sizeof n)) {
lwsl_warn("Failed to set SNDBUF to %d", n);
return 1;
}
lwsl_parser("accepted v%02d connection\n",
wsi->ietf_spec_revision);
} /* while all chars are handled */
return 0;
bail_nuke_ah:
/* drop the header info */
if (wsi->u.hdr.ah)
free(wsi->u.hdr.ah);
return 1;
}
struct libwebsocket *
libwebsocket_create_new_server_wsi(struct libwebsocket_context *context)
{
struct libwebsocket *new_wsi;
new_wsi = (struct libwebsocket *)malloc(sizeof(struct libwebsocket));
if (new_wsi == NULL) {
lwsl_err("Out of memory for new connection\n");
return NULL;
}
memset(new_wsi, 0, sizeof(struct libwebsocket));
new_wsi->pending_timeout = NO_PENDING_TIMEOUT;
/* intialize the instance struct */
new_wsi->state = WSI_STATE_HTTP;
new_wsi->mode = LWS_CONNMODE_HTTP_SERVING;
new_wsi->hdr_parsing_completed = 0;
if (lws_allocate_header_table(new_wsi)) {
free(new_wsi);
return NULL;
}
/*
* these can only be set once the protocol is known
* we set an unestablished connection's protocol pointer
* to the start of the supported list, so it can look
* for matching ones during the handshake
*/
new_wsi->protocol = context->protocols;
new_wsi->user_space = NULL;
new_wsi->ietf_spec_revision = 0;
/*
* outermost create notification for wsi
* no user_space because no protocol selection
*/
context->protocols[0].callback(context, new_wsi,
LWS_CALLBACK_WSI_CREATE, NULL, NULL, 0);
return new_wsi;
}
int lws_server_socket_service(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
{
struct libwebsocket *new_wsi = NULL;
int accept_fd = 0;
socklen_t clilen;
struct sockaddr_in cli_addr;
int n;
int len;
switch (wsi->mode) {
case LWS_CONNMODE_HTTP_SERVING:
case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
/* handle http headers coming in */
/* pending truncated sends have uber priority */
if (wsi->truncated_send_malloc) {
if (pollfd->revents & LWS_POLLOUT)
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
wsi->truncated_send_offset,
wsi->truncated_send_len) < 0) {
lwsl_info("closing from socket service\n");
return -1;
}
/*
* we can't afford to allow input processing send
* something new, so spin around he event loop until
* he doesn't have any partials
*/
break;
}
/* any incoming data ready? */
if (pollfd->revents & LWS_POLLIN) {
len = lws_ssl_capable_read(wsi,
context->service_buffer,
sizeof(context->service_buffer));
switch (len) {
case 0:
lwsl_info("lws_server_skt_srv: read 0 len\n");
/* lwsl_info(" state=%d\n", wsi->state); */
if (!wsi->hdr_parsing_completed)
free(wsi->u.hdr.ah);
/* fallthru */
case LWS_SSL_CAPABLE_ERROR:
libwebsocket_close_and_free_session(
context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return 0;
case LWS_SSL_CAPABLE_MORE_SERVICE:
break;
}
/* just ignore incoming if waiting for close */
if (wsi->state != WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
/* hm this may want to send (via HTTP callback for example) */
n = libwebsocket_read(context, wsi,
context->service_buffer, len);
if (n < 0)
/* we closed wsi */
return 0;
/* hum he may have used up the writability above */
break;
}
}
/* this handles POLLOUT for http serving fragments */
if (!(pollfd->revents & LWS_POLLOUT))
break;
/* one shot */
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
goto fail;
lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);
if (wsi->state != WSI_STATE_HTTP_ISSUING_FILE) {
n = user_callback_handle_rxflow(
wsi->protocol->callback,
wsi->protocol->owning_server,
wsi, LWS_CALLBACK_HTTP_WRITEABLE,
wsi->user_space,
NULL,
0);
if (n < 0)
libwebsocket_close_and_free_session(
context, wsi, LWS_CLOSE_STATUS_NOSTATUS);
break;
}
/* nonzero for completion or error */
if (libwebsockets_serve_http_file_fragment(context, wsi))
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
break;
case LWS_CONNMODE_SERVER_LISTENER:
/* pollin means a client has connected to us then */
if (!(pollfd->revents & LWS_POLLIN))
break;
/* listen socket got an unencrypted connection... */
clilen = sizeof(cli_addr);
lws_latency_pre(context, wsi);
accept_fd = accept(pollfd->fd, (struct sockaddr *)&cli_addr,
&clilen);
lws_latency(context, wsi,
"unencrypted accept LWS_CONNMODE_SERVER_LISTENER",
accept_fd, accept_fd >= 0);
if (accept_fd < 0) {
if (LWS_ERRNO == LWS_EAGAIN || LWS_ERRNO == LWS_EWOULDBLOCK) {
lwsl_debug("accept asks to try again\n");
break;
}
lwsl_warn("ERROR on accept: %s\n", strerror(LWS_ERRNO));
break;
}
lws_plat_set_socket_options(context, accept_fd);
/*
* look at who we connected to and give user code a chance
* to reject based on client IP. There's no protocol selected
* yet so we issue this to protocols[0]
*/
if ((context->protocols[0].callback)(context, wsi,
LWS_CALLBACK_FILTER_NETWORK_CONNECTION,
NULL, (void *)(long)accept_fd, 0)) {
lwsl_debug("Callback denied network connection\n");
compatible_close(accept_fd);
break;
}
new_wsi = libwebsocket_create_new_server_wsi(context);
if (new_wsi == NULL) {
compatible_close(accept_fd);
break;
}
new_wsi->sock = accept_fd;
/* the transport is accepted... give him time to negotiate */
libwebsocket_set_timeout(new_wsi,
PENDING_TIMEOUT_ESTABLISH_WITH_SERVER,
AWAITING_TIMEOUT);
/*
* A new connection was accepted. Give the user a chance to
* set properties of the newly created wsi. There's no protocol
* selected yet so we issue this to protocols[0]
*/
(context->protocols[0].callback)(context, new_wsi,
LWS_CALLBACK_SERVER_NEW_CLIENT_INSTANTIATED, NULL, NULL, 0);
lws_libev_accept(context, new_wsi, accept_fd);
if (!LWS_SSL_ENABLED(context)) {
lwsl_debug("accepted new conn port %u on fd=%d\n",
ntohs(cli_addr.sin_port), accept_fd);
insert_wsi_socket_into_fds(context, new_wsi);
}
break;
default:
break;
}
if (lws_server_socket_service_ssl(context, &wsi, new_wsi, accept_fd, pollfd))
goto fail;
return 0;
fail:
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
return 1;
}
static const char *err400[] = {
"Bad Request",
"Unauthorized",
"Payment Required",
"Forbidden",
"Not Found",
"Method Not Allowed",
"Not Acceptable",
"Proxy Auth Required",
"Request Timeout",
"Conflict",
"Gone",
"Length Required",
"Precondition Failed",
"Request Entity Too Large",
"Request URI too Long",
"Unsupported Media Type",
"Requested Range Not Satisfiable",
"Expectation Failed"
};
static const char *err500[] = {
"Internal Server Error",
"Not Implemented",
"Bad Gateway",
"Service Unavailable",
"Gateway Timeout",
"HTTP Version Not Supported"
};
/**
* libwebsockets_return_http_status() - Return simple http status
* @context: libwebsockets context
* @wsi: Websocket instance (available from user callback)
* @code: Status index, eg, 404
* @html_body: User-readable HTML description, or NULL
*
* Helper to report HTTP errors back to the client cleanly and
* consistently
*/
LWS_VISIBLE int libwebsockets_return_http_status(
struct libwebsocket_context *context, struct libwebsocket *wsi,
unsigned int code, const char *html_body)
{
int n, m;
const char *description = "";
if (!html_body)
html_body = "";
if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
description = err400[code - 400];
if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
description = err500[code - 500];
n = sprintf((char *)context->service_buffer,
"HTTP/1.0 %u %s\x0d\x0a"
"Server: libwebsockets\x0d\x0a"
"Content-Type: text/html\x0d\x0a\x0d\x0a"
"<h1>%u %s</h1>%s",
code, description, code, description, html_body);
lwsl_info((const char *)context->service_buffer);
m = libwebsocket_write(wsi, context->service_buffer, n, LWS_WRITE_HTTP);
return m;
}
/**
* libwebsockets_serve_http_file() - Send a file back to the client using http
* @context: libwebsockets context
* @wsi: Websocket instance (available from user callback)
* @file: The file to issue over http
* @content_type: The http content type, eg, text/html
* @other_headers: NULL or pointer to \0-terminated other header string
*
* This function is intended to be called from the callback in response
* to http requests from the client. It allows the callback to issue
* local files down the http link in a single step.
*
* Returning <0 indicates error and the wsi should be closed. Returning
* >0 indicates the file was completely sent and the wsi should be closed.
* ==0 indicates the file transfer is started and needs more service later,
* the wsi should be left alone.
*/
LWS_VISIBLE int libwebsockets_serve_http_file(
struct libwebsocket_context *context,
struct libwebsocket *wsi, const char *file,
const char *content_type, const char *other_headers)
{
unsigned char *p = context->service_buffer;
int ret = 0;
int n;
wsi->u.http.fd = lws_plat_open_file(file, &wsi->u.http.filelen);
if (wsi->u.http.fd == LWS_INVALID_FILE) {
lwsl_err("Unable to open '%s'\n", file);
libwebsockets_return_http_status(context, wsi,
HTTP_STATUS_NOT_FOUND, NULL);
return -1;
}
p += sprintf((char *)p,
"HTTP/1.0 200 OK\x0d\x0aServer: libwebsockets\x0d\x0a""Content-Type: %s\x0d\x0a",
content_type);
if (other_headers) {
n = strlen(other_headers);
memcpy(p, other_headers, n);
p += n;
}
p += sprintf((char *)p,
"Content-Length: %lu\x0d\x0a\x0d\x0a", wsi->u.http.filelen);
ret = libwebsocket_write(wsi, context->service_buffer,
p - context->service_buffer, LWS_WRITE_HTTP);
if (ret != (p - context->service_buffer)) {
lwsl_err("_write returned %d from %d\n", ret, (p - context->service_buffer));
return -1;
}
wsi->u.http.filepos = 0;
wsi->state = WSI_STATE_HTTP_ISSUING_FILE;
return libwebsockets_serve_http_file_fragment(context, wsi);
}
int libwebsocket_interpret_incoming_packet(struct libwebsocket *wsi,
unsigned char *buf, size_t len)
{
size_t n = 0;
int m;
#if 0
lwsl_parser("received %d byte packet\n", (int)len);
lwsl_hexdump(buf, len);
#endif
/* let the rx protocol state machine have as much as it needs */
while (n < len) {
/*
* we were accepting input but now we stopped doing so
*/
if (!(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) {
/* his RX is flowcontrolled, don't send remaining now */
if (!wsi->u.ws.rxflow_buffer) {
/* a new rxflow, buffer it and warn caller */
lwsl_info("new rxflow input buffer len %d\n",
len - n);
wsi->u.ws.rxflow_buffer =
(unsigned char *)malloc(len - n);
wsi->u.ws.rxflow_len = len - n;
wsi->u.ws.rxflow_pos = 0;
memcpy(wsi->u.ws.rxflow_buffer,
buf + n, len - n);
} else
/* rxflow while we were spilling prev rxflow */
lwsl_info("stalling in existing rxflow buf\n");
return 1;
}
/* account for what we're using in rxflow buffer */
if (wsi->u.ws.rxflow_buffer)
wsi->u.ws.rxflow_pos++;
/* process the byte */
m = libwebsocket_rx_sm(wsi, buf[n++]);
if (m < 0)
return -1;
}
return 0;
}
LWS_VISIBLE void
lws_server_get_canonical_hostname(struct libwebsocket_context *context,
struct lws_context_creation_info *info)
{
if (info->options & LWS_SERVER_OPTION_SKIP_SERVER_CANONICAL_NAME)
return;
/* find canonical hostname */
gethostname((char *)context->canonical_hostname,
sizeof(context->canonical_hostname) - 1);
lwsl_notice(" canonical_hostname = %s\n", context->canonical_hostname);
}

View File

@ -1,514 +0,0 @@
/*
* libwebsockets - small server side websockets and web server implementation
*
* Copyright (C) 2010-2014 Andy Green <andy@warmcat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation:
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
#include "private-libwebsockets.h"
int
lws_handle_POLLOUT_event(struct libwebsocket_context *context,
struct libwebsocket *wsi, struct libwebsocket_pollfd *pollfd)
{
int n;
struct lws_tokens eff_buf;
int ret;
int m;
int handled = 0;
/* pending truncated sends have uber priority */
if (wsi->truncated_send_len) {
if (lws_issue_raw(wsi, wsi->truncated_send_malloc +
wsi->truncated_send_offset,
wsi->truncated_send_len) < 0) {
lwsl_info("lws_handle_POLLOUT_event signalling to close\n");
return -1;
}
/* leave POLLOUT active either way */
return 0;
} else
if (wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) {
lwsl_info("***** %x signalling to close in POLLOUT handler\n", wsi);
return -1; /* retry closing now */
}
m = lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_IS_WRITEABLE,
NULL, 0);
if (handled == 1)
goto notify_action;
#ifndef LWS_NO_EXTENSIONS
if (!wsi->extension_data_pending || handled == 2)
goto user_service;
#endif
/*
* check in on the active extensions, see if they
* had pending stuff to spill... they need to get the
* first look-in otherwise sequence will be disordered
*
* NULL, zero-length eff_buf means just spill pending
*/
ret = 1;
while (ret == 1) {
/* default to nobody has more to spill */
ret = 0;
eff_buf.token = NULL;
eff_buf.token_len = 0;
/* give every extension a chance to spill */
m = lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_PACKET_TX_PRESEND,
&eff_buf, 0);
if (m < 0) {
lwsl_err("ext reports fatal error\n");
return -1;
}
if (m)
/*
* at least one extension told us he has more
* to spill, so we will go around again after
*/
ret = 1;
/* assuming they gave us something to send, send it */
if (eff_buf.token_len) {
n = lws_issue_raw(wsi, (unsigned char *)eff_buf.token,
eff_buf.token_len);
if (n < 0) {
lwsl_info("closing from POLLOUT spill\n");
return -1;
}
/*
* Keep amount spilled small to minimize chance of this
*/
if (n != eff_buf.token_len) {
lwsl_err("Unable to spill ext %d vs %s\n",
eff_buf.token_len, n);
return -1;
}
} else
continue;
/* no extension has more to spill */
if (!ret)
continue;
/*
* There's more to spill from an extension, but we just sent
* something... did that leave the pipe choked?
*/
if (!lws_send_pipe_choked(wsi))
/* no we could add more */
continue;
lwsl_info("choked in POLLOUT service\n");
/*
* Yes, he's choked. Leave the POLLOUT masked on so we will
* come back here when he is unchoked. Don't call the user
* callback to enforce ordering of spilling, he'll get called
* when we come back here and there's nothing more to spill.
*/
return 0;
}
#ifndef LWS_NO_EXTENSIONS
wsi->extension_data_pending = 0;
user_service:
#endif
/* one shot */
if (pollfd) {
if (lws_change_pollfd(wsi, LWS_POLLOUT, 0))
return 1;
lws_libev_io(context, wsi, LWS_EV_STOP | LWS_EV_WRITE);
}
notify_action:
if (wsi->mode == LWS_CONNMODE_WS_CLIENT)
n = LWS_CALLBACK_CLIENT_WRITEABLE;
else
n = LWS_CALLBACK_SERVER_WRITEABLE;
return user_callback_handle_rxflow(wsi->protocol->callback, context,
wsi, (enum libwebsocket_callback_reasons) n,
wsi->user_space, NULL, 0);
}
int
libwebsocket_service_timeout_check(struct libwebsocket_context *context,
struct libwebsocket *wsi, unsigned int sec)
{
/*
* if extensions want in on it (eg, we are a mux parent)
* give them a chance to service child timeouts
*/
if (lws_ext_callback_for_each_active(wsi, LWS_EXT_CALLBACK_1HZ, NULL, sec) < 0)
return 0;
if (!wsi->pending_timeout)
return 0;
/*
* if we went beyond the allowed time, kill the
* connection
*/
if (sec > wsi->pending_timeout_limit) {
lwsl_info("TIMEDOUT WAITING on %d\n", wsi->pending_timeout);
libwebsocket_close_and_free_session(context,
wsi, LWS_CLOSE_STATUS_NOSTATUS);
return 1;
}
return 0;
}
/**
* libwebsocket_service_fd() - Service polled socket with something waiting
* @context: Websocket context
* @pollfd: The pollfd entry describing the socket fd and which events
* happened.
*
* This function takes a pollfd that has POLLIN or POLLOUT activity and
* services it according to the state of the associated
* struct libwebsocket.
*
* The one call deals with all "service" that might happen on a socket
* including listen accepts, http files as well as websocket protocol.
*
* If a pollfd says it has something, you can just pass it to
* libwebsocket_serice_fd() whether it is a socket handled by lws or not.
* If it sees it is a lws socket, the traffic will be handled and
* pollfd->revents will be zeroed now.
*
* If the socket is foreign to lws, it leaves revents alone. So you can
* see if you should service yourself by checking the pollfd revents
* after letting lws try to service it.
*/
LWS_VISIBLE int
libwebsocket_service_fd(struct libwebsocket_context *context,
struct libwebsocket_pollfd *pollfd)
{
struct libwebsocket *wsi;
int n;
int m;
int listen_socket_fds_index = 0;
time_t now;
int timed_out = 0;
int our_fd = 0;
char draining_flow = 0;
int more;
struct lws_tokens eff_buf;
if (context->listen_service_fd)
listen_socket_fds_index = context->lws_lookup[
context->listen_service_fd]->position_in_fds_table;
/*
* you can call us with pollfd = NULL to just allow the once-per-second
* global timeout checks; if less than a second since the last check
* it returns immediately then.
*/
time(&now);
/* TODO: if using libev, we should probably use timeout watchers... */
if (context->last_timeout_check_s != now) {
context->last_timeout_check_s = now;
lws_plat_service_periodic(context);
/* global timeout check once per second */
if (pollfd)
our_fd = pollfd->fd;
for (n = 0; n < context->fds_count; n++) {
m = context->fds[n].fd;
wsi = context->lws_lookup[m];
if (!wsi)
continue;
if (libwebsocket_service_timeout_check(context, wsi, now))
/* he did time out... */
if (m == our_fd) {
/* it was the guy we came to service! */
timed_out = 1;
/* mark as handled */
pollfd->revents = 0;
}
}
}
/* the socket we came to service timed out, nothing to do */
if (timed_out)
return 0;
/* just here for timeout management? */
if (pollfd == NULL)
return 0;
/* no, here to service a socket descriptor */
wsi = context->lws_lookup[pollfd->fd];
if (wsi == NULL)
/* not lws connection ... leave revents alone and return */
return 0;
/*
* so that caller can tell we handled, past here we need to
* zero down pollfd->revents after handling
*/
/*
* deal with listen service piggybacking
* every listen_service_modulo services of other fds, we
* sneak one in to service the listen socket if there's anything waiting
*
* To handle connection storms, as found in ab, if we previously saw a
* pending connection here, it causes us to check again next time.
*/
if (context->listen_service_fd && pollfd !=
&context->fds[listen_socket_fds_index]) {
context->listen_service_count++;
if (context->listen_service_extraseen ||
context->listen_service_count ==
context->listen_service_modulo) {
context->listen_service_count = 0;
m = 1;
if (context->listen_service_extraseen > 5)
m = 2;
while (m--) {
/*
* even with extpoll, we prepared this
* internal fds for listen
*/
n = lws_poll_listen_fd(&context->fds[listen_socket_fds_index]);
if (n > 0) { /* there's a conn waiting for us */
libwebsocket_service_fd(context,
&context->
fds[listen_socket_fds_index]);
context->listen_service_extraseen++;
} else {
if (context->listen_service_extraseen)
context->
listen_service_extraseen--;
break;
}
}
}
}
/* handle session socket closed */
if ((!(pollfd->revents & LWS_POLLIN)) &&
(pollfd->revents & LWS_POLLHUP)) {
lwsl_debug("Session Socket %p (fd=%d) dead\n",
(void *)wsi, pollfd->fd);
goto close_and_handled;
}
/* okay, what we came here to do... */
switch (wsi->mode) {
case LWS_CONNMODE_HTTP_SERVING:
case LWS_CONNMODE_HTTP_SERVING_ACCEPTED:
case LWS_CONNMODE_SERVER_LISTENER:
case LWS_CONNMODE_SSL_ACK_PENDING:
n = lws_server_socket_service(context, wsi, pollfd);
if (n < 0)
goto close_and_handled;
goto handled;
case LWS_CONNMODE_WS_SERVING:
case LWS_CONNMODE_WS_CLIENT:
/* the guy requested a callback when it was OK to write */
if ((pollfd->revents & LWS_POLLOUT) &&
(wsi->state == WSI_STATE_ESTABLISHED ||
wsi->state == WSI_STATE_FLUSHING_STORED_SEND_BEFORE_CLOSE) &&
lws_handle_POLLOUT_event(context, wsi, pollfd)) {
lwsl_info("libwebsocket_service_fd: closing\n");
goto close_and_handled;
}
if (wsi->u.ws.rxflow_buffer &&
(wsi->u.ws.rxflow_change_to & LWS_RXFLOW_ALLOW)) {
lwsl_info("draining rxflow\n");
/* well, drain it */
eff_buf.token = (char *)wsi->u.ws.rxflow_buffer +
wsi->u.ws.rxflow_pos;
eff_buf.token_len = wsi->u.ws.rxflow_len -
wsi->u.ws.rxflow_pos;
draining_flow = 1;
goto drain;
}
/* any incoming data ready? */
if (!(pollfd->revents & LWS_POLLIN))
break;
read_pending:
eff_buf.token_len = lws_ssl_capable_read(wsi,
context->service_buffer,
sizeof(context->service_buffer));
switch (eff_buf.token_len) {
case 0:
lwsl_info("service_fd: closing due to 0 length read\n");
goto close_and_handled;
case LWS_SSL_CAPABLE_ERROR:
n = 0;
goto handled;
case LWS_SSL_CAPABLE_MORE_SERVICE:
goto close_and_handled;
}
/*
* give any active extensions a chance to munge the buffer
* before parse. We pass in a pointer to an lws_tokens struct
* prepared with the default buffer and content length that's in
* there. Rather than rewrite the default buffer, extensions
* that expect to grow the buffer can adapt .token to
* point to their own per-connection buffer in the extension
* user allocation. By default with no extensions or no
* extension callback handling, just the normal input buffer is
* used then so it is efficient.
*/
eff_buf.token = (char *)context->service_buffer;
drain:
do {
more = 0;
m = lws_ext_callback_for_each_active(wsi,
LWS_EXT_CALLBACK_PACKET_RX_PREPARSE, &eff_buf, 0);
if (m < 0)
goto close_and_handled;
if (m)
more = 1;
/* service incoming data */
if (eff_buf.token_len) {
n = libwebsocket_read(context, wsi,
(unsigned char *)eff_buf.token,
eff_buf.token_len);
if (n < 0) {
/* we closed wsi */
n = 0;
goto handled;
}
}
eff_buf.token = NULL;
eff_buf.token_len = 0;
} while (more);
if (draining_flow && wsi->u.ws.rxflow_buffer &&
wsi->u.ws.rxflow_pos == wsi->u.ws.rxflow_len) {
lwsl_info("flow buffer: drained\n");
free(wsi->u.ws.rxflow_buffer);
wsi->u.ws.rxflow_buffer = NULL;
/* having drained the rxflow buffer, can rearm POLLIN */
n = _libwebsocket_rx_flow_control(wsi); /* n ignored, needed for NO_SERVER case */
}
if (lws_ssl_pending(wsi))
goto read_pending;
break;
default:
#ifdef LWS_NO_CLIENT
break;
#else
n = lws_client_socket_service(context, wsi, pollfd);
goto handled;
#endif
}
n = 0;
goto handled;
close_and_handled:
libwebsocket_close_and_free_session(context, wsi,
LWS_CLOSE_STATUS_NOSTATUS);
n = 1;
handled:
pollfd->revents = 0;
return n;
}
/**
* libwebsocket_service() - Service any pending websocket activity
* @context: Websocket context
* @timeout_ms: Timeout for poll; 0 means return immediately if nothing needed
* service otherwise block and service immediately, returning
* after the timeout if nothing needed service.
*
* This function deals with any pending websocket traffic, for three
* kinds of event. It handles these events on both server and client
* types of connection the same.
*
* 1) Accept new connections to our context's server
*
* 2) Call the receive callback for incoming frame data received by
* server or client connections.
*
* You need to call this service function periodically to all the above
* functions to happen; if your application is single-threaded you can
* just call it in your main event loop.
*
* Alternatively you can fork a new process that asynchronously handles
* calling this service in a loop. In that case you are happy if this
* call blocks your thread until it needs to take care of something and
* would call it with a large nonzero timeout. Your loop then takes no
* CPU while there is nothing happening.
*
* If you are calling it in a single-threaded app, you don't want it to
* wait around blocking other things in your loop from happening, so you
* would call it with a timeout_ms of 0, so it returns immediately if
* nothing is pending, or as soon as it services whatever was pending.
*/
LWS_VISIBLE int
libwebsocket_service(struct libwebsocket_context *context, int timeout_ms)
{
return lws_plat_service(context, timeout_ms);
}

View File

@ -1,299 +0,0 @@
/*
* Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the project nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/*
* FIPS pub 180-1: Secure Hash Algorithm (SHA-1)
* based on: http://csrc.nist.gov/fips/fip180-1.txt
* implemented by Jun-ichiro itojun Itoh <itojun@itojun.org>
*/
#include "private-libwebsockets.h"
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
struct sha1_ctxt {
union {
unsigned char b8[20];
unsigned int b32[5];
} h;
union {
unsigned char b8[8];
u_int64_t b64[1];
} c;
union {
unsigned char b8[64];
unsigned int b32[16];
} m;
unsigned char count;
};
/* sanity check */
#if !defined(BYTE_ORDER) || !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN)
# define unsupported 1
#elif BYTE_ORDER != BIG_ENDIAN
# if BYTE_ORDER != LITTLE_ENDIAN
# define unsupported 1
# endif
#endif
#ifndef unsupported
/* constant table */
static const unsigned int _K[] =
{ 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xca62c1d6 };
#define K(t) _K[(t) / 20]
#define F0(b, c, d) (((b) & (c)) | ((~(b)) & (d)))
#define F1(b, c, d) (((b) ^ (c)) ^ (d))
#define F2(b, c, d) (((b) & (c)) | ((b) & (d)) | ((c) & (d)))
#define F3(b, c, d) (((b) ^ (c)) ^ (d))
#define S(n, x) (((x) << (n)) | ((x) >> (32 - n)))
#define H(n) (ctxt->h.b32[(n)])
#define COUNT (ctxt->count)
#define BCOUNT (ctxt->c.b64[0] / 8)
#define W(n) (ctxt->m.b32[(n)])
#define PUTBYTE(x) { \
ctxt->m.b8[(COUNT % 64)] = (x); \
COUNT++; \
COUNT %= 64; \
ctxt->c.b64[0] += 8; \
if (COUNT % 64 == 0) \
sha1_step(ctxt); \
}
#define PUTPAD(x) { \
ctxt->m.b8[(COUNT % 64)] = (x); \
COUNT++; \
COUNT %= 64; \
if (COUNT % 64 == 0) \
sha1_step(ctxt); \
}
static void
sha1_step(struct sha1_ctxt *ctxt)
{
unsigned int a, b, c, d, e, tmp;
size_t t, s;
#if BYTE_ORDER == LITTLE_ENDIAN
struct sha1_ctxt tctxt;
memcpy(&tctxt.m.b8[0], &ctxt->m.b8[0], 64);
ctxt->m.b8[0] = tctxt.m.b8[3]; ctxt->m.b8[1] = tctxt.m.b8[2];
ctxt->m.b8[2] = tctxt.m.b8[1]; ctxt->m.b8[3] = tctxt.m.b8[0];
ctxt->m.b8[4] = tctxt.m.b8[7]; ctxt->m.b8[5] = tctxt.m.b8[6];
ctxt->m.b8[6] = tctxt.m.b8[5]; ctxt->m.b8[7] = tctxt.m.b8[4];
ctxt->m.b8[8] = tctxt.m.b8[11]; ctxt->m.b8[9] = tctxt.m.b8[10];
ctxt->m.b8[10] = tctxt.m.b8[9]; ctxt->m.b8[11] = tctxt.m.b8[8];
ctxt->m.b8[12] = tctxt.m.b8[15]; ctxt->m.b8[13] = tctxt.m.b8[14];
ctxt->m.b8[14] = tctxt.m.b8[13]; ctxt->m.b8[15] = tctxt.m.b8[12];
ctxt->m.b8[16] = tctxt.m.b8[19]; ctxt->m.b8[17] = tctxt.m.b8[18];
ctxt->m.b8[18] = tctxt.m.b8[17]; ctxt->m.b8[19] = tctxt.m.b8[16];
ctxt->m.b8[20] = tctxt.m.b8[23]; ctxt->m.b8[21] = tctxt.m.b8[22];
ctxt->m.b8[22] = tctxt.m.b8[21]; ctxt->m.b8[23] = tctxt.m.b8[20];
ctxt->m.b8[24] = tctxt.m.b8[27]; ctxt->m.b8[25] = tctxt.m.b8[26];
ctxt->m.b8[26] = tctxt.m.b8[25]; ctxt->m.b8[27] = tctxt.m.b8[24];
ctxt->m.b8[28] = tctxt.m.b8[31]; ctxt->m.b8[29] = tctxt.m.b8[30];
ctxt->m.b8[30] = tctxt.m.b8[29]; ctxt->m.b8[31] = tctxt.m.b8[28];
ctxt->m.b8[32] = tctxt.m.b8[35]; ctxt->m.b8[33] = tctxt.m.b8[34];
ctxt->m.b8[34] = tctxt.m.b8[33]; ctxt->m.b8[35] = tctxt.m.b8[32];
ctxt->m.b8[36] = tctxt.m.b8[39]; ctxt->m.b8[37] = tctxt.m.b8[38];
ctxt->m.b8[38] = tctxt.m.b8[37]; ctxt->m.b8[39] = tctxt.m.b8[36];
ctxt->m.b8[40] = tctxt.m.b8[43]; ctxt->m.b8[41] = tctxt.m.b8[42];
ctxt->m.b8[42] = tctxt.m.b8[41]; ctxt->m.b8[43] = tctxt.m.b8[40];
ctxt->m.b8[44] = tctxt.m.b8[47]; ctxt->m.b8[45] = tctxt.m.b8[46];
ctxt->m.b8[46] = tctxt.m.b8[45]; ctxt->m.b8[47] = tctxt.m.b8[44];
ctxt->m.b8[48] = tctxt.m.b8[51]; ctxt->m.b8[49] = tctxt.m.b8[50];
ctxt->m.b8[50] = tctxt.m.b8[49]; ctxt->m.b8[51] = tctxt.m.b8[48];
ctxt->m.b8[52] = tctxt.m.b8[55]; ctxt->m.b8[53] = tctxt.m.b8[54];
ctxt->m.b8[54] = tctxt.m.b8[53]; ctxt->m.b8[55] = tctxt.m.b8[52];
ctxt->m.b8[56] = tctxt.m.b8[59]; ctxt->m.b8[57] = tctxt.m.b8[58];
ctxt->m.b8[58] = tctxt.m.b8[57]; ctxt->m.b8[59] = tctxt.m.b8[56];
ctxt->m.b8[60] = tctxt.m.b8[63]; ctxt->m.b8[61] = tctxt.m.b8[62];
ctxt->m.b8[62] = tctxt.m.b8[61]; ctxt->m.b8[63] = tctxt.m.b8[60];
#endif
a = H(0); b = H(1); c = H(2); d = H(3); e = H(4);
for (t = 0; t < 20; t++) {
s = t & 0x0f;
if (t >= 16)
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
W((s+2) & 0x0f) ^ W(s));
tmp = S(5, a) + F0(b, c, d) + e + W(s) + K(t);
e = d; d = c; c = S(30, b); b = a; a = tmp;
}
for (t = 20; t < 40; t++) {
s = t & 0x0f;
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
W((s+2) & 0x0f) ^ W(s));
tmp = S(5, a) + F1(b, c, d) + e + W(s) + K(t);
e = d; d = c; c = S(30, b); b = a; a = tmp;
}
for (t = 40; t < 60; t++) {
s = t & 0x0f;
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
W((s+2) & 0x0f) ^ W(s));
tmp = S(5, a) + F2(b, c, d) + e + W(s) + K(t);
e = d; d = c; c = S(30, b); b = a; a = tmp;
}
for (t = 60; t < 80; t++) {
s = t & 0x0f;
W(s) = S(1, W((s+13) & 0x0f) ^ W((s+8) & 0x0f) ^
W((s+2) & 0x0f) ^ W(s));
tmp = S(5, a) + F3(b, c, d) + e + W(s) + K(t);
e = d; d = c; c = S(30, b); b = a; a = tmp;
}
H(0) = H(0) + a;
H(1) = H(1) + b;
H(2) = H(2) + c;
H(3) = H(3) + d;
H(4) = H(4) + e;
bzero(&ctxt->m.b8[0], 64);
}
/*------------------------------------------------------------*/
static void
sha1_init(struct sha1_ctxt *ctxt)
{
bzero(ctxt, sizeof(struct sha1_ctxt));
H(0) = 0x67452301;
H(1) = 0xefcdab89;
H(2) = 0x98badcfe;
H(3) = 0x10325476;
H(4) = 0xc3d2e1f0;
}
void
sha1_pad(struct sha1_ctxt *ctxt)
{
size_t padlen; /*pad length in bytes*/
size_t padstart;
PUTPAD(0x80);
padstart = COUNT % 64;
padlen = 64 - padstart;
if (padlen < 8) {
bzero(&ctxt->m.b8[padstart], padlen);
COUNT += padlen;
COUNT %= 64;
sha1_step(ctxt);
padstart = COUNT % 64; /* should be 0 */
padlen = 64 - padstart; /* should be 64 */
}
bzero(&ctxt->m.b8[padstart], padlen - 8);
COUNT += (padlen - 8);
COUNT %= 64;
#if BYTE_ORDER == BIG_ENDIAN
PUTPAD(ctxt->c.b8[0]); PUTPAD(ctxt->c.b8[1]);
PUTPAD(ctxt->c.b8[2]); PUTPAD(ctxt->c.b8[3]);
PUTPAD(ctxt->c.b8[4]); PUTPAD(ctxt->c.b8[5]);
PUTPAD(ctxt->c.b8[6]); PUTPAD(ctxt->c.b8[7]);
#else
PUTPAD(ctxt->c.b8[7]); PUTPAD(ctxt->c.b8[6]);
PUTPAD(ctxt->c.b8[5]); PUTPAD(ctxt->c.b8[4]);
PUTPAD(ctxt->c.b8[3]); PUTPAD(ctxt->c.b8[2]);
PUTPAD(ctxt->c.b8[1]); PUTPAD(ctxt->c.b8[0]);
#endif
}
void
sha1_loop(struct sha1_ctxt *ctxt, const unsigned char *input, size_t len)
{
size_t gaplen;
size_t gapstart;
size_t off;
size_t copysiz;
off = 0;
while (off < len) {
gapstart = COUNT % 64;
gaplen = 64 - gapstart;
copysiz = (gaplen < len - off) ? gaplen : len - off;
memcpy(&ctxt->m.b8[gapstart], &input[off], copysiz);
COUNT += copysiz;
COUNT %= 64;
ctxt->c.b64[0] += copysiz * 8;
if (COUNT % 64 == 0)
sha1_step(ctxt);
off += copysiz;
}
}
void
sha1_result(struct sha1_ctxt *ctxt, void *digest0)
{
unsigned char *digest;
digest = (unsigned char *)digest0;
sha1_pad(ctxt);
#if BYTE_ORDER == BIG_ENDIAN
memcpy(digest, &ctxt->h.b8[0], 20);
#else
digest[0] = ctxt->h.b8[3]; digest[1] = ctxt->h.b8[2];
digest[2] = ctxt->h.b8[1]; digest[3] = ctxt->h.b8[0];
digest[4] = ctxt->h.b8[7]; digest[5] = ctxt->h.b8[6];
digest[6] = ctxt->h.b8[5]; digest[7] = ctxt->h.b8[4];
digest[8] = ctxt->h.b8[11]; digest[9] = ctxt->h.b8[10];
digest[10] = ctxt->h.b8[9]; digest[11] = ctxt->h.b8[8];
digest[12] = ctxt->h.b8[15]; digest[13] = ctxt->h.b8[14];
digest[14] = ctxt->h.b8[13]; digest[15] = ctxt->h.b8[12];
digest[16] = ctxt->h.b8[19]; digest[17] = ctxt->h.b8[18];
digest[18] = ctxt->h.b8[17]; digest[19] = ctxt->h.b8[16];
#endif
}
/*
* This should look and work like the libcrypto implementation
*/
unsigned char *
SHA1(const unsigned char *d, size_t n, unsigned char *md)
{
struct sha1_ctxt ctx;
sha1_init(&ctx);
sha1_loop(&ctx, d, n);
sha1_result(&ctx, (void *)md);
return md;
}
#endif /*unsupported*/

View File

@ -16,7 +16,7 @@
#define TIME_PRESCALE
#define PICO_SUPPORT_THREADING
*/
#ifdef RELEASE
#if defined(RELEASE) && !defined(DEBUGFAST)
#define dbg(...)
#else
#define dbg printf

View File

@ -543,7 +543,7 @@ static int ppp_fcs_verify(uint8_t *buf, uint32_t len)
}
/* Serial send (DTE->DCE) functions */
static int pico_ppp_ctl_send(struct pico_device *dev, uint16_t code, uint8_t *pkt, uint32_t len)
static int pico_ppp_ctl_send(struct pico_device *dev, uint16_t code, uint8_t *pkt, uint32_t len, uint32_t no_escape)
{
struct pico_device_ppp *ppp = (struct pico_device_ppp *) dev;
uint16_t fcs;
@ -567,7 +567,15 @@ static int pico_ppp_ctl_send(struct pico_device *dev, uint16_t code, uint8_t *pk
pkt[len - 3] = (uint8_t)(fcs & 0xFFu);
pkt[len - 2] = (uint8_t)((fcs & 0xFF00u) >> 8);
pkt[len - 1] = PPPF_FLAG_SEQ;
uint32_t asyncmap;
if (no_escape)
{
asyncmap = ppp->asyncmap;
ppp->asyncmap = 0xffffffff;
}
ppp_serial_send_escape(ppp, pkt, (int)len);
if (no_escape)
ppp->asyncmap = asyncmap;
return (int)len;
}
@ -912,7 +920,8 @@ static void lcp_send_configure_request(struct pico_device_ppp *ppp)
sizeof(struct pico_lcp_hdr) + /* LCP HDR */
optsize + /* Actual options size */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1u) /* STOP Byte */
1u), /* STOP Byte */
1 /* no escape */
);
PICO_FREE(lcpbuf);
ppp->timer_val = PICO_PPP_DEFAULT_TIMER;
@ -1007,8 +1016,9 @@ static void lcp_send_configure_ack(struct pico_device_ppp *ppp)
PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */
short_be(lcpreq->len) + /* Actual options size + hdr (whole lcp packet) */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1 /* STOP Byte */
);
1, /* STOP Byte */
1 /* no escape */
);
}
static void lcp_send_terminate_request(struct pico_device_ppp *ppp)
@ -1023,7 +1033,8 @@ static void lcp_send_terminate_request(struct pico_device_ppp *ppp)
PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */
sizeof(struct pico_lcp_hdr) + /* Actual options size + hdr (whole lcp packet) */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1 /* STOP Byte */
1, /* STOP Byte */
1 /* no escape */
);
lcp_timer_start(ppp, PPP_TIMER_ON_LCPTERM);
}
@ -1042,7 +1053,8 @@ static void lcp_send_terminate_ack(struct pico_device_ppp *ppp)
PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */
short_be(lcpreq->len) + /* Actual options size + hdr (whole lcp packet) */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1 /* STOP Byte */
1, /* STOP Byte */
1 /* no escape */
);
}
@ -1088,7 +1100,8 @@ static void lcp_send_configure_nack(struct pico_device_ppp *ppp)
sizeof(struct pico_lcp_hdr) + /* LCP HDR */
dstopts_len + /* Actual options size */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1u) /* STOP Byte */
1u), /* STOP Byte */
1 /* no escape */
);
}
@ -1216,7 +1229,8 @@ static void ipcp_send_ack(struct pico_device_ppp *ppp)
PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */
short_be(ipcpreq->len) + /* Actual options size + hdr (whole ipcp packet) */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1 /* STOP Byte */
1, /* STOP Byte */
0 /* escape */
);
}
@ -1267,7 +1281,8 @@ static void ipcp_send_req(struct pico_device_ppp *ppp)
(uint32_t)(prefix + /* PPP Header, etc. */
(uint32_t)len + /* IPCP Header + options */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1u) /* STOP Byte */
1u), /* STOP Byte */
0 /* escape */
);
}
@ -1295,7 +1310,8 @@ static void ipcp_reject_vj(struct pico_device_ppp *ppp, uint8_t *comp_req)
sizeof(struct pico_ipcp_hdr) + /* LCP HDR */
IPCP_VJ_LEN + /* Actual options size */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1u) /* STOP Byte */
1u), /* STOP Byte */
0 /* escape */
);
}
@ -1574,8 +1590,9 @@ static void lcp_send_echo_reply(struct pico_device_ppp *ppp)
PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */
short_be(lcpreq->len) + /* Actual options size + hdr (whole lcp packet) */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1 /* STOP Byte */
);
1, /* STOP Byte */
0 /* escape */
);
}
static const struct pico_ppp_fsm ppp_lcp_fsm[PPP_LCP_STATE_MAX][PPP_LCP_EVENT_MAX] = {
@ -1618,7 +1635,7 @@ static const struct pico_ppp_fsm ppp_lcp_fsm[PPP_LCP_STATE_MAX][PPP_LCP_EVENT_MA
[PPP_LCP_STATE_CLOSED] = {
[PPP_LCP_EVENT_UP] = { PPP_LCP_STATE_CLOSED, {} },
[PPP_LCP_EVENT_DOWN] = { PPP_LCP_STATE_INITIAL, {} },
[PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request} },
[PPP_LCP_EVENT_OPEN] = { PPP_LCP_STATE_REQ_SENT, { lcp_send_configure_request } },
[PPP_LCP_EVENT_CLOSE] = { PPP_LCP_STATE_CLOSED, {} },
[PPP_LCP_EVENT_TO_POS] = { PPP_LCP_STATE_CLOSED, {} },
[PPP_LCP_EVENT_TO_NEG] = { PPP_LCP_STATE_CLOSED, {} },
@ -1871,7 +1888,8 @@ static void auth_req(struct pico_device_ppp *ppp)
PPP_HDR_SIZE + PPP_PROTO_SLOT_SIZE + /* PPP Header, etc. */
pap_len + /* Authentication packet len */
PPP_FCS_SIZE + /* FCS */
1) /* STOP Byte */
1), /* STOP Byte */
0 /* escape */
);
PICO_FREE(req);
}
@ -1916,7 +1934,8 @@ static void auth_rsp(struct pico_device_ppp *ppp)
1 + /* Value length */
CHAP_MD5_SIZE + /* Actual payload size */
PPP_FCS_SIZE + /* FCS at the end of the frame */
1) /* STOP Byte */
1), /* STOP Byte */
0 /* escape */
);
}
@ -2051,7 +2070,8 @@ static void ipcp_send_nack(struct pico_device_ppp *ppp)
ppp_dbg("Sending IPCP CONF NAK\n");
pico_ppp_ctl_send(&ppp->dev, PPP_PROTO_IPCP,
ipcp_req, /* Start of PPP packet */
(uint32_t)sizeof(ipcp_req));
(uint32_t)sizeof(ipcp_req),
0); /* escape */
}
static void ipcp_bring_up(struct pico_device_ppp *ppp)
@ -2329,6 +2349,7 @@ struct pico_device *pico_ppp_create(void)
ppp->lcp_state = PPP_LCP_STATE_INITIAL;
ppp->auth_state = PPP_AUTH_STATE_INITIAL;
ppp->ipcp_state = PPP_IPCP_STATE_INITIAL;
ppp->asyncmap = 0xffffffff;
ppp->timer = pico_timer_add(1000, pico_ppp_tick, ppp);
if (!ppp->timer) {

View File

@ -2770,7 +2770,7 @@ static uint8_t invalid_flags(struct pico_socket *s, uint8_t flags)
static const uint8_t valid_flags[PICO_SOCKET_STATE_TCP_ARRAYSIZ][MAX_VALID_FLAGS] = {
{ /* PICO_SOCKET_STATE_TCP_UNDEF */ 0, },
{ /* PICO_SOCKET_STATE_TCP_CLOSED */ 0, },
{ /* PICO_SOCKET_STATE_TCP_LISTEN */ PICO_TCP_SYN },
{ /* PICO_SOCKET_STATE_TCP_LISTEN */ PICO_TCP_SYN, PICO_TCP_SYN | PICO_TCP_PSH },
{ /* PICO_SOCKET_STATE_TCP_SYN_SENT */ PICO_TCP_SYNACK, PICO_TCP_RST, PICO_TCP_RSTACK},
{ /* PICO_SOCKET_STATE_TCP_SYN_RECV */ PICO_TCP_SYN, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST},
{ /* PICO_SOCKET_STATE_TCP_ESTABLISHED*/ PICO_TCP_SYN, PICO_TCP_SYNACK, PICO_TCP_ACK, PICO_TCP_PSH, PICO_TCP_PSHACK, PICO_TCP_FIN, PICO_TCP_FINACK, PICO_TCP_FINPSHACK, PICO_TCP_RST, PICO_TCP_RSTACK},
@ -2850,7 +2850,7 @@ int pico_tcp_input(struct pico_socket *s, struct pico_frame *f)
if(invalid_flags(s, flags)) {
pico_tcp_reply_rst(f);
}
else if (flags == PICO_TCP_SYN) {
else if (flags == PICO_TCP_SYN || flags == (PICO_TCP_SYN | PICO_TCP_PSH)) {
tcp_action_call(action->syn, s, f);
} else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) {
tcp_action_call(action->synack, s, f);

View File

@ -33,7 +33,7 @@ extern "C" {
}
#define VIXL_CODE_BUFFER_MALLOC
//#define VIXL_DEBUG
#if defined(_ANDROID) && defined(VIXL_DEBUG)
#include <android/log.h>

View File

@ -8,6 +8,10 @@
#ifndef ZCONF_H
#define ZCONF_H
#ifndef _MSC_VER
#define HAVE_UNISTD_H 1
#endif
/*
* If you *really* need a unique prefix for all types and library functions,
* compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.

View File

@ -381,6 +381,9 @@ void x86_encode_opcode_tmpl(x86_block* block, const x86_opcode* op, encoded_type
case enc_imm_32 :
block->write32(p3);
break;
case enc_imm_none:
break;
}
}

View File

@ -99,7 +99,7 @@ void libAICA_TimeStep()
SCIPD->SAMPLE_DONE=1;
if (settings.aica.NoBatch)
if (settings.aica.NoBatch || settings.aica.DSPEnabled)
AICA_Sample();
//Make sure sh4/arm interrupt system is up to date :)
@ -199,21 +199,22 @@ s32 libAICA_Init()
MCIRE=(InterruptInfo*)&aica_reg[0x28B4+8];
sgc_Init();
for (int i=0;i<3;i++)
timers[i].Init(aica_reg,i);
return rv_ok;
}
void libAICA_Reset(bool manual)
void libAICA_Reset(bool hard)
{
if (!manual)
if (hard)
init_mem();
sgc_Init();
aica_Reset(manual);
for (int i = 0; i < 3; i++)
timers[i].Init(aica_reg, i);
aica_Reset(hard);
}
void libAICA_Term()
{
sgc_Term();
term_mem();
}

View File

@ -16,50 +16,50 @@
#define TIMER_C (0x2890+8)
#define REG_L (0x2D00)
#define REG_M (0x2D04)
#define entry(name,sz) u32 name:sz;
struct CommonData_struct
{
//+0
entry(MVOL,4);
entry(VER,4);
entry(DAC18B,1);
entry(MEM8MB,1);
entry(pad0_0,5);
entry(Mono,1);
u32 MVOL:4;
u32 VER:4;
u32 DAC18B:1;
u32 MEM8MB:1;
u32 pad0_0:5;
u32 Mono:1;
u32 :16;
//+4
entry(RBP,12);
entry(pad1_0,1);
entry(RBL,2);
entry(TESTB0,1);
u32 RBP:12;
u32 pad1_0:1;
u32 RBL:2;
u32 TESTB0:1;
u32 :16;
//+8
entry(MIBUF,8);
entry(MIEMP,1);
entry(MIFUL ,1);
entry(MIOVF ,1);
entry(MOEMP ,1);
entry(MOFUL ,1);
entry(pad3_0,3);
u32 MIBUF:8;
u32 MIEMP:1;
u32 MIFUL :1;
u32 MIOVF :1;
u32 MOEMP :1;
u32 MOFUL :1;
u32 pad3_0:3;
u32 :16;
//+C
entry(MOBUF,8);
entry(MSLC,6);
entry(AFSET,1);
entry(padC_0,1);
u32 MOBUF:8;
u32 MSLC:6;
u32 AFSET:1;
u32 padC_0:1;
u32 :16;
//+10
entry(EG,13);
entry(SGC,2);
entry(LP,1);
u32 EG:13;
u32 SGC:2;
u32 LP:1;
u32 :16;
//+14
entry(CA,16);
u32 CA:16;
u32 :16;
@ -67,101 +67,101 @@ struct CommonData_struct
u8 pad_med_0[0x6C-4];
//+80
entry(MRWINH,4);
entry($T,1);
entry($TSCD,3);
entry(pad80_0,1);
entry(DMEA_hi,7);
u32 MRWINH:4;
u32 $T:1;
u32 $TSCD:3;
u32 pad80_0:1;
u32 DMEA_hi:7;
u32 :16;
//+84
entry(pad84_0,2);
entry(DMEA_lo,14);
u32 pad84_0:2;
u32 DMEA_lo:14;
u32 :16;
//+88
entry(pad88_0,2);
entry(DRGA,13);
entry(DGATE,1);
u32 pad88_0:2;
u32 DRGA:13;
u32 DGATE:1;
u32 :16;
//+8C
entry(DEXE,1);
entry(pad8C_0,1);
entry(DLG,13);
entry(DDIR,1);
u32 DEXE:1;
u32 pad8C_0:1;
u32 DLG:13;
u32 DDIR:1;
u32 :16;
//+90
entry(TIMA,8);
entry(TACTL,3);
entry(pad90_0,5);
u32 TIMA:8;
u32 TACTL:3;
u32 pad90_0:5;
u32 :16;
//+94
entry(TIMB,8);
entry(TBCTL,3);
entry(pad94_0,5);
u32 TIMB:8;
u32 TBCTL:3;
u32 pad94_0:5;
u32 :16;
//+98
entry(TIMC,8);
entry(TCCTL,3);
entry(pad98_0,5);
u32 TIMC:8;
u32 TCCTL:3;
u32 pad98_0:5;
u32 :16;
//+9C
entry(SCIEB,11);
entry(pad9C_0,5);
u32 SCIEB:11;
u32 pad9C_0:5;
u32 :16;
//+A0
entry(SCIPD,11);
entry(padA0_0,5);
u32 SCIPD:11;
u32 padA0_0:5;
u32 :16;
//+A4
entry(SCIRE,11);
entry(padA4_0,5);
u32 SCIRE:11;
u32 padA4_0:5;
u32 :16;
//+A8
entry(SCILV0,8);
entry(padA8_0,8);
u32 SCILV0:8;
u32 padA8_0:8;
u32 :16;
//+AC
entry(SCILV1,8);
entry(padAC_0,8);
u32 SCILV1:8;
u32 padAC_0:8;
u32 :16;
//+B0
entry(SCILV2,8);
entry(padB0_0,8);
u32 SCILV2:8;
u32 padB0_0:8;
u32 :16;
//+B4
entry(MCIEB,11);
entry(padB4_0,5)
u32 MCIEB:11;
u32 padB4_0:5;
u32 :16;
//+B8
entry(MCIPD,11);
entry(padB8_0,5)
u32 MCIPD:11;
u32 padB8_0:5;
u32 :16;
//+BC
entry(MCIRE,11);
entry(padBC_0,5)
u32 MCIRE:11;
u32 padBC_0:5;
u32 :16;
@ -169,10 +169,10 @@ struct CommonData_struct
u8 pad_lot_0[0x344-4];
//+400 , hopefully :p
entry(AR,1);
entry(pad400_0,7);
entry(VREG,2);
entry(pad400_1,6);
u32 AR:1;
u32 pad400_0:7;
u32 VREG:2;
u32 pad400_1:6;
u32 :16;
@ -180,32 +180,32 @@ struct CommonData_struct
u8 pad_lot_1[0x100-4];
//+500 , hopefully :p
entry(L0_r,1);
entry(L1_r,1);
entry(L2_r,1);
entry(L3_r,1);
entry(L4_r,1);
entry(L5_r,1);
entry(L6_r,1);
entry(L7_r,1);
u32 L0_r:1;
u32 L1_r:1;
u32 L2_r:1;
u32 L3_r:1;
u32 L4_r:1;
u32 L5_r:1;
u32 L6_r:1;
u32 L7_r:1;
entry(pad500_0,8);
u32 pad500_0:8;
u32 :16;
//+504
entry(M0_r,1);
entry(M1_r,1);
entry(M2_r,1);
entry(M3_r,1);
entry(M4_r,1);
entry(M5_r,1);
entry(M6_r,1);
entry(M7_r,1);
entry(RP,1);
u32 M0_r:1;
u32 M1_r:1;
u32 M2_r:1;
u32 M3_r:1;
u32 M4_r:1;
u32 M5_r:1;
u32 M6_r:1;
u32 M7_r:1;
u32 RP:1;
entry(pad504_0,7);
u32 pad504_0:7;
u32 :16;
};
@ -263,30 +263,30 @@ union InterruptInfo
struct
{
//Bit 0 (R): Requests interrupt to external interrupt input pin "INTON". (SCSI)
entry(INTON,1);
u32 INTON:1;
//Bit 1 (R): Reserved.
entry(res_1,1);
u32 res_1:1;
//Bit 2 (R): Reserved.
entry(res_3,1);
u32 res_3:1;
//Bit 3 (R): MIDI input interrupt.
//(Interrupt request generated when input FIFO has fetched valid data. Hence, if the CPU reads FIFO data, it must read the lot once and leave the FIFO empty. When the FIFO has changed to empty status, the interrupt request is canceled automatically.)
entry(MIDI_IN,1);
u32 MIDI_IN:1;
//Bit 4 (R): DMA end interrupt
entry(DMA_END,1);
u32 DMA_END:1;
//Bit 5 (R/W): SCPU interrupt caused by data being written to the CPU, so only "1" can be written. (Writing "0" has no effect.) This flag can be set from either the MCPU or the SCPU.
entry(SCPU,1);
u32 SCPU:1;
//Bit 6 (R): Timer A interrupt
entry(TimerA,1);
u32 TimerA:1;
//Bit 7 (R): Timer B interrupt
entry(TimerB,1);
u32 TimerB:1;
//Bit 8 (R): Timer C interrupt
entry(TimerC,1);
u32 TimerC:1;
//Bit 9 (R): MIDI output interrupt.
//(If the output FIFO changes to empty status, an interrupt request is generated.)
//(If the status is no longer empty because data is written to the output FIFO, the interrupt request is canceled automatically.)
entry(MIDI_OUT,1);
u32 MIDI_OUT:1;
//Bit 10 (R): Interrupt of one sample interval
entry(SAMPLE_DONE,1);
u32 SAMPLE_DONE:1;
};
u32 full;
};
@ -297,8 +297,6 @@ extern InterruptInfo* SCIEB;
extern InterruptInfo* SCIPD;
extern InterruptInfo* SCIRE;
#undef entry
extern CommonData_struct* CommonData;
extern DSPData_struct* DSPData;

View File

@ -47,7 +47,7 @@ u32 ReadMem_aica_rtc(u32 addr,u32 sz)
return 0;
}
printf("ReadMem_aica_rtc : invalid address\n");
WARN_LOG(AICA, "ReadMem_aica_rtc : invalid address %x sz %d", addr, sz);
return 0;
}
@ -123,12 +123,12 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
if (addr==0x2C01)
{
VREG=data;
printf("VREG = %02X\n",VREG);
INFO_LOG(AICA, "VREG = %02X", VREG);
}
else if (addr==0x2C00)
{
ARMRST=data;
printf("ARMRST = %02X\n",ARMRST);
INFO_LOG(AICA, "ARMRST = %02X", ARMRST);
ArmSetRST();
}
else
@ -142,7 +142,7 @@ void WriteMem_aica_reg(u32 addr,u32 data,u32 sz)
{
VREG=(data>>8)&0xFF;
ARMRST=data&0xFF;
printf("VREG = %02X ARMRST %02X\n",VREG,ARMRST);
INFO_LOG(AICA, "VREG = %02X ARMRST %02X", VREG, ARMRST);
ArmSetRST();
}
else
@ -157,7 +157,7 @@ void aica_Init()
RealTimeClock = GetRTC_now();
}
void aica_Reset(bool Manual)
void aica_Reset(bool hard)
{
aica_Init();
VREG = 0;
@ -216,17 +216,9 @@ void Write_SB_ADST(u32 addr, u32 data)
u32 tmp=src;
src=dst;
dst=tmp;
printf("**AICA DMA : SB_ADDIR==1: Not sure this works, please report if broken/missing sound or crash\n**");
}
WriteMemBlock_nommu_dma(dst,src,len);
/*
for (u32 i=0;i<len;i+=4)
{
u32 data=ReadMem32_nommu(src+i);
WriteMem32_nommu(dst+i,data);
}
*/
// idicate that dma is in progress
SB_ADSUSP &= ~0x10;
@ -273,10 +265,10 @@ void Write_SB_E1ST(u32 addr, u32 data)
u32 t=src;
src=dst;
dst=t;
printf("G2-EXT1 DMA : SB_E1DIR==1 DMA Read to 0x%X from 0x%X %d bytes\n",dst,src,len);
DEBUG_LOG(AICA, "G2-EXT1 DMA : SB_E1DIR==1 DMA Read to 0x%X from 0x%X %d bytes", dst, src, len);
}
else
printf("G2-EXT1 DMA : SB_E1DIR==0:DMA Write to 0x%X from 0x%X %d bytes\n",dst,src,len);
DEBUG_LOG(AICA, "G2-EXT1 DMA : SB_E1DIR==0:DMA Write to 0x%X from 0x%X %d bytes", dst, src, len);
WriteMemBlock_nommu_dma(dst,src,len);
@ -316,10 +308,10 @@ void Write_SB_E2ST(u32 addr, u32 data)
u32 t=src;
src=dst;
dst=t;
printf("G2-EXT2 DMA : SB_E2DIR==1 DMA Read to 0x%X from 0x%X %d bytes\n",dst,src,len);
DEBUG_LOG(AICA, "G2-EXT2 DMA : SB_E2DIR==1 DMA Read to 0x%X from 0x%X %d bytes", dst, src, len);
}
else
printf("G2-EXT2 DMA : SB_E2DIR==0:DMA Write to 0x%X from 0x%X %d bytes\n",dst,src,len);
DEBUG_LOG(AICA, "G2-EXT2 DMA : SB_E2DIR==0:DMA Write to 0x%X from 0x%X %d bytes", dst, src, len);
WriteMemBlock_nommu_dma(dst,src,len);
@ -365,7 +357,7 @@ void aica_sb_Init()
dma_sched_id = sh4_sched_register(0, &dma_end_sched);
}
void aica_sb_Reset(bool Manual)
void aica_sb_Reset(bool hard)
{
}

View File

@ -8,7 +8,4 @@ void init_mem();
void term_mem();
extern u8 aica_reg[0x8000];
#define aica_reg_16 ((u16*)aica_reg)
#define AICA_RAM_SIZE (ARAM_SIZE)
#define AICA_RAM_MASK (ARAM_MASK)

View File

@ -246,8 +246,8 @@ void dsp_rec_DRAM_CI(x86_block& x86e,_INST& prev_op,u32 step,x86_gpr_reg MEM_RD_
if (!(step&1))
{
//Get and mask ram address :)
x86e.Emit(op_mov32,EAX,&dsp.regs.MEM_ADDR);
x86e.Emit(op_and32,EAX,AICA_RAM_MASK);
x86e.Emit(op_mov32, EAX, &dsp.regs.MEM_ADDR);
x86e.Emit(op_and32, EAX, ARAM_MASK);
x86e.Emit(op_add32,EAX,(unat)aica_ram.data);

View File

@ -36,7 +36,7 @@ public:
void Compile(struct dsp_t *DSP)
{
this->DSP = DSP;
//printf("DSPAssembler::DSPCompile recompiling for arm64 at %p\n", GetBuffer()->GetStartAddress<void*>());
DEBUG_LOG(AICA_ARM, "DSPAssembler::DSPCompile recompiling for arm64 at %p", GetBuffer()->GetStartAddress<void*>());
if (DSP->Stopped)
{
@ -101,7 +101,7 @@ public:
#ifndef _ANDROID
Instruction* instr_cur = GetBuffer()->GetEndAddress<Instruction*>();
printf("DSP PROLOGUE\n");
DEBUG_LOG(AICA_ARM, "DSP PROLOGUE");
Disassemble(instr_start, instr_cur);
instr_start = instr_cur;
#endif
@ -358,7 +358,7 @@ public:
}
#ifndef _ANDROID
instr_cur = GetBuffer()->GetEndAddress<Instruction*>();
printf("DSP STEP %d: %04x %04x %04x %04x\n", step, mpro[0], mpro[1], mpro[2], mpro[3]);
DEBUG_LOG(AICA_ARM, "DSP STEP %d: %04x %04x %04x %04x", step, mpro[0], mpro[1], mpro[2], mpro[3]);
Disassemble(instr_start, instr_cur);
instr_start = instr_cur;
#endif
@ -380,7 +380,7 @@ public:
Ret();
#ifndef _ANDROID
instr_cur = GetBuffer()->GetEndAddress<Instruction*>();
printf("DSP EPILOGUE\n");
DEBUG_LOG(AICA_ARM, "DSP EPILOGUE");
Disassemble(instr_start, instr_cur);
instr_start = instr_cur;
#endif
@ -486,9 +486,7 @@ private:
Instruction* instr;
for (instr = instr_start; instr < instr_end; instr += kInstructionSize) {
decoder.Decode(instr);
printf("\t %p:\t%s\n",
reinterpret_cast<void*>(instr),
disasm.GetOutput());
DEBUG_LOG(AICA_ARM, " %p:\t%s", reinterpret_cast<void*>(instr), disasm.GetOutput());
}
}

View File

@ -8,9 +8,9 @@ using namespace std;
#undef FAR
//#define CLIP_WARN
#define key_printf(...)
#define aeg_printf(...)
#define step_printf(...)
#define key_printf(...) DEBUG_LOG(AICA, __VA_ARGS__)
#define aeg_printf(...) DEBUG_LOG(AICA, __VA_ARGS__)
#define step_printf(...) DEBUG_LOG(AICA, __VA_ARGS__)
#ifdef CLIP_WARN
#define clip_verify(x) verify(x)
@ -490,7 +490,7 @@ struct ChannelEx
StepStreamInitial(this);
key_printf("[%d] KEY_ON %s @ %f Hz, loop : %d\n",Channel,stream_names[ChanData->PCMS],(44100.0*update_rate)/1024,ChanData->LPCTL);
key_printf("[%p] KEY_ON %s @ %f Hz, loop : %d", this, stream_names[ccd->PCMS], (44100.0 * update_rate) / 1024, ccd->LPCTL);
}
else
{
@ -501,7 +501,7 @@ struct ChannelEx
{
if (AEG.state!=EG_Release)
{
key_printf("[%d] KEY_OFF -> Release\n",Channel);
key_printf("[%p] KEY_OFF -> Release", this);
SetAegState(EG_Release);
//switch to release state
}
@ -862,7 +862,7 @@ void StreamStep(ChannelEx* ch)
if ((ch->AEG.state==EG_Attack) && (CA>=ch->loop.LSA))
{
step_printf("[%d]LPSLNK : Switching to EG_Decay1 %X\n",Channel,AEG.GetValue());
step_printf("[%p]LPSLNK : Switching to EG_Decay1 %X", ch, ch->AEG.GetValue());
ch->SetAegState(EG_Decay1);
}
}
@ -963,7 +963,7 @@ void AegStep(ChannelEx* ch)
ch->AEG.SetValue(0);
if (!ch->ccd->LPSLNK)
{
aeg_printf("[%d]AEG_step : Switching to EG_Decay1 %d\n",ch->AEG.GetValue());
aeg_printf("[%p]AEG_step : Switching to EG_Decay1 %d", ch, ch->AEG.GetValue());
ch->SetAegState(EG_Decay1);
}
}
@ -975,7 +975,7 @@ void AegStep(ChannelEx* ch)
ch->AEG.val+=ch->AEG.Decay1Rate;
if (((u32)ch->AEG.GetValue())>=ch->AEG.Decay2Value)
{
aeg_printf("[%d]AEG_step : Switching to EG_Decay2 @ %x\n",ch->AEG.GetValue());
aeg_printf("[%p]AEG_step : Switching to EG_Decay2 @ %x", ch, ch->AEG.GetValue());
ch->SetAegState(EG_Decay2);
}
}
@ -986,7 +986,7 @@ void AegStep(ChannelEx* ch)
ch->AEG.val+=ch->AEG.Decay2Rate;
if (ch->AEG.GetValue()>=0x3FF)
{
aeg_printf("[%d]AEG_step : Switching to EG_Release @ %x\n",ch->AEG.GetValue());
aeg_printf("[%p]AEG_step : Switching to EG_Release @ %x", ch, ch->AEG.GetValue());
ch->AEG.SetValue(0x3FF);
ch->SetAegState(EG_Release);
}
@ -998,7 +998,7 @@ void AegStep(ChannelEx* ch)
if (ch->AEG.GetValue()>=0x3FF)
{
aeg_printf("[%d]AEG_step : EG_Release End @ %x\n",ch->AEG.GetValue());
aeg_printf("[%p]AEG_step : EG_Release End @ %x", ch, ch->AEG.GetValue());
ch->AEG.SetValue(0x3FF); // TODO: mnn, should we do anything about it running wild ?
ch->disable(); // TODO: Is this ok here? It's a speed optimisation (since the channel is muted)
}
@ -1169,8 +1169,8 @@ void WriteCommonReg8(u32 reg,u32 data)
WriteMemArr(aica_reg,reg,data,1);
if (reg==0x2804 || reg==0x2805)
{
dsp.RBL=(8192<<CommonData->RBL)-1;
dsp.RBP=( CommonData->RBP*2048&AICA_RAM_MASK);
dsp.RBL = (8192 << CommonData->RBL) - 1;
dsp.RBP = (CommonData->RBP * 2048) & ARAM_MASK;
dsp.dyndirty=true;
}
}
@ -1179,19 +1179,17 @@ void WriteCommonReg8(u32 reg,u32 data)
s16 cdda_sector[CDDA_SIZE]={0};
u32 cdda_index=CDDA_SIZE<<1;
SampleType mxlr[64];
u32 samples_gen;
//no DSP for now in this version
void AICA_Sample32()
{
if (settings.aica.NoBatch)
if (settings.aica.NoBatch || settings.aica.DSPEnabled)
{
return;
}
SampleType mxlr[64];
memset(mxlr,0,sizeof(mxlr));
//Generate 32 samples for each channel, before moving to next channel
@ -1344,7 +1342,7 @@ void AICA_Sample()
DSPData->EXTS[0] = 0;
DSPData->EXTS[1] = 0;
}
//if (settings.aica.DSPEnabled)
if (settings.aica.DSPEnabled)
{
dsp_step();

View File

@ -157,7 +157,7 @@ void armv_end(void* codestart, u32 cycl)
Instruction* instr;
for (instr = instr_start; instr < instr_end; instr += kInstructionSize) {
decoder.Decode(instr);
printf("arm64 arec\t %p:\t%s\n",
DEBUG_LOG(AICA_ARM, "arm64 arec\t %p:\t%s",
reinterpret_cast<void*>(instr),
disasm.GetOutput());
}
@ -206,7 +206,7 @@ class android_buf : public std::stringbuf
{
public:
virtual int sync() override {
LOGI("ARM7: %s\n", this->str().c_str());
DEBUG_LOG(AICA_ARM, "ARM7: %s", this->str().c_str());
str("");
return 0;
@ -501,13 +501,7 @@ __asm__ (
".hidden arm_dispatch \n"
"arm_dispatch: \n\t"
"ldp w0, w1, [x28, #184] \n\t" // load Next PC, interrupt
#if ARAM_SIZE == 2*1024*1024
"ubfx w2, w0, #2, #19 \n\t" // w2 = pc >> 2. Note: assuming address space == 2 MB (21 bits)
#elif ARAM_SIZE == 8*1024*1024
"ubfx w2, w0, #2, #21 \n\t" // w2 = pc >> 2. Note: assuming address space == 8 MB (23 bits)
#else
#error Unsupported AICA RAM size
#endif
"cbnz w1, arm_dofiq \n\t" // if interrupt pending, handle it
"add x2, x26, x2, lsl #3 \n\t" // x2 = EntryPoints + pc << 1

View File

@ -4,16 +4,8 @@
#include <map>
#define arm_printf(...) DEBUG_LOG(AICA_ARM, __VA_ARGS__)
#define C_CORE
#if 0
#define arm_printf printf
#else
void arm_printf(...) { }
#endif
//#define CPUReadHalfWordQuick(addr) arm_ReadMem16(addr & 0x7FFFFF)
#define CPUReadMemoryQuick(addr) (*(u32*)&aica_ram[addr&ARAM_MASK])
#define CPUReadByte arm_ReadMem8
#define CPUReadMemory arm_ReadMem32
@ -49,12 +41,6 @@ void CPUSwap(u32 *a, u32 *b)
*a = c;
}
/*
bool N_FLAG;
bool Z_FLAG;
bool C_FLAG;
bool V_FLAG;
*/
#define N_FLAG (reg[RN_PSR_FLAGS].FLG.N)
#define Z_FLAG (reg[RN_PSR_FLAGS].FLG.Z)
#define C_FLAG (reg[RN_PSR_FLAGS].FLG.C)
@ -62,10 +48,9 @@ bool V_FLAG;
bool armIrqEnable;
bool armFiqEnable;
//bool armState;
int armMode;
bool Arm7Enabled=false;
bool Arm7Enabled = false;
u8 cpuBitsSet[256];
@ -75,16 +60,20 @@ void CPUUpdateCPSR();
void CPUUpdateFlags();
void CPUSoftwareInterrupt(int comment);
void CPUUndefinedException();
void libAICA_TimeStep();
#if FEAT_AREC == DYNAREC_NONE
//
// ARM7 interpreter
//
void arm_Run_(u32 CycleCount)
{
if (!Arm7Enabled)
return;
u32 clockTicks=0;
while (clockTicks<CycleCount)
u32 clockTicks = 0;
while (clockTicks < CycleCount)
{
if (reg[INTR_PEND].I)
{
@ -96,16 +85,22 @@ void arm_Run_(u32 CycleCount)
}
}
void arm_Run(u32 CycleCount) {
for (int i=0;i<32;i++)
{
arm_Run_(CycleCount/32);
libAICA_TimeStep();
}
}
#endif
void armt_init();
//void CreateTables();
void arm_Init()
{
#if FEAT_AREC != DYNAREC_NONE
armt_init();
#endif
//CreateTables();
arm_Reset();
for (int i = 0; i < 256; i++)
@ -224,7 +219,7 @@ void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
reg[17].I = reg[SPSR_UND].I;
break;
default:
printf("Unsupported ARM mode %02x\n", mode);
ERROR_LOG(AICA_ARM, "Unsupported ARM mode %02x", mode);
die("Arm error..");
break;
}
@ -239,22 +234,8 @@ void CPUUpdateCPSR()
CPSR.I = reg[RN_CPSR].I & 0x40;
/*
if(N_FLAG)
CPSR |= 0x80000000;
if(Z_FLAG)
CPSR |= 0x40000000;
if(C_FLAG)
CPSR |= 0x20000000;
if(V_FLAG)
CPSR |= 0x10000000;
if(!armState)
CPSR |= 0x00000020;
*/
CPSR.PSR.NZCV=reg[RN_PSR_FLAGS].FLG.NZCV;
if (!armFiqEnable)
CPSR.I |= 0x40;
if(!armIrqEnable)
@ -271,13 +252,6 @@ void CPUUpdateFlags()
reg[RN_PSR_FLAGS].FLG.NZCV=reg[16].PSR.NZCV;
/*
N_FLAG = (CPSR & 0x80000000) ? true: false;
Z_FLAG = (CPSR & 0x40000000) ? true: false;
C_FLAG = (CPSR & 0x20000000) ? true: false;
V_FLAG = (CPSR & 0x10000000) ? true: false;
*/
//armState = (CPSR & 0x20) ? false : true;
armIrqEnable = (CPSR & 0x80) ? false : true;
armFiqEnable = (CPSR & 0x40) ? false : true;
update_armintc();
@ -286,26 +260,21 @@ void CPUUpdateFlags()
void CPUSoftwareInterrupt(int comment)
{
u32 PC = reg[R15_ARM_NEXT].I+4;
//bool savedArmState = armState;
CPUSwitchMode(0x13, true, false);
reg[14].I = PC;
// reg[15].I = 0x08;
armIrqEnable = false;
armNextPC = 0x08;
// reg[15].I += 4;
}
void CPUUndefinedException()
{
printf("arm7: CPUUndefinedException(). SOMETHING WENT WRONG\n");
WARN_LOG(AICA_ARM, "arm7: CPUUndefinedException(). SOMETHING WENT WRONG");
u32 PC = reg[R15_ARM_NEXT].I+4;
CPUSwitchMode(0x1b, true, false);
reg[14].I = PC;
// reg[15].I = 0x04;
armIrqEnable = false;
armNextPC = 0x04;
// reg[15].I += 4;
}
void FlushCache();
@ -315,6 +284,12 @@ void arm_Reset()
#if FEAT_AREC != DYNAREC_NONE
FlushCache();
#endif
aica_interr = false;
aica_reg_L = 0;
e68k_out = false;
e68k_reg_L = 0;
e68k_reg_M = 0;
Arm7Enabled = false;
// clean registers
memset(&arm_Reg[0], 0, sizeof(arm_Reg));
@ -330,7 +305,6 @@ void arm_Reset()
armFiqEnable = false;
update_armintc();
//armState = true;
C_FLAG = V_FLAG = N_FLAG = Z_FLAG = false;
// disable FIQ
@ -342,45 +316,18 @@ void arm_Reset()
reg[15].I += 4;
}
/*
//NO IRQ on aica ..
void CPUInterrupt()
{
u32 PC = reg[15].I;
//bool savedState = armState;
CPUSwitchMode(0x12, true, false);
reg[14].I = PC;
//if(!savedState)
// reg[14].I += 2;
reg[15].I = 0x18;
//armState = true;
armIrqEnable = false;
armNextPC = reg[15].I;
reg[15].I += 4;
}
*/
extern "C"
NOINLINE
void CPUFiq()
{
u32 PC = reg[R15_ARM_NEXT].I+4;
//bool savedState = armState;
CPUSwitchMode(0x11, true, false);
reg[14].I = PC;
//if(!savedState)
// reg[14].I += 2;
//reg[15].I = 0x1c;
//armState = true;
armIrqEnable = false;
armFiqEnable = false;
update_armintc();
armNextPC = 0x1c;
//reg[15].I += 4;
}
@ -410,17 +357,10 @@ void update_armintc()
reg[INTR_PEND].I=e68k_out && armFiqEnable;
}
void libAICA_TimeStep();
#if FEAT_AREC == DYNAREC_NONE
void arm_Run(u32 CycleCount) {
for (int i=0;i<32;i++)
{
arm_Run_(CycleCount/32);
libAICA_TimeStep();
}
}
#else // FEAT_AREC != DYNAREC_NONE
#if FEAT_AREC != DYNAREC_NONE
//
// ARM7 Recompiler
//
#if HOST_OS == OS_DARWIN
#include <sys/mman.h>
@ -742,9 +682,9 @@ u32 DYNACALL DoMemOp(u32 addr,u32 data)
arm_WriteMem32(addr,data);
}
#if HOST_CPU==CPU_X86
virt_arm_reg(0)=rv;
#endif
#if HOST_CPU==CPU_X86
virt_arm_reg(0)=rv;
#endif
return rv;
}
@ -1301,7 +1241,7 @@ void *armGetEmitPtr()
return NULL;
}
#if HOST_CPU == CPU_X86 && FEAT_AREC != DYNAREC_NONE
#if HOST_CPU == CPU_X86
/* X86 backend
* Uses a mix of
@ -1345,7 +1285,7 @@ void DumpRegs(const char* output)
void DYNACALL PrintOp(u32 opcd)
{
printf("%08X\n",opcd);
DEBUG_LOG(AICA_ARM, "%08X", opcd);
}
void armv_imm_to_reg(u32 regn, u32 imm)
@ -2173,15 +2113,15 @@ void armt_init()
//align to next page ..
ICache = (u8*)(((unat)ARM7_TCB+4095)& ~4095);
#if HOST_OS==OS_DARWIN
//Can't just mprotect on iOS
munmap(ICache, ICacheSize);
ICache = (u8*)mmap(ICache, ICacheSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
#endif
#ifdef TARGET_IPHONE
//Can't just mprotect on iOS
munmap(ICache, ICacheSize);
ICache = (u8*)mmap(ICache, ICacheSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0);
#endif
mem_region_set_exec(ICache, ICacheSize);
#if TARGET_IPHONE
#ifdef TARGET_IPHONE
memset((u8*)mmap(ICache, ICacheSize, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE | MAP_ANON, 0, 0),0xFF,ICacheSize);
#else
memset(ICache,0xFF,ICacheSize);
@ -2191,4 +2131,4 @@ void armt_init()
}
#endif
#endif // FEAT_AREC != DYNAREC_NONE

View File

@ -54,14 +54,10 @@ static inline void DYNACALL WriteMemArm(u32 addr,T data)
u32 sh4_ReadMem_reg(u32 addr,u32 size);
void sh4_WriteMem_reg(u32 addr,u32 data,u32 size);
void init_mem();
void term_mem();
#define aica_reg_16 ((u16*)aica_reg)
#define AICA_RAM_SIZE (ARAM_SIZE)
#define AICA_RAM_MASK (ARAM_MASK)
extern bool aica_interr;
extern u32 aica_reg_L;
extern bool e68k_out;
extern u32 e68k_reg_L;
extern u32 e68k_reg_M;
void update_armintc();

View File

@ -9,7 +9,6 @@
//called when plugin is used by emu (you should do first time init here)
s32 libARM_Init()
{
init_mem();
arm_Init();
return rv_ok;
@ -18,12 +17,11 @@ s32 libARM_Init()
//called when plugin is unloaded by emu, only if dcInit is called (eg, not called to enumerate plugins)
void libARM_Term()
{
term_mem();
//arm7_Term ?
}
//It's supposed to reset anything
void libARM_Reset(bool Manual)
void libARM_Reset(bool hard)
{
arm_Reset();
arm_SetEnabled(false);

View File

@ -2,12 +2,8 @@
#if HOST_CPU==CPU_X86 && FEAT_AREC != DYNAREC_NONE
#define C_CORE
namespace VARM
{
//#define CPUReadHalfWordQuick(addr) arm_ReadMem16(addr & 0x7FFFFF)
//#define CPUReadMemoryQuick(addr) (*(u32*)(addr))
#define CPUReadByte(addr) (*(u8*)(addr))
#define CPUReadMemory(addr) (*(u32*)(addr))
#define CPUReadHalfWord(addr) (*(u16*)(addr))
@ -99,115 +95,6 @@ namespace VARM
void CPUSwitchMode(int mode, bool saveState, bool breakLoop)
{
verify(mode==0x10);
/*
CPUUpdateCPSR();
switch(armMode) {
case 0x10:
case 0x1F:
reg[R13_USR].I = reg[13].I;
reg[R14_USR].I = reg[14].I;
reg[17].I = reg[16].I;
break;
case 0x11:
CPUSwap(&reg[R8_FIQ].I, &reg[8].I);
CPUSwap(&reg[R9_FIQ].I, &reg[9].I);
CPUSwap(&reg[R10_FIQ].I, &reg[10].I);
CPUSwap(&reg[R11_FIQ].I, &reg[11].I);
CPUSwap(&reg[R12_FIQ].I, &reg[12].I);
reg[R13_FIQ].I = reg[13].I;
reg[R14_FIQ].I = reg[14].I;
reg[SPSR_FIQ].I = reg[17].I;
break;
case 0x12:
reg[R13_IRQ].I = reg[13].I;
reg[R14_IRQ].I = reg[14].I;
reg[SPSR_IRQ].I = reg[17].I;
break;
case 0x13:
reg[R13_SVC].I = reg[13].I;
reg[R14_SVC].I = reg[14].I;
reg[SPSR_SVC].I = reg[17].I;
break;
case 0x17:
reg[R13_ABT].I = reg[13].I;
reg[R14_ABT].I = reg[14].I;
reg[SPSR_ABT].I = reg[17].I;
break;
case 0x1b:
reg[R13_UND].I = reg[13].I;
reg[R14_UND].I = reg[14].I;
reg[SPSR_UND].I = reg[17].I;
break;
}
u32 CPSR = reg[16].I;
u32 SPSR = reg[17].I;
switch(mode) {
case 0x10:
case 0x1F:
reg[13].I = reg[R13_USR].I;
reg[14].I = reg[R14_USR].I;
reg[16].I = SPSR;
break;
case 0x11:
CPUSwap(&reg[8].I, &reg[R8_FIQ].I);
CPUSwap(&reg[9].I, &reg[R9_FIQ].I);
CPUSwap(&reg[10].I, &reg[R10_FIQ].I);
CPUSwap(&reg[11].I, &reg[R11_FIQ].I);
CPUSwap(&reg[12].I, &reg[R12_FIQ].I);
reg[13].I = reg[R13_FIQ].I;
reg[14].I = reg[R14_FIQ].I;
if(saveState)
reg[17].I = CPSR;
else
reg[17].I = reg[SPSR_FIQ].I;
break;
case 0x12:
reg[13].I = reg[R13_IRQ].I;
reg[14].I = reg[R14_IRQ].I;
reg[16].I = SPSR;
if(saveState)
reg[17].I = CPSR;
else
reg[17].I = reg[SPSR_IRQ].I;
break;
case 0x13:
reg[13].I = reg[R13_SVC].I;
reg[14].I = reg[R14_SVC].I;
reg[16].I = SPSR;
if(saveState)
reg[17].I = CPSR;
else
reg[17].I = reg[SPSR_SVC].I;
break;
case 0x17:
reg[13].I = reg[R13_ABT].I;
reg[14].I = reg[R14_ABT].I;
reg[16].I = SPSR;
if(saveState)
reg[17].I = CPSR;
else
reg[17].I = reg[SPSR_ABT].I;
break;
case 0x1b:
reg[13].I = reg[R13_UND].I;
reg[14].I = reg[R14_UND].I;
reg[16].I = SPSR;
if(saveState)
reg[17].I = CPSR;
else
reg[17].I = reg[SPSR_UND].I;
break;
default:
printf("Unsupported ARM mode %02x\n", mode);
die("Arm error..");
break;
}
armMode = mode;
CPUUpdateFlags();
CPUUpdateCPSR();*/
}
void CPUUpdateCPSR()

View File

@ -40,6 +40,11 @@ struct MemChip
return rv;
}
virtual void Write(u32 addr, u32 data, u32 size)
{
die("Method not supported");
}
bool Load(const string& file)
{
FILE* f=fopen(file.c_str(),"rb");
@ -101,7 +106,7 @@ struct MemChip
if (Load(temp))
{
printf("Loaded %s as %s\n\n",temp,title.c_str());
INFO_LOG(FLASHROM, "Loaded %s as %s", temp, title.c_str());
return true;
}
} while(next);
@ -116,23 +121,23 @@ struct MemChip
sprintf(path,"%s%s%s",root.c_str(),prefix.c_str(),name_ro.c_str());
Save(path);
printf("Saved %s as %s\n\n",path,title.c_str());
INFO_LOG(FLASHROM, "Saved %s as %s", path, title.c_str());
}
virtual void Reset() {}
virtual bool Serialize(void **data, unsigned int *total_size) { return true; }
virtual bool Unserialize(void **data, unsigned int *total_size) { return true; }
};
struct RomChip : MemChip
{
RomChip(u32 sz, u32 write_protect_size = 0) : MemChip(sz, write_protect_size) {}
void Write(u32 addr,u32 data,u32 sz)
{
die("Write to RomChip is not possible, address=%x, data=%x, size=%d");
}
};
struct SRamChip : MemChip
{
SRamChip(u32 sz, u32 write_protect_size = 0) : MemChip(sz, write_protect_size) {}
void Write(u32 addr,u32 val,u32 sz)
void Write(u32 addr,u32 val,u32 sz) override
{
addr&=mask;
if (addr < write_protect_size)
@ -152,6 +157,18 @@ struct SRamChip : MemChip
die("invalid access size");
}
}
virtual bool Serialize(void **data, unsigned int *total_size) override
{
REICAST_SA(&this->data[write_protect_size], size - write_protect_size);
return true;
}
virtual bool Unserialize(void **data, unsigned int *total_size) override
{
REICAST_USA(&this->data[write_protect_size], size - write_protect_size);
return true;
}
};
//
@ -233,28 +250,29 @@ struct DCFlashChip : MemChip
state = FS_Normal;
}
virtual u8 Read8(u32 addr)
virtual u8 Read8(u32 addr) override
{
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
switch (addr)
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
{
case 0x1A002:
case 0x1A0A2:
if (settings.dreamcast.region <= 2)
return '0' + settings.dreamcast.region;
break;
case 0x1A003:
case 0x1A0A3:
if (settings.dreamcast.language <= 5)
return '0' + settings.dreamcast.language;
break;
case 0x1A004:
case 0x1A0A4:
if (settings.dreamcast.broadcast <= 3)
return '0' + settings.dreamcast.broadcast;
break;
switch (addr)
{
case 0x1A002:
case 0x1A0A2:
if (settings.dreamcast.region <= 2)
return '0' + settings.dreamcast.region;
break;
case 0x1A003:
case 0x1A0A3:
if (settings.dreamcast.language <= 5)
return '0' + settings.dreamcast.language;
break;
case 0x1A004:
case 0x1A0A4:
if (settings.dreamcast.broadcast <= 3)
return '0' + settings.dreamcast.broadcast;
break;
}
}
#endif
u32 rv=MemChip::Read8(addr);
@ -262,7 +280,7 @@ struct DCFlashChip : MemChip
}
void Write(u32 addr,u32 val,u32 sz)
void Write(u32 addr,u32 val,u32 sz) override
{
if (sz != 1)
die("invalid access size");
@ -283,13 +301,13 @@ struct DCFlashChip : MemChip
state = FS_ReadAMDID1;
break;
default:
printf("Unknown FlashWrite mode: %x\n", val);
INFO_LOG(FLASHROM, "Unknown FlashWrite mode: %x\n", val);
break;
}
break;
case FS_ReadAMDID1:
if ((addr & 0xffff) == 0x2aa && (val & 0xff) == 0x55)
if ((addr & 0xffff) == 0x02aa && (val & 0xff) == 0x55)
state = FS_ReadAMDID2;
else if ((addr & 0xffff) == 0x2aaa && (val & 0xff) == 0x55)
state = FS_ReadAMDID2;
@ -297,19 +315,19 @@ struct DCFlashChip : MemChip
state = FS_ReadAMDID2;
else
{
printf("FlashRom: ReadAMDID1 unexpected write @ %x: %x\n", addr, val);
WARN_LOG(FLASHROM, "FlashRom: ReadAMDID1 unexpected write @ %x: %x", addr, val);
state = FS_Normal;
}
break;
case FS_ReadAMDID2:
if ((addr & 0xffff) == 0x555 && (val & 0xff) == 0x80)
if ((addr & 0xffff) == 0x0555 && (val & 0xff) == 0x80)
state = FS_EraseAMD1;
else if ((addr & 0xffff) == 0x5555 && (val & 0xff) == 0x80)
state = FS_EraseAMD1;
else if ((addr & 0xfff) == 0xaaa && (val & 0xff) == 0x80)
state = FS_EraseAMD1;
else if ((addr & 0xffff) == 0x555 && (val & 0xff) == 0xa0)
else if ((addr & 0xffff) == 0x0555 && (val & 0xff) == 0xa0)
state = FS_ByteProgram;
else if ((addr & 0xffff) == 0x5555 && (val & 0xff) == 0xa0)
state = FS_ByteProgram;
@ -317,7 +335,7 @@ struct DCFlashChip : MemChip
state = FS_ByteProgram;
else
{
printf("FlashRom: ReadAMDID2 unexpected write @ %x: %x\n", addr, val);
WARN_LOG(FLASHROM, "FlashRom: ReadAMDID2 unexpected write @ %x: %x", addr, val);
state = FS_Normal;
}
break;
@ -334,12 +352,12 @@ struct DCFlashChip : MemChip
state = FS_EraseAMD2;
else
{
printf("FlashRom: EraseAMD1 unexpected write @ %x: %x\n", addr, val);
WARN_LOG(FLASHROM, "FlashRom: EraseAMD1 unexpected write @ %x: %x", addr, val);
}
break;
case FS_EraseAMD2:
if ((addr & 0xffff) == 0x2aa && (val & 0xff) == 0x55)
if ((addr & 0xffff) == 0x02aa && (val & 0xff) == 0x55)
state = FS_EraseAMD3;
else if ((addr & 0xffff) == 0x2aaa && (val & 0xff) == 0x55)
state = FS_EraseAMD3;
@ -347,7 +365,7 @@ struct DCFlashChip : MemChip
state = FS_EraseAMD3;
else
{
printf("FlashRom: EraseAMD2 unexpected write @ %x: %x\n", addr, val);
WARN_LOG(FLASHROM, "FlashRom: EraseAMD2 unexpected write @ %x: %x", addr, val);
}
break;
@ -356,16 +374,14 @@ struct DCFlashChip : MemChip
|| ((addr & 0xfff) == 0xaaa && (val & 0xff) == 0x10))
{
// chip erase
printf("Erasing Chip!\n");
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
INFO_LOG(FLASHROM, "Erasing Chip!");
u8 save[0x2000];
// this area is write-protected on AW
memcpy(save, data + 0x1a000, 0x2000);
#endif
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
// this area is write-protected on AW
memcpy(save, data + 0x1a000, 0x2000);
memset(data + write_protect_size, 0xff, size - write_protect_size);
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
memcpy(data + 0x1a000, save, 0x2000);
#endif
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
memcpy(data + 0x1a000, save, 0x2000);
state = FS_Normal;
}
else if ((val & 0xff) == 0x30)
@ -373,22 +389,20 @@ struct DCFlashChip : MemChip
// sector erase
if (addr >= write_protect_size)
{
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
u8 save[0x2000];
// this area is write-protected on AW
memcpy(save, data + 0x1a000, 0x2000);
#endif
printf("Erase Sector %08X! (%08X)\n",addr,addr&(~0x3FFF));
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
// this area is write-protected on AW
memcpy(save, data + 0x1a000, 0x2000);
INFO_LOG(FLASHROM, "Erase Sector %08X! (%08X)", addr, addr & ~0x3FFF);
memset(&data[addr&(~0x3FFF)],0xFF,0x4000);
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
memcpy(data + 0x1a000, save, 0x2000);
#endif
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
memcpy(data + 0x1a000, save, 0x2000);
}
state = FS_Normal;
}
else
{
printf("FlashRom: EraseAMD3 unexpected write @ %x: %x\n", addr, val);
WARN_LOG(FLASHROM, "FlashRom: EraseAMD3 unexpected write @ %x: %x", addr, val);
}
break;
}
@ -617,7 +631,7 @@ private:
if (user.block_id == block_id)
{
if (!validate_crc(&user))
printf("flash_lookup_block physical block %d has an invalid crc\n", phys_id);
WARN_LOG(FLASHROM, "flash_lookup_block physical block %d has an invalid crc", phys_id);
else
result = phys_id;
}
@ -627,4 +641,18 @@ private:
return result;
}
virtual bool Serialize(void **data, unsigned int *total_size) override
{
REICAST_S(state);
REICAST_SA(&this->data[write_protect_size], size - write_protect_size);
return true;
}
virtual bool Unserialize(void **data, unsigned int *total_size) override
{
REICAST_US(state);
REICAST_USA(&this->data[write_protect_size], size - write_protect_size);
return true;
}
};

View File

@ -59,13 +59,11 @@ u32 data_write_mode=0;
//end
void nilprintf(...){}
#define printf_rm nilprintf
#define printf_ata nilprintf
#define printf_spi nilprintf
#define printf_spicmd nilprintf
#define printf_subcode nilprintf
#define printf_rm(...) DEBUG_LOG(GDROM, __VA_ARGS__)
#define printf_ata(...) DEBUG_LOG(GDROM, __VA_ARGS__)
#define printf_spi(...) DEBUG_LOG(GDROM, __VA_ARGS__)
#define printf_spicmd(...) DEBUG_LOG(GDROM, __VA_ARGS__)
#define printf_subcode(...) DEBUG_LOG(GDROM, __VA_ARGS__)
void libCore_CDDA_Sector(s16* sector)
{
@ -309,7 +307,7 @@ u32 GetFAD(u8* data, bool msf)
{
if(msf)
{
printf("GDROM: MSF FORMAT\n");
INFO_LOG(GDROM, "GDROM: MSF FORMAT");
return ((data[0]*60*75) + (data[1]*75) + (data[2]));
}
else
@ -372,7 +370,7 @@ void gd_process_ata_cmd()
switch(ata_cmd.command)
{
case ATA_NOP:
printf_ata("ATA_NOP\n");
printf_ata("ATA_NOP");
/*
Setting "abort" in the error register
Setting an error in the status register
@ -394,29 +392,28 @@ void gd_process_ata_cmd()
case ATA_SOFT_RESET:
{
printf_ata("ATA_SOFT_RESET\n");
printf_ata("ATA_SOFT_RESET");
//DRV -> preserved -> wtf is it anyway ?
gd_reset();
}
break;
case ATA_EXEC_DIAG:
printf_ata("ATA_EXEC_DIAG\n");
printf("ATA_EXEC_DIAG -- not implemented\n");
printf_ata("ATA_EXEC_DIAG -- not implemented");
break;
case ATA_SPI_PACKET:
printf_ata("ATA_SPI_PACKET\n");
printf_ata("ATA_SPI_PACKET");
gd_set_state(gds_waitpacket);
break;
case ATA_IDENTIFY_DEV:
printf_ata("ATA_IDENTIFY_DEV\n");
printf_ata("ATA_IDENTIFY_DEV");
gd_spi_pio_end((u8*)&reply_a1[packet_cmd.data_8[2]>>1],packet_cmd.data_8[4]);
break;
case ATA_SET_FEATURES:
printf_ata("ATA_SET_FEATURES\n");
printf_ata("ATA_SET_FEATURES");
//Set features sets :
//Error : ABRT
@ -440,10 +437,10 @@ void gd_process_ata_cmd()
void gd_process_spi_cmd()
{
printf_spi("Sense: %02x %02x %02x \n", sns_asc, sns_ascq, sns_key);
printf_spi("Sense: %02x %02x %02x", sns_asc, sns_ascq, sns_key);
printf_spi("SPI command %02x;",packet_cmd.data_8[0]);
printf_spi("Params: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x \n",
printf_spi("Params: %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
packet_cmd.data_8[0], packet_cmd.data_8[1], packet_cmd.data_8[2], packet_cmd.data_8[3], packet_cmd.data_8[4], packet_cmd.data_8[5],
packet_cmd.data_8[6], packet_cmd.data_8[7], packet_cmd.data_8[8], packet_cmd.data_8[9], packet_cmd.data_8[10], packet_cmd.data_8[11] );
@ -455,7 +452,7 @@ void gd_process_spi_cmd()
switch(packet_cmd.data_8[0])
{
case SPI_TEST_UNIT:
printf_spicmd("SPI_TEST_UNIT\n");
printf_spicmd("SPI_TEST_UNIT");
GDStatus.CHECK=SecNumber.Status==GD_BUSY; // Drive is ready ;)
@ -463,7 +460,7 @@ void gd_process_spi_cmd()
break;
case SPI_REQ_MODE:
printf_spicmd("SPI_REQ_MODE\n");
printf_spicmd("SPI_REQ_MODE");
gd_spi_pio_end((u8*)&reply_11[packet_cmd.data_8[2]>>1],packet_cmd.data_8[4]);
break;
@ -477,7 +474,7 @@ void gd_process_spi_cmd()
if (readcmd.head ==1 && readcmd.subh==1 && readcmd.data==1 && readcmd.expdtype==3 && readcmd.other==0)
sector_type=2340;
else if(readcmd.head ||readcmd.subh || readcmd.other || (!readcmd.data)) // assert
printf("GDROM: *FIXME* ADD MORE CD READ SETTINGS %d %d %d %d 0x%01X\n",readcmd.head,readcmd.subh,readcmd.other,readcmd.data,readcmd.expdtype);
WARN_LOG(GDROM, "GDROM: *FIXME* ADD MORE CD READ SETTINGS %d %d %d %d 0x%01X",readcmd.head,readcmd.subh,readcmd.other,readcmd.data,readcmd.expdtype);
u32 start_sector = GetFAD(&readcmd.b[2],readcmd.prmtype);
u32 sector_count = (readcmd.b[8]<<16) | (readcmd.b[9]<<8) | (readcmd.b[10]);
@ -486,7 +483,7 @@ void gd_process_spi_cmd()
read_params.remaining_sectors=sector_count;
read_params.sector_type = sector_type;//yeah i know , not really many types supported...
printf_spicmd("SPI_CD_READ - Sector=%d Size=%d/%d DMA=%d\n",read_params.start_sector,read_params.remaining_sectors,read_params.sector_type,Features.CDRead.DMA);
printf_spicmd("SPI_CD_READ - Sector=%d Size=%d/%d DMA=%d",read_params.start_sector,read_params.remaining_sectors,read_params.sector_type,Features.CDRead.DMA);
if (Features.CDRead.DMA == 1)
{
gd_set_state(gds_readsector_dma);
@ -500,7 +497,7 @@ void gd_process_spi_cmd()
case SPI_GET_TOC:
{
printf_spicmd("SPI_GET_TOC\n");
printf_spicmd("SPI_GET_TOC");
//printf("SPI_GET_TOC - %d\n",(packet_cmd.data_8[4]) | (packet_cmd.data_8[3]<<8) );
u32 toc_gd[102];
@ -514,7 +511,7 @@ void gd_process_spi_cmd()
//mount/map drive ? some kind of reset/unlock ??
//seems like a non data command :)
case 0x70:
printf_spicmd("SPI : unknown ? [0x70]\n");
printf_spicmd("SPI : unknown ? [0x70]");
//printf("SPI : unknown ? [0x70]\n");
/*GDStatus.full=0x50; //FIXME
RaiseInterrupt(holly_GDROM_CMD);*/
@ -530,7 +527,7 @@ void gd_process_spi_cmd()
// This is more or less a hack until more info about this command becomes available. ~Psy
case 0x71:
{
printf_spicmd("SPI : unknown ? [0x71]\n");
printf_spicmd("SPI : unknown ? [0x71]");
//printf("SPI : unknown ? [0x71]\n");
extern u32 reply_71_sz;
@ -545,7 +542,7 @@ void gd_process_spi_cmd()
break;
case SPI_SET_MODE:
{
printf_spicmd("SPI_SET_MODE\n");
printf_spicmd("SPI_SET_MODE");
u32 Offset = packet_cmd.data_8[2];
u32 Count = packet_cmd.data_8[4];
verify((Offset+Count)<11); //cant set write olny things :P
@ -556,8 +553,7 @@ void gd_process_spi_cmd()
break;
case SPI_CD_READ2:
printf_spicmd("SPI_CD_READ2\n");
printf("GDROM: Unhandled Sega SPI frame: SPI_CD_READ2\n");
printf_spicmd("SPI_CD_READ2 Unhandled");
gd_set_state(gds_procpacketdone);
break;
@ -565,8 +561,7 @@ void gd_process_spi_cmd()
case SPI_REQ_STAT:
{
printf_spicmd("SPI_REQ_STAT\n");
//printf("GDROM: Unhandled Sega SPI frame: SPI_REQ_STAT\n");
printf_spicmd("SPI_REQ_STAT");
u8 stat[10];
//0 0 0 0 0 STATUS
@ -597,8 +592,7 @@ void gd_process_spi_cmd()
break;
case SPI_REQ_ERROR:
printf_spicmd("SPI_REQ_ERROR\n");
//printf("GDROM: Unhandled Sega SPI frame: SPI_REQ_ERROR\n");
printf_spicmd("SPI_REQ_ERROR");
u8 resp[10];
resp[0]=0xF0;
@ -617,7 +611,7 @@ void gd_process_spi_cmd()
break;
case SPI_REQ_SES:
printf_spicmd("SPI_REQ_SES\n");
printf_spicmd("SPI_REQ_SES");
u8 ses_inf[6];
libGDR_GetSessionInfo(ses_inf,packet_cmd.data_8[2]);
@ -626,24 +620,21 @@ void gd_process_spi_cmd()
break;
case SPI_CD_OPEN:
printf_spicmd("SPI_CD_OPEN\n");
printf("GDROM: Unhandled Sega SPI frame: SPI_CD_OPEN\n");
printf_spicmd("SPI_CD_OPEN Unhandled");
gd_set_state(gds_procpacketdone);
break;
case SPI_CD_PLAY:
{
printf_spicmd("SPI_CD_PLAY\n");
printf("GDROM: Unhandled Sega SPI frame: SPI_CD_PLAY\n");
printf_spicmd("SPI_CD_PLAY");
//cdda.CurrAddr.FAD=60000;
cdda.playing=true;
SecNumber.Status=GD_PLAY;
u32 param_type=packet_cmd.data_8[1]&0x7;
printf("param_type=%d\n",param_type);
DEBUG_LOG(GDROM, "param_type=%d", param_type);
if (param_type==1)
{
cdda.StartAddr.FAD=cdda.CurrAddr.FAD=GetFAD(&packet_cmd.data_8[2],0);
@ -665,11 +656,11 @@ void gd_process_spi_cmd()
die("SPI_CD_SEEK : not known parameter..");
}
cdda.repeats=packet_cmd.data_8[6]&0xF;
printf("cdda.StartAddr=%d\n",cdda.StartAddr.FAD);
printf("cdda.EndAddr=%d\n",cdda.EndAddr.FAD);
printf("cdda.repeats=%d\n",cdda.repeats);
printf("cdda.playing=%d\n",cdda.playing);
printf("cdda.CurrAddr=%d\n",cdda.CurrAddr.FAD);
DEBUG_LOG(GDROM, "cdda.StartAddr=%d",cdda.StartAddr.FAD);
DEBUG_LOG(GDROM, "cdda.EndAddr=%d",cdda.EndAddr.FAD);
DEBUG_LOG(GDROM, "cdda.repeats=%d",cdda.repeats);
DEBUG_LOG(GDROM, "cdda.playing=%d",cdda.playing);
DEBUG_LOG(GDROM, "cdda.CurrAddr=%d",cdda.CurrAddr.FAD);
gd_set_state(gds_procpacketdone);
}
@ -677,14 +668,13 @@ void gd_process_spi_cmd()
case SPI_CD_SEEK:
{
printf_spicmd("SPI_CD_SEEK\n");
printf("GDROM: Unhandled Sega SPI frame: SPI_CD_SEEK\n");
printf_spicmd("SPI_CD_SEEK");
SecNumber.Status=GD_PAUSE;
cdda.playing=false;
u32 param_type=packet_cmd.data_8[1]&0x7;
printf("param_type=%d\n",param_type);
DEBUG_LOG(GDROM, "param_type=%d",param_type);
if (param_type==1)
{
cdda.StartAddr.FAD=cdda.CurrAddr.FAD=GetFAD(&packet_cmd.data_8[2],0);
@ -711,11 +701,11 @@ void gd_process_spi_cmd()
die("SPI_CD_SEEK : not known parameter..");
}
printf("cdda.StartAddr=%d\n",cdda.StartAddr.FAD);
printf("cdda.EndAddr=%d\n",cdda.EndAddr.FAD);
printf("cdda.repeats=%d\n",cdda.repeats);
printf("cdda.playing=%d\n",cdda.playing);
printf("cdda.CurrAddr=%d\n",cdda.CurrAddr.FAD);
DEBUG_LOG(GDROM, "cdda.StartAddr=%d",cdda.StartAddr.FAD);
DEBUG_LOG(GDROM, "cdda.EndAddr=%d",cdda.EndAddr.FAD);
DEBUG_LOG(GDROM, "cdda.repeats=%d",cdda.repeats);
DEBUG_LOG(GDROM, "cdda.playing=%d",cdda.playing);
DEBUG_LOG(GDROM, "cdda.CurrAddr=%d",cdda.CurrAddr.FAD);
gd_set_state(gds_procpacketdone);
@ -723,8 +713,7 @@ void gd_process_spi_cmd()
break;
case SPI_CD_SCAN:
printf_spicmd("SPI_CD_SCAN\n");
printf("GDROM: Unhandled Sega SPI frame: SPI_CD_SCAN\n");
printf_spicmd("SPI_CD_SCAN Unhandled");
gd_set_state(gds_procpacketdone);
@ -732,8 +721,7 @@ void gd_process_spi_cmd()
case SPI_GET_SCD:
{
printf_spicmd("SPI_GET_SCD\n");
//printf("\nGDROM:\tUnhandled Sega SPI frame: SPI_GET_SCD\n");
printf_spicmd("SPI_GET_SCD");
u32 format;
format=packet_cmd.data_8[1]&0xF;
@ -804,7 +792,7 @@ void gd_process_spi_cmd()
data_q[8]=0x0; //(u8)(cdda.CurrAddr.FAD>>8);
data_q[9]=0x96;//(u8)(cdda.CurrAddr.FAD>>0);
sz=0xE;
printf_subcode("NON raw subcode read -- partially wrong [format=%d]\n",format);
printf_subcode("NON raw subcode read -- partially wrong [format=%d]",format);
}
gd_spi_pio_end((u8*)&subc_info[0],sz);
@ -812,7 +800,7 @@ void gd_process_spi_cmd()
break;
default:
printf("GDROM: Unhandled Sega SPI frame: %X\n", packet_cmd.data_8[0]);
INFO_LOG(GDROM, "GDROM: Unhandled Sega SPI frame: %X", packet_cmd.data_8[0]);
gd_set_state(gds_procpacketdone);
break;
@ -826,30 +814,30 @@ u32 ReadMem_gdrom(u32 Addr, u32 sz)
//cancel interrupt
case GD_STATUS_Read :
asic_CancelInterrupt(holly_GDROM_CMD); //Clear INTRQ signal
printf_rm("GDROM: STATUS [cancel int](v=%X)\n",GDStatus.full);
printf_rm("GDROM: STATUS [cancel int](v=%X)",GDStatus.full);
return GDStatus.full | (1<<4);
case GD_ALTSTAT_Read:
printf_rm("GDROM: Read From AltStatus (v=%X)\n",GDStatus.full);
printf_rm("GDROM: Read From AltStatus (v=%X)",GDStatus.full);
return GDStatus.full | (1<<4);
case GD_BYCTLLO :
printf_rm("GDROM: Read From GD_BYCTLLO\n");
printf_rm("GDROM: Read From GD_BYCTLLO");
return ByteCount.low;
case GD_BYCTLHI :
printf_rm("GDROM: Read From GD_BYCTLHI\n");
printf_rm("GDROM: Read From GD_BYCTLHI");
return ByteCount.hi;
case GD_DATA:
if(2!=sz)
printf("GDROM: Bad size on DATA REG Read\n");
INFO_LOG(GDROM, "GDROM: Bad size on DATA REG Read");
//if (gd_state == gds_pio_send_data)
//{
if (pio_buff.index == pio_buff.size)
{
printf("GDROM: Illegal Read From DATA (underflow)\n");
INFO_LOG(GDROM, "GDROM: Illegal Read From DATA (underflow)");
}
else
{
@ -872,24 +860,24 @@ u32 ReadMem_gdrom(u32 Addr, u32 sz)
return 0;
case GD_DRVSEL:
printf_rm("GDROM: Read From DriveSel\n");
printf_rm("GDROM: Read From DriveSel");
return DriveSel;
case GD_ERROR_Read:
printf_rm("GDROM: Read from ERROR Register\n");
printf_rm("GDROM: Read from ERROR Register");
Error.Sense=sns_key;
return Error.full;
case GD_IREASON_Read:
printf_rm("GDROM: Read from INTREASON Register\n");
printf_rm("GDROM: Read from INTREASON Register");
return IntReason.full;
case GD_SECTNUM:
printf_rm("GDROM: Read from SecNumber Register (v=%X)\n", SecNumber.full);
printf_rm("GDROM: Read from SecNumber Register (v=%X)", SecNumber.full);
return SecNumber.full;
default:
printf("GDROM: Unhandled read from address %X, Size:%X\n",Addr,sz);
INFO_LOG(GDROM, "GDROM: Unhandled read from address %X, Size:%X",Addr,sz);
return 0;
}
}
@ -900,19 +888,19 @@ void WriteMem_gdrom(u32 Addr, u32 data, u32 sz)
switch(Addr)
{
case GD_BYCTLLO:
printf_rm("GDROM: Write to GD_BYCTLLO = %X, Size:%X\n",data,sz);
printf_rm("GDROM: Write to GD_BYCTLLO = %X, Size:%X",data,sz);
ByteCount.low =(u8) data;
break;
case GD_BYCTLHI:
printf_rm("GDROM: Write to GD_BYCTLHI = %X, Size:%X\n",data,sz);
printf_rm("GDROM: Write to GD_BYCTLHI = %X, Size:%X",data,sz);
ByteCount.hi =(u8) data;
break;
case GD_DATA:
{
if(2!=sz)
printf("GDROM: Bad size on DATA REG\n");
INFO_LOG(GDROM, "GDROM: Bad size on DATA REG");
if (gd_state == gds_waitpacket)
{
packet_cmd.data_16[packet_cmd.index]=(u16)data;
@ -932,18 +920,18 @@ void WriteMem_gdrom(u32 Addr, u32 data, u32 sz)
}
else
{
printf("GDROM: Illegal Write to DATA\n");
INFO_LOG(GDROM, "GDROM: Illegal Write to DATA");
}
return;
}
case GD_DEVCTRL_Write:
printf("GDROM: Write GD_DEVCTRL (Not implemented on Dreamcast)\n");
INFO_LOG(GDROM, "GDROM: Write GD_DEVCTRL (Not implemented on Dreamcast)");
break;
case GD_DRVSEL:
if (data != 0) {
printf("GDROM: Write to GD_DRVSEL, !=0. Value is: %02X\n", data);
INFO_LOG(GDROM, "GDROM: Write to GD_DRVSEL, !=0. Value is: %02X", data);
}
DriveSel = data;
break;
@ -953,17 +941,17 @@ void WriteMem_gdrom(u32 Addr, u32 data, u32 sz)
// The actual transfer mode is specified by the Sector Counter Register.
case GD_FEATURES_Write:
printf_rm("GDROM: Write to GD_FEATURES\n");
printf_rm("GDROM: Write to GD_FEATURES");
Features.full =(u8) data;
break;
case GD_SECTCNT_Write:
printf("GDROM: Write to SecCount = %X\n", data);
DEBUG_LOG(GDROM, "GDROM: Write to SecCount = %X", data);
SecCount.full =(u8) data;
break;
case GD_SECTNUM:
printf("GDROM: Write to SecNum; not possible = %X\n", data);
INFO_LOG(GDROM, "GDROM: Write to SecNum; not possible = %X", data);
break;
case GD_COMMAND_Write:
@ -976,7 +964,7 @@ void WriteMem_gdrom(u32 Addr, u32 data, u32 sz)
break;
default:
printf("\nGDROM:\tUnhandled write to address %X <= %X, Size:%X\n",Addr,data,sz);
INFO_LOG(GDROM, "GDROM: Unhandled write to address %X <= %X, Size:%X",Addr,data,sz);
break;
}
}
@ -1027,13 +1015,13 @@ int GDRomschd(int i, int c, int j)
// do we need to do this for GDROM DMA?
if(0x8201 != (dmaor &DMAOR_MASK))
{
printf("\n!\tGDROM: DMAOR has invalid settings (%X) !\n", dmaor);
INFO_LOG(GDROM, "GDROM: DMAOR has invalid settings (%X)", dmaor);
//return;
}
if(len == 0)
{
printf("\n!\tGDROM: Len: %X, Abnormal Termination !\n", len);
INFO_LOG(GDROM, "GDROM: Len: %X, Abnormal Termination !", len);
}
u32 len_backup = len;
@ -1063,7 +1051,7 @@ int GDRomschd(int i, int c, int j)
}
else
{
msgboxf("GDROM: SB_GDDIR %X (TO AICA WAVE MEM?)", MBX_ICONERROR, SB_GDDIR);
WARN_LOG(GDROM, "GDROM: SB_GDDIR %X (TO AICA WAVE MEM?)", src);
}
//SB_GDLEN = 0x00000000; //13/5/2k7 -> according to docs these regs are not updated by hardware
@ -1098,7 +1086,7 @@ void GDROM_DmaStart(u32 addr, u32 data)
{
if (SB_GDEN==0)
{
printf("Invalid GD-DMA start, SB_GDEN=0.Ingoring it.\n");
INFO_LOG(GDROM, "Invalid GD-DMA start, SB_GDEN=0.Ingoring it.");
return;
}
SB_GDST|=data&1;
@ -1107,7 +1095,7 @@ void GDROM_DmaStart(u32 addr, u32 data)
{
SB_GDSTARD=SB_GDSTAR;
SB_GDLEND=0;
//printf("GDROM-DMA start addr %08X len %d\n", SB_GDSTAR, SB_GDLEN);
DEBUG_LOG(GDROM, "GDROM-DMA start addr %08X len %d", SB_GDSTAR, SB_GDLEN);
int ticks = getGDROMTicks();
if (ticks < 448) // FIXME #define
@ -1125,7 +1113,7 @@ void GDROM_DmaEnable(u32 addr, u32 data)
SB_GDEN = (data & 1);
if (SB_GDEN == 0 && SB_GDST == 1)
{
printf_spi("GD-DMA aborted\n");
printf_spi("GD-DMA aborted");
SB_GDST = 0;
}
}
@ -1133,27 +1121,18 @@ void GDROM_DmaEnable(u32 addr, u32 data)
//Init/Term/Res
void gdrom_reg_Init()
{
sb_rio_register(SB_GDST_addr, RIO_WF, 0, &GDROM_DmaStart);
/*
sb_regs[(SB_GDST_addr-SB_BASE)>>2].flags=REG_32BIT_READWRITE | REG_READ_DATA;
sb_regs[(SB_GDST_addr-SB_BASE)>>2].writeFunction=GDROM_DmaStart;
*/
sb_rio_register(SB_GDEN_addr, RIO_WF, 0, &GDROM_DmaEnable);
/*
sb_regs[(SB_GDEN_addr-SB_BASE)>>2].flags=REG_32BIT_READWRITE | REG_READ_DATA;
sb_regs[(SB_GDEN_addr-SB_BASE)>>2].writeFunction=GDROM_DmaEnable;
*/
gdrom_schid = sh4_sched_register(0, &GDRomschd);
}
void gdrom_reg_Term()
{
}
void gdrom_reg_Reset(bool Manual)
void gdrom_reg_Reset(bool hard)
{
sb_rio_register(SB_GDST_addr, RIO_WF, 0, &GDROM_DmaStart);
sb_rio_register(SB_GDEN_addr, RIO_WF, 0, &GDROM_DmaEnable);
SB_GDST = 0;
SB_GDEN = 0;
}

View File

@ -248,7 +248,7 @@ void asic_reg_Term()
}
//Reset -> Reset - Initialise to default values
void asic_reg_Reset(bool Manual)
void asic_reg_Reset(bool hard)
{
}

View File

@ -35,7 +35,7 @@ u32 sb_ReadMem(u32 addr,u32 sz)
#ifdef TRACE
if (offset & 3/*(size-1)*/) //4 is min align size
{
EMUERROR("Unaligned System Bus register read");
INFO_LOG(HOLLY, "Unaligned System Bus register read");
}
#endif
@ -59,7 +59,7 @@ u32 sb_ReadMem(u32 addr,u32 sz)
//printf("SB: %08X\n",addr);
if ((sb_regs[offset].flags & REG_WO) || sb_regs[offset].readFunctionAddr == NULL)
{
EMUERROR("sb_ReadMem write-only reg %08x %d\n", addr, sz);
INFO_LOG(HOLLY, "sb_ReadMem write-only reg %08x %d", addr, sz);
return 0;
}
return sb_regs[offset].readFunctionAddr(addr);
@ -69,7 +69,7 @@ u32 sb_ReadMem(u32 addr,u32 sz)
else
{
if (!(sb_regs[offset].flags& REG_NOT_IMPL))
EMUERROR("ERROR [wrong size read on register]");
INFO_LOG(HOLLY, "ERROR [wrong size read on register]");
}
#endif
// if ((sb_regs[offset].flags& REG_NOT_IMPL))
@ -83,7 +83,7 @@ void sb_WriteMem(u32 addr,u32 data,u32 sz)
#ifdef TRACE
if (offset & 3/*(size-1)*/) //4 is min align size
{
EMUERROR("Unaligned System bus register write");
INFO_LOG(HOLLY, "Unaligned System bus register write");
}
#endif
offset>>=2;
@ -128,10 +128,10 @@ offset>>=2;
else
{
if (!(sb_regs[offset].flags& REG_NOT_IMPL))
EMUERROR4("ERROR :wrong size write on register ; offset=%x , data=%x,sz=%d",offset,data,sz);
INFO_LOG(HOLLY, "ERROR: wrong size write on register; offset=%x, data=%x, sz=%d", offset, data, sz);
}
if ((sb_regs[offset].flags& REG_NOT_IMPL))
EMUERROR3("Write to System Control Regs , not implemented , addr=%x,data=%x",addr,data);
INFO_LOG(HOLLY, "Write to System Control Regs, not implemented, addr=%x, data=%x", addr, data);
#endif
}
@ -773,43 +773,53 @@ void sb_Init()
asic_reg_Init();
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
gdrom_reg_Init();
#else
naomi_reg_Init();
#endif
pvr_sb_Init();
maple_Init();
aica_sb_Init();
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST && defined(ENABLE_MODEM)
#ifdef ENABLE_MODEM
ModemInit();
#endif
}
void sb_Reset(bool Manual)
void sb_Reset(bool hard)
{
asic_reg_Reset(Manual);
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
gdrom_reg_Reset(Manual);
#else
naomi_reg_Reset(Manual);
if (hard)
{
for (u32 i = 0; i < sb_regs.Size; i++)
{
if (!(sb_regs[i].flags & (REG_RO|REG_WO|REG_RF)))
sb_regs[i].data32 = 0;
}
}
SB_ISTNRM = 0;
SB_FFST_rc = 0;
SB_FFST = 0;
#ifdef ENABLE_MODEM
ModemTerm();
#endif
pvr_sb_Reset(Manual);
maple_Reset(Manual);
aica_sb_Reset(Manual);
asic_reg_Reset(hard);
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
gdrom_reg_Reset(hard);
else
naomi_reg_Reset(hard);
pvr_sb_Reset(hard);
maple_Reset(hard);
aica_sb_Reset(hard);
}
void sb_Term()
{
#ifdef ENABLE_MODEM
ModemTerm();
#endif
aica_sb_Term();
maple_Term();
pvr_sb_Term();
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
gdrom_reg_Term();
#else
naomi_reg_Term();
#endif
asic_reg_Term();
}

View File

@ -18,132 +18,139 @@
#include "hw/flashrom/flashrom.h"
#include "reios/reios.h"
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
DCFlashChip sys_rom(BIOS_SIZE, BIOS_SIZE / 2);
#else
RomChip sys_rom(BIOS_SIZE);
#endif
#ifdef FLASH_SIZE
DCFlashChip sys_nvmem(FLASH_SIZE);
#endif
#ifdef BBSRAM_SIZE
SRamChip sys_nvmem(BBSRAM_SIZE);
#endif
MemChip *sys_rom;
MemChip *sys_nvmem;
extern bool bios_loaded;
static std::string getRomPrefix()
{
switch (settings.platform.system)
{
case DC_PLATFORM_DREAMCAST:
return "dc_";
case DC_PLATFORM_NAOMI:
return "naomi_";
case DC_PLATFORM_ATOMISWAVE:
return "aw_";
default:
die("Unsupported platform");
return "";
}
}
static bool nvmemOptional()
{
return settings.platform.system != DC_PLATFORM_DREAMCAST;
}
bool LoadRomFiles(const string& root)
{
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
if (!sys_rom.Load(root, ROM_PREFIX, "%boot.bin;%boot.bin.bin;%bios.bin;%bios.bin.bin" ROM_NAMES, "bootrom"))
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
{
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
// Dreamcast absolutely needs a BIOS
msgboxf("Unable to find bios in %s. Exiting...", MBX_ICONERROR, root.c_str());
return false;
#endif
}
else
bios_loaded = true;
#endif
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
if (!sys_nvmem.Load(root, ROM_PREFIX, "%nvmem.bin;%flash_wb.bin;%flash.bin;%flash.bin.bin", "nvram"))
#else
if (!sys_nvmem.Load(get_game_save_prefix() + ".nvmem"))
#endif
{
if (NVR_OPTIONAL)
if (!sys_rom->Load(root, getRomPrefix(), "%boot.bin;%boot.bin.bin;%bios.bin;%bios.bin.bin", "bootrom"))
{
printf("flash/nvmem is missing, will create new file...\n");
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
{
// Dreamcast absolutely needs a BIOS
msgboxf("Unable to find bios in %s. Exiting...", MBX_ICONERROR, root.c_str());
return false;
}
}
else
bios_loaded = true;
}
bool rc;
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
rc = sys_nvmem->Load(root, getRomPrefix(), "%nvmem.bin;%flash_wb.bin;%flash.bin;%flash.bin.bin", "nvram");
else
rc = sys_nvmem->Load(get_game_save_prefix() + ".nvmem");
if (!rc)
{
if (nvmemOptional())
{
INFO_LOG(FLASHROM, "flash/nvmem is missing, will create new file...");
}
else
{
msgboxf("Unable to find flash/nvmem in \n%s\nExiting...", MBX_ICONERROR, root.c_str());
msgboxf("Unable to find flash/nvmem in %s. Exiting...", MBX_ICONERROR, root.c_str());
return false;
}
}
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
struct flash_syscfg_block syscfg;
int res = sys_nvmem.ReadBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg);
if (!res)
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
{
// write out default settings
memset(&syscfg, 0xff, sizeof(syscfg));
syscfg.time_lo = 0;
syscfg.time_hi = 0;
syscfg.lang = 0;
syscfg.mono = 0;
syscfg.autostart = 1;
struct flash_syscfg_block syscfg;
int res = static_cast<DCFlashChip*>(sys_nvmem)->ReadBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg);
if (!res)
{
// write out default settings
memset(&syscfg, 0xff, sizeof(syscfg));
syscfg.time_lo = 0;
syscfg.time_hi = 0;
syscfg.lang = 0;
syscfg.mono = 0;
syscfg.autostart = 1;
}
u32 time = GetRTC_now();
syscfg.time_lo = time & 0xffff;
syscfg.time_hi = time >> 16;
if (settings.dreamcast.language <= 5)
syscfg.lang = settings.dreamcast.language;
if (static_cast<DCFlashChip*>(sys_nvmem)->WriteBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg) != 1)
WARN_LOG(FLASHROM, "Failed to save time and language to flash RAM");
}
u32 time = GetRTC_now();
syscfg.time_lo = time & 0xffff;
syscfg.time_hi = time >> 16;
if (settings.dreamcast.language <= 5)
syscfg.lang = settings.dreamcast.language;
if (sys_nvmem.WriteBlock(FLASH_PT_USER, FLASH_USER_SYSCFG, &syscfg) != 1)
printf("Failed to save time and language to flash RAM\n");
#endif
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
sys_rom.Load(get_game_save_prefix() + ".nvmem2");
#endif
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
sys_rom->Load(get_game_save_prefix() + ".nvmem2");
return true;
}
void SaveRomFiles(const string& root)
{
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
sys_nvmem.Save(root, ROM_PREFIX, "nvmem.bin", "nvmem");
#else
sys_nvmem.Save(get_game_save_prefix() + ".nvmem");
#endif
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
sys_rom.Save(get_game_save_prefix() + ".nvmem2");
#endif
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
sys_nvmem->Save(root, getRomPrefix(), "nvmem.bin", "nvmem");
else
sys_nvmem->Save(get_game_save_prefix() + ".nvmem");
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
sys_rom->Save(get_game_save_prefix() + ".nvmem2");
}
bool LoadHle(const string& root) {
if (!sys_nvmem.Load(root, ROM_PREFIX, "%nvmem.bin;%flash_wb.bin;%flash.bin;%flash.bin.bin", "nvram")) {
printf("No nvmem loaded\n");
if (!sys_nvmem->Load(root, getRomPrefix(), "%nvmem.bin;%flash_wb.bin;%flash.bin;%flash.bin.bin", "nvram")) {
INFO_LOG(FLASHROM, "No nvmem loaded");
}
return reios_init(sys_rom.data, sys_nvmem.data);
return reios_init(sys_rom->data, sys_nvmem->data);
}
u32 ReadFlash(u32 addr,u32 sz) { return sys_nvmem.Read(addr,sz); }
void WriteFlash(u32 addr,u32 data,u32 sz) { sys_nvmem.Write(addr,data,sz); }
u32 ReadFlash(u32 addr,u32 sz) { return sys_nvmem->Read(addr,sz); }
void WriteFlash(u32 addr,u32 data,u32 sz) { sys_nvmem->Write(addr,data,sz); }
#if (DC_PLATFORM == DC_PLATFORM_DREAMCAST) || (DC_PLATFORM == DC_PLATFORM_DEV_UNIT) || (DC_PLATFORM == DC_PLATFORM_NAOMI) || (DC_PLATFORM == DC_PLATFORM_NAOMI2)
u32 ReadBios(u32 addr,u32 sz)
{
return sys_rom->Read(addr, sz);
}
u32 ReadBios(u32 addr,u32 sz) { return sys_rom.Read(addr,sz); }
void WriteBios(u32 addr,u32 data,u32 sz) { EMUERROR4("Write to [Boot ROM] is not possible, addr=%x,data=%x,size=%d",addr,data,sz); }
#elif (DC_PLATFORM == DC_PLATFORM_ATOMISWAVE)
u32 ReadBios(u32 addr,u32 sz)
{
return sys_rom.Read(addr, sz);
}
void WriteBios(u32 addr,u32 data,u32 sz)
void WriteBios(u32 addr,u32 data,u32 sz)
{
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
{
if (sz != 1)
{
EMUERROR("Invalid access size @%08x data %x sz %d\n", addr, data, sz);
INFO_LOG(MEMORY, "Invalid access size @%08x data %x sz %d", addr, data, sz);
return;
}
sys_rom.Write(addr, data, sz);
sys_rom->Write(addr, data, sz);
}
#else
#error unknown flash
#endif
else
{
INFO_LOG(MEMORY, "Write to [Boot ROM] is not possible, addr=%x, data=%x, size=%d", addr, data, sz);
}
}
//Area 0 mem map
//0x00000000- 0x001FFFFF :MPX System/Boot ROM
@ -174,11 +181,9 @@ T DYNACALL ReadMem_area0(u32 addr)
//map 0x0000 to 0x01FF to Default handler
//mirror 0x0200 to 0x03FF , from 0x0000 to 0x03FFF
//map 0x0000 to 0x001F
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
if (base<=0x001F)// :MPX System/Boot ROM
#else
if (base<=0x0001) // Only 128k BIOS on AtomisWave
#endif
// :MPX System/Boot ROM
if (base <= (settings.platform.system == DC_PLATFORM_ATOMISWAVE ? 0x0001 : 0x001F)) // Only 128k BIOS on AtomisWave
{
return ReadBios(addr,sz);
}
@ -192,15 +197,14 @@ T DYNACALL ReadMem_area0(u32 addr)
{
if ( /*&& (addr>= 0x00400000)*/ (addr<= 0x005F67FF)) // :Unassigned
{
EMUERROR2("Read from area0_32 not implemented [Unassigned], addr=%x",addr);
INFO_LOG(MEMORY, "Read from area0_32 not implemented [Unassigned], addr=%x", addr);
}
else if ((addr>= 0x005F7000) && (addr<= 0x005F70FF)) // GD-ROM
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
return (T)ReadMem_naomi(addr,sz);
#else
return (T)ReadMem_gdrom(addr,sz);
#endif
if (settings.platform.system != DC_PLATFORM_DREAMCAST)
return (T)ReadMem_naomi(addr, sz);
else
return (T)ReadMem_gdrom(addr, sz);
}
else if (likely((addr>= 0x005F6800) && (addr<=0x005F7CFF))) // /*:PVR i/f Control Reg.*/ -> ALL SB registers now
{
@ -217,12 +221,13 @@ T DYNACALL ReadMem_area0(u32 addr)
//map 0x0060 to 0x0060
else if ((base ==0x0060) /*&& (addr>= 0x00600000)*/ && (addr<= 0x006007FF)) // :MODEM
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
return (T)libExtDevice_ReadMem_A0_006(addr, sz);
#elif defined(ENABLE_MODEM)
return (T)ModemReadMem_A0_006(addr, sz);
if (settings.platform.system != DC_PLATFORM_DREAMCAST)
return (T)libExtDevice_ReadMem_A0_006(addr, sz);
else
#if defined(ENABLE_MODEM)
return (T)ModemReadMem_A0_006(addr, sz);
#else
return (T)0;
return (T)0;
#endif
}
//map 0x0060 to 0x006F
@ -261,12 +266,8 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
const u32 base=(addr>>16);
//map 0x0000 to 0x001F
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
if ((base <=0x001F) /*&& (addr<=0x001FFFFF)*/)// :MPX System/Boot ROM
#else
if (base <= 0x0001) // Only 128k BIOS on AtomisWave
#endif
// :MPX System/Boot ROM
if (base <= (settings.platform.system == DC_PLATFORM_ATOMISWAVE ? 0x0001 : 0x001F)) // Only 128k BIOS on AtomisWave
{
WriteBios(addr,data,sz);
}
@ -285,11 +286,10 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
}
else if ((addr>= 0x005F7000) && (addr<= 0x005F70FF)) // GD-ROM
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
WriteMem_naomi(addr,data,sz);
#else
WriteMem_gdrom(addr,data,sz);
#endif
if (settings.platform.system != DC_PLATFORM_DREAMCAST)
WriteMem_naomi(addr,data,sz);
else
WriteMem_gdrom(addr,data,sz);
}
else if ( likely((addr>= 0x005F6800) && (addr<=0x005F7CFF)) ) // /*:PVR i/f Control Reg.*/ -> ALL SB registers
{
@ -304,10 +304,11 @@ void DYNACALL WriteMem_area0(u32 addr,T data)
//map 0x0060 to 0x0060
else if ((base ==0x0060) /*&& (addr>= 0x00600000)*/ && (addr<= 0x006007FF)) // MODEM
{
#if DC_PLATFORM == DC_PLATFORM_NAOMI || DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
libExtDevice_WriteMem_A0_006(addr, data, sz);
#elif defined(ENABLE_MODEM)
ModemWriteMem_A0_006(addr, data, sz);
if (settings.platform.system != DC_PLATFORM_DREAMCAST)
libExtDevice_WriteMem_A0_006(addr, data, sz);
#if defined(ENABLE_MODEM)
else
ModemWriteMem_A0_006(addr, data, sz);
#endif
}
//map 0x0060 to 0x006F
@ -347,17 +348,57 @@ void sh4_area0_Init()
sb_Init();
}
void sh4_area0_Reset(bool Manual)
void sh4_area0_Reset(bool hard)
{
sb_Reset(Manual);
sys_rom.Reset();
#if defined(FLASH_SIZE) || defined(BBSRAM_SIZE)
sys_nvmem.Reset();
#endif
if (hard)
{
if (sys_rom != NULL)
{
delete sys_rom;
sys_rom = NULL;
}
if (sys_nvmem != NULL)
{
delete sys_nvmem;
sys_nvmem = NULL;
}
switch (settings.platform.system)
{
case DC_PLATFORM_DREAMCAST:
sys_rom = new RomChip(settings.platform.bios_size);
sys_nvmem = new DCFlashChip(settings.platform.flash_size);
break;
case DC_PLATFORM_NAOMI:
sys_rom = new RomChip(settings.platform.bios_size);
sys_nvmem = new SRamChip(settings.platform.bbsram_size);
break;
case DC_PLATFORM_ATOMISWAVE:
sys_rom = new DCFlashChip(settings.platform.bios_size, settings.platform.bios_size / 2);
sys_nvmem = new SRamChip(settings.platform.bbsram_size);
break;
}
}
else
{
sys_rom->Reset();
sys_nvmem->Reset();
}
sb_Reset(hard);
}
void sh4_area0_Term()
{
if (sys_rom != NULL)
{
delete sys_rom;
sys_rom = NULL;
}
if (sys_nvmem != NULL)
{
delete sys_nvmem;
sys_nvmem = NULL;
}
sb_Term();
}

View File

@ -77,33 +77,36 @@ struct MapleConfigMap : IMapleConfigMap
UpdateInputState(player_num);
pjs->kcode=kcode[player_num];
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
pjs->kcode |= 0xF901; // mask off DPad2, C, D and Z
pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[player_num]);
pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[player_num]);
pjs->trigger[PJTI_R]=rt[player_num];
pjs->trigger[PJTI_L]=lt[player_num];
#elif DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
pjs->kcode = 0xFFFF;
for (int i = 0; i < 16; i++)
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
{
if ((kcode[player_num] & (1 << i)) == 0)
pjs->kcode &= ~awave_button_mapping[i];
pjs->kcode |= 0xF901; // mask off DPad2, C, D and Z
pjs->joy[PJAI_X1]=GetBtFromSgn(joyx[player_num]);
pjs->joy[PJAI_Y1]=GetBtFromSgn(joyy[player_num]);
pjs->trigger[PJTI_R]=rt[player_num];
pjs->trigger[PJTI_L]=lt[player_num];
}
pjs->joy[PJAI_X1] = GetBtFromSgn(joyx[player_num]);
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[1].name != NULL && NaomiGameInputs->axes[1].type == Half)
else if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
{
// Driving games: put axis 2 on RT (accel) and axis 3 on LT (brake)
pjs->joy[PJAI_Y1] = rt[player_num];
pjs->joy[PJAI_X2] = lt[player_num];
pjs->kcode = 0xFFFF;
for (int i = 0; i < 16; i++)
{
if ((kcode[player_num] & (1 << i)) == 0)
pjs->kcode &= ~awave_button_mapping[i];
}
pjs->joy[PJAI_X1] = GetBtFromSgn(joyx[player_num]);
if (NaomiGameInputs != NULL && NaomiGameInputs->axes[1].name != NULL && NaomiGameInputs->axes[1].type == Half)
{
// Driving games: put axis 2 on RT (accel) and axis 3 on LT (brake)
pjs->joy[PJAI_Y1] = rt[player_num];
pjs->joy[PJAI_X2] = lt[player_num];
}
else
{
pjs->joy[PJAI_Y1] = GetBtFromSgn(joyy[player_num]);
pjs->joy[PJAI_X2] = rt[player_num];
pjs->joy[PJAI_Y2] = lt[player_num];
}
}
else
{
pjs->joy[PJAI_Y1] = GetBtFromSgn(joyy[player_num]);
pjs->joy[PJAI_X2] = rt[player_num];
pjs->joy[PJAI_Y2] = lt[player_num];
}
#endif
}
void SetImage(void* img)
{
@ -134,12 +137,14 @@ void mcfg_Create(MapleDeviceType type, u32 bus, u32 port, s32 player_num = -1)
void mcfg_CreateNAOMIJamma()
{
mcfg_DestroyDevices();
mcfg_Create(MDT_NaomiJamma, 0, 5);
// mcfg_Create(MDT_Keyboard, 2, 5);
}
void mcfg_CreateAtomisWaveControllers()
{
mcfg_DestroyDevices();
// Looks like two controllers needs to be on bus 0 and 1 for digital inputs
// Then other devices on port 2 and 3 for analog axes, light guns, ...
mcfg_Create(MDT_SegaController, 0, 5);
@ -199,6 +204,25 @@ void mcfg_CreateDevices()
if (settings.input.maple_expansion_devices[bus][0] != MDT_None)
mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0);
break;
case MDT_TwinStick:
mcfg_Create(MDT_TwinStick, bus, 5);
if (settings.input.maple_expansion_devices[bus][0] != MDT_None)
mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0);
break;
case MDT_AsciiStick:
mcfg_Create(MDT_AsciiStick, bus, 5);
if (settings.input.maple_expansion_devices[bus][0] != MDT_None)
mcfg_Create((MapleDeviceType)settings.input.maple_expansion_devices[bus][0], bus, 0);
break;
case MDT_None:
break;
default:
WARN_LOG(MAPLE, "Invalid device type %d for port %d", settings.input.maple_devices[bus], bus);
break;
}
}
}
@ -240,7 +264,7 @@ void mcfg_SerializeDevices(void **data, unsigned int *total_size)
}
}
void mcfg_UnserializeDevices(void **data, unsigned int *total_size)
void mcfg_UnserializeDevices(void **data, unsigned int *total_size, bool old)
{
mcfg_DestroyDevices();
@ -251,6 +275,42 @@ void mcfg_UnserializeDevices(void **data, unsigned int *total_size)
MapleDeviceType device_type = (MapleDeviceType)**p;
*p = *p + 1;
*total_size = *total_size + 1;
if (old)
{
switch ((OldMapleDeviceType::MapleDeviceType)device_type)
{
case OldMapleDeviceType::MDT_None:
device_type = MDT_None;
break;
case OldMapleDeviceType::MDT_SegaController:
device_type = MDT_SegaController;
break;
case OldMapleDeviceType::MDT_SegaVMU:
device_type = MDT_SegaVMU;
break;
case OldMapleDeviceType::MDT_PurupuruPack:
device_type = MDT_PurupuruPack;
break;
case OldMapleDeviceType::MDT_Microphone:
device_type = MDT_Microphone;
break;
case OldMapleDeviceType::MDT_Keyboard:
device_type = MDT_Keyboard;
break;
case OldMapleDeviceType::MDT_Mouse:
device_type = MDT_Mouse;
break;
case OldMapleDeviceType::MDT_LightGun:
device_type = MDT_LightGun;
break;
case OldMapleDeviceType::MDT_NaomiJamma:
device_type = MDT_NaomiJamma;
break;
default:
die("Invalid maple device type");
break;
}
}
if (device_type != MDT_None)
{
mcfg_Create(device_type, i, j);

View File

@ -58,15 +58,12 @@ struct IMapleConfigMap
virtual ~IMapleConfigMap() {}
};
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
void mcfg_CreateDevices();
#else
void mcfg_CreateNAOMIJamma();
void mcfg_CreateAtomisWaveControllers();
#endif
void mcfg_DestroyDevices();
void mcfg_SerializeDevices(void **data, unsigned int *total_size);
void mcfg_UnserializeDevices(void **data, unsigned int *total_size);
void mcfg_UnserializeDevices(void **data, unsigned int *total_size, bool old_type_numbering);
bool maple_atomiswave_coin_chute(int slot);

View File

@ -13,18 +13,7 @@
#include "deps/zlib/zlib.h"
#include "deps/xxhash/xxhash.h"
#if _ANDROID
#include <android/log.h>
#include <jni.h>
#else
#define LOGW printf
#define LOGI printf
#endif
#ifndef RELEASE
#define LOGJVS(...) LOGI(__VA_ARGS__)
#else
#define LOGJVS(...)
#endif
#define LOGJVS(...) DEBUG_LOG(JVS, __VA_ARGS__)
#define SAVE_EEPROM 1
@ -37,6 +26,8 @@ const char* maple_sega_dreameye_name_2 = "Dreamcast Camera Flash LDevic";
const char* maple_sega_mic_name = "MicDevice for Dreameye";
const char* maple_sega_purupuru_name = "Puru Puru Pack";
const char* maple_sega_lightgun_name = "Dreamcast Gun";
const char* maple_sega_twinstick_name = "Twin Stick";
const char* maple_ascii_stick_name = "ASCII STICK";
const char* maple_sega_brand = "Produced By or Under License From SEGA ENTERPRISES,LTD.";
@ -91,7 +82,7 @@ enum MapleDeviceRV
MDRE_UnknownFunction = 0xFE, //0 words
MDRE_UnknownCmd = 0xFD, //0 words
MDRE_TransmitAgain = 0xFC, //1 word, 1 or 2?
MDRE_TransmitAgain = 0xFC, //0 words
MDRE_FileError = 0xFB, //1 word, bitfield
MDRE_LCDError = 0xFA, //1 word, bitfield
MDRE_ARGunError = 0xF9, //1 word, bitfield
@ -153,7 +144,7 @@ struct maple_base: maple_device
u8 r8() { u8 rv=*((u8*)dma_buffer_in);dma_buffer_in+=1;dma_count_in-=1; return rv; }
u16 r16() { u16 rv=*((u16*)dma_buffer_in);dma_buffer_in+=2;dma_count_in-=2; return rv; }
u32 r32() { u32 rv=*(u32*)dma_buffer_in;dma_buffer_in+=4;dma_count_in-=4; return rv; }
void rptr(const void* dst,u32 len)
void rptr(void* dst, u32 len)
{
u8* dst8=(u8*)dst;
while(len--)
@ -233,9 +224,19 @@ struct maple_sega_controller: maple_base
return MDT_SegaController;
}
virtual const char *get_device_name()
{
return maple_sega_controller_name;
}
virtual const char *get_device_brand()
{
return maple_sega_brand;
}
virtual u32 dma(u32 cmd)
{
//printf("maple_sega_controller::dma Called 0x%X;Command %d\n",device_instance->port,Command);
//printf("maple_sega_controller::dma Called 0x%X;Command %d\n", bus_id, cmd);
switch (cmd)
{
case MDC_DeviceRequest:
@ -256,10 +257,10 @@ struct maple_sega_controller: maple_base
w8(0);
//30
wstr(maple_sega_controller_name,30);
wstr(get_device_name(), 30);
//60
wstr(maple_sega_brand,60);
wstr(get_device_brand(), 60);
//2
w16(0x01AE); // 43 mA
@ -305,7 +306,7 @@ struct maple_sega_controller: maple_base
return MDRS_DataTransfer;
default:
//printf("UNKOWN MAPLE COMMAND %d\n",cmd);
//printf("maple_sega_controller UNKOWN MAPLE COMMAND %d\n",cmd);
return MDRE_UnknownCmd;
}
}
@ -343,6 +344,73 @@ struct maple_atomiswave_controller: maple_sega_controller
}
};
/*
Sega Twin Stick Controller
*/
struct maple_sega_twinstick: maple_sega_controller
{
virtual u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xfefe0000; // no analog axes, X Y A B D Start U/D/L/R U2/D2/L2/R2
}
virtual u32 transform_kcode(u32 kcode) override {
return kcode | 0x0101;
}
virtual MapleDeviceType get_device_type() override
{
return MDT_TwinStick;
}
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
return 0x80;
}
virtual const char *get_device_name() override
{
return maple_sega_twinstick_name;
}
};
/*
Ascii Stick (Arcade/FT Stick)
*/
struct maple_ascii_stick: maple_sega_controller
{
virtual u32 get_capabilities() override {
// byte 0: 0 0 0 0 0 0 0 0
// byte 1: 0 0 a5 a4 a3 a2 a1 a0
// byte 2: R2 L2 D2 U2 D X Y Z
// byte 3: R L D U St A B C
return 0xff070000; // no analog axes, X Y Z A B C Start U/D/L/R
}
virtual u32 transform_kcode(u32 kcode) override {
return kcode | 0xF800;
}
virtual MapleDeviceType get_device_type() override
{
return MDT_AsciiStick;
}
virtual u32 get_analog_axis(int index, const PlainJoystickState &pjs) override {
return 0x80;
}
virtual const char *get_device_name() override
{
return maple_ascii_stick_name;
}
};
/*
Sega Dreamcast Visual Memory Unit
This is pretty much done (?)
@ -350,24 +418,24 @@ struct maple_atomiswave_controller: maple_sega_controller
u8 vmu_default[] = {
0x78,0x9c,0xed,0xd2,0x31,0x4e,0x02,0x61,0x10,0x06,0xd0,0x8f,0x04,0x28,0x4c,0x2c,
0x28,0x2d,0x0c,0xa5,0x57,0xe0,0x16,0x56,0x16,0x76,0x14,0x1e,0xc4,0x03,0x50,0x98,
0x50,0x40,0x69,0xc1,0x51,0x28,0xbc,0x8e,0x8a,0x0a,0xeb,0xc2,0xcf,0x66,0x13,0x1a,
0x13,0xa9,0x30,0x24,0xe6,0xbd,0xc9,0x57,0xcc,0x4c,0x33,0xc5,0x2c,0xb3,0x48,0x6e,
0x67,0x01,0x00,0x00,0x00,0x00,0x00,0x4e,0xaf,0xdb,0xe4,0x7a,0xd2,0xcf,0x53,0x16,
0x6d,0x46,0x99,0xb6,0xc9,0x78,0x9e,0x3c,0x5f,0x9c,0xfb,0x3c,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x80,0x5f,0xd5,0x45,0xfd,0xef,0xaa,0xca,0x6b,0xde,0xf2,0x9e,0x55,
0x3e,0xf2,0x99,0xaf,0xac,0xb3,0x49,0x95,0xef,0xd4,0xa9,0x9a,0xdd,0xdd,0x0f,0x9d,
0x52,0xca,0xc3,0x91,0x7f,0xb9,0x9a,0x0f,0x6e,0x92,0xfb,0xee,0xa1,0x2f,0x6d,0x76,
0xe9,0x64,0x9b,0xcb,0xf4,0xf2,0x92,0x61,0x33,0x79,0xfc,0xeb,0xb7,0xe5,0x44,0xf6,
0x77,0x19,0x06,0xef,
0x78,0x9c,0xed,0xd2,0x31,0x4e,0x02,0x61,0x10,0x06,0xd0,0x8f,0x04,0x28,0x4c,0x2c,
0x28,0x2d,0x0c,0xa5,0x57,0xe0,0x16,0x56,0x16,0x76,0x14,0x1e,0xc4,0x03,0x50,0x98,
0x50,0x40,0x69,0xc1,0x51,0x28,0xbc,0x8e,0x8a,0x0a,0xeb,0xc2,0xcf,0x66,0x13,0x1a,
0x13,0xa9,0x30,0x24,0xe6,0xbd,0xc9,0x57,0xcc,0x4c,0x33,0xc5,0x2c,0xb3,0x48,0x6e,
0x67,0x01,0x00,0x00,0x00,0x00,0x00,0x4e,0xaf,0xdb,0xe4,0x7a,0xd2,0xcf,0x53,0x16,
0x6d,0x46,0x99,0xb6,0xc9,0x78,0x9e,0x3c,0x5f,0x9c,0xfb,0x3c,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x80,0x5f,0xd5,0x45,0xfd,0xef,0xaa,0xca,0x6b,0xde,0xf2,0x9e,0x55,
0x3e,0xf2,0x99,0xaf,0xac,0xb3,0x49,0x95,0xef,0xd4,0xa9,0x9a,0xdd,0xdd,0x0f,0x9d,
0x52,0xca,0xc3,0x91,0x7f,0xb9,0x9a,0x0f,0x6e,0x92,0xfb,0xee,0xa1,0x2f,0x6d,0x76,
0xe9,0x64,0x9b,0xcb,0xf4,0xf2,0x92,0x61,0x33,0x79,0xfc,0xeb,0xb7,0xe5,0x44,0xf6,
0x77,0x19,0x06,0xef,
};
struct maple_sega_vmu: maple_base
@ -385,7 +453,7 @@ struct maple_sega_vmu: maple_base
// creates an empty VMU
bool init_emptyvmu()
{
printf("Initialising empty VMU...\n");
INFO_LOG(MAPLE, "Initialising empty VMU...");
uLongf dec_sz = sizeof(flash_data);
int rv = uncompress(flash_data, &dec_sz, vmu_default, sizeof(vmu_default));
@ -421,24 +489,24 @@ struct maple_sega_vmu: maple_base
file = fopen(apath.c_str(), "rb+");
if (!file)
{
printf("Unable to open VMU save file \"%s\", creating new file\n",apath.c_str());
INFO_LOG(MAPLE, "Unable to open VMU save file \"%s\", creating new file", apath.c_str());
file = fopen(apath.c_str(), "wb");
if (file) {
if (!init_emptyvmu())
printf("Failed to initialize an empty VMU, you should reformat it using the BIOS\n");
INFO_LOG(MAPLE, "Failed to initialize an empty VMU, you should reformat it using the BIOS");
fwrite(flash_data, sizeof(flash_data), 1, file);
fseek(file, 0, SEEK_SET);
}
else
{
printf("Unable to create VMU!\n");
INFO_LOG(MAPLE, "Unable to create VMU!");
}
}
if (!file)
{
printf("Failed to create VMU save file \"%s\"\n",apath.c_str());
INFO_LOG(MAPLE, "Failed to create VMU save file \"%s\"", apath.c_str());
}
else
{
@ -462,12 +530,12 @@ struct maple_sega_vmu: maple_base
fseek(file, 0, SEEK_SET);
}
else {
printf("Unable to create VMU!\n");
INFO_LOG(MAPLE, "Unable to create VMU!");
}
}
else
{
printf("Failed to initialize an empty VMU, you should reformat it using the BIOS\n");
INFO_LOG(MAPLE, "Failed to initialize an empty VMU, you should reformat it using the BIOS");
}
}
@ -478,7 +546,7 @@ struct maple_sega_vmu: maple_base
}
virtual u32 dma(u32 cmd)
{
//printf("maple_sega_vmu::dma Called for port 0x%X, Command %d\n",device_instance->port,Command);
//printf("maple_sega_vmu::dma Called for port %d:%d, Command %d\n", bus_id, bus_port, cmd);
switch (cmd)
{
case MDC_DeviceRequest:
@ -522,30 +590,8 @@ struct maple_sega_vmu: maple_base
{
w32(MFID_1_Storage);
//total_size;
w16(0xff);
//partition_number;
w16(0);
//system_area_block;
w16(0xFF);
//fat_area_block;
w16(0xfe);
//number_fat_areas_block;
w16(1);
//file_info_block;
w16(0xfd);
//number_info_blocks;
w16(0xd);
//volume_icon;
w8(0);
//reserved1;
w8(0);
//save_area_block;
w16(0xc8);
//number_of_save_blocks;
w16(0x1f);
//reserverd0 (something for execution files?)
w32(0);
// Get data from the vmu system area (block 0xFF)
wptr(flash_data + 0xFF * 512 + 0x40, 24);
return MDRS_DataTransfer;//data transfer
}
@ -556,7 +602,7 @@ struct maple_sega_vmu: maple_base
u32 pt=r32();
if (pt!=0)
{
printf("VMU: MDCF_GetMediaInfo -> bad input |%08X|, returning MDRE_UnknownCmd\n",pt);
INFO_LOG(MAPLE, "VMU: MDCF_GetMediaInfo -> bad input |%08X|, returning MDRE_UnknownCmd", pt);
return MDRE_UnknownCmd;
}
else
@ -566,7 +612,7 @@ struct maple_sega_vmu: maple_base
w8(47); //X dots -1
w8(31); //Y dots -1
w8(((1)<<4) | (0)); //1 Color, 0 contrast levels
w8(0); //Padding
w8(2); //Padding
return MDRS_DataTransfer;
}
@ -574,7 +620,7 @@ struct maple_sega_vmu: maple_base
break;
default:
printf("VMU: MDCF_GetMediaInfo -> Bad function used |%08X|, returning -2\n",function);
INFO_LOG(MAPLE, "VMU: MDCF_GetMediaInfo -> Bad function used |%08X|, returning -2", function);
return MDRE_UnknownFunction;//bad function
}
}
@ -594,8 +640,8 @@ struct maple_sega_vmu: maple_base
if (Block>255)
{
printf("Block read : %d\n",Block);
printf("BLOCK READ ERROR\n");
DEBUG_LOG(MAPLE, "Block read : %d", Block);
DEBUG_LOG(MAPLE, "BLOCK READ ERROR");
Block&=255;
}
wptr(flash_data+Block*512,512);
@ -618,7 +664,7 @@ struct maple_sega_vmu: maple_base
{
if (r32()!=0)
{
printf("VMU: Block read: MFID_3_Clock : invalid params \n");
INFO_LOG(MAPLE, "VMU: Block read: MFID_3_Clock : invalid params");
return MDRE_TransmitAgain; //invalid params
}
else
@ -642,7 +688,13 @@ struct maple_sega_vmu: maple_base
w8(timenow->tm_sec);
w8(0);
printf("VMU: CLOCK Read-> datetime is %04d/%02d/%02d ~ %02d:%02d:%02d!\n",timebuf[0]+timebuf[1]*256,timebuf[2],timebuf[3],timebuf[4],timebuf[5],timebuf[6]);
DEBUG_LOG(MAPLE, "VMU: CLOCK Read-> datetime is %04d/%02d/%02d ~ %02d:%02d:%02d!",
timebuf[0] + timebuf[1] * 256,
timebuf[2],
timebuf[3],
timebuf[4],
timebuf[5],
timebuf[6]);
return MDRS_DataTransfer;//transfer reply ...
}
@ -650,7 +702,7 @@ struct maple_sega_vmu: maple_base
break;
default:
printf("VMU: cmd MDCF_BlockRead -> Bad function |%08X| used, returning -2\n",function);
INFO_LOG(MAPLE, "VMU: cmd MDCF_BlockRead -> Bad function |%08X| used, returning -2", function);
return MDRE_UnknownFunction;//bad function
}
}
@ -677,7 +729,7 @@ struct maple_sega_vmu: maple_base
}
else
{
printf("Failed to save VMU %s data\n",logical_port);
INFO_LOG(MAPLE, "Failed to save VMU %s data", logical_port);
}
return MDRS_DeviceReply;//just ko
}
@ -768,7 +820,8 @@ struct maple_sega_vmu: maple_base
{
u8 timebuf[8];
rptr(timebuf,8);
printf("VMU: CLOCK Write-> datetime is %04d/%02d/%02d ~ %02d:%02d:%02d! Nothing set tho ...\n",timebuf[0]+timebuf[1]*256,timebuf[2],timebuf[3],timebuf[4],timebuf[5],timebuf[6]);
DEBUG_LOG(MAPLE, "VMU: CLOCK Write-> datetime is %04d/%02d/%02d ~ %02d:%02d:%02d! Nothing set tho ...",
timebuf[0]+timebuf[1]*256,timebuf[2],timebuf[3],timebuf[4],timebuf[5],timebuf[6]);
return MDRS_DeviceReply;//ok !
}
}
@ -776,7 +829,7 @@ struct maple_sega_vmu: maple_base
default:
{
printf("VMU: command MDCF_BlockWrite -> Bad function used, returning MDRE_UnknownFunction\n");
INFO_LOG(MAPLE, "VMU: command MDCF_BlockWrite -> Bad function used, returning MDRE_UnknownFunction");
return MDRE_UnknownFunction;//bad function
}
}
@ -795,7 +848,7 @@ struct maple_sega_vmu: maple_base
u32 bp=r32();
if (bp)
{
printf("BEEP : %08X\n",bp);
INFO_LOG(MAPLE, "BEEP : %08X", bp);
}
return MDRS_DeviceReply;//just ko
}
@ -803,7 +856,7 @@ struct maple_sega_vmu: maple_base
default:
{
printf("VMU: command MDCF_SetCondition -> Bad function used, returning MDRE_UnknownFunction\n");
INFO_LOG(MAPLE, "VMU: command MDCF_SetCondition -> Bad function used, returning MDRE_UnknownFunction");
return MDRE_UnknownFunction;//bad function
}
break;
@ -812,7 +865,7 @@ struct maple_sega_vmu: maple_base
default:
//printf("Unknown MAPLE COMMAND %d\n",cmd);
DEBUG_LOG(MAPLE, "Unknown MAPLE COMMAND %d", cmd);
return MDRE_UnknownCmd;
}
}
@ -851,7 +904,7 @@ struct maple_microphone: maple_base
switch (cmd)
{
case MDC_DeviceRequest:
LOGI("maple_microphone::dma MDC_DeviceRequest\n");
DEBUG_LOG(MAPLE, "maple_microphone::dma MDC_DeviceRequest");
//this was copied from the controller case with just the id and name replaced!
//caps
@ -886,7 +939,7 @@ struct maple_microphone: maple_base
case MDCF_GetCondition:
{
LOGI("maple_microphone::dma MDCF_GetCondition\n");
DEBUG_LOG(MAPLE, "maple_microphone::dma MDCF_GetCondition");
//this was copied from the controller case with just the id replaced!
//PlainJoystickState pjs;
@ -923,7 +976,7 @@ struct maple_microphone: maple_base
case MDC_DeviceReset:
//uhhh do nothing?
LOGI("maple_microphone::dma MDC_DeviceReset\n");
DEBUG_LOG(MAPLE, "maple_microphone::dma MDC_DeviceReset");
return MDRS_DeviceReply;
case MDCF_MICControl:
@ -986,29 +1039,29 @@ struct maple_microphone: maple_base
return MDRS_DataTransfer;
}
case 0x02:
LOGI("maple_microphone::dma MDCF_MICControl toggle recording %#010x\n",secondword);
DEBUG_LOG(MAPLE, "maple_microphone::dma MDCF_MICControl toggle recording %#010x", secondword);
return MDRS_DeviceReply;
case 0x03:
LOGI("maple_microphone::dma MDCF_MICControl set gain %#010x\n",secondword);
DEBUG_LOG(MAPLE, "maple_microphone::dma MDCF_MICControl set gain %#010x", secondword);
return MDRS_DeviceReply;
case MDRE_TransmitAgain:
LOGW("maple_microphone::dma MDCF_MICControl MDRE_TransmitAgain\n");
WARN_LOG(MAPLE, "maple_microphone::dma MDCF_MICControl MDRE_TransmitAgain");
//apparently this doesnt matter
//wptr(micdata, SIZE_OF_MIC_DATA);
return MDRS_DeviceReply;//MDRS_DataTransfer;
default:
LOGW("maple_microphone::dma UNHANDLED secondword %#010x\n",secondword);
INFO_LOG(MAPLE, "maple_microphone::dma UNHANDLED secondword %#010x", secondword);
return MDRE_UnknownFunction;
}
}
default:
LOGW("maple_microphone::dma UNHANDLED function %#010x\n",function);
INFO_LOG(MAPLE, "maple_microphone::dma UNHANDLED function %#010x", function);
return MDRE_UnknownFunction;
}
}
default:
LOGW("maple_microphone::dma UNHANDLED MAPLE COMMAND %d\n",cmd);
INFO_LOG(MAPLE, "maple_microphone::dma UNHANDLED MAPLE COMMAND %d", cmd);
return MDRE_UnknownCmd;
}
}
@ -1143,7 +1196,7 @@ struct maple_sega_purupuru : maple_base
return MDRS_DeviceReply;
default:
//printf("UNKOWN MAPLE COMMAND %d\n",cmd);
INFO_LOG(MAPLE, "UNKOWN MAPLE COMMAND %d", cmd);
return MDRE_UnknownCmd;
}
}
@ -1214,7 +1267,7 @@ struct maple_keyboard : maple_base
return MDRS_DataTransfer;
default:
//printf("Keyboard: unknown MAPLE COMMAND %d\n", cmd);
INFO_LOG(MAPLE, "Keyboard: unknown MAPLE COMMAND %d", cmd);
return MDRE_UnknownCmd;
}
}
@ -1321,7 +1374,7 @@ struct maple_mouse : maple_base
return MDRS_DataTransfer;
default:
//printf("Mouse: unknown MAPLE COMMAND %d\n", cmd);
INFO_LOG(MAPLE, "Mouse: unknown MAPLE COMMAND %d", cmd);
return MDRE_UnknownCmd;
}
}
@ -1401,7 +1454,7 @@ struct maple_lightgun : maple_base
return MDRS_DataTransfer;
default:
//printf("Light gun: unknown MAPLE COMMAND %d\n", cmd);
INFO_LOG(MAPLE, "Light gun: unknown MAPLE COMMAND %d", cmd);
return MDRE_UnknownCmd;
}
}
@ -1697,6 +1750,10 @@ struct maple_naomi_jamma : maple_sega_controller
break;
}
}
virtual ~maple_naomi_jamma()
{
EEPROM_loaded = false;
}
virtual MapleDeviceType get_device_type()
{
@ -1869,7 +1926,7 @@ struct maple_naomi_jamma : maple_sega_controller
case 0x13: // Store repeated request
if (len > 0 && node_id > 0 && node_id <= 0x1f)
{
printf("JVS node %d: Storing %d cmd bytes\n", node_id, len);
INFO_LOG(MAPLE, "JVS node %d: Storing %d cmd bytes", node_id, len);
jvs_repeat_request[node_id - 1][0] = len;
memcpy(&jvs_repeat_request[node_id - 1][1], cmd, len);
}
@ -1974,7 +2031,7 @@ struct maple_naomi_jamma : maple_sega_controller
{
int address = dma_buffer_in[1];
int size = dma_buffer_in[2];
//printf("EEprom write %08X %08X\n",address,size);
DEBUG_LOG(MAPLE, "EEprom write %08X %08X\n", address, size);
//printState(Command,buffer_in,buffer_in_len);
memcpy(EEPROM + address, dma_buffer_in + 4, size);
@ -1985,10 +2042,10 @@ struct maple_naomi_jamma : maple_sega_controller
{
fwrite(EEPROM, 1, 0x80, f);
fclose(f);
printf("Saved EEPROM to %s\n", eeprom_file.c_str());
INFO_LOG(MAPLE, "Saved EEPROM to %s", eeprom_file.c_str());
}
else
printf("EEPROM SAVE FAILED to %s\n", eeprom_file.c_str());
WARN_LOG(MAPLE, "EEPROM SAVE FAILED to %s", eeprom_file.c_str());
#endif
w8(MDRS_JVSReply);
w8(0x00);
@ -2012,15 +2069,15 @@ struct maple_naomi_jamma : maple_sega_controller
{
fread(EEPROM, 1, 0x80, f);
fclose(f);
printf("Loaded EEPROM from %s\n", eeprom_file.c_str());
DEBUG_LOG(MAPLE, "Loaded EEPROM from %s", eeprom_file.c_str());
}
else if (naomi_default_eeprom != NULL)
{
printf("Using default EEPROM file\n");
DEBUG_LOG(MAPLE, "Using default EEPROM file");
memcpy(EEPROM, naomi_default_eeprom, 0x80);
}
else
printf("EEPROM file not found at %s and no default found\n", eeprom_file.c_str());
DEBUG_LOG(MAPLE, "EEPROM file not found at %s and no default found", eeprom_file.c_str());
}
#endif
//printf("EEprom READ\n");
@ -2075,7 +2132,7 @@ struct maple_naomi_jamma : maple_sega_controller
break;
default:
printf("JVS: Unknown 0x86 sub-command %x\n", subcode);
INFO_LOG(MAPLE, "JVS: Unknown 0x86 sub-command %x", subcode);
w8(MDRE_UnknownCmd);
w8(0x00);
w8(0x20);
@ -2133,7 +2190,7 @@ struct maple_naomi_jamma : maple_sega_controller
if (fw_dump == NULL)
{
fw_dump = fopen(filename, "w");
printf("Saving JVS firmware to %s\n", filename);
INFO_LOG(MAPLE, "Saving JVS firmware to %s", filename);
break;
}
}
@ -2211,8 +2268,16 @@ struct maple_naomi_jamma : maple_sega_controller
break;
case MDCF_GetCondition:
w8(MDRE_UnknownCmd);
w8(0x00);
w8(0x00);
w8(0x00);
break;
default:
//printf("Unknown Maple command %x\n", cmd);
INFO_LOG(MAPLE, "Unknown Maple command %x", cmd);
w8(MDRE_UnknownCmd);
w8(0x00);
w8(0x00);
@ -2375,8 +2440,6 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
LOGJVS("JVS Node %d: ", node_id);
PlainJoystickState pjs;
parent->config->GetInput(&pjs);
u32 keycode = ~kcode[0];
u32 keycode2 = ~kcode[1];
JVS_STATUS1(); // status
for (int cmdi = 0; cmdi < length_in; )
@ -2387,6 +2450,8 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
{
JVS_STATUS1(); // report byte
u32 keycode = ~kcode[0];
u32 keycode2 = ~kcode[1];
u16 buttons[4] = { 0 };
for (int player = 0; player < buffer_in[cmdi + 1] && first_player + player < ARRAY_SIZE(kcode); player++)
{
@ -2419,17 +2484,25 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
{
JVS_STATUS1(); // report byte
LOGJVS("coins ");
u32 mask = 0;
for (int i = 0; i < 16; i++)
{
if (naomi_button_mapping[i] == NAOMI_COIN_KEY)
{
mask = 1 << i;
break;
}
}
for (int slot = 0; slot < buffer_in[cmdi + 1]; slot++)
{
u16 keycode = ~kcode[first_player + slot];
bool coin_chute = false;
u32 keycode = ~kcode[first_player + slot];
for (int i = 0; i < 16 && !coin_chute; i++)
if (keycode & mask)
{
if (naomi_button_mapping[i] == NAOMI_COIN_KEY && (keycode & (1 << i)) != 0)
coin_chute = true;
coin_chute = true;
if (!old_coin_chute[first_player + slot])
coin_count[first_player + slot] += 1;
}
if (coin_chute && !old_coin_chute[first_player + slot])
coin_count[first_player + slot] += 1;
old_coin_chute[first_player + slot] = coin_chute;
LOGJVS("%d:%d ", slot + 1 + first_player, coin_count[first_player + slot]);
@ -2583,7 +2656,7 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
break;
default:
printf("JVS: Unknown input type %x\n", buffer_in[cmdi]);
DEBUG_LOG(MAPLE, "JVS: Unknown input type %x", buffer_in[cmdi]);
JVS_OUT(2); // report byte: command error
cmdi = length_in; // Ignore subsequent commands
break;
@ -2593,7 +2666,7 @@ u32 jvs_io_board::handle_jvs_message(u8 *buffer_in, u32 length_in, u8 *buffer_ou
}
else
{
printf("JVS: Unknown JVS command %x\n", jvs_cmd);
INFO_LOG(MAPLE, "JVS: Unknown JVS command %x", jvs_cmd);
JVS_OUT(2); // Unknown command
}
break;
@ -2625,11 +2698,10 @@ maple_device* maple_Create(MapleDeviceType type)
switch(type)
{
case MDT_SegaController:
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_sega_controller();
#else
rv = new maple_atomiswave_controller();
#endif
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
rv = new maple_sega_controller();
else
rv = new maple_atomiswave_controller();
break;
case MDT_Microphone:
@ -2653,19 +2725,28 @@ maple_device* maple_Create(MapleDeviceType type)
break;
case MDT_LightGun:
#if DC_PLATFORM != DC_PLATFORM_ATOMISWAVE
rv = new maple_lightgun();
#else
rv = new atomiswave_lightgun();
#endif
if (settings.platform.system != DC_PLATFORM_ATOMISWAVE)
rv = new maple_lightgun();
else
rv = new atomiswave_lightgun();
break;
case MDT_NaomiJamma:
rv = new maple_naomi_jamma();
break;
case MDT_TwinStick:
rv = new maple_sega_twinstick();
break;
case MDT_AsciiStick:
rv = new maple_ascii_stick();
break;
default:
return 0;
ERROR_LOG(MAPLE, "Invalid device type %d", type);
die("Invalid maple device type");
break;
}
return rv;

View File

@ -1,6 +1,27 @@
#pragma once
#include "types.h"
enum MapleDeviceType
{
MDT_SegaController,
MDT_SegaVMU,
MDT_Microphone,
MDT_PurupuruPack,
MDT_AsciiStick,
MDT_Keyboard,
MDT_Mouse,
MDT_LightGun,
MDT_TwinStick,
MDT_NaomiJamma,
MDT_None,
MDT_Count
};
namespace OldMapleDeviceType
{
enum MapleDeviceType
{
MDT_SegaController,
@ -17,6 +38,7 @@ enum MapleDeviceType
MDT_None,
MDT_Count
};
}
enum NAOMI_KEYS
{

View File

@ -52,11 +52,11 @@ void maple_vblank()
{
if (maple_ddt_pending_reset)
{
//printf("DDT vblank ; reset pending\n");
DEBUG_LOG(MAPLE, "DDT vblank ; reset pending");
}
else
{
//printf("DDT vblank\n");
DEBUG_LOG(MAPLE, "DDT vblank");
SB_MDST = 1;
maple_DoDma();
SB_MDST = 0;
@ -71,9 +71,8 @@ void maple_vblank()
maple_ddt_pending_reset=false;
}
}
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
maple_handle_reconnect();
#endif
if (settings.platform.system == DC_PLATFORM_DREAMCAST)
maple_handle_reconnect();
}
void maple_SB_MSHTCL_Write(u32 addr, u32 data)
{
@ -98,7 +97,7 @@ void maple_SB_MDEN_Write(u32 addr, u32 data)
if ((data & 0x1)==0 && SB_MDST)
{
printf("Maple DMA abort ?\n");
INFO_LOG(MAPLE, "Maple DMA abort ?");
}
}
@ -122,9 +121,7 @@ void maple_DoDma()
verify(SB_MDEN &1)
verify(SB_MDST &1)
#if debug_maple
printf("Maple: DoMapleDma SB_MDSTAR=%x\n", SB_MDSTAR);
#endif
DEBUG_LOG(MAPLE, "Maple: DoMapleDma SB_MDSTAR=%x", SB_MDSTAR);
u32 addr = SB_MDSTAR;
u32 xfer_count=0;
bool last = false;
@ -147,7 +144,7 @@ void maple_DoDma()
{
if (!IsOnSh4Ram(header_2))
{
printf("MAPLE ERROR : DESTINATION NOT ON SH4 RAM 0x%X\n",header_2);
INFO_LOG(MAPLE, "MAPLE ERROR : DESTINATION NOT ON SH4 RAM 0x%X", header_2);
header_2&=0xFFFFFF;
header_2|=(3<<26);
}
@ -157,7 +154,7 @@ void maple_DoDma()
u32* p_data =(u32*) GetMemPtr(addr + 8,(plen)*sizeof(u32));
if (p_data == NULL)
{
printf("MAPLE ERROR : INVALID SB_MDSTAR value 0x%X\n", addr);
INFO_LOG(MAPLE, "MAPLE ERROR : INVALID SB_MDSTAR value 0x%X", addr);
SB_MDST=0;
return;
}
@ -183,7 +180,7 @@ void maple_DoDma()
else
{
if (port != 5 && command != 1)
printf("MAPLE: Unknown device bus %d port %d cmd %d\n", bus, port, command);
INFO_LOG(MAPLE, "MAPLE: Unknown device bus %d port %d cmd %d", bus, port, command);
outlen=4;
p_out[0]=0xFFFFFFFF;
}
@ -216,7 +213,7 @@ void maple_DoDma()
break;
default:
printf("MAPLE: Unknown maple_op == %d length %d\n", maple_op, plen * 4);
INFO_LOG(MAPLE, "MAPLE: Unknown maple_op == %d length %d", maple_op, plen * 4);
addr += 1 * 4;
}
}
@ -234,7 +231,7 @@ int maple_schd(int tag, int c, int j)
}
else
{
printf("WARNING: MAPLE DMA ABORT\n");
INFO_LOG(MAPLE, "WARNING: MAPLE DMA ABORT");
SB_MDST=0; //I really wonder what this means, can the DMA be continued ?
}
@ -262,7 +259,7 @@ void maple_Init()
maple_schid=sh4_sched_register(0,&maple_schd);
}
void maple_Reset(bool Manual)
void maple_Reset(bool hard)
{
maple_ddt_pending_reset=false;
SB_MDTSEL = 0x00000000;
@ -279,7 +276,6 @@ void maple_Term()
}
#if DC_PLATFORM == DC_PLATFORM_DREAMCAST
static u64 reconnect_time;
void maple_ReconnectDevices()
@ -296,4 +292,3 @@ static void maple_handle_reconnect()
mcfg_CreateDevices();
}
}
#endif

View File

@ -1,4 +1,5 @@
#include "_vmem.h"
#include "vmem32.h"
#include "hw/aica/aica_if.h"
#include "hw/sh4/dyna/blockmanager.h"
@ -96,6 +97,46 @@ void* _vmem_read_const(u32 addr,bool& ismem,u32 sz)
return 0;
}
void* _vmem_write_const(u32 addr,bool& ismem,u32 sz)
{
u32 page=addr>>24;
unat iirf=(unat)_vmem_MemInfo_ptr[page];
void* ptr=(void*)(iirf&~HANDLER_MAX);
if (ptr==0)
{
ismem=false;
const unat id=iirf;
if (sz==1)
{
return (void*)_vmem_WF8[id/4];
}
else if (sz==2)
{
return (void*)_vmem_WF16[id/4];
}
else if (sz==4)
{
return (void*)_vmem_WF32[id/4];
}
else
{
die("Invalid size");
}
}
else
{
ismem=true;
addr<<=iirf;
addr>>=iirf;
return &(((u8*)ptr)[addr]);
}
die("Invalid memory size");
return 0;
}
void* _vmem_page_info(u32 addr,bool& ismem,u32 sz,u32& page_sz,bool rw)
{
u32 page=addr>>24;
@ -182,6 +223,11 @@ INLINE Trv DYNACALL _vmem_readt(u32 addr)
}
}
}
template u8 DYNACALL _vmem_readt<u8, u8>(u32 addr);
template u16 DYNACALL _vmem_readt<u16, u16>(u32 addr);
template u32 DYNACALL _vmem_readt<u32, u32>(u32 addr);
template u64 DYNACALL _vmem_readt<u64, u64>(u32 addr);
template<typename T>
INLINE void DYNACALL _vmem_writet(u32 addr,T data)
{
@ -224,6 +270,10 @@ INLINE void DYNACALL _vmem_writet(u32 addr,T data)
}
}
}
template void DYNACALL _vmem_writet<u8>(u32 addr, u8 data);
template void DYNACALL _vmem_writet<u16>(u32 addr, u16 data);
template void DYNACALL _vmem_writet<u32>(u32 addr, u32 data);
template void DYNACALL _vmem_writet<u64>(u32 addr, u64 data);
//ReadMem/WriteMem functions
//ReadMem
@ -249,31 +299,31 @@ void DYNACALL _vmem_WriteMem64(u32 Address,u64 data) { _vmem_writet<u64>(Address
//default read handlers
u8 DYNACALL _vmem_ReadMem8_not_mapped(u32 addresss)
{
//printf("[sh4]Read8 from 0x%X, not mapped [_vmem default handler]\n",addresss);
INFO_LOG(MEMORY, "[sh4]Read8 from 0x%X, not mapped [_vmem default handler]", addresss);
return (u8)MEM_ERROR_RETURN_VALUE;
}
u16 DYNACALL _vmem_ReadMem16_not_mapped(u32 addresss)
{
//printf("[sh4]Read16 from 0x%X, not mapped [_vmem default handler]\n",addresss);
INFO_LOG(MEMORY, "[sh4]Read16 from 0x%X, not mapped [_vmem default handler]", addresss);
return (u16)MEM_ERROR_RETURN_VALUE;
}
u32 DYNACALL _vmem_ReadMem32_not_mapped(u32 addresss)
u32 DYNACALL _vmem_ReadMem32_not_mapped(u32 address)
{
//printf("[sh4]Read32 from 0x%X, not mapped [_vmem default handler]\n",addresss);
INFO_LOG(MEMORY, "[sh4]Read32 from 0x%X, not mapped [_vmem default handler]", address);
return (u32)MEM_ERROR_RETURN_VALUE;
}
//default write handers
void DYNACALL _vmem_WriteMem8_not_mapped(u32 addresss,u8 data)
{
//printf("[sh4]Write8 to 0x%X=0x%X, not mapped [_vmem default handler]\n",addresss,data);
INFO_LOG(MEMORY, "[sh4]Write8 to 0x%X=0x%X, not mapped [_vmem default handler]", addresss, data);
}
void DYNACALL _vmem_WriteMem16_not_mapped(u32 addresss,u16 data)
{
//printf("[sh4]Write16 to 0x%X=0x%X, not mapped [_vmem default handler]\n",addresss,data);
INFO_LOG(MEMORY, "[sh4]Write16 to 0x%X=0x%X, not mapped [_vmem default handler]", addresss, data);
}
void DYNACALL _vmem_WriteMem32_not_mapped(u32 addresss,u32 data)
{
//printf("[sh4]Write32 to 0x%X=0x%X, not mapped [_vmem default handler]\n",addresss,data);
INFO_LOG(MEMORY, "[sh4]Write32 to 0x%X=0x%X, not mapped [_vmem default handler]", addresss, data);
}
//code to register handlers
//0 is considered error :)
@ -390,6 +440,8 @@ void _vmem_term() {}
#include "hw/sh4/sh4_mem.h"
u8* virt_ram_base;
bool vmem_4gb_space;
static VMemType vmemstatus;
void* malloc_pages(size_t size) {
#if HOST_OS == OS_WINDOWS
@ -437,21 +489,72 @@ bool BM_LockedWrite(u8* address) {
return false;
}
static void _vmem_set_p0_mappings()
{
const vmem_mapping mem_mappings[] = {
// P0/U0
{0x00000000, 0x00800000, 0, 0, false}, // Area 0 -> unused
{0x00800000, 0x01000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // Aica
{0x01000000, 0x02800000, 0, 0, false}, // unused
{0x02800000, 0x03000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // Aica mirror
{0x03000000, 0x04000000, 0, 0, false}, // unused
{0x04000000, 0x05000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x10000000, 0x80000000, 0, 0, false}, // Area 4-7 (unused)
};
vmem_platform_create_mappings(&mem_mappings[0], ARRAY_SIZE(mem_mappings));
}
bool _vmem_reserve() {
// TODO: Static assert?
verify((sizeof(Sh4RCB)%PAGE_SIZE)==0);
VMemType vmemstatus = MemTypeError;
vmemstatus = MemTypeError;
// Use vmem only if settings mandate so, and if we have proper exception handlers.
#ifndef TARGET_NO_EXCEPTIONS
#ifndef TARGET_NO_EXCEPTIONS
if (!settings.dynarec.disable_nvmem)
vmemstatus = vmem_platform_init((void**)&virt_ram_base, (void**)&p_sh4rcb);
#endif
#endif
return true;
}
static void _vmem_term_mappings()
{
if (vmemstatus == MemTypeError) {
if (p_sh4rcb != NULL)
{
free(p_sh4rcb);
p_sh4rcb = NULL;
}
if (mem_b.data != NULL)
{
free(mem_b.data);
mem_b.data = NULL;
}
if (vram.data != NULL)
{
free(vram.data);
vram.data = NULL;
}
if (aica_ram.data != NULL)
{
free(aica_ram.data);
aica_ram.data = NULL;
}
}
}
void _vmem_init_mappings()
{
_vmem_term_mappings();
// Fallback to statically allocated buffers, this results in slow-ops being generated.
if (vmemstatus == MemTypeError) {
printf("Warning! nvmem is DISABLED (due to failure or not being built-in\n");
WARN_LOG(VMEM, "Warning! nvmem is DISABLED (due to failure or not being built-in");
virt_ram_base = 0;
// Allocate it all and initialize it.
@ -468,44 +571,95 @@ bool _vmem_reserve() {
aica_ram.data = (u8*)malloc_pages(ARAM_SIZE);
}
else {
printf("Info: nvmem is enabled, with addr space of size %s\n", vmemstatus == MemType4GB ? "4GB" : "512MB");
printf("Info: p_sh4rcb: %p virt_ram_base: %p\n", p_sh4rcb, virt_ram_base);
NOTICE_LOG(VMEM, "Info: nvmem is enabled, with addr space of size %s", vmemstatus == MemType4GB ? "4GB" : "512MB");
INFO_LOG(VMEM, "Info: p_sh4rcb: %p virt_ram_base: %p", p_sh4rcb, virt_ram_base);
// Map the different parts of the memory file into the new memory range we got.
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
const vmem_mapping mem_mappings[] = {
{0x00000000, 0x00800000, 0, 0, false}, // Area 0 -> unused
{0x00800000, 0x01000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, false}, // Aica, wraps too
{0x20000000, 0x20000000+ARAM_SIZE, MAP_ARAM_START_OFFSET, ARAM_SIZE, true},
{0x01000000, 0x04000000, 0, 0, false}, // More unused
{0x04000000, 0x05000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x10000000, 0x20000000, 0, 0, false}, // Area 4-7 (unused)
};
vmem_platform_create_mappings(&mem_mappings[0], sizeof(mem_mappings) / sizeof(mem_mappings[0]));
if (vmemstatus == MemType512MB)
{
const vmem_mapping mem_mappings[] = {
{0x00000000, 0x00800000, 0, 0, false}, // Area 0 -> unused
{0x00800000, 0x01000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, false}, // Aica
{0x01000000, 0x04000000, 0, 0, false}, // More unused
{0x04000000, 0x05000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0x05000000, 0x06000000, 0, 0, false}, // 32 bit path (unused)
{0x06000000, 0x07000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x07000000, 0x08000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x08000000, 0x0C000000, 0, 0, false}, // Area 2
{0x0C000000, 0x10000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x10000000, 0x20000000, 0, 0, false}, // Area 4-7 (unused)
// This is outside of the 512MB addr space
{0x20000000, 0x20800000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // writable aica ram
};
vmem_platform_create_mappings(&mem_mappings[0], ARRAY_SIZE(mem_mappings));
// Point buffers to actual data pointers
aica_ram.data = &virt_ram_base[0x20000000]; // Points to the writable AICA addrspace
vram.data = &virt_ram_base[0x04000000]; // Points to first vram mirror (writable and lockable)
mem_b.data = &virt_ram_base[0x0C000000]; // Main memory, first mirror
}
else
{
_vmem_set_p0_mappings();
const vmem_mapping mem_mappings[] = {
// P1
{0x80000000, 0x80800000, 0, 0, false}, // Area 0 -> unused
{0x80800000, 0x81000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // Aica
{0x81000000, 0x82800000, 0, 0, false}, // unused
{0x82800000, 0x83000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // Aica mirror
{0x83000000, 0x84000000, 0, 0, false}, // unused
{0x84000000, 0x85000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0x85000000, 0x86000000, 0, 0, false}, // 32 bit path (unused)
{0x86000000, 0x87000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0x87000000, 0x88000000, 0, 0, false}, // 32 bit path (unused) mirror
{0x88000000, 0x8C000000, 0, 0, false}, // Area 2
{0x8C000000, 0x90000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0x90000000, 0xA0000000, 0, 0, false}, // Area 4-7 (unused)
// P2
{0xA0000000, 0xA0800000, 0, 0, false}, // Area 0 -> unused
{0xA0800000, 0xA1000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // Aica
{0xA1000000, 0xA2800000, 0, 0, false}, // unused
{0xA2800000, 0xA3000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // Aica mirror
{0xA3000000, 0xA4000000, 0, 0, false}, // unused
{0xA4000000, 0xA5000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0xA5000000, 0xA6000000, 0, 0, false}, // 32 bit path (unused)
{0xA6000000, 0xA7000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0xA7000000, 0xA8000000, 0, 0, false}, // 32 bit path (unused) mirror
{0xA8000000, 0xAC000000, 0, 0, false}, // Area 2
{0xAC000000, 0xB0000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0xB0000000, 0xC0000000, 0, 0, false}, // Area 4-7 (unused)
// P3
{0xC0000000, 0xC0800000, 0, 0, false}, // Area 0 -> unused
{0xC0800000, 0xC1000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // Aica
{0xC1000000, 0xC2800000, 0, 0, false}, // unused
{0xC2800000, 0xC3000000, MAP_ARAM_START_OFFSET, ARAM_SIZE, true}, // Aica mirror
{0xC3000000, 0xC4000000, 0, 0, false}, // unused
{0xC4000000, 0xC5000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // Area 1 (vram, 16MB, wrapped on DC as 2x8MB)
{0xC5000000, 0xC6000000, 0, 0, false}, // 32 bit path (unused)
{0xC6000000, 0xC7000000, MAP_VRAM_START_OFFSET, VRAM_SIZE, true}, // VRAM mirror
{0xC7000000, 0xC8000000, 0, 0, false}, // 32 bit path (unused) mirror
{0xC8000000, 0xCC000000, 0, 0, false}, // Area 2
{0xCC000000, 0xD0000000, MAP_RAM_START_OFFSET, RAM_SIZE, true}, // Area 3 (main RAM + 3 mirrors)
{0xD0000000, 0x100000000L, 0, 0, false}, // Area 4-7 (unused)
};
vmem_platform_create_mappings(&mem_mappings[0], ARRAY_SIZE(mem_mappings));
// Point buffers to actual data pointers
aica_ram.data = &virt_ram_base[0x80800000]; // Points to the first AICA addrspace in P1
vram.data = &virt_ram_base[0x84000000]; // Points to first vram mirror (writable and lockable) in P1
mem_b.data = &virt_ram_base[0x8C000000]; // Main memory, first mirror in P1
vmem_4gb_space = true;
}
// Point buffers to actual data pointers
aica_ram.size = ARAM_SIZE;
aica_ram.data = &virt_ram_base[0x20000000]; // Points to the writtable AICA addrspace
vram.size = VRAM_SIZE;
vram.data = &virt_ram_base[0x04000000]; // Points to first vram mirror (writtable and lockable)
mem_b.size = RAM_SIZE;
mem_b.data = &virt_ram_base[0x0C000000]; // Main memory, first mirror
}
// Clear out memory
aica_ram.Zero();
vram.Zero();
mem_b.Zero();
return true;
}
#define freedefptr(x) \
@ -522,3 +676,114 @@ void _vmem_release() {
}
}
void _vmem_enable_mmu(bool enable)
{
if (enable)
{
vmem32_init();
}
else
{
// Restore P0/U0 mem mappings
vmem32_term();
if (_nvmem_4gb_space())
_vmem_set_p0_mappings();
}
}
void _vmem_protect_vram(u32 addr, u32 size)
{
addr &= VRAM_MASK;
if (!mmu_enabled())
{
mem_region_lock(virt_ram_base + 0x04000000 + addr, size); // P0
//mem_region_lock(virt_ram_base + 0x06000000 + addr, size); // P0 - mirror
if (VRAM_SIZE == 0x800000)
{
// wraps when only 8MB VRAM
mem_region_lock(virt_ram_base + 0x04000000 + addr + VRAM_SIZE, size);
//mem_region_lock(virt_ram_base + 0x06000000 + addr + VRAM_SIZE, size);
}
}
if (_nvmem_4gb_space())
{
mem_region_lock(virt_ram_base + 0x84000000 + addr, size); // P1
//mem_region_lock(virt_ram_base + 0x86000000 + addr, size); // P1 - mirror
// We should also lock P2 and P3, and the mirrors, but they don't seem to be used...
//mem_region_lock(virt_ram_base + 0xA4000000 + addr, size); // P2
//mem_region_lock(virt_ram_base + 0xA6000000 + addr, size); // P2 - mirror
//mem_region_lock(virt_ram_base + 0xC4000000 + addr, size); // P3
//mem_region_lock(virt_ram_base + 0xC6000000 + addr, size); // P3 - mirror
if (VRAM_SIZE == 0x800000)
{
mem_region_lock(virt_ram_base + 0x84000000 + addr + VRAM_SIZE, size);
//mem_region_lock(virt_ram_base + 0x86000000 + addr + VRAM_SIZE, size);
//mem_region_lock(virt_ram_base + 0xA4000000 + addr + VRAM_SIZE, size);
//mem_region_lock(virt_ram_base + 0xC4000000 + addr + VRAM_SIZE, size);
}
vmem32_protect_vram(addr, size);
}
}
void _vmem_unprotect_vram(u32 addr, u32 size)
{
addr &= VRAM_MASK;
if (!mmu_enabled())
{
mem_region_unlock(virt_ram_base + 0x04000000 + addr, size); // P0
//mem_region_unlock(virt_ram_base + 0x06000000 + addr, size); // P0 - mirror
if (VRAM_SIZE == 0x800000)
{
// wraps when only 8MB VRAM
mem_region_unlock(virt_ram_base + 0x04000000 + addr + VRAM_SIZE, size);
//mem_region_unlock(virt_ram_base + 0x06000000 + addr + VRAM_SIZE, size);
}
}
if (_nvmem_4gb_space())
{
mem_region_unlock(virt_ram_base + 0x84000000 + addr, size); // P1
//mem_region_unlock(virt_ram_base + 0x86000000 + addr, size); // P1 - mirror
// We should also lock P2 and P3, and the mirrors, but they don't seem to be used...
//mem_region_unlock(virt_ram_base + 0xA4000000 + addr, size); // P2
//mem_region_unlock(virt_ram_base + 0xA6000000 + addr, size); // P2 - mirror
//mem_region_unlock(virt_ram_base + 0xC4000000 + addr, size); // P3
//mem_region_unlock(virt_ram_base + 0xC6000000 + addr, size); // P3 - mirror
if (VRAM_SIZE == 0x800000)
{
mem_region_unlock(virt_ram_base + 0x84000000 + addr + VRAM_SIZE, size);
//mem_region_unlock(virt_ram_base + 0x86000000 + addr + VRAM_SIZE, size);
//mem_region_unlock(virt_ram_base + 0xA4000000 + addr + VRAM_SIZE, size);
//mem_region_unlock(virt_ram_base + 0xC4000000 + addr + VRAM_SIZE, size);
}
}
}
u32 _vmem_get_vram_offset(void *addr)
{
ptrdiff_t offset = (u8*)addr - virt_ram_base;
if (_nvmem_4gb_space())
{
if (mmu_enabled())
{
// Only kernel mirrors
if (offset < 0x80000000 || offset >= 0xE0000000)
return -1;
}
else
{
if (offset < 0 || offset >= 0xE0000000)
return -1;
}
offset &= 0x1FFFFFFF;
}
else
{
if (offset < 0 || offset >= 0x20000000)
return -1;
}
if ((offset >> 24) != 4)
return -1;
verify((((u8*)addr - virt_ram_base) >> 29) == 0 || (((u8*)addr - virt_ram_base) >> 29) == 4); // others areas aren't mapped atm
return offset & VRAM_MASK;
}

View File

@ -8,8 +8,8 @@ enum VMemType {
};
struct vmem_mapping {
u32 start_address, end_address;
unsigned memoffset, memsize;
u64 start_address, end_address;
u64 memoffset, memsize;
bool allow_writes;
};
@ -55,6 +55,7 @@ typedef u32 _vmem_handler;
void _vmem_init();
void _vmem_reset();
void _vmem_term();
void _vmem_init_mappings();
//functions to register and map handlers/memory
_vmem_handler _vmem_register_handler(_vmem_ReadMem8FP* read8,_vmem_ReadMem16FP* read16,_vmem_ReadMem32FP* read32, _vmem_WriteMem8FP* write8,_vmem_WriteMem16FP* write16,_vmem_WriteMem32FP* write32);
@ -75,7 +76,13 @@ void _vmem_map_handler(_vmem_handler Handler,u32 start,u32 end);
void _vmem_map_block(void* base,u32 start,u32 end,u32 mask);
void _vmem_mirror_mapping(u32 new_region,u32 start,u32 size);
#define _vmem_map_block_mirror(base,start,end,blck_size) {u32 block_size=(blck_size)>>24;u32 map_sz=(end)-(start)+1;/*verify((map_sz%block_size)==0);u32 map_times=map_sz/(block_size);*/ for (u32 _maip=(start);_maip<(end);_maip+=block_size) _vmem_map_block((base),_maip,_maip+block_size-1,blck_size-1);}
#define _vmem_map_block_mirror(base, start, end, blck_size) { \
u32 block_size = (blck_size) >> 24; \
u32 map_sz = (end) - (start) + 1; \
/* verify((map_sz % block_size) == 0); */ \
for (u32 _maip = (start); _maip <= (end); _maip += block_size) \
_vmem_map_block((base), _maip, _maip + block_size - 1, blck_size - 1); \
}
//ReadMem(s)
u32 DYNACALL _vmem_ReadMem8SX32(u32 Address);
@ -84,11 +91,13 @@ u8 DYNACALL _vmem_ReadMem8(u32 Address);
u16 DYNACALL _vmem_ReadMem16(u32 Address);
u32 DYNACALL _vmem_ReadMem32(u32 Address);
u64 DYNACALL _vmem_ReadMem64(u32 Address);
template<typename T, typename Trv> Trv DYNACALL _vmem_readt(u32 addr);
//WriteMem(s)
void DYNACALL _vmem_WriteMem8(u32 Address,u8 data);
void DYNACALL _vmem_WriteMem16(u32 Address,u16 data);
void DYNACALL _vmem_WriteMem32(u32 Address,u32 data);
void DYNACALL _vmem_WriteMem64(u32 Address,u64 data);
template<typename T> void DYNACALL _vmem_writet(u32 addr, T data);
//should be called at start up to ensure it will succeed :)
bool _vmem_reserve();
@ -98,11 +107,24 @@ void _vmem_release();
void _vmem_get_ptrs(u32 sz,bool write,void*** vmap,void*** func);
void* _vmem_get_ptr2(u32 addr,u32& mask);
void* _vmem_read_const(u32 addr,bool& ismem,u32 sz);
void* _vmem_write_const(u32 addr,bool& ismem,u32 sz);
extern u8* virt_ram_base;
extern bool vmem_4gb_space;
static inline bool _nvmem_enabled() {
return virt_ram_base != 0;
}
static inline bool _nvmem_4gb_space() {
return vmem_4gb_space;
}
void _vmem_bm_reset();
void _vmem_enable_mmu(bool enable);
#define MAP_RAM_START_OFFSET 0
#define MAP_VRAM_START_OFFSET (MAP_RAM_START_OFFSET+RAM_SIZE)
#define MAP_ARAM_START_OFFSET (MAP_VRAM_START_OFFSET+VRAM_SIZE)
void _vmem_protect_vram(u32 addr, u32 size);
void _vmem_unprotect_vram(u32 addr, u32 size);
u32 _vmem_get_vram_offset(void *addr);

396
core/hw/mem/vmem32.cpp Normal file
View File

@ -0,0 +1,396 @@
/*
Created on: Apr 11, 2019
Copyright 2019 flyinghead
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#include <unordered_set>
#include "build.h"
#include "vmem32.h"
#include "_vmem.h"
#if HOST_OS == OS_WINDOWS
#include <Windows.h>
#else
#include <sys/mman.h>
#include <sys/stat.h> /* For mode constants */
#include <fcntl.h> /* For O_* constants */
#include <unistd.h>
#include <errno.h>
#ifdef _ANDROID
#include <linux/ashmem.h>
#endif
#endif
#ifndef MAP_NOSYNC
#define MAP_NOSYNC 0
#endif
#include "types.h"
#include "hw/sh4/dyna/ngen.h"
#include "hw/sh4/modules/mmu.h"
extern bool VramLockedWriteOffset(size_t offset);
extern cMutex vramlist_lock;
#if HOST_OS == OS_WINDOWS
extern HANDLE mem_handle;
#else
extern int vmem_fd;
#endif
#define VMEM32_ERROR_NOT_MAPPED 0x100
static const u64 VMEM32_SIZE = 0x100000000L;
static const u64 USER_SPACE = 0x80000000L;
static const u64 AREA7_ADDRESS = 0x7C000000L;
#define VRAM_PROT_SEGMENT (1024 * 1024) // vram protection regions are grouped by 1MB segment
static std::unordered_set<u32> vram_mapped_pages;
struct vram_lock {
u32 start;
u32 end;
};
static std::vector<vram_lock> vram_blocks[VRAM_SIZE_MAX / VRAM_PROT_SEGMENT];
static u8 sram_mapped_pages[USER_SPACE / PAGE_SIZE / 8]; // bit set to 1 if page is mapped
bool vmem32_inited;
// stats
//u64 vmem32_page_faults;
//u64 vmem32_flush;
static void* vmem32_map_buffer(u32 dst, u32 addrsz, u32 offset, u32 size, bool write)
{
void* ptr;
void* rv;
//printf("MAP32 %08X w/ %d\n",dst,offset);
u32 map_times = addrsz / size;
#if HOST_OS == OS_WINDOWS
rv = MapViewOfFileEx(mem_handle, FILE_MAP_READ | (write ? FILE_MAP_WRITE : 0), 0, offset, size, &virt_ram_base[dst]);
if (rv == NULL)
return NULL;
for (u32 i = 1; i < map_times; i++)
{
dst += size;
ptr = MapViewOfFileEx(mem_handle, FILE_MAP_READ | (write ? FILE_MAP_WRITE : 0), 0, offset, size, &virt_ram_base[dst]);
if (ptr == NULL)
return NULL;
}
#else
u32 prot = PROT_READ | (write ? PROT_WRITE : 0);
rv = mmap(&virt_ram_base[dst], size, prot, MAP_SHARED | MAP_NOSYNC | MAP_FIXED, vmem_fd, offset);
if (MAP_FAILED == rv)
{
ERROR_LOG(VMEM, "MAP1 failed %d", errno);
return NULL;
}
for (u32 i = 1; i < map_times; i++)
{
dst += size;
ptr = mmap(&virt_ram_base[dst], size, prot , MAP_SHARED | MAP_NOSYNC | MAP_FIXED, vmem_fd, offset);
if (MAP_FAILED == ptr)
{
ERROR_LOG(VMEM, "MAP2 failed %d", errno);
return NULL;
}
}
#endif
return rv;
}
static void vmem32_unmap_buffer(u32 start, u64 end)
{
#if HOST_OS == OS_WINDOWS
UnmapViewOfFile(&virt_ram_base[start]);
#else
mmap(&virt_ram_base[start], end - start, PROT_NONE, MAP_FIXED | MAP_PRIVATE | MAP_ANON, -1, 0);
#endif
}
static void vmem32_protect_buffer(u32 start, u32 size)
{
verify((start & PAGE_MASK) == 0);
#if HOST_OS == OS_WINDOWS
DWORD old;
VirtualProtect(virt_ram_base + start, size, PAGE_READONLY, &old);
#else
mprotect(&virt_ram_base[start], size, PROT_READ);
#endif
}
static void vmem32_unprotect_buffer(u32 start, u32 size)
{
verify((start & PAGE_MASK) == 0);
#if HOST_OS == OS_WINDOWS
DWORD old;
VirtualProtect(virt_ram_base + start, size, PAGE_READWRITE, &old);
#else
mprotect(&virt_ram_base[start], size, PROT_READ | PROT_WRITE);
#endif
}
void vmem32_protect_vram(u32 addr, u32 size)
{
if (!vmem32_inited)
return;
for (int page = (addr & VRAM_MASK) / VRAM_PROT_SEGMENT; page <= ((addr & VRAM_MASK) + size - 1) / VRAM_PROT_SEGMENT; page++)
{
vram_blocks[page].push_back({ addr, addr + size - 1 });
}
}
void vmem32_unprotect_vram(u32 addr, u32 size)
{
if (!vmem32_inited)
return;
for (int page = (addr & VRAM_MASK) / VRAM_PROT_SEGMENT; page <= ((addr & VRAM_MASK) + size - 1) / VRAM_PROT_SEGMENT; page++)
{
std::vector<vram_lock>& block_list = vram_blocks[page];
for (auto it = block_list.begin(); it != block_list.end(); )
{
if (it->start >= addr && it->end < addr + size)
it = block_list.erase(it);
else
it++;
}
}
}
static const u32 page_sizes[] = { 1024, 4 * 1024, 64 * 1024, 1024 * 1024 };
static u32 vmem32_paddr_to_offset(u32 address)
{
u32 low_addr = address & 0x1FFFFFFF;
switch ((address >> 26) & 7)
{
case 0: // area 0
// Aica ram
if (low_addr >= 0x00800000 && low_addr < 0x00800000 + 0x00800000)
{
return ((low_addr - 0x00800000) & (ARAM_SIZE - 1)) + MAP_ARAM_START_OFFSET;
}
else if (low_addr >= 0x02800000 && low_addr < 0x02800000 + 0x00800000)
{
return low_addr - 0x02800000 + MAP_ARAM_START_OFFSET;
}
break;
case 1: // area 1
// Vram
if (low_addr >= 0x04000000 && low_addr < 0x04000000 + 0x01000000)
{
return ((low_addr - 0x04000000) & (VRAM_SIZE - 1)) + MAP_VRAM_START_OFFSET;
}
else if (low_addr >= 0x06000000 && low_addr < 0x06000000 + 0x01000000)
{
return ((low_addr - 0x06000000) & (VRAM_SIZE - 1)) + MAP_VRAM_START_OFFSET;
}
break;
case 3: // area 3
// System ram
if (low_addr >= 0x0C000000 && low_addr < 0x0C000000 + 0x04000000)
{
return ((low_addr - 0x0C000000) & (RAM_SIZE - 1)) + MAP_RAM_START_OFFSET;
}
break;
//case 4:
// TODO vram?
//break;
default:
break;
}
// Unmapped address
return -1;
}
static u32 vmem32_map_mmu(u32 address, bool write)
{
#ifndef NO_MMU
u32 pa;
const TLB_Entry *entry;
u32 rc = mmu_full_lookup<false>(address, &entry, pa);
if (rc == MMU_ERROR_NONE)
{
//0X & User mode-> protection violation
//if ((entry->Data.PR >> 1) == 0 && p_sh4rcb->cntx.sr.MD == 0)
// return MMU_ERROR_PROTECTED;
//if (write)
//{
// if ((entry->Data.PR & 1) == 0)
// return MMU_ERROR_PROTECTED;
// if (entry->Data.D == 0)
// return MMU_ERROR_FIRSTWRITE;
//}
u32 page_size = page_sizes[entry->Data.SZ1 * 2 + entry->Data.SZ0];
if (page_size == 1024)
return VMEM32_ERROR_NOT_MAPPED;
u32 vpn = (entry->Address.VPN << 10) & ~(page_size - 1);
u32 ppn = (entry->Data.PPN << 10) & ~(page_size - 1);
u32 offset = vmem32_paddr_to_offset(ppn);
if (offset == -1)
return VMEM32_ERROR_NOT_MAPPED;
bool allow_write = (entry->Data.PR & 1) != 0;
if (offset >= MAP_VRAM_START_OFFSET && offset < MAP_VRAM_START_OFFSET + VRAM_SIZE)
{
// Check vram protected regions
u32 start = offset - MAP_VRAM_START_OFFSET;
if (!vram_mapped_pages.insert(vpn).second)
{
// page has been mapped already: vram locked write
vmem32_unprotect_buffer(address & ~PAGE_MASK, PAGE_SIZE);
u32 addr_offset = start + (address & (page_size - 1));
VramLockedWriteOffset(addr_offset);
return MMU_ERROR_NONE;
}
verify(vmem32_map_buffer(vpn, page_size, offset, page_size, allow_write) != NULL);
u32 end = start + page_size;
const vector<vram_lock>& blocks = vram_blocks[start / VRAM_PROT_SEGMENT];
vramlist_lock.Lock();
for (int i = blocks.size() - 1; i >= 0; i--)
{
if (blocks[i].start < end && blocks[i].end >= start)
{
u32 prot_start = max(start, blocks[i].start);
u32 prot_size = min(end, blocks[i].end + 1) - prot_start;
prot_size += prot_start % PAGE_SIZE;
prot_start &= ~PAGE_MASK;
vmem32_protect_buffer(vpn + (prot_start & (page_size - 1)), prot_size);
}
}
vramlist_lock.Unlock();
}
else if (offset >= MAP_RAM_START_OFFSET && offset < MAP_RAM_START_OFFSET + RAM_SIZE)
{
// Check system RAM protected pages
u32 start = offset - MAP_RAM_START_OFFSET;
if (bm_IsRamPageProtected(start) && allow_write)
{
if (sram_mapped_pages[start >> 15] & (1 << ((start >> 12) & 7)))
{
// Already mapped => write access
vmem32_unprotect_buffer(address & ~PAGE_MASK, PAGE_SIZE);
bm_RamWriteAccess(ppn);
}
else
{
sram_mapped_pages[start >> 15] |= (1 << ((start >> 12) & 7));
verify(vmem32_map_buffer(vpn, page_size, offset, page_size, false) != NULL);
}
}
else
verify(vmem32_map_buffer(vpn, page_size, offset, page_size, allow_write) != NULL);
}
else
// Not vram or system ram
verify(vmem32_map_buffer(vpn, page_size, offset, page_size, allow_write) != NULL);
return MMU_ERROR_NONE;
}
#else
u32 rc = MMU_ERROR_PROTECTED;
#endif
return rc;
}
static u32 vmem32_map_address(u32 address, bool write)
{
u32 area = address >> 29;
switch (area)
{
case 3: // P0/U0
if (address >= AREA7_ADDRESS)
// area 7: unmapped
return VMEM32_ERROR_NOT_MAPPED;
/* no break */
case 0:
case 1:
case 2:
case 6: // P3
return vmem32_map_mmu(address, write);
default:
break;
}
return VMEM32_ERROR_NOT_MAPPED;
}
#if !defined(NO_MMU) && defined(HOST_64BIT_CPU)
bool vmem32_handle_signal(void *fault_addr, bool write, u32 exception_pc)
{
if (!vmem32_inited || (u8*)fault_addr < virt_ram_base || (u8*)fault_addr >= virt_ram_base + VMEM32_SIZE)
return false;
//vmem32_page_faults++;
u32 guest_addr = (u8*)fault_addr - virt_ram_base;
u32 rv = vmem32_map_address(guest_addr, write);
DEBUG_LOG(VMEM, "vmem32_handle_signal handled signal %s @ %p -> %08x rv=%d", write ? "W" : "R", fault_addr, guest_addr, rv);
if (rv == MMU_ERROR_NONE)
return true;
if (rv == VMEM32_ERROR_NOT_MAPPED)
return false;
#if HOST_CPU == CPU_ARM64
p_sh4rcb->cntx.pc = exception_pc;
#else
p_sh4rcb->cntx.pc = p_sh4rcb->cntx.exception_pc;
#endif
DoMMUException(guest_addr, rv, write ? MMU_TT_DWRITE : MMU_TT_DREAD);
ngen_HandleException();
// not reached
return true;
}
#endif
void vmem32_flush_mmu()
{
//vmem32_flush++;
vram_mapped_pages.clear();
memset(sram_mapped_pages, 0, sizeof(sram_mapped_pages));
vmem32_unmap_buffer(0, USER_SPACE);
// TODO flush P3?
}
bool vmem32_init()
{
#if HOST_OS == OS_WINDOWS
return false;
#else
if (settings.dynarec.disable_vmem32 || !_nvmem_4gb_space())
return false;
vmem32_inited = true;
vmem32_flush_mmu();
return true;
#endif
}
void vmem32_term()
{
if (vmem32_inited)
{
vmem32_inited = false;
vmem32_flush_mmu();
}
}

33
core/hw/mem/vmem32.h Normal file
View File

@ -0,0 +1,33 @@
/*
Created on: Apr 11, 2019
Copyright 2019 flyinghead
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
#include "_vmem.h"
bool vmem32_init();
void vmem32_term();
bool vmem32_handle_signal(void *fault_addr, bool write, u32 exception_pc);
void vmem32_flush_mmu();
void vmem32_protect_vram(u32 addr, u32 size);
void vmem32_unprotect_vram(u32 addr, u32 size);
extern bool vmem32_inited;
static inline bool vmem32_enabled() {
return vmem32_inited;
}

View File

@ -43,11 +43,7 @@
#define MODEM_DEVICE_TYPE_336K 0
#ifdef RELEASE
#define LOG(...)
#else
#define LOG(...) do { printf("[%d.%03d] MODEM ", (int)os_GetSeconds(), (int)(os_GetSeconds() * 1000) % 1000); printf(__VA_ARGS__); putchar('\n'); } while (false);
#endif
#define LOG(...) DEBUG_LOG(MODEM, __VA_ARGS__)
const static u32 MODEM_ID[2] =
{
@ -125,7 +121,8 @@ static void ControllerTestEnd();
static void DSPTestStart();
static void DSPTestEnd();
static double last_dial_time;
static u64 last_dial_time;
static u64 connected_time;
#ifndef RELEASE
static double last_comm_stats;
@ -135,14 +132,14 @@ static FILE *recv_fp;
static FILE *sent_fp;
#endif
static int modem_sched_func(int tag, int c, int j)
static int modem_sched_func(int tag, int cycles, int jitter)
{
#ifndef RELEASE
if (os_GetSeconds() - last_comm_stats >= 2)
{
if (last_comm_stats != 0)
{
printf("Stats sent %d (%.2f kB/s) received %d (%.2f kB/s) TDBE %d RDBF %d\n", sent_bytes, sent_bytes / 2000.0,
DEBUG_LOG(MODEM, "Stats sent %d (%.2f kB/s) received %d (%.2f kB/s) TDBE %d RDBF %d\n", sent_bytes, sent_bytes / 2000.0,
recvd_bytes, recvd_bytes / 2000.0,
modem_regs.reg1e.TDBE, modem_regs.reg1e.RDBF);
sent_bytes = 0;
@ -170,7 +167,7 @@ static int modem_sched_func(int tag, int c, int j)
switch (connect_state)
{
case DIALING:
if (last_dial_time != 0 && os_GetSeconds() - last_dial_time > 0.99)
if (last_dial_time != 0 && sh4_sched_now64() - last_dial_time >= SH4_MAIN_CLOCK + jitter)
{
LOG("Switching to RINGING state");
connect_state = RINGING;
@ -178,7 +175,7 @@ static int modem_sched_func(int tag, int c, int j)
}
else
{
last_dial_time = os_GetSeconds();
last_dial_time = sh4_sched_now64();
modem_regs.reg1e.TDBE = 1;
schedule_callback(1000); // To switch to Ringing state
@ -205,23 +202,26 @@ static int modem_sched_func(int tag, int c, int j)
SET_STATUS_BIT(0x0f, modem_regs.reg0f.RI, 0);
SET_STATUS_BIT(0x0b, modem_regs.reg0b.ATV25, 0);
callback_cycles = SH4_MAIN_CLOCK / 1000000 * 500; // 500 ms
callback_cycles = SH4_MAIN_CLOCK / 1000 * 500; // 500 ms
connect_state = PRE_CONNECTED;
break;
case PRE_CONNECTED:
printf("MODEM Connected\n");
INFO_LOG(MODEM, "MODEM Connected");
if (modem_regs.reg03.RLSDE)
SET_STATUS_BIT(0x0f, modem_regs.reg0f.RLSD, 1);
if (modem_regs.reg12 == 0xAA)
{
// V8 AUTO mode
dspram[0x302] |= 1 << 4; // protocol octet received
dspram[0x302] = (dspram[0x302] & 0x1f) | (dspram[0x304] & 0xe0); // Received Call Function
dspram[0x301] |= 1 << 4; // JM detected
dspram[0x303] |= 0xE0; // Received protocol bits (?)
dspram[0x2e3] |= 5; // Symbol rate 3429
dspram[0x239] |= 12; // RTD 0 @ 3429 sym rate
dspram[0x2e3] = 5; // Symbol rate 3429
dspram[0x2e4] = 0xe; // V.34 Receiver Speed 33.6
dspram[0x2e5] = 0xe; // V.34 Transmitter Speed 33.6
dspram[0x239] = 12; // RTD 0 @ 3429 sym rate
if (modem_regs.reg08.ASYN)
{
modem_regs.reg12 = 0xce; // CONF V34 - K56flex
@ -257,7 +257,7 @@ static int modem_sched_func(int tag, int c, int j)
if (modem_regs.reg02.v0.RTSDE)
SET_STATUS_BIT(0x0f, modem_regs.reg0f.RTSDT, 1);
// What is this? This is required for games to detect the connection
// Energy detected. Required for games to detect the connection
SET_STATUS_BIT(0x0f, modem_regs.reg0f.FED, 1);
// V.34 Remote Modem Data Rate Capability
@ -267,6 +267,7 @@ static int modem_sched_func(int tag, int c, int j)
start_pppd();
connect_state = CONNECTED;
callback_cycles = SH4_MAIN_CLOCK / 1000000 * 238; // 238 us
connected_time = 0;
break;
@ -280,10 +281,13 @@ static int modem_sched_func(int tag, int c, int j)
LOG("modem_regs %02x == %02x", i, modem_regs.ptr[i]);
}
#endif
if (connected_time == 0)
connected_time = sh4_sched_now64();
if (!modem_regs.reg1e.RDBF)
{
int c = read_pppd();
if (c >= 0)
// Delay reading from ppp to avoid choking WinCE
if (c >= 0 && sh4_sched_now64() - connected_time >= SH4_MAIN_CLOCK / 4)
{
//LOG("pppd received %02x", c);
#ifndef RELEASE
@ -319,6 +323,11 @@ void ModemInit()
modem_sched = sh4_sched_register(0, &modem_sched_func);
}
void ModemTerm()
{
stop_pppd();
}
static void schedule_callback(int ms)
{
sh4_sched_request(modem_sched, SH4_MAIN_CLOCK / 1000 * ms);
@ -428,7 +437,7 @@ static void modem_reset(u32 v)
state=MS_RESETING;
modem_regs.ptr[0x20]=1;
ControllerTestStart();
printf("MODEM Reset\n");
INFO_LOG(MODEM, "MODEM Reset");
}
}
@ -495,7 +504,7 @@ static void ModemNormalWrite(u32 reg, u32 data)
//LOG("ModemNormalWrite : TBUFFER = %X", data);
if (connect_state == DISCONNECTED)
{
printf("MODEM Dialing\n");
INFO_LOG(MODEM, "MODEM Dialing");
connect_state = DIALING;
}
schedule_callback(100);
@ -571,10 +580,7 @@ static void ModemNormalWrite(u32 reg, u32 data)
u32 dspram_addr = modem_regs.reg1c_1d.MEMADD_l | (modem_regs.reg1c_1d.MEMADD_h << 8);
if (modem_regs.reg1c_1d.MEMW)
{
//LOG("DSP mem Write%s address %08x = %x",
// word_dspram_write ? " (w)" : "",
// dspram_addr,
// modem_regs.reg18_19 );
LOG("DSP mem Write%s address %08x = %x", word_dspram_write ? " (w)" : "", dspram_addr, modem_regs.reg18_19);
if (word_dspram_write)
{
if (dspram_addr & 1)
@ -594,9 +600,7 @@ static void ModemNormalWrite(u32 reg, u32 data)
modem_regs.reg18_19 = dspram[dspram_addr] | (dspram[dspram_addr + 1] << 8);
else
modem_regs.reg18_19 = *(u16*)&dspram[dspram_addr];
//LOG("DSP mem Read address %08x == %x",
// dspram_addr,
// modem_regs.reg18_19 );
LOG("DSP mem Read address %08x == %x", dspram_addr, modem_regs.reg18_19 );
}
}
break;
@ -630,7 +634,7 @@ static void ModemNormalWrite(u32 reg, u32 data)
break;
default:
//printf("ModemNormalWrite : undef %03X=%X\n",reg,data);
//LOG("ModemNormalWrite : undef %03X = %X", reg, data);
break;
}
update_interrupt();

View File

@ -25,5 +25,6 @@
#include "types.h"
void ModemInit();
void ModemTerm();
u32 ModemReadMem_A0_006(u32 addr,u32 size);
void ModemWriteMem_A0_006(u32 addr,u32 data,u32 size);

View File

@ -22,7 +22,7 @@
*/
#pragma once
#pragma pack(1)
#pragma pack(push, 1)
union modemreg_t
{
u8 ptr[0x21];
@ -318,6 +318,7 @@ union modemreg_t
} reg1f;
};
};
#pragma pack(pop)
u8 regs_write_mask[] = {
//00 Receive Data Buffer (RBUFFER)/Voice Receive Data Buffer (VBUFR)
@ -433,7 +434,7 @@ static const u8 por_dspram[] =
/* 0x060 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x070 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x080 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x090 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9F avail mod type (wince): 80, 30, 00?
/* 0x0A0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x0B0 */ 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x0C0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -458,10 +459,10 @@ static const u8 por_dspram[] =
/* 0x1E0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x1F0 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x200 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x200 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 204-5 rate_seq_R2, 208-209 rate_seq_R3
/* 0x210 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xDD, 0xAD, 0x08, 0x07, 0x99, 0x00, 0x23, 0xA0,
/* 0x220 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00,
/* 0x230 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x230 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 239 Round Trip Far Echo Delay
/* 0x240 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x250 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* 0x260 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 26F Saved Filtered EQM (???)

View File

@ -24,13 +24,15 @@ typedef int sock_t;
#define L_EAGAIN EAGAIN
#define get_last_error() (errno)
#define INVALID_SOCKET (-1)
#define perror(s) do { INFO_LOG(MODEM, "%s: %s", (s) != NULL ? (s) : "", strerror(get_last_error())); } while (false)
#else
typedef SOCKET sock_t;
#define VALID(s) ((s) != INVALID_SOCKET)
#define L_EWOULDBLOCK WSAEWOULDBLOCK
#define L_EAGAIN WSAEWOULDBLOCK
#define get_last_error() (WSAGetLastError())
#define perror(s) do { if (s) printf("%s: ", s); printf("Winsock error: %d\n", WSAGetLastError()); } while (false)
#define perror(s) do { INFO_LOG(MODEM, "%s: Winsock error: %d\n", (s) != NULL ? (s) : "", WSAGetLastError()); } while (false)
#endif
#endif

View File

@ -213,7 +213,7 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s)
if (it == tcp_sockets.end())
{
if (tcp_connecting_sockets.find(s) == tcp_connecting_sockets.end())
printf("Unknown socket: remote port %d\n", short_be(s->remote_port));
INFO_LOG(MODEM, "Unknown socket: remote port %d", short_be(s->remote_port));
}
else
{
@ -234,7 +234,7 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s)
{
// Also called for child sockets
if (tcp_sockets.find(s) == tcp_sockets.end())
printf("pico_socket_accept: %s\n", strerror(pico_err));
INFO_LOG(MODEM, "pico_socket_accept: %s\n", strerror(pico_err));
}
else
{
@ -270,8 +270,7 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s)
if (get_last_error() != EINPROGRESS && get_last_error() != L_EWOULDBLOCK)
{
pico_ipv4_to_string(peer, sock_a->local_addr.ip4.addr);
printf("TCP connection to %s:%d failed: ", peer, short_be(sock_a->local_port));
perror(NULL);
INFO_LOG(MODEM, "TCP connection to %s:%d failed: %s", peer, short_be(sock_a->local_port), strerror(get_last_error()));
closesocket(sockfd);
}
else
@ -291,7 +290,7 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s)
auto it = tcp_sockets.find(s);
if (it == tcp_sockets.end())
{
printf("PICO_SOCK_EV_FIN: Unknown socket: remote port %d\n", short_be(s->remote_port));
INFO_LOG(MODEM, "PICO_SOCK_EV_FIN: Unknown socket: remote port %d", short_be(s->remote_port));
}
else
{
@ -301,11 +300,11 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s)
}
if (ev & PICO_SOCK_EV_ERR) {
printf("Socket error received: %s\n", strerror(pico_err));
INFO_LOG(MODEM, "Socket error received: %s", strerror(pico_err));
auto it = tcp_sockets.find(s);
if (it == tcp_sockets.end())
{
printf("PICO_SOCK_EV_ERR: Unknown socket: remote port %d\n", short_be(s->remote_port));
INFO_LOG(MODEM, "PICO_SOCK_EV_ERR: Unknown socket: remote port %d", short_be(s->remote_port));
}
else
{
@ -319,7 +318,7 @@ static void tcp_callback(uint16_t ev, struct pico_socket *s)
auto it = tcp_sockets.find(s);
if (it == tcp_sockets.end())
{
printf("PICO_SOCK_EV_CLOSE: Unknown socket: remote port %d\n", short_be(s->remote_port));
INFO_LOG(MODEM, "PICO_SOCK_EV_CLOSE: Unknown socket: remote port %d", short_be(s->remote_port));
}
else
{
@ -374,7 +373,7 @@ static void udp_callback(uint16_t ev, struct pico_socket *s)
if (r <= 0)
{
if (r < 0)
printf("%s: error UDP recv: %s\n", __FUNCTION__, strerror(pico_err));
INFO_LOG(MODEM, "error UDP recv: %s", strerror(pico_err));
break;
}
@ -394,7 +393,7 @@ static void udp_callback(uint16_t ev, struct pico_socket *s)
}
if (ev & PICO_SOCK_EV_ERR) {
printf("UDP Callback error received\n");
INFO_LOG(MODEM, "UDP Callback error received");
}
}
@ -420,7 +419,7 @@ static void read_native_sockets()
struct pico_socket *ps = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &tcp_callback);
if (ps == NULL)
{
printf("pico_socket_open failed: error %d\n", pico_err);
INFO_LOG(MODEM, "pico_socket_open failed: error %d", pico_err);
closesocket(sockfd);
continue;
}
@ -428,7 +427,7 @@ static void read_native_sockets()
ps->local_port = src_addr.sin_port;
if (pico_socket_connect(ps, &dcaddr.addr, it->first) != 0)
{
printf("pico_socket_connect failed: error %d\n", pico_err);
INFO_LOG(MODEM, "pico_socket_connect failed: error %d", pico_err);
closesocket(sockfd);
pico_socket_close(ps);
continue;
@ -469,8 +468,7 @@ static void read_native_sockets()
{
char peer[30];
pico_ipv4_to_string(peer, it->first->local_addr.ip4.addr);
printf("TCP connection to %s:%d failed: ", peer, short_be(it->first->local_port));
perror(NULL);
INFO_LOG(MODEM, "TCP connection to %s:%d failed: %s", peer, short_be(it->first->local_port), strerror(get_last_error()));
pico_socket_close(it->first);
closesocket(it->second);
}
@ -511,7 +509,7 @@ static void read_native_sockets()
//printf("read_native_sockets UDP received %d bytes from %08x:%d\n", r, long_be(msginfo.local_addr.ip4.addr), short_be(msginfo.local_port));
int r2 = pico_socket_sendto_extended(pico_udp_socket, buf, r, &dcaddr, it->first, &msginfo);
if (r2 < r)
printf("%s: error UDP sending to %d: %s\n", __FUNCTION__, short_be(it->first), strerror(pico_err));
INFO_LOG(MODEM, "error UDP sending to %d: %s", short_be(it->first), strerror(pico_err));
}
else if (r < 0 && get_last_error() != L_EAGAIN && get_last_error() != L_EWOULDBLOCK)
{
@ -543,10 +541,10 @@ static void read_native_sockets()
int r2 = pico_socket_send(it->first, buf, r);
if (r2 < 0)
printf("%s: error TCP sending: %s\n", __FUNCTION__, strerror(pico_err));
INFO_LOG(MODEM, "error TCP sending: %s", strerror(pico_err));
else if (r2 < r)
// FIXME EAGAIN errors. Need to buffer data or wait for call back.
printf("%s: truncated send: %d -> %d\n", __FUNCTION__, r, r2);
INFO_LOG(MODEM, "truncated send: %d -> %d", r, r2);
}
else if (r == 0)
{
@ -629,7 +627,7 @@ static void check_dns_entries()
dns_query_start = 0;
char myip[16];
pico_ipv4_to_string(myip, public_ip.addr);
printf("My IP is %s\n", myip);
INFO_LOG(MODEM, "My IP is %s", myip);
}
else
{
@ -662,7 +660,7 @@ static void check_dns_entries()
dns_query_start = 0;
char afoip[16];
pico_ipv4_to_string(afoip, afo_ip.addr);
printf("AFO server IP is %s\n", afoip);
INFO_LOG(MODEM, "AFO server IP is %s", afoip);
}
else
{
@ -698,7 +696,7 @@ static void *pico_thread_func(void *)
#if _WIN32
static WSADATA wsaData;
if (WSAStartup(MAKEWORD(2, 0), &wsaData) != 0)
printf("WSAStartup failed\n");
WARN_LOG(MODEM, "WSAStartup failed");
#endif
}
@ -717,28 +715,28 @@ static void *pico_thread_func(void *)
pico_udp_socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &udp_callback);
if (pico_udp_socket == NULL) {
printf("%s: error opening UDP socket: %s\n", __FUNCTION__, strerror(pico_err));
INFO_LOG(MODEM, "error opening UDP socket: %s", strerror(pico_err));
}
int yes = 1;
struct pico_ip4 inaddr_any = {0};
uint16_t listen_port = 0;
int ret = pico_socket_bind(pico_udp_socket, &inaddr_any, &listen_port);
if (ret < 0)
printf("%s: error binding UDP socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err));
INFO_LOG(MODEM, "error binding UDP socket to port %u: %s", short_be(listen_port), strerror(pico_err));
pico_tcp_socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &tcp_callback);
if (pico_tcp_socket == NULL) {
printf("%s: error opening TCP socket: %s\n", __FUNCTION__, strerror(pico_err));
INFO_LOG(MODEM, "error opening TCP socket: %s", strerror(pico_err));
}
pico_socket_setoption(pico_tcp_socket, PICO_TCP_NODELAY, &yes);
ret = pico_socket_bind(pico_tcp_socket, &inaddr_any, &listen_port);
if (ret < 0) {
printf("%s: error binding TCP socket to port %u: %s\n", __FUNCTION__, short_be(listen_port), strerror(pico_err));
INFO_LOG(MODEM, "error binding TCP socket to port %u: %s", short_be(listen_port), strerror(pico_err));
}
else
{
if (pico_socket_listen(pico_tcp_socket, 10) != 0)
printf("%s: error listening on port %u\n", __FUNCTION__, short_be(listen_port));
INFO_LOG(MODEM, "error listening on port %u", short_be(listen_port));
}
ppp->proxied = 1;

View File

@ -190,11 +190,11 @@ u32 AWCartridge::ReadMem(u32 address, u32 size) {
if (roffset >= (mpr_offset / 2))
roffset += mpr_bank * 0x4000000;
u16 retval = (RomSize > (roffset * 2)) ? ((u16 *)RomPtr)[roffset] : 0; // not endian-safe?
//printf("AWCART ReadMem %08x: %x\n", address, retval);
DEBUG_LOG(NAOMI, "AWCART ReadMem %08x: %x", address, retval);
return retval;
}
default:
EMUERROR("%X, %d", address, size);
INFO_LOG(NAOMI, "Unhandled awcart read %X, %d", address, size);
return 0xffff;
}
}
@ -209,7 +209,7 @@ void AWCartridge::WriteMem(u32 address, u32 data, u32 size)
break;
case AW_EPR_OFFSETL_addr:
epr_offset = (epr_offset & 0xffff0000) | data;
epr_offset = (epr_offset & 0xffff0000) | (u16)data;
recalc_dma_offset(EPR);
break;
@ -229,18 +229,19 @@ void AWCartridge::WriteMem(u32 address, u32 data, u32 size)
break;
case AW_MPR_FILE_OFFSETL_addr:
mpr_file_offset = (mpr_file_offset & 0xffff0000) | data;
mpr_file_offset = (mpr_file_offset & 0xffff0000) | (u16)data;
recalc_dma_offset(MPR_FILE);
break;
case AW_PIO_DATA_addr:
// write to ROM board address space, including FlashROM programming using CFI (TODO)
DEBUG_LOG(NAOMI, "Write to AW_PIO_DATA: %x", data);
if (epr_offset == 0x7fffff)
mpr_bank = data & 3;
break;
default:
EMUERROR("%X: %d sz %d", address, data, size);
INFO_LOG(NAOMI, "Unhandled awcart write %X: %d sz %d", address, data, size);
break;
}
}
@ -336,7 +337,7 @@ u16 AWCartridge::decrypt(u16 cipherText, u32 address, const u32 key)
void AWCartridge::Init()
{
mpr_offset = decrypt16(0x58/2) | (decrypt16(0x5a/2) << 16);
printf("AWCartridge::SetKey rombd_key %08x mpr_offset %08x\n", rombd_key, mpr_offset);
INFO_LOG(NAOMI, "AWCartridge::SetKey rombd_key %08x mpr_offset %08x", rombd_key, mpr_offset);
device_reset();
}
@ -389,10 +390,11 @@ void AWCartridge::recalc_dma_offset(int mode)
void *AWCartridge::GetDmaPtr(u32 &limit)
{
limit = std::min(std::min(limit, (u32)32), dma_limit - dma_offset);
u32 offset = dma_offset / 2;
for (int i = 0; i < 16; i++)
for (int i = 0; i < limit / 2; i++)
decrypted_buf[i] = decrypt16(offset + i);
limit = min(limit, (u32)32);
// printf("AWCART Decrypted data @ %08x:\n", dma_offset);
// for (int i = 0; i < 16; i++)
// {

View File

@ -53,7 +53,7 @@ private:
static const u8 permutation_table[4][16];
static const sbox_set sboxes_table[4];
static u16 decrypt(u16 cipherText, u32 address, const u32 key);
u16 decrypt16(u32 address) { return decrypt(((u16 *)RomPtr)[address], address, rombd_key); }
u16 decrypt16(u32 address) { return decrypt(((u16 *)RomPtr)[address % (RomSize / 2)], address, rombd_key); }
void set_key();
void recalc_dma_offset(int mode);

View File

@ -409,7 +409,7 @@ void GDCartridge::find_file(const char *name, const u8 *dir_sector, u32 &file_st
{
file_start = 0;
file_size = 0;
printf("Looking for file [%s]\n", name);
DEBUG_LOG(NAOMI, "Looking for file [%s]", name);
for(u32 pos = 0; pos < 2048; pos += dir_sector[pos]) {
int fnlen = 0;
if(!(dir_sector[pos+25] & 2)) {
@ -441,7 +441,7 @@ void GDCartridge::find_file(const char *name, const u8 *dir_sector, u32 &file_st
(dir_sector[pos+12] << 16) |
(dir_sector[pos+13] << 24));
printf("start %08x size %08x\n", file_start, file_size);
DEBUG_LOG(NAOMI, "start %08x size %08x", file_start, file_size);
break;
}
if (dir_sector[pos] == 0)
@ -470,7 +470,7 @@ void GDCartridge::device_start()
if (RomSize > 0 && gdrom_name != NULL)
{
if (RomSize >= 0x4000) {
printf("Real PIC binary found\n");
DEBUG_LOG(NAOMI, "Real PIC binary found");
for(int i=0;i<7;i++)
name[i] = picdata[0x7c0+i*2];
for(int i=0;i<7;i++)
@ -499,7 +499,7 @@ void GDCartridge::device_start()
(u64(picdata[0x29]) << 0));
}
printf("key is %08x%08x\n", (u32)((key & 0xffffffff00000000ULL)>>32), (u32)(key & 0x00000000ffffffffULL));
DEBUG_LOG(NAOMI, "key is %08x%08x", (u32)((key & 0xffffffff00000000ULL)>>32), (u32)(key & 0x00000000ffffffffULL));
u8 buffer[2048];
std::string gdrom_path = get_game_basename() + "/" + gdrom_name;
@ -507,7 +507,8 @@ void GDCartridge::device_start()
if (gdrom == NULL)
gdrom = OpenDisc((gdrom_path + ".gdi").c_str());
if (gdrom == NULL)
return;
throw NaomiCartException("Naomi GDROM: Cannot open " + gdrom_path + ".chd or " + gdrom_path + ".gdi");
// primary volume descriptor
// read frame 0xb06e (frame=sector+150)
// dimm board firmware starts straight from this frame
@ -564,6 +565,7 @@ void GDCartridge::device_start()
u32 file_rounded_size = (file_size + 2047) & -2048;
for (dimm_data_size = 4096; dimm_data_size < file_rounded_size; dimm_data_size <<= 1);
dimm_data = (u8 *)malloc(dimm_data_size);
verify(dimm_data != NULL);
if (dimm_data_size != file_rounded_size)
memset(dimm_data + file_rounded_size, 0, dimm_data_size - file_rounded_size);
@ -583,7 +585,7 @@ void GDCartridge::device_start()
delete gdrom;
if (!dimm_data)
printf("Naomi GDROM: Could not find the file to decrypt.\n");
throw NaomiCartException("Naomi GDROM: Could not find the file to decrypt.");
}
}
@ -593,6 +595,11 @@ void GDCartridge::device_reset()
}
void *GDCartridge::GetDmaPtr(u32 &size)
{
if (dimm_data == NULL)
{
size = 0;
return NULL;
}
dimm_cur_address = DmaOffset & (dimm_data_size-1);
size = min(size, dimm_data_size - dimm_cur_address);
return dimm_data + dimm_cur_address;
@ -607,6 +614,11 @@ void GDCartridge::AdvancePtr(u32 size)
bool GDCartridge::Read(u32 offset, u32 size, void *dst)
{
if (dimm_data == NULL)
{
*(u32 *)dst = 0;
return true;
}
u32 addr = offset & (dimm_data_size-1);
memcpy(dst, &dimm_data[addr], min(size, dimm_data_size - addr));
return true;

View File

@ -7,6 +7,8 @@
#include "hw/sh4/sh4_mem.h"
#include "hw/holly/holly_intc.h"
#include "hw/maple/maple_cfg.h"
#include "hw/sh4/sh4_sched.h"
#include "hw/sh4/modules/dmac.h"
#include "naomi.h"
#include "naomi_cart.h"
@ -55,7 +57,7 @@ unsigned int ShiftCRC(unsigned int CRC,unsigned int rounds)
return CRC;
}
unsigned short CRCSerial(unsigned char *Serial,unsigned int len)
unsigned short CRCSerial(const u8 *Serial,unsigned int len)
{
unsigned int CRC=0xDEBDEB00;
unsigned int i;
@ -339,23 +341,6 @@ u16 NaomiGameIDRead()
return (GSerialBuffer&(1<<(31-GBufPos)))?1:0;
}
u32 _ReadMem_naomi(u32 Addr, u32 sz)
{
verify(sz!=1);
EMUERROR("naomi?WTF? ReadMem: %X, %d", Addr, sz);
return 1;
}
void _WriteMem_naomi(u32 Addr, u32 data, u32 sz)
{
EMUERROR("naomi?WTF? WriteMem: %X <= %X, %d", Addr, data, sz);
}
//DIMM board
//Uses interrupt ext#3 (holly_EXT_PCI)
@ -381,35 +366,34 @@ void _WriteMem_naomi(u32 Addr, u32 data, u32 sz)
//n1 bios writes the value -1, meaning it expects the bit 0 to be set
//.//
u32 reg_dimm_3c; //IO window ! written, 0x1E03 some flag ?
u32 reg_dimm_40; //parameters
u32 reg_dimm_44; //parameters
u32 reg_dimm_48; //parameters
u32 reg_dimm_4c=0x11; //status/control reg ?
u32 reg_dimm_command; // command, written, 0x1E03 some flag ?
u32 reg_dimm_offsetl;
u32 reg_dimm_parameterl;
u32 reg_dimm_parameterh;
u32 reg_dimm_status = 0x11;
bool NaomiDataRead = false;
static bool aw_ram_test_skipped = false;
void naomi_process(u32 r3c,u32 r40,u32 r44, u32 r48)
void naomi_process(u32 command, u32 offsetl, u32 parameterl, u32 parameterh)
{
printf("Naomi process 0x%04X 0x%04X 0x%04X 0x%04X\n",r3c,r40,r44,r48);
printf("Possible format 0 %d 0x%02X 0x%04X\n",r3c>>15,(r3c&0x7e00)>>9,r3c&0x1FF);
printf("Possible format 1 0x%02X 0x%02X\n",(r3c&0xFF00)>>8,r3c&0xFF);
DEBUG_LOG(NAOMI, "Naomi process 0x%04X 0x%04X 0x%04X 0x%04X", command, offsetl, parameterl, parameterh);
DEBUG_LOG(NAOMI, "Possible format 0 %d 0x%02X 0x%04X",command >> 15,(command & 0x7e00) >> 9, command & 0x1FF);
DEBUG_LOG(NAOMI, "Possible format 1 0x%02X 0x%02X", (command & 0xFF00) >> 8,command & 0xFF);
u32 param=(r3c&0xFF);
u32 param=(command&0xFF);
if (param==0xFF)
{
printf("invalid opcode or smth ?");
DEBUG_LOG(NAOMI, "invalid opcode or smth ?");
}
static int opcd=0;
//else if (param!=3)
if (opcd<255)
{
reg_dimm_3c=0x8000 | (opcd%12<<9) | (0x0);
printf("new reg is 0x%X\n",reg_dimm_3c);
reg_dimm_command=0x8000 | (opcd%12<<9) | (0x0);
DEBUG_LOG(NAOMI, "new reg is 0x%X", reg_dimm_command);
asic_RaiseInterrupt(holly_EXP_PCI);
printf("Interrupt raised\n");
DEBUG_LOG(NAOMI, "Interrupt raised");
opcd++;
}
}
@ -419,7 +403,7 @@ u32 ReadMem_naomi(u32 Addr, u32 sz)
verify(sz!=1);
if (unlikely(CurrentCartridge == NULL))
{
EMUERROR("called without cartridge\n");
INFO_LOG(NAOMI, "called without cartridge");
return 0xFFFF;
}
return CurrentCartridge->ReadMem(Addr, sz);
@ -429,7 +413,7 @@ void WriteMem_naomi(u32 Addr, u32 data, u32 sz)
{
if (unlikely(CurrentCartridge == NULL))
{
EMUERROR("called without cartridge\n");
INFO_LOG(NAOMI, "called without cartridge");
return;
}
CurrentCartridge->WriteMem(Addr, data, sz);
@ -440,7 +424,7 @@ void Naomi_DmaStart(u32 addr, u32 data)
{
if (SB_GDEN==0)
{
printf("Invalid (NAOMI)GD-DMA start, SB_GDEN=0.Ingoring it.\n");
INFO_LOG(NAOMI, "Invalid (NAOMI)GD-DMA start, SB_GDEN=0. Ignoring it.");
return;
}
@ -450,11 +434,12 @@ void Naomi_DmaStart(u32 addr, u32 data)
if (SB_GDST==1)
{
verify(1 == SB_GDDIR );
SB_GDSTARD=SB_GDSTAR+SB_GDLEN;
DEBUG_LOG(NAOMI, "NAOMI-DMA start addr %08X len %d", SB_GDSTAR, SB_GDLEN);
SB_GDSTARD = SB_GDSTAR + SB_GDLEN;
SB_GDLEND=SB_GDLEN;
SB_GDST=0;
SB_GDLEND = SB_GDLEN;
SB_GDST = 0;
if (CurrentCartridge != NULL)
{
u32 len = SB_GDLEN;
@ -463,6 +448,11 @@ void Naomi_DmaStart(u32 addr, u32 data)
{
u32 block_len = len;
void* ptr = CurrentCartridge->GetDmaPtr(block_len);
if (block_len == 0)
{
INFO_LOG(NAOMI, "Aborted DMA transfer. Read past end of cart?");
break;
}
WriteMemBlock_nommu_ptr(SB_GDSTAR + offset, (u32*)ptr, block_len);
CurrentCartridge->AdvancePtr(block_len);
len -= block_len;
@ -480,7 +470,7 @@ void Naomi_DmaEnable(u32 addr, u32 data)
SB_GDEN=data&1;
if (SB_GDEN==0 && SB_GDST==1)
{
printf("(NAOMI)GD-DMA aborted\n");
INFO_LOG(NAOMI, "(NAOMI)GD-DMA aborted");
SB_GDST=0;
}
}
@ -532,10 +522,6 @@ void naomi_reg_Init()
}
#endif
NaomiInit();
sb_rio_register(SB_GDST_addr, RIO_WF, 0, &Naomi_DmaStart);
sb_rio_register(SB_GDEN_addr, RIO_WF, 0, &Naomi_DmaEnable);
}
void naomi_reg_Term()
@ -551,96 +537,50 @@ void naomi_reg_Term()
}
#endif
}
void naomi_reg_Reset(bool Manual)
void naomi_reg_Reset(bool hard)
{
sb_rio_register(SB_GDST_addr, RIO_WF, 0, &Naomi_DmaStart);
sb_rio_register(SB_GDEN_addr, RIO_WF, 0, &Naomi_DmaEnable);
SB_GDST = 0;
SB_GDEN = 0;
NaomiDataRead = false;
aw_ram_test_skipped = false;
GSerialBuffer = 0;
BSerialBuffer = 0;
GBufPos = 0;
BBufPos = 0;
GState = 0;
BState = 0;
GOldClk = 0;
BOldClk = 0;
BControl = 0;
BCmd = 0;
BLastCmd = 0;
}
void Update_naomi()
{
/*
if (naomi_updates>1)
{
naomi_updates--;
}
else if (naomi_updates==1)
{
naomi_updates=0;
asic_RaiseInterrupt(holly_EXP_PCI);
}*/
#if 0
if(!(SB_GDST&1) || !(SB_GDEN &1))
return;
//SB_GDST=0;
//TODO : Fix dmaor
u32 dmaor = DMAC_DMAOR.full;
u32 src = SB_GDSTARD,
len = SB_GDLEN-SB_GDLEND ;
//len=min(len,(u32)32);
// do we need to do this for gdrom dma ?
if(0x8201 != (dmaor &DMAOR_MASK)) {
printf("\n!\tGDROM: DMAOR has invalid settings (%X) !\n", dmaor);
//return;
}
if(len & 0x1F) {
printf("\n!\tGDROM: SB_GDLEN has invalid size (%X) !\n", len);
return;
}
if(0 == len)
{
printf("\n!\tGDROM: Len: %X, Abnormal Termination !\n", len);
}
u32 len_backup=len;
if( 1 == SB_GDDIR )
{
WriteMemBlock_nommu_ptr(dst,NaomiRom+(DmaOffset&0x7ffffff),size);
DmaCount=0xffff;
}
else
msgboxf(L"GDROM: SB_GDDIR %X (TO AICA WAVE MEM?)",MBX_ICONERROR, SB_GDDIR);
//SB_GDLEN = 0x00000000; //13/5/2k7 -> acording to docs these regs are not updated by hardware
//SB_GDSTAR = (src + len_backup);
SB_GDLEND+= len_backup;
SB_GDSTARD+= len_backup;//(src + len_backup)&0x1FFFFFFF;
if (SB_GDLEND==SB_GDLEN)
{
//printf("Streamed GDMA end - %d bytes trasnfered\n",SB_GDLEND);
SB_GDST=0;//done
// The DMA end interrupt flag
asic_RaiseInterrupt(holly_GDROM_DMA);
}
//Readed ALL sectors
if (read_params.remaining_sectors==0)
{
u32 buff_size =read_buff.cache_size - read_buff.cache_index;
//And all buffer :p
if (buff_size==0)
{
verify(!SB_GDST&1)
gd_set_state(gds_procpacketdone);
}
}
#endif
GControl = 0;
GCmd = 0;
GLastCmd = 0;
SerStep = 0;
SerStep2 = 0;
reg_dimm_command = 0;
reg_dimm_offsetl = 0;
reg_dimm_parameterl = 0;
reg_dimm_parameterh = 0;
reg_dimm_status = 0x11;
}
static u8 aw_maple_devs;
static u64 coin_chute_time[4];
u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
addr &= 0x7ff;
//printf("libExtDevice_ReadMem_A0_006 %d@%08x: %x\n", size, addr, mem600[addr]);
switch (addr)
{
// case 0:
// return 0;
// case 4:
// return 1;
case 0x280:
// 0x00600280 r 0000dcba
// a/b - 1P/2P coin inputs (JAMMA), active low
@ -655,9 +595,25 @@ u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
}
{
u8 coin_input = 0xF;
u64 now = sh4_sched_now64();
for (int slot = 0; slot < 4; slot++)
{
if (maple_atomiswave_coin_chute(slot))
coin_input &= ~(1 << slot);
{
// ggx15 needs 4 or 5 reads to register the coin but it needs to be limited to avoid coin errors
// 1 s of cpu time is too much, 1/2 s seems to work, let's use 100 ms
if (coin_chute_time[slot] == 0 || now - coin_chute_time[slot] < SH4_MAIN_CLOCK / 10)
{
if (coin_chute_time[slot] == 0)
coin_chute_time[slot] = now;
coin_input &= ~(1 << slot);
}
}
else
{
coin_chute_time[slot] = 0;
}
}
return coin_input;
}
@ -673,7 +629,7 @@ u32 libExtDevice_ReadMem_A0_006(u32 addr,u32 size) {
return 0;
}
EMUERROR("Unhandled read @ %x sz %d", addr, size);
INFO_LOG(NAOMI, "Unhandled read @ %x sz %d", addr, size);
return 0xFF;
}
@ -683,7 +639,7 @@ void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size) {
switch (addr)
{
case 0x284: // Atomiswave maple devices
printf("NAOMI 600284 write %x\n", data);
DEBUG_LOG(NAOMI, "NAOMI 600284 write %x", data);
aw_maple_devs = data & 0xF0;
return;
case 0x288:
@ -693,5 +649,5 @@ void libExtDevice_WriteMem_A0_006(u32 addr,u32 data,u32 size) {
default:
break;
}
EMUERROR("Unhandled write @ %x (%d): %x", addr, size, data);
INFO_LOG(NAOMI, "Unhandled write @ %x (%d): %x", addr, size, data);
}

View File

@ -8,8 +8,6 @@ void naomi_reg_Init();
void naomi_reg_Term();
void naomi_reg_Reset(bool Manual);
void Update_naomi();
u32 ReadMem_naomi(u32 Addr, u32 sz);
void WriteMem_naomi(u32 Addr, u32 data, u32 sz);
@ -20,21 +18,11 @@ u16 NaomiGameIDRead();
void NaomiGameIDWrite(const u16 Data);
void naomi_process(u32 r3c,u32 r40,u32 r44, u32 r48);
typedef u16 (*getNaomiAxisFP)();
struct NaomiInputMapping {
getNaomiAxisFP axis[8];
u8 button_mapping_byte[16];
u8 button_mapping_mask[16];
};
extern NaomiInputMapping Naomi_Mapping;
extern u32 reg_dimm_3c; //IO window ! written, 0x1E03 some flag ?
extern u32 reg_dimm_40; //parameters
extern u32 reg_dimm_44; //parameters
extern u32 reg_dimm_48; //parameters
extern u32 reg_dimm_4c; //status/control reg ?
extern u32 reg_dimm_command; // command, written, 0x1E03 some flag ?
extern u32 reg_dimm_offsetl;
extern u32 reg_dimm_parameterl;
extern u32 reg_dimm_parameterh;
extern u32 reg_dimm_status;
extern bool NaomiDataRead;
extern u32 naomi_updates;

View File

@ -1,3 +1,25 @@
/*
This file is part of reicast.
reicast is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
reicast is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with reicast. If not, see <https://www.gnu.org/licenses/>.
*/
// Naomi comm board emulation from mame
// https://github.com/mamedev/mame/blob/master/src/mame/machine/m3comm.cpp
// license:BSD-3-Clause
// copyright-holders:MetalliC
#include <memory>
#include "naomi_cart.h"
#include "naomi_regs.h"
#include "cfg/cfg.h"
@ -34,7 +56,7 @@ char naomi_game_id[33];
InputDescriptors *NaomiGameInputs;
u8 *naomi_default_eeprom;
extern RomChip sys_rom;
extern MemChip *sys_rom;
static bool naomi_LoadBios(const char *filename, Archive *child_archive, Archive *parent_archive, int region)
{
@ -44,18 +66,14 @@ static bool naomi_LoadBios(const char *filename, Archive *child_archive, Archive
break;
if (BIOS[biosid].name == NULL)
{
printf("Unknown BIOS %s\n", filename);
WARN_LOG(NAOMI, "Unknown BIOS %s", filename);
return false;
}
struct BIOS_t *bios = &BIOS[biosid];
#if HOST_OS != OS_DARWIN
std::string basepath = get_readonly_data_path("/data/");
#else
std::string basepath = get_readonly_data_path("/");
#endif
Archive *bios_archive = OpenArchive((basepath + filename).c_str());
std::string basepath = get_readonly_data_path(DATA_PATH);
std::unique_ptr<Archive> bios_archive(OpenArchive((basepath + filename).c_str()));
bool found_region = false;
@ -73,71 +91,66 @@ static bool naomi_LoadBios(const char *filename, Archive *child_archive, Archive
{
verify(bios->blobs[romid].offset + bios->blobs[romid].length <= BIOS_SIZE);
verify(bios->blobs[romid].src_offset + bios->blobs[romid].length <= BIOS_SIZE);
memcpy(sys_rom.data + bios->blobs[romid].offset, sys_rom.data + bios->blobs[romid].src_offset, bios->blobs[romid].length);
printf("Copied: %x bytes from %07x to %07x\n", bios->blobs[romid].length, bios->blobs[romid].src_offset, bios->blobs[romid].offset);
memcpy(sys_rom->data + bios->blobs[romid].offset, sys_rom->data + bios->blobs[romid].src_offset, bios->blobs[romid].length);
DEBUG_LOG(NAOMI, "Copied: %x bytes from %07x to %07x", bios->blobs[romid].length, bios->blobs[romid].src_offset, bios->blobs[romid].offset);
}
else
{
ArchiveFile *file = NULL;
std::unique_ptr<ArchiveFile> file;
if (child_archive != NULL)
file = child_archive->OpenFile(bios->blobs[romid].filename);
if (file == NULL && parent_archive != NULL)
file = parent_archive->OpenFile(bios->blobs[romid].filename);
if (file == NULL && bios_archive != NULL)
file = bios_archive->OpenFile(bios->blobs[romid].filename);
file.reset(child_archive->OpenFile(bios->blobs[romid].filename));
if (!file && parent_archive != NULL)
file.reset(parent_archive->OpenFile(bios->blobs[romid].filename));
if (!file && bios_archive != NULL)
file.reset(bios_archive->OpenFile(bios->blobs[romid].filename));
if (!file) {
printf("%s: Cannot open %s\n", filename, bios->blobs[romid].filename);
goto error;
WARN_LOG(NAOMI, "%s: Cannot open %s", filename, bios->blobs[romid].filename);
return false;
}
if (bios->blobs[romid].blob_type == Normal)
switch (bios->blobs[romid].blob_type)
{
verify(bios->blobs[romid].offset + bios->blobs[romid].length <= BIOS_SIZE);
u32 read = file->Read(sys_rom.data + bios->blobs[romid].offset, bios->blobs[romid].length);
printf("Mapped %s: %x bytes at %07x\n", bios->blobs[romid].filename, read, bios->blobs[romid].offset);
}
else if (bios->blobs[romid].blob_type == InterleavedWord)
{
u8 *buf = (u8 *)malloc(bios->blobs[romid].length);
if (buf == NULL)
case Normal:
{
printf("malloc failed\n");
delete file;
goto error;
verify(bios->blobs[romid].offset + bios->blobs[romid].length <= BIOS_SIZE);
u32 read = file->Read(sys_rom->data + bios->blobs[romid].offset, bios->blobs[romid].length);
DEBUG_LOG(NAOMI, "Mapped %s: %x bytes at %07x", bios->blobs[romid].filename, read, bios->blobs[romid].offset);
}
verify(bios->blobs[romid].offset + bios->blobs[romid].length <= BIOS_SIZE);
u32 read = file->Read(buf, bios->blobs[romid].length);
u16 *to = (u16 *)(sys_rom.data + bios->blobs[romid].offset);
u16 *from = (u16 *)buf;
for (int i = bios->blobs[romid].length / 2; --i >= 0; to++)
*to++ = *from++;
free(buf);
printf("Mapped %s: %x bytes (interleaved word) at %07x\n", bios->blobs[romid].filename, read, bios->blobs[romid].offset);
}
else
break;
case InterleavedWord:
{
u8 *buf = (u8 *)malloc(bios->blobs[romid].length);
if (buf == NULL)
throw NaomiCartException(std::string("Memory allocation failed"));
verify(bios->blobs[romid].offset + bios->blobs[romid].length <= BIOS_SIZE);
u32 read = file->Read(buf, bios->blobs[romid].length);
u16 *to = (u16 *)(sys_rom->data + bios->blobs[romid].offset);
u16 *from = (u16 *)buf;
for (int i = bios->blobs[romid].length / 2; --i >= 0; to++)
*to++ = *from++;
free(buf);
DEBUG_LOG(NAOMI, "Mapped %s: %x bytes (interleaved word) at %07x", bios->blobs[romid].filename, read, bios->blobs[romid].offset);
}
break;
default:
die("Unknown blob type\n");
delete file;
break;
}
}
}
if (bios_archive != NULL)
delete bios_archive;
#if DC_PLATFORM == DC_PLATFORM_ATOMISWAVE
// Reload the writeable portion of the FlashROM
sys_rom.Reload();
#endif
if (settings.platform.system == DC_PLATFORM_ATOMISWAVE)
// Reload the writeable portion of the FlashROM
sys_rom->Reload();
return found_region;
error:
if (bios_archive != NULL)
delete bios_archive;
return false;
}
static bool naomi_cart_LoadZip(char *filename)
static Game *FindGame(const char *filename)
{
char *p = strrchr(filename, '/');
const char *p = strrchr(filename, '/');
#ifdef _WIN32
p = strrchr(p == NULL ? filename : p, '\\');
#endif
@ -157,195 +170,182 @@ static bool naomi_cart_LoadZip(char *filename)
if (!stricmp(Games[gameid].name, game_name))
break;
if (Games[gameid].name == NULL)
{
printf("Unknown game %s\n", filename);
return false;
}
return NULL;
struct Game *game = &Games[gameid];
#if DC_PLATFORM == DC_PLATFORM_NAOMI
if (game->cart_type == AW)
{
msgboxf("Atomiswave cartridges are not supported by NAOMI", 0);
return false;
}
#else
if (game->cart_type != AW)
{
msgboxf("NAOMI cartridges are not supported by Atomiswave", 0);
return false;
}
#endif
Archive *archive = OpenArchive(filename);
return &Games[gameid];
}
static void naomi_cart_LoadZip(const char *filename)
{
Game *game = FindGame(filename);
if (game == NULL)
throw NaomiCartException("Unknown game");
// Open archive and parent archive if any
std::unique_ptr<Archive> archive(OpenArchive(filename));
if (archive != NULL)
printf("Opened %s\n", filename);
INFO_LOG(NAOMI, "Opened %s", filename);
Archive *parent_archive = NULL;
std::unique_ptr<Archive> parent_archive;
if (game->parent_name != NULL)
{
parent_archive = OpenArchive((get_game_dir() + game->parent_name).c_str());
parent_archive.reset(OpenArchive((get_game_dir() + game->parent_name).c_str()));
if (parent_archive != NULL)
printf("Opened %s\n", game->parent_name);
INFO_LOG(NAOMI, "Opened %s", game->parent_name);
}
if (archive == NULL && parent_archive == NULL)
{
if (game->parent_name != NULL)
printf("Cannot open %s or %s\n", filename, game->parent_name);
throw NaomiCartException(std::string("Cannot open ") + filename + std::string(" or ") + game->parent_name);
else
printf("Cannot open %s\n", filename);
return false;
throw NaomiCartException(std::string("Cannot open ") + filename);
}
// Load the BIOS
const char *bios = "naomi";
if (game->bios != NULL)
bios = game->bios;
u32 region_flag = settings.dreamcast.region;
if (region_flag > game->region_flag)
region_flag = game->region_flag;
if (!naomi_LoadBios(bios, archive, parent_archive, region_flag))
if (!naomi_LoadBios(bios, archive.get(), parent_archive.get(), region_flag))
{
printf("Warning: Region %d bios not found in %s\n", region_flag, bios);
if (!naomi_LoadBios(bios, archive, parent_archive, -1))
WARN_LOG(NAOMI, "Warning: Region %d bios not found in %s", region_flag, bios);
if (!naomi_LoadBios(bios, archive.get(), parent_archive.get(), -1))
{
// If a specific BIOS is needed for this game, fail.
if (game->bios != NULL || !bios_loaded)
{
printf("Error: cannot load BIOS. Exiting\n");
return false;
}
throw NaomiCartException(std::string("Error: cannot load BIOS ") + (game->bios != NULL ? game->bios : "naomi.zip") + " in " + get_readonly_data_path(DATA_PATH));
// otherwise use the default BIOS
}
}
bios_loaded = true;
switch (game->cart_type)
{
case M1:
CurrentCartridge = new M1Cartridge(game->size);
break;
case M2:
CurrentCartridge = new M2Cartridge(game->size);
break;
case M4:
CurrentCartridge = new M4Cartridge(game->size);
break;
case AW:
CurrentCartridge = new AWCartridge(game->size);
break;
case GD:
// Now load the cartridge data
try {
switch (game->cart_type)
{
GDCartridge *gdcart = new GDCartridge(game->size);
gdcart->SetGDRomName(game->gdrom_name);
CurrentCartridge = gdcart;
}
break;
default:
die("Unsupported cartridge type\n");
break;
}
CurrentCartridge->SetKey(game->key);
NaomiGameInputs = game->inputs;
for (int romid = 0; game->blobs[romid].filename != NULL; romid++)
{
u32 len = game->blobs[romid].length;
if (game->blobs[romid].blob_type == Copy)
{
u8 *dst = (u8 *)CurrentCartridge->GetPtr(game->blobs[romid].offset, len);
u8 *src = (u8 *)CurrentCartridge->GetPtr(game->blobs[romid].src_offset, len);
memcpy(dst, src, game->blobs[romid].length);
printf("Copied: %x bytes from %07x to %07x\n", game->blobs[romid].length, game->blobs[romid].src_offset, game->blobs[romid].offset);
}
else
{
ArchiveFile* file = NULL;
if (archive != NULL)
file = archive->OpenFile(game->blobs[romid].filename);
if (file == NULL && parent_archive != NULL)
file = parent_archive->OpenFile(game->blobs[romid].filename);
if (!file) {
printf("%s: Cannot open %s\n", filename, game->blobs[romid].filename);
if (game->blobs[romid].blob_type != Eeprom)
// Default eeprom file is optional
goto error;
else
continue;
case M1:
CurrentCartridge = new M1Cartridge(game->size);
break;
case M2:
CurrentCartridge = new M2Cartridge(game->size);
break;
case M4:
CurrentCartridge = new M4Cartridge(game->size);
break;
case AW:
CurrentCartridge = new AWCartridge(game->size);
break;
case GD:
{
GDCartridge *gdcart = new GDCartridge(game->size);
gdcart->SetGDRomName(game->gdrom_name);
CurrentCartridge = gdcart;
}
if (game->blobs[romid].blob_type == Normal)
break;
default:
die("Unsupported cartridge type\n");
break;
}
CurrentCartridge->SetKey(game->key);
NaomiGameInputs = game->inputs;
for (int romid = 0; game->blobs[romid].filename != NULL; romid++)
{
u32 len = game->blobs[romid].length;
if (game->blobs[romid].blob_type == Copy)
{
u8 *dst = (u8 *)CurrentCartridge->GetPtr(game->blobs[romid].offset, len);
u32 read = file->Read(dst, game->blobs[romid].length);
printf("Mapped %s: %x bytes at %07x\n", game->blobs[romid].filename, read, game->blobs[romid].offset);
}
else if (game->blobs[romid].blob_type == InterleavedWord)
{
u8 *buf = (u8 *)malloc(game->blobs[romid].length);
if (buf == NULL)
{
printf("malloc failed\n");
delete file;
goto error;
}
u32 read = file->Read(buf, game->blobs[romid].length);
u16 *to = (u16 *)CurrentCartridge->GetPtr(game->blobs[romid].offset, len);
u16 *from = (u16 *)buf;
for (int i = game->blobs[romid].length / 2; --i >= 0; to++)
*to++ = *from++;
free(buf);
printf("Mapped %s: %x bytes (interleaved word) at %07x\n", game->blobs[romid].filename, read, game->blobs[romid].offset);
}
else if (game->blobs[romid].blob_type == Key)
{
u8 *buf = (u8 *)malloc(game->blobs[romid].length);
if (buf == NULL)
{
printf("malloc failed\n");
delete file;
goto error;
}
u32 read = file->Read(buf, game->blobs[romid].length);
CurrentCartridge->SetKeyData(buf);
printf("Loaded %s: %x bytes cart key\n", game->blobs[romid].filename, read);
}
else if (game->blobs[romid].blob_type == Eeprom)
{
naomi_default_eeprom = (u8 *)malloc(game->blobs[romid].length);
if (naomi_default_eeprom == NULL)
{
printf("malloc failed\n");
delete file;
goto error;
}
u32 read = file->Read(naomi_default_eeprom, game->blobs[romid].length);
printf("Loaded %s: %x bytes default eeprom\n", game->blobs[romid].filename, read);
u8 *src = (u8 *)CurrentCartridge->GetPtr(game->blobs[romid].src_offset, len);
memcpy(dst, src, game->blobs[romid].length);
DEBUG_LOG(NAOMI, "Copied: %x bytes from %07x to %07x", game->blobs[romid].length, game->blobs[romid].src_offset, game->blobs[romid].offset);
}
else
die("Unknown blob type\n");
delete file;
{
std::unique_ptr<ArchiveFile> file;
if (archive != NULL)
file.reset(archive->OpenFile(game->blobs[romid].filename));
if (file == NULL && parent_archive != NULL)
file.reset(parent_archive->OpenFile(game->blobs[romid].filename));
if (!file) {
WARN_LOG(NAOMI, "%s: Cannot open %s", filename, game->blobs[romid].filename);
if (game->blobs[romid].blob_type != Eeprom)
// Default eeprom file is optional
throw NaomiCartException(std::string("Cannot find ") + game->blobs[romid].filename);
else
continue;
}
switch (game->blobs[romid].blob_type)
{
case Normal:
{
u8 *dst = (u8 *)CurrentCartridge->GetPtr(game->blobs[romid].offset, len);
u32 read = file->Read(dst, game->blobs[romid].length);
DEBUG_LOG(NAOMI, "Mapped %s: %x bytes at %07x", game->blobs[romid].filename, read, game->blobs[romid].offset);
}
break;
case InterleavedWord:
{
u8 *buf = (u8 *)malloc(game->blobs[romid].length);
if (buf == NULL)
throw NaomiCartException(std::string("Memory allocation failed"));
u32 read = file->Read(buf, game->blobs[romid].length);
u16 *to = (u16 *)CurrentCartridge->GetPtr(game->blobs[romid].offset, len);
u16 *from = (u16 *)buf;
for (int i = game->blobs[romid].length / 2; --i >= 0; to++)
*to++ = *from++;
free(buf);
DEBUG_LOG(NAOMI, "Mapped %s: %x bytes (interleaved word) at %07x", game->blobs[romid].filename, read, game->blobs[romid].offset);
}
break;
case Key:
{
u8 *buf = (u8 *)malloc(game->blobs[romid].length);
if (buf == NULL)
throw NaomiCartException(std::string("Memory allocation failed"));
u32 read = file->Read(buf, game->blobs[romid].length);
CurrentCartridge->SetKeyData(buf);
DEBUG_LOG(NAOMI, "Loaded %s: %x bytes cart key", game->blobs[romid].filename, read);
}
break;
case Eeprom:
{
naomi_default_eeprom = (u8 *)malloc(game->blobs[romid].length);
if (naomi_default_eeprom == NULL)
throw NaomiCartException(std::string("Memory allocation failed"));
u32 read = file->Read(naomi_default_eeprom, game->blobs[romid].length);
DEBUG_LOG(NAOMI, "Loaded %s: %x bytes default eeprom", game->blobs[romid].filename, read);
}
break;
default:
die("Unknown blob type\n");
break;
}
}
}
CurrentCartridge->Init();
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
} catch (ReicastException& ex) {
delete CurrentCartridge;
CurrentCartridge = NULL;
throw ex;
}
if (archive != NULL)
delete archive;
if (parent_archive != NULL)
delete parent_archive;
CurrentCartridge->Init();
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
printf("NAOMI GAME ID [%s]\n", naomi_game_id);
return true;
error:
if (archive != NULL)
delete archive;
if (parent_archive != NULL)
delete parent_archive;
delete CurrentCartridge;
CurrentCartridge = NULL;
return false;
}
#if HOST_OS == OS_WINDOWS
@ -354,9 +354,9 @@ error:
#define CloseFile(f) close(f)
#endif
bool naomi_cart_LoadRom(char* file)
void naomi_cart_LoadRom(const char* file)
{
printf("\nnullDC-Naomi rom loader v1.2\n");
INFO_LOG(NAOMI, "nullDC-Naomi rom loader v1.2");
naomi_cart_Close();
@ -377,25 +377,25 @@ bool naomi_cart_LoadRom(char* file)
u32 setsize = 0;
bool raw_bin_file = false;
char *pdot = strrchr(file, '.');
const char *pdot = strrchr(file, '.');
if (pdot != NULL
&& (!strcmp(pdot, ".zip") || !strcmp(pdot, ".ZIP")
|| !strcmp(pdot, ".7z") || !strcmp(pdot, ".7Z")))
return naomi_cart_LoadZip(file);
{
naomi_cart_LoadZip(file);
return;
}
// Try to load BIOS from naomi.zip
if (!naomi_LoadBios("naomi", NULL, NULL, settings.dreamcast.region))
{
printf("Warning: Region %d bios not found in naomi.zip\n", settings.dreamcast.region);
if (!naomi_LoadBios("naomi", NULL, NULL, -1))
{
if (!bios_loaded)
{
printf("Error: cannot load BIOS. Exiting\n");
return false;
}
}
WARN_LOG(NAOMI, "Warning: Region %d bios not found in naomi.zip", settings.dreamcast.region);
if (!naomi_LoadBios("naomi", NULL, NULL, -1))
{
if (!bios_loaded)
throw new ReicastException("Error: cannot load BIOS from naomi.zip");
}
}
u8* RomPtr;
@ -407,28 +407,28 @@ bool naomi_cart_LoadRom(char* file)
FILE* fl = fopen(t, "r");
if (!fl)
return false;
throw new ReicastException("Error: can't open " + std::string(t));
char* line = fgets(t, 512, fl);
if (!line)
{
fclose(fl);
return false;
throw new ReicastException("Error: Invalid LST file");
}
char* eon = strstr(line, "\n");
if (!eon)
printf("+Loading naomi rom that has no name\n");
DEBUG_LOG(NAOMI, "+Loading naomi rom that has no name");
else
*eon = 0;
printf("+Loading naomi rom : %s\n", line);
DEBUG_LOG(NAOMI, "+Loading naomi rom : %s", line);
line = fgets(t, 512, fl);
if (!line)
{
fclose(fl);
return false;
throw new ReicastException("Error: Invalid LST file");
}
RomSize = 0;
@ -446,7 +446,7 @@ bool naomi_cart_LoadRom(char* file)
RomSize = max(RomSize, (addr + sz));
}
else if (line[0] != 0 && line[0] != '\n' && line[0] != '\r')
printf("Warning: invalid line in .lst file: %s\n", line);
WARN_LOG(NAOMI, "Warning: invalid line in .lst file: %s", line);
line = fgets(t, 512, fl);
}
@ -457,7 +457,7 @@ bool naomi_cart_LoadRom(char* file)
// BIN loading
FILE* fp = fopen(t, "rb");
if (fp == NULL)
return false;
throw new ReicastException("Error: can't open " + std::string(t));
fseek(fp, 0, SEEK_END);
u32 file_size = ftell(fp);
@ -470,7 +470,7 @@ bool naomi_cart_LoadRom(char* file)
raw_bin_file = true;
}
printf("+%ld romfiles, %.2f MB set size, %.2f MB set address space\n", files.size(), setsize / 1024.f / 1024.f, RomSize / 1024.f / 1024.f);
INFO_LOG(NAOMI, "+%zd romfiles, %.2f MB set size, %.2f MB set address space", files.size(), setsize / 1024.f / 1024.f, RomSize / 1024.f / 1024.f);
if (RomCacheMap)
{
@ -520,7 +520,7 @@ bool naomi_cart_LoadRom(char* file)
#endif
if (RomCache == INVALID_FD)
{
printf("-Unable to read file %s: error %d\n", t, errno);
ERROR_LOG(NAOMI, "-Unable to read file %s: error %d", t, errno);
RomCacheMap[i] = INVALID_FD;
load_error = true;
break;
@ -550,7 +550,7 @@ bool naomi_cart_LoadRom(char* file)
for (size_t i = 0; i < files.size(); i++)
if (RomCacheMap[i] != INVALID_FD)
CloseFile(RomCacheMap[i]);
return false;
throw new ReicastException("Error: Failed to load BIN/DAT file");
}
//We have all file mapping objects, we start to map the ram
@ -572,20 +572,20 @@ bool naomi_cart_LoadRom(char* file)
bool mapped = RomDest == (u8 *)mem_region_map_file((void *)(uintptr_t)RomCacheMap[i], RomDest, fsize[i], 0, false);
if (!mapped)
{
printf("-Mapping ROM FAILED: %s @ %08x size %x\n", files[i].c_str(), fstart[i], fsize[i]);
return false;
ERROR_LOG(NAOMI, "-Mapping ROM FAILED: %s @ %08x size %x", files[i].c_str(), fstart[i], fsize[i]);
throw new ReicastException("Memory mapping of ROM failed");
}
}
}
//done :)
printf("\nMapped ROM Successfully !\n\n");
INFO_LOG(NAOMI, "Mapped ROM Successfully !");
CurrentCartridge = new DecryptedCartridge(RomPtr, RomSize);
strcpy(naomi_game_id, CurrentCartridge->GetGameId().c_str());
printf("NAOMI GAME ID [%s]\n", naomi_game_id);
NOTICE_LOG(NAOMI, "NAOMI GAME ID [%s]", naomi_game_id);
return true;
return;
}
void naomi_cart_Close()
@ -604,23 +604,18 @@ void naomi_cart_Close()
delete[] RomCacheMap;
RomCacheMap = NULL;
}
bios_loaded = false;
}
bool naomi_cart_SelectFile()
int naomi_cart_GetPlatform(const char *path)
{
char SelectedFile[512];
cfgLoadStr("config", "image", SelectedFile, "null");
if (!naomi_cart_LoadRom(SelectedFile))
{
printf("Cannot load %s: error %d\n", SelectedFile, errno);
cfgSetVirtual("config", "image", "");
return false;
}
return true;
Game *game = FindGame(path);
if (game == NULL)
return DC_PLATFORM_NAOMI;
else if (game->cart_type == AW)
return DC_PLATFORM_ATOMISWAVE;
else
return DC_PLATFORM_NAOMI;
}
Cartridge::Cartridge(u32 size)
@ -644,7 +639,7 @@ bool Cartridge::Read(u32 offset, u32 size, void* dst)
static u32 ones = 0xffffffff;
// Makes Outtrigger boot
EMUERROR("offset %d > %d\n", offset, RomSize);
INFO_LOG(NAOMI, "offset %d > %d", offset, RomSize);
memcpy(dst, &ones, size);
}
else
@ -657,7 +652,7 @@ bool Cartridge::Read(u32 offset, u32 size, void* dst)
bool Cartridge::Write(u32 offset, u32 size, u32 data)
{
EMUERROR("Invalid write @ %08x data %x\n", offset, data);
INFO_LOG(NAOMI, "Invalid write @ %08x data %x", offset, data);
return false;
}
@ -689,7 +684,7 @@ void* NaomiCartridge::GetDmaPtr(u32& size)
{
if ((DmaOffset & 0x1fffffff) >= RomSize)
{
EMUERROR("Error: DmaOffset >= RomSize\n");
INFO_LOG(NAOMI, "Error: DmaOffset >= RomSize");
size = 0;
return NULL;
}
@ -703,23 +698,25 @@ void NaomiCartridge::AdvancePtr(u32 size) {
u32 NaomiCartridge::ReadMem(u32 address, u32 size)
{
verify(size!=1);
//printf("+naomi?WTF? ReadMem: %X, %d\n", address, size);
switch(address & 255)
{
case 0x3c:
EMUERROR("naomi GD? READ: %X, %d", address, size);
return reg_dimm_3c | (NaomiDataRead ? 0 : -1); //pretend the board isn't there for the bios
case 0x40:
EMUERROR("naomi GD? READ: %X, %d", address, size);
return reg_dimm_40;
case 0x44:
EMUERROR("naomi GD? READ: %X, %d", address, size);
return reg_dimm_44;
case 0x48:
EMUERROR("naomi GD? READ: %X, %d", address, size);
return reg_dimm_48;
case 0x3c: // 5f703c: DIMM COMMAND
DEBUG_LOG(NAOMI, "DIMM COMMAND read<%d>", size);
return reg_dimm_command | (NaomiDataRead ? 0 : -1); //pretend the board isn't there for the bios
case 0x40: // 5f7040: DIMM OFFSETL
DEBUG_LOG(NAOMI, "DIMM OFFSETL read<%d>", size);
return reg_dimm_offsetl;
case 0x44: // 5f7044: DIMM PARAMETERL
DEBUG_LOG(NAOMI, "DIMM PARAMETERL read<%d>", size);
return reg_dimm_parameterl;
case 0x48: // 5f7048: DIMM PARAMETERH
DEBUG_LOG(NAOMI, "DIMM PARAMETERH read<%d>", size);
return reg_dimm_parameterh;
case 0x04C: // 5f704c: DIMM STATUS
DEBUG_LOG(NAOMI, "DIMM STATUS read<%d>", size);
return reg_dimm_status;
//These are known to be valid on normal ROMs and DIMM board
case NAOMI_ROM_OFFSETH_addr&255:
return RomPioOffset>>16 | (RomPioAutoIncrement << 15);
@ -745,12 +742,12 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
//What should i do to emulate 'nothing' ?
case NAOMI_COMM_OFFSET_addr&255:
#ifdef NAOMI_COMM
printf("naomi COMM offs READ: %X, %d\n", address, size);
DEBUG_LOG(NAOMI, "naomi COMM offs READ: %X, %d", address, size);
return CommOffset;
#endif
case NAOMI_COMM_DATA_addr&255:
#ifdef NAOMI_COMM
printf("naomi COMM data read: %X, %d\n", CommOffset, size);
DEBUG_LOG(NAOMI, "naomi COMM data read: %X, %d", CommOffset, size);
if (CommSharedMem)
{
return CommSharedMem[CommOffset&0xF];
@ -759,63 +756,83 @@ u32 NaomiCartridge::ReadMem(u32 address, u32 size)
return 1;
//This should be valid
case NAOMI_DMA_OFFSETH_addr&255:
return DmaOffset>>16;
case NAOMI_DMA_OFFSETL_addr&255:
return DmaOffset&0xFFFF;
case NAOMI_BOARDID_WRITE_addr&255:
EMUERROR("naomi ReadBoardId: %X, %d", address, size);
DEBUG_LOG(NAOMI, "naomi ReadBoardId: %X, %d", address, size);
return 1;
case 0x04C:
EMUERROR("naomi GD? READ: %X, %d", address, size);
return reg_dimm_4c;
case NAOMI_COMM2_CTRL_addr & 255:
DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL read");
return comm_ctrl;
case 0x18:
printf("naomi reg 0x18 : returning random data\n");
return 0x4000^rand();
case NAOMI_COMM2_OFFSET_addr & 255:
DEBUG_LOG(NAOMI, "NAOMI_COMM2_OFFSET read");
return comm_offset;
case NAOMI_COMM2_DATA_addr & 255:
{
DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA read @ %04x", comm_offset);
u16 value;
if (comm_ctrl & 1)
value = m68k_ram[comm_offset / 2];
else {
// TODO u16 *commram = (u16*)membank("comm_ram")->base();
value = comm_ram[comm_offset / 2];
}
comm_offset += 2;
return value;
}
case NAOMI_COMM2_STATUS0_addr & 255:
DEBUG_LOG(NAOMI, "NAOMI_COMM2_STATUS0 read");
return comm_offset_status0;
case NAOMI_COMM2_STATUS1_addr & 255:
DEBUG_LOG(NAOMI, "NAOMI_COMM2_STATUS1 read");
return comm_offset_status1;
default:
break;
default: break;
}
//EMUERROR("naomi?WTF? ReadMem: %X, %d", address, size);
DEBUG_LOG(NAOMI, "naomi?WTF? ReadMem: %X, %d", address, size);
return 0xFFFF;
}
void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
{
// printf("+naomi WriteMem: %X <= %X, %d\n", address, data, size);
switch(address & 255)
{
case 0x3c:
if (0x1E03==data)
case 0x3c: // 5f703c: DIMM COMMAND
if (0x1E03 == data)
{
/*
if (!(reg_dimm_4c&0x100))
if (!(reg_dimm_status & 0x100))
asic_RaiseInterrupt(holly_EXP_PCI);
reg_dimm_4c|=1;*/
reg_dimm_status |= 1;*/
}
reg_dimm_3c=data;
EMUERROR("naomi GD? Write: %X <= %X, %d", address, data, size);
reg_dimm_command = data;
DEBUG_LOG(NAOMI, "DIMM COMMAND Write: %X <= %X, %d", address, data, size);
return;
case 0x40:
reg_dimm_40=data;
EMUERROR("naomi GD? Write: %X <= %X, %d", address, data, size);
case 0x40: // 5f7040: DIMM OFFSETL
reg_dimm_offsetl = data;
DEBUG_LOG(NAOMI, "DIMM OFFSETL Write: %X <= %X, %d", address, data, size);
return;
case 0x44:
reg_dimm_44=data;
EMUERROR("naomi GD? Write: %X <= %X, %d", address, data, size);
case 0x44: // 5f7044: DIMM PARAMETERL
reg_dimm_parameterl = data;
DEBUG_LOG(NAOMI, "DIMM PARAMETERL Write: %X <= %X, %d", address, data, size);
return;
case 0x48:
reg_dimm_48=data;
EMUERROR("naomi GD? Write: %X <= %X, %d", address, data, size);
case 0x48: // 5f7048: DIMM PARAMETERH
reg_dimm_parameterh = data;
DEBUG_LOG(NAOMI, "DIMM PARAMETERH Write: %X <= %X, %d", address, data, size);
return;
case 0x4C:
case 0x4C: // 5f704c: DIMM STATUS
if (data&0x100)
{
asic_CancelInterrupt(holly_EXP_PCI);
@ -826,10 +843,10 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
/*FILE* ramd=fopen("c:\\ndc.ram.bin","wb");
fwrite(mem_b.data,1,RAM_SIZE,ramd);
fclose(ramd);*/
naomi_process(reg_dimm_3c,reg_dimm_40,reg_dimm_44,reg_dimm_48);
naomi_process(reg_dimm_command, reg_dimm_offsetl, reg_dimm_parameterl, reg_dimm_parameterh);
}
reg_dimm_4c=data&~0x100;
EMUERROR("naomi GD? Write: %X <= %X, %d", address, data, size);
reg_dimm_status = data & ~0x100;
DEBUG_LOG(NAOMI, "DIMM STATUS Write: %X <= %X, %d", address, data, size);
return;
//These are known to be valid on normal ROMs and DIMM board
@ -877,14 +894,14 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
//What should i do to emulate 'nothing' ?
case NAOMI_COMM_OFFSET_addr&255:
#ifdef NAOMI_COMM
printf("naomi COMM ofset Write: %X <= %X, %d\n", address, data, size);
DEBUG_LOG(NAOMI, "naomi COMM ofset Write: %X <= %X, %d", address, data, size);
CommOffset=data&0xFFFF;
#endif
return;
case NAOMI_COMM_DATA_addr&255:
#ifdef NAOMI_COMM
printf("naomi COMM data Write: %X <= %X, %d\n", CommOffset, data, size);
DEBUG_LOG(NAOMI, "naomi COMM data Write: %X <= %X, %d", CommOffset, data, size);
if (CommSharedMem)
{
CommSharedMem[CommOffset&0xF]=data;
@ -894,12 +911,43 @@ void NaomiCartridge::WriteMem(u32 address, u32 data, u32 size)
//This should be valid
case NAOMI_BOARDID_READ_addr&255:
EMUERROR("naomi WriteMem: %X <= %X, %d", address, data, size);
DEBUG_LOG(NAOMI, "naomi WriteMem: %X <= %X, %d", address, data, size);
return;
case NAOMI_COMM2_CTRL_addr & 255:
comm_ctrl = (u16)data;
DEBUG_LOG(NAOMI, "NAOMI_COMM2_CTRL set to %x", comm_ctrl);
return;
case NAOMI_COMM2_OFFSET_addr & 255:
comm_offset = (u16)data;
DEBUG_LOG(NAOMI, "NAOMI_COMM2_OFFSET set to %x", comm_offset);
return;
case NAOMI_COMM2_DATA_addr & 255:
DEBUG_LOG(NAOMI, "NAOMI_COMM2_DATA written @ %04x %04x", comm_offset, (u16)data);
if (comm_ctrl & 1)
m68k_ram[comm_offset / 2] = (u16)data;
else {
// TODO u16 *commram = (u16*)membank("comm_ram")->base();
comm_ram[comm_offset / 2] = (u16)data;
}
comm_offset += 2;
return;
case NAOMI_COMM2_STATUS0_addr & 255:
comm_offset_status0 = (u16)data;
DEBUG_LOG(NAOMI, "NAOMI_COMM2_STATUS0 set to %x", comm_offset_status0);
return;
case NAOMI_COMM2_STATUS1_addr & 255:
comm_offset_status1 = (u16)data;
DEBUG_LOG(NAOMI, "NAOMI_COMM2_STATUS1 set to %x", comm_offset_status1);
return;
default: break;
}
EMUERROR("naomi?WTF? WriteMem: %X <= %X, %d", address, data, size);
DEBUG_LOG(NAOMI, "naomi?WTF? WriteMem: %X <= %X, %d", address, data, size);
}
void NaomiCartridge::Serialize(void** data, unsigned int* total_size)
@ -932,7 +980,7 @@ bool M2Cartridge::Read(u32 offset, u32 size, void* dst)
*(u16 *)dst = data;
return true;
}
EMUERROR("Invalid read @ %08x\n", offset);
INFO_LOG(NAOMI, "Invalid read @ %08x", offset);
return false;
}
else if (!(RomPioOffset & 0x20000000))

View File

@ -52,6 +52,13 @@ protected:
u32 DmaOffset;
u32 DmaCount;
u32 key;
// Naomi 840-0001E communication board
u16 comm_ctrl = 0xC000;
u16 comm_offset = 0;
u16 comm_offset_status0 = 0;
u16 comm_offset_status1 = 0;
u16 m68k_ram[128 * 1024 / sizeof(u16)];
u16 comm_ram[64 * 1024 / sizeof(u16)];
};
class DecryptedCartridge : public NaomiCartridge
@ -78,8 +85,15 @@ private:
u8 naomi_cart_ram[64 * 1024];
};
bool naomi_cart_SelectFile();
class NaomiCartException : public ReicastException
{
public:
NaomiCartException(std::string reason) : ReicastException(reason) {}
};
void naomi_cart_LoadRom(const char* file);
void naomi_cart_Close();
int naomi_cart_GetPlatform(const char *path);
extern char naomi_game_id[];
extern u8 *naomi_default_eeprom;

View File

@ -12,6 +12,13 @@ enum
NAOMI_DMA_OFFSETH_addr = 0x5f700C,
NAOMI_DMA_OFFSETL_addr = 0x5f7010,
NAOMI_DMA_COUNT_addr = 0x5f7014,
// Naomi 840-0001E communication board
NAOMI_COMM2_CTRL_addr = 0x5f7018,
NAOMI_COMM2_OFFSET_addr = 0x5f701C,
NAOMI_COMM2_DATA_addr = 0x5F7020,
NAOMI_COMM2_STATUS0_addr = 0x5F7024,
NAOMI_COMM2_STATUS1_addr = 0x5F7028,
NAOMI_BOARDID_WRITE_addr = 0x5F7078,
NAOMI_BOARDID_READ_addr = 0x5F707C,
NAOMI_COMM_OFFSET_addr = 0x5F7050,

View File

@ -3,6 +3,7 @@
#include "hw/pvr/pvr_mem.h"
#include "rend/TexCache.h"
#include "rend/gui.h"
#include "hw/mem/_vmem.h"
#include "deps/zlib/zlib.h"
@ -78,12 +79,15 @@ u32 FrameCount=1;
Renderer* renderer;
static Renderer* fallback_renderer;
bool renderer_enabled = true; // Signals the renderer thread to exit
bool renderer_changed = false; // Signals the renderer thread to switch renderer
volatile bool renderer_enabled = true; // Signals the renderer thread to exit
volatile bool renderer_changed = false; // Signals the renderer thread to switch renderer
volatile bool renderer_reinit_requested = false; // Signals the renderer thread to reinit the renderer
#if !defined(TARGET_NO_THREADS)
cResetEvent rs, re;
#endif
static bool swap_pending;
static bool do_swap;
int max_idx,max_mvo,max_op,max_pt,max_tr,max_vtx,max_modt, ovrn;
@ -94,8 +98,6 @@ bool fb_dirty;
TA_context* _pvrrc;
void SetREP(TA_context* cntx);
void killtex();
bool render_output_framebuffer();
static void rend_create_renderer();
void dump_frame(const char* file, TA_context* ctx, u8* vram, u8* vram_ref = NULL) {
@ -202,7 +204,7 @@ TA_context* read_frame(const char* file, u8* vram_ref = NULL) {
fread(&t, 1, sizeof(t), fw);
verify(t == VRAM_SIZE);
vram.UnLockRegion(0, VRAM_SIZE);
_vmem_unprotect_vram(0, VRAM_SIZE);
uLongf compressed_size;
@ -249,6 +251,14 @@ bool rend_frame(TA_context* ctx, bool draw_osd) {
dump_frame_switch = false;
}
bool proc = renderer->Process(ctx);
if ((ctx->rend.isRTT || ctx->rend.isRenderFramebuffer) && swap_pending)
{
// If there is a frame swap pending, we want to do it now.
// The current frame "swapping" detection mechanism (using FB_R_SOF1) doesn't work
// if a RTT frame is rendered in between.
renderer->Present();
swap_pending = false;
}
#if !defined(TARGET_NO_THREADS)
if (!proc || (!ctx->rend.isRTT && !ctx->rend.isRenderFramebuffer))
// If rendering to texture, continue locking until the frame is rendered
@ -287,6 +297,7 @@ bool rend_single_frame()
// Use the rendering start event to wait between two frames but save its value
if (rs.Wait(17))
rs.Set();
swap_pending = false;
return true;
}
else
@ -296,12 +307,18 @@ bool rend_single_frame()
if (!rs.Wait(100))
return false;
if (do_swap)
{
do_swap = false;
renderer->Present();
}
}
#else
if (gui_is_open())
{
gui_display_ui();
FinishRender(NULL);
swap_pending = false;
return true;
}
if (renderer != NULL)
@ -314,6 +331,7 @@ bool rend_single_frame()
}
while (!_pvrrc);
bool do_swp = rend_frame(_pvrrc, true);
swap_pending = do_swp && !_pvrrc->rend.isRenderFramebuffer;
#if !defined(TARGET_NO_THREADS)
if (_pvrrc->rend.isRTT)
@ -366,7 +384,7 @@ void rend_init_renderer()
delete fallback_renderer;
die("Renderer initialization failed\n");
}
printf("Selected renderer initialization failed. Falling back to default renderer.\n");
INFO_LOG(PVR, "Selected renderer initialization failed. Falling back to default renderer.");
renderer = fallback_renderer;
fallback_renderer = NULL; // avoid double-free
}
@ -374,7 +392,6 @@ void rend_init_renderer()
void rend_term_renderer()
{
killtex();
gui_term();
renderer->Term();
delete renderer;
@ -388,6 +405,8 @@ void rend_term_renderer()
void* rend_thread(void* p)
{
renderer_enabled = true;
rend_init_renderer();
//we don't know if this is true, so let's not speculate here
@ -396,7 +415,26 @@ void* rend_thread(void* p)
while (renderer_enabled)
{
if (rend_single_frame())
renderer->Present();
{
if (FB_R_SOF1 == FB_W_SOF1 || !swap_pending)
{
renderer->Present();
swap_pending = false;
}
}
if (renderer_changed)
{
renderer_changed = false;
renderer_reinit_requested = false;
rend_term_renderer();
rend_create_renderer();
rend_init_renderer();
}
else if (renderer_reinit_requested)
{
renderer_reinit_requested = false;
rend_init_renderer();
}
}
rend_term_renderer();
@ -444,7 +482,7 @@ void rend_start_render()
int ch = fgetc(fCheckFrames);
if (ch == EOF) {
printf("Testing: TA Hash log matches, exiting\n");
INFO_LOG(PVR, "Testing: TA Hash log matches, exiting");
exit(1);
}
@ -507,7 +545,7 @@ void rend_start_render()
else
{
ovrn++;
printf("WARNING: Rendering context is overrun (%d), aborting frame\n",ovrn);
INFO_LOG(PVR, "WARNING: Rendering context is overrun (%d), aborting frame", ovrn);
tactx_Recycle(ctx);
}
}
@ -544,6 +582,7 @@ void rend_vblank()
{
if (!render_called && fb_dirty && FB_R_CTRL.fb_enable)
{
DEBUG_LOG(PVR, "Direct framebuffer write detected");
SetCurrentTARC(CORE_CURRENT_CTX);
ta_ctx->rend.isRenderFramebuffer = true;
rend_start_render();
@ -568,3 +607,12 @@ void rend_cancel_emu_wait()
#endif
}
void rend_swap_frame()
{
if (swap_pending)
{
swap_pending = false;
do_swap = true;
rs.Set();
}
}

View File

@ -13,6 +13,8 @@ void rend_start_render();
void rend_end_render();
void rend_cancel_emu_wait();
bool rend_single_frame();
void rend_swap_frame();
void *rend_thread(void *);
void rend_set_fb_scale(float x,float y);
void rend_resize(int width, int height);
@ -34,6 +36,7 @@ extern TA_context* _pvrrc;
struct Renderer
{
virtual bool Init()=0;
virtual ~Renderer() {}
virtual void Resize(int w, int h)=0;
@ -51,8 +54,9 @@ struct Renderer
};
extern Renderer* renderer;
extern bool renderer_enabled; // Signals the renderer thread to exit
extern bool renderer_changed; // Signals the renderer thread to switch renderer
extern volatile bool renderer_enabled; // Signals the renderer thread to exit
extern volatile bool renderer_changed; // Signals the renderer thread to switch renderer
extern volatile bool renderer_reinit_requested; // Signals the renderer thread to reinit the renderer
Renderer* rend_GLES2();
#if !defined(GLES) && HOST_OS != OS_DARWIN

View File

@ -16,7 +16,7 @@
#include "pvr_regs.h"
#include "pvr_mem.h"
#include "Renderer_if.h"
#include "rend/TexCache.h"
void libPvr_LockedBlockWrite (vram_block* block,u32 addr)
{
@ -24,10 +24,11 @@ void libPvr_LockedBlockWrite (vram_block* block,u32 addr)
}
void libPvr_Reset(bool Manual)
void libPvr_Reset(bool hard)
{
Regs_Reset(Manual);
spg_Reset(Manual);
KillTex = true;
Regs_Reset(hard);
spg_Reset(hard);
}
s32 libPvr_Init()

View File

@ -19,7 +19,7 @@ struct List
*overrun |= true;
Clear();
if (list_name != NULL)
printf("List overrun for list %s\n", list_name);
WARN_LOG(PVR, "List overrun for list %s", list_name);
return daty;
}

View File

@ -212,7 +212,7 @@ void YUV_data(u32* data , u32 count)
//read
u8 DYNACALL pvr_read_area1_8(u32 addr)
{
printf("8-bit VRAM reads are not possible\n");
INFO_LOG(MEMORY, "%08x: 8-bit VRAM reads are not possible", addr);
return 0;
}
@ -228,7 +228,7 @@ u32 DYNACALL pvr_read_area1_32(u32 addr)
//write
void DYNACALL pvr_write_area1_8(u32 addr,u8 data)
{
printf("8-bit VRAM writes are not possible\n");
INFO_LOG(MEMORY, "%08x: 8-bit VRAM writes are not possible", addr);
}
void DYNACALL pvr_write_area1_16(u32 addr,u16 data)
{
@ -263,7 +263,7 @@ void TAWrite(u32 address,u32* data,u32 count)
else //Vram Writef
{
//shouldn't really get here (?) -> works on dc :D need to handle lmmodes
//printf("Vram TAWrite 0x%X , bkls %d\n",address,count);
DEBUG_LOG(MEMORY, "Vram TAWrite 0x%X , bkls %d\n", address, count);
verify(SB_LMMODE0 == 0);
memcpy(&vram.data[address&VRAM_MASK],data,count*32);
}
@ -293,11 +293,10 @@ extern "C" void DYNACALL TAWriteSQ(u32 address,u8* sqb)
else //Vram Writef
{
// Used by WinCE
//printf("Vram TAWriteSQ 0x%X SB_LMMODE0 %d\n",address, SB_LMMODE0);
DEBUG_LOG(MEMORY, "Vram TAWriteSQ 0x%X SB_LMMODE0 %d", address, SB_LMMODE0);
if (SB_LMMODE0 == 0)
{
// 64b path
u8* vram=sqb+512+0x04000000;
MemWrite32(&vram[address_w&(VRAM_MASK-0x1F)],sq);
}
else

View File

@ -38,6 +38,8 @@ void pvr_WriteReg(u32 paddr,u32 data)
{
ta_vtx_ListInit();
data=0;
TA_NEXT_OPB = TA_NEXT_OPB_INIT;
TA_ITP_CURRENT = TA_ISP_BASE;
}
}
@ -84,12 +86,25 @@ void pvr_WriteReg(u32 paddr,u32 data)
}
return;
}
if (addr == TA_YUV_TEX_BASE_addr || addr == TA_YUV_TEX_CTRL_addr)
if (addr == TA_YUV_TEX_BASE_addr)
{
PvrReg(addr, u32) = data & 0x00FFFFF8;
YUV_init();
return;
}
else if (addr == TA_YUV_TEX_CTRL_addr)
{
PvrReg(addr, u32) = data;
YUV_init();
return;
}
else if (addr == FB_R_SOF1_addr)
{
if (data == FB_W_SOF1)
{
rend_swap_frame();
}
}
if (addr>=PALETTE_RAM_START_addr && PvrReg(addr,u32)!=data)
{
@ -103,8 +118,10 @@ void pvr_WriteReg(u32 paddr,u32 data)
PvrReg(addr,u32)=data;
}
void Regs_Reset(bool Manual)
void Regs_Reset(bool hard)
{
if (hard)
memset(&pvr_regs[0], 0, sizeof(pvr_regs));
ID = 0x17FD11DB;
REVISION = 0x00000011;
SOFTRESET = 0x00000007;

View File

@ -33,13 +33,13 @@ void do_pvr_dma()
if(0x8201 != (dmaor &DMAOR_MASK))
{
printf("\n!\tDMAC: DMAOR has invalid settings (%X) !\n", dmaor);
INFO_LOG(PVR, "DMAC: DMAOR has invalid settings (%X) !", dmaor);
return;
}
if (len & 0x1F)
{
printf("\n!\tDMAC: SB_C2DLEN has invalid size (%X) !\n", len);
INFO_LOG(PVR, "DMAC: SB_C2DLEN has invalid size (%X) !", len);
return;
}
@ -55,7 +55,7 @@ void do_pvr_dma()
}
DMAC_SAR(0) = (src + len);
DMAC_CHCR(0).full &= 0xFFFFFFFE;
DMAC_CHCR(0).TE = 1;
DMAC_DMATCR(0) = 0x00000000;
SB_PDST = 0x00000000;
@ -73,7 +73,7 @@ void RegWrite_SB_PDST(u32 addr, u32 data)
}
u32 calculate_start_link_addr()
{
u8* base=&mem_b[SB_SDSTAW & RAM_MASK];
u8* base = &mem_b[SB_SDSTAW & (RAM_MASK - 31)];
u32 rv;
if (SB_SDWLT==0)
{
@ -94,9 +94,9 @@ void pvr_do_sort_dma()
SB_SDDIV=0;//index is 0 now :)
u32 link_addr=calculate_start_link_addr();
u32 link_base_addr = SB_SDBAAW;
u32 link_base_addr = SB_SDBAAW & ~31;
while (link_addr!=1)
while (link_addr != 2)
{
if (SB_SDLAS==1)
link_addr*=32;
@ -107,7 +107,7 @@ void pvr_do_sort_dma()
link_addr=ea_ptr[0x1C>>2];//Next link
//transfer global param
ta_vtx_data(ea_ptr,ea_ptr[0x18>>2]);
if (link_addr==2)
if (link_addr == 1)
{
link_addr=calculate_start_link_addr();
}
@ -115,6 +115,7 @@ void pvr_do_sort_dma()
// End of DMA :)
SB_SDST=0;
SB_SDSTAW += 32;
asic_RaiseInterrupt(holly_PVR_SortDMA);
}
// Auto sort DMA :|
@ -143,6 +144,6 @@ void pvr_sb_Term()
{
}
//Reset -> Reset - Initialise
void pvr_sb_Reset(bool Manual)
void pvr_sb_Reset(bool hard)
{
}

Some files were not shown because too many files have changed in this diff Show More