微羽网站服务器 PLAPI 插件系统 Demo

PLAPI.h

#pragma once
#include <iostream>

#ifndef NULL
#define NULL 0
#endif
#ifndef WINAPI
#define WINAPI __stdcall
#endif
#define NEW(p, size) { p = (char *)malloc(size); memset( p, 0, size ); }
#define DEL(p) { free((void*)p); p = NULL; }
#ifndef MAX_PATH
#define MAX_PATH 260
#endif
#ifndef MAKEWORD
#define MAKEWORD(a, b) ((unsigned short)(((unsigned char)(a)) | ((unsigned short)((unsigned char)(b))) << 8))
#endif

#define PLAPI extern "C" __declspec(dllexport)
#define PLAPI_ServerFunc bool (WINAPI *ServerFunc)(int dwServerID, int dwConnID, int dwAction, int dwFlag, void *lpvBuffer, int ilength)
#define PLAPI_GetEnvVar bool(WINAPI *GetEnvVar)(int dwServerID, int dwConnID, const char *lpszVarName, void *lpvBuffer)
#define PLAPI_Read bool(WINAPI *Read)(int dwServerID, int dwConnID, void *lpvBuffer, int dwBytesToRead, int *dwBytesRead)
#define PLAPI_Write bool(WINAPI *Write)(int dwServerID, int dwConnID, const void *lpvBuffer, int ilength)

#define PLUME_EVENT_BEGIN_CONN 1
#define PLUME_EVENT_DONE_CONN 2
#define PLUME_EVENT_BEGIN_REQUEST 3
#define PLUME_EVENT_DONE_REQUEST 4
#define PLUME_EVENT_ONSEND 5
#define PLUME_EVENT_ONBODY 6
#define PLUME_EVENT_RESULT_STOP 0
#define PLUME_EVENT_RESULT_CONTINUE 1
#define PLUME_EVENT_RESULT_DISCONNECT 2

#define PLUME_ACTION_REGISTER_EVENT 0
#define PLUME_ACTION_LOG 1
#define PLUME_ACTION_SEND_CUSTOM_ERROR 2
#define PLUME_ACTION_READ_CONFIG 3
#define PLUME_ACTION_SEND_HEADER 4
#define PLUME_ACTION_DONE_REQUEST 5
#define PLUME_ACTION_GET_CONNECTION_COUNTS 6

#define PLUME_PROC_RESULT_SUCCESS 1
#define PLUME_PROC_RESULT_FAILURE 0

typedef struct plume_server
{
 int dwServerID;
 int dwConnID;
 PLAPI_GetEnvVar;
 PLAPI_Read;
 PLAPI_Write;
 PLAPI_ServerFunc;
} plume_server;

typedef struct plume_path_struct
{
 char* pConnDIR;
 char* pPathTranslated;
 char* pPath;
} plume_path_struct;

typedef struct plume_readconfig_struct
{
 char* pSectionName;
 char* pKeyName;
 char* pValue;
} plume_readconfig_struct;

PLAPI bool WINAPI Plume_InitPlugin(int dwServerVersion, PLAPI_ServerFunc);
PLAPI int WINAPI Plume_PluginProc(plume_server * plume_server);
PLAPI void WINAPI Plume_GetPluginDesc(char **lpszName, char **lpszVersion, char **lpszAuthor, char **lpszDescription);

// Usage :
// char **pConnDIR, **pPathTranslated, **pPath, **pPathInfo;
// Plume_GetPathStruct(s, &pConnDIR, &pPathTranslated, &pPath, &pPathInfo);
// strcpy(*..., "Dest String");
bool Plume_GetPathStruct(plume_server *s, char ***pConnDIR, char ***pPathTranslated, char ***pPath)
{
 int ptr;
 if (!s->GetEnvVar(s->dwServerID, s->dwConnID, "Plume_PathStruct", &ptr))
 return false;

 *pConnDIR = (char **)ptr;
 *pPathTranslated = (char **)(ptr + 4);
 *pPath = (char **)(ptr + 8);
 return true;
}

PLAPI.cpp

#include "PLAPI.h"

#define PLUGIN_NAME "SDK Plugin"
#define PLUGIN_VER "1.0.0"
#define PLUGIN_AUTHOR "iEdon"
#define PLUGIN_DESC "Plume PLAPI 插件系统 SDK"

// PLAPI SDK
// (C) 2012-2017 iEdon Inside
// 注意:生成 DLL 请注意设置项目属性:链接器-->输入-->模块定义文件为 PLAPI.def,项目类型为动态链接库 (DLL)

int Plugin_Event_Callback(plume_server *s, int dwEventType);

PLAPI void WINAPI Plume_GetPluginDesc(char **lpszName, char **lpszVersion, char **lpszAuthor, char **lpszDescription)
{
 *lpszName = PLUGIN_NAME;
 *lpszVersion = PLUGIN_VER;
 *lpszAuthor = PLUGIN_AUTHOR;
 *lpszDescription = PLUGIN_DESC;
}

PLAPI bool WINAPI Plume_InitPlugin(int dwServerVersion, PLAPI_ServerFunc)
{
 char *log = "\tPlume SDK Plugin v1.0.1\n";
 ServerFunc(NULL, NULL, PLUME_ACTION_LOG, NULL, log, strlen(log)); // 向错误日志输出信息
 printf(log); // 向调试控制台输入信息

 if (MAKEWORD(4, 0) > dwServerVersion)
 {
 log = "Not supported version yet.\n";
 ServerFunc(NULL, NULL, PLUME_ACTION_LOG, NULL, log, strlen(log));
 printf(log);
 return false;
 }

 ServerFunc(NULL, NULL, PLUME_ACTION_REGISTER_EVENT, PLUME_EVENT_BEGIN_REQUEST, Plugin_Event_Callback, NULL); // 注册插件事件为开始请求时调用。
 return true;
}

PLAPI int WINAPI Plume_PluginProc(plume_server * s) // 扩展处理请求
{
 /*
 POST 获取数据做法:(注:可通过获取环境变量 REQUEST_METHOD 来判断当前请求类型)
 
 // TODO Your Code...
 
 char *lpvBuffer = (char *)malloc(4096);
 memset(lpvBuffer, 0, 4096);
 s->GetEnvVar(s->dwServerID, s->dwConnID, "CONTENT_LENGTH", lpvBuffer);
 if(atoi(lpvBuffer) <= 0)
 {
 s->ServerFunc(s->dwServerID, s->dwConnID, PLUME_ACTION_SEND_CUSTOM_ERROR, 500, "发生了错误,POST 数据长度错误", strlen("发生了错误,POST 数据长度错误"));
 free(lpvBuffer);
 return PLUME_PROC_RESULT_FAILURE; // POST 数据长度不对
 }
 free(lpvBuffer);
 int dwBytesRead;
 lpvBuffer = (char *)malloc(40960);
 while(s->Read(s->dwServerID, s->dwConnID, lpvBuffer, 40960, &dwBytesRead))
 {
 // TODO ... 此处为每块 POST 数据的处理
 memset(lpvBuffer, 0, 40960);
 }
 free(lpvBuffer);
 
 // TODO Your Code...
 */
 
 /*
 ServerFunc (PLUME_ACTION_READ_CONFIG) 用法:
 
 PLUME_ACTION_READ_CONFIG 用于读取当前网站INI配置文件中的自定义配置信息,
 需要构建一个 plume_readconfig_struct,并依次填充INI配置项名、键名,并为接收值分配 MAX_PATH 长度的内存。
 
 // TODO Your Code...
 
 plume_readconfig_struct prs;
 
 char *lpszValue = (char *)malloc(MAX_PATH);
 memset(lpszValue, 0, MAX_PATH);
 
 prs.pSectionName = "TestConfig";
 prs.pKeyName = "keyname";
 prs.pValue = lpszValue;
 
 s->ServerFunc(s->dwServerID, s->dwConnID, PLUME_ACTION_READ_CONFIG, (int)&prs, NULL, NULL); // 读取配置,获得的返回内容存放于 prs.value。
 
 // TODO Your Code...
 
 free(lpszValue);
 
 // 这样,就相当于读取了虚拟主机配置文件中 [TestConfig] 里 keyname 的内容。
 
 // ServerFunc (PLUME_ACTION_GET_CONNECTION_COUNTS) 用法:
 int iConnCounts = 0;
 s->ServerFunc(s->dwServerID, NULL, PLUME_ACTION_GET_CONNECTION_COUNTS, &iConnCounts, NULL, NULL);

 */
 
 // 准备正文
 char *lpvBuffer = (char *)malloc(4096);
 memset(lpvBuffer, 0, 4096);
 s->GetEnvVar(s->dwServerID, s->dwConnID, "SERVER_SOFTWARE", lpvBuffer); // 例:获取环境变量 SERVER_SOFTWARE 的内容
 char lpszContext[1024];
 sprintf(lpszContext, "<h1>Plume SDK Plugin</h1><br />You are running : %s", lpvBuffer);

 // 同CGI一样,预处理头部
 // 提示:如果输出内容不定长或无法预知长度,可以指定 Transfer-Encoding: chunked 而无需计算 Content-Length。发送头部以后,采用 chunked 编码自由输出不定长内容。
 char lpszHeader[128];
 sprintf(lpszHeader, "Content-Type: text/html; charset=gb2312\r\nContent-Length: %d", strlen(lpszContext));

 s->ServerFunc(s->dwServerID, s->dwConnID, PLUME_ACTION_SEND_HEADER, NULL, lpszHeader, strlen(lpszHeader)); // 同CGI一样,先发送头部

 s->Write(s->dwServerID, s->dwConnID, lpszContext, strlen(lpszContext)); // 然后就可以发送正文

 s->ServerFunc(s->dwServerID, s->dwConnID, PLUME_ACTION_DONE_REQUEST, NULL, NULL, NULL); // 正常响应后,使用 Done Request 来结束会话并释放连接资源。 

 // 释放申请的内存
 free(lpvBuffer);
 
 // 返回成功
 return PLUME_PROC_RESULT_SUCCESS;
}

int Plugin_Event_Callback(plume_server *s, int dwEventType, void *lpvBuffer, int iLength) // 插件事件处理请求
{
 if (dwEventType == PLUME_EVENT_BEGIN_REQUEST) // 连接开始
 {
 return PLUME_EVENT_RESULT_CONTINUE; // 继续处理
 }
 else
 {
 // 发送自定义错误页面后不需要 Done Request.
 s->ServerFunc(s->dwServerID, s->dwConnID, PLUME_ACTION_SEND_CUSTOM_ERROR, 500, "发生了错误,事件类型不存在。", strlen("发生了错误,事件类型不存在。"));
 return PLUME_EVENT_RESULT_STOP; // 立即停止处理
 }
 return PLUME_EVENT_RESULT_DISCONNECT; // 立即断开与客户端的连接
}

12 responses to “微羽网站服务器 PLAPI 插件系统 Demo”

  1. 满满的全是一屏的代码,能看懂一点。

    1. 是啊,C++可以写死人

      1. 我想大喊一句,php是世界上最好的语言 😛

Leave a Reply to Young小杰 Cancel reply

Your email address will not be published. Required fields are marked *