mirror of
https://github.com/esp8266/Arduino.git
synced 2025-07-27 18:02:17 +03:00
28
libraries/DNSServer/examples/DNSServer/DNSServer.ino
Normal file
28
libraries/DNSServer/examples/DNSServer/DNSServer.ino
Normal file
@ -0,0 +1,28 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <DNSServer.h>
|
||||
|
||||
const byte DNS_PORT = 53;
|
||||
IPAddress apIP(192, 168, 1, 1);
|
||||
DNSServer dnsServer;
|
||||
|
||||
void setup() {
|
||||
WiFi.mode(WIFI_AP);
|
||||
WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
|
||||
WiFi.softAP("DNSServer example");
|
||||
|
||||
// modify TTL associated with the domain name (in seconds)
|
||||
// default is 60 seconds
|
||||
dnsServer.setTTL(300);
|
||||
// set which return code will be used for all other domains (e.g. sending
|
||||
// ServerFailure instead of NonExistentDomain will reduce number of queries
|
||||
// sent by clients)
|
||||
// default is DNSReplyCode::NonExistentDomain
|
||||
dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure);
|
||||
|
||||
//start DNS server for a specific domain name
|
||||
dnsServer.start(DNS_PORT, "www.example.com", apIP);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
dnsServer.processNextRequest();
|
||||
}
|
9
libraries/DNSServer/library.properties
Normal file
9
libraries/DNSServer/library.properties
Normal file
@ -0,0 +1,9 @@
|
||||
name=DNSServer
|
||||
version=1.0.0
|
||||
author=Kristijan Novoselić
|
||||
maintainer=Kristijan Novoselić, <kristijan.novoselic@gmail.com>
|
||||
sentence=A simple DNS server for ESP8266.
|
||||
paragraph=This library implements a simple DNS server.
|
||||
category=Communication
|
||||
url=
|
||||
architectures=esp8266
|
133
libraries/DNSServer/src/DNSServer.cpp
Normal file
133
libraries/DNSServer/src/DNSServer.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
#include "DNSServer.h"
|
||||
#include <lwip/def.h>
|
||||
#include <Arduino.h>
|
||||
|
||||
DNSServer::DNSServer()
|
||||
{
|
||||
_ttl = htonl(60);
|
||||
_errorReplyCode = DNSReplyCode::NonExistentDomain;
|
||||
}
|
||||
|
||||
bool DNSServer::start(const uint16_t &port, const String &domainName,
|
||||
const IPAddress &resolvedIP)
|
||||
{
|
||||
_port = port;
|
||||
_domainName = domainName;
|
||||
_resolvedIP[0] = resolvedIP[0];
|
||||
_resolvedIP[1] = resolvedIP[1];
|
||||
_resolvedIP[2] = resolvedIP[2];
|
||||
_resolvedIP[3] = resolvedIP[3];
|
||||
downcaseAndRemoveWwwPrefix(_domainName);
|
||||
return _udp.begin(_port) == 1;
|
||||
}
|
||||
|
||||
void DNSServer::setErrorReplyCode(const DNSReplyCode &replyCode)
|
||||
{
|
||||
_errorReplyCode = replyCode;
|
||||
}
|
||||
|
||||
void DNSServer::setTTL(const uint32_t &ttl)
|
||||
{
|
||||
_ttl = htonl(ttl);
|
||||
}
|
||||
|
||||
void DNSServer::stop()
|
||||
{
|
||||
_udp.stop();
|
||||
}
|
||||
|
||||
void DNSServer::downcaseAndRemoveWwwPrefix(String &domainName)
|
||||
{
|
||||
domainName.toLowerCase();
|
||||
domainName.replace("www.", "");
|
||||
}
|
||||
|
||||
void DNSServer::processNextRequest()
|
||||
{
|
||||
_currentPacketSize = _udp.parsePacket();
|
||||
if (_currentPacketSize)
|
||||
{
|
||||
_buffer = (unsigned char*)malloc(_currentPacketSize * sizeof(char));
|
||||
_udp.read(_buffer, _currentPacketSize);
|
||||
_dnsHeader = (DNSHeader*) _buffer;
|
||||
|
||||
if (_dnsHeader->QR == DNS_QR_QUERY &&
|
||||
_dnsHeader->OPCode == DNS_OPCODE_QUERY &&
|
||||
requestIncludesOnlyOneQuestion() &&
|
||||
getDomainNameWithoutWwwPrefix() == _domainName)
|
||||
{
|
||||
replyWithIP();
|
||||
}
|
||||
else if (_dnsHeader->QR == DNS_QR_QUERY)
|
||||
{
|
||||
replyWithCustomCode();
|
||||
}
|
||||
|
||||
free(_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
bool DNSServer::requestIncludesOnlyOneQuestion()
|
||||
{
|
||||
return ntohs(_dnsHeader->QDCount) == 1 &&
|
||||
_dnsHeader->ANCount == 0 &&
|
||||
_dnsHeader->NSCount == 0 &&
|
||||
_dnsHeader->ARCount == 0;
|
||||
}
|
||||
|
||||
String DNSServer::getDomainNameWithoutWwwPrefix()
|
||||
{
|
||||
String parsedDomainName = "";
|
||||
unsigned char *start = _buffer + 12;
|
||||
if (*start == 0)
|
||||
{
|
||||
return parsedDomainName;
|
||||
}
|
||||
int pos = 0;
|
||||
while(true)
|
||||
{
|
||||
unsigned char labelLength = *(start + pos);
|
||||
for(int i = 0; i < labelLength; i++)
|
||||
{
|
||||
pos++;
|
||||
parsedDomainName += (char)*(start + pos);
|
||||
}
|
||||
pos++;
|
||||
if (*(start + pos) == 0)
|
||||
{
|
||||
downcaseAndRemoveWwwPrefix(parsedDomainName);
|
||||
return parsedDomainName;
|
||||
}
|
||||
else
|
||||
{
|
||||
parsedDomainName += ".";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DNSServer::replyWithIP()
|
||||
{
|
||||
_dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
_dnsHeader->ANCount = _dnsHeader->QDCount;
|
||||
_dnsHeader->QDCount = 0;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write(_buffer, _currentPacketSize);
|
||||
_udp.write((unsigned char*)&_ttl, 4);
|
||||
// Length of RData is 4 bytes (because, in this case, RData is IPv4)
|
||||
_udp.write((uint8_t)0);
|
||||
_udp.write((uint8_t)4);
|
||||
_udp.write(_resolvedIP, sizeof(_resolvedIP));
|
||||
_udp.endPacket();
|
||||
}
|
||||
|
||||
void DNSServer::replyWithCustomCode()
|
||||
{
|
||||
_dnsHeader->QR = DNS_QR_RESPONSE;
|
||||
_dnsHeader->RCode = (unsigned char)_errorReplyCode;
|
||||
_dnsHeader->QDCount = 0;
|
||||
|
||||
_udp.beginPacket(_udp.remoteIP(), _udp.remotePort());
|
||||
_udp.write(_buffer, sizeof(DNSHeader));
|
||||
_udp.endPacket();
|
||||
}
|
72
libraries/DNSServer/src/DNSServer.h
Normal file
72
libraries/DNSServer/src/DNSServer.h
Normal file
@ -0,0 +1,72 @@
|
||||
#ifndef DNSServer_h
|
||||
#define DNSServer_h
|
||||
#include <WiFiUdp.h>
|
||||
|
||||
#define DNS_QR_QUERY 0
|
||||
#define DNS_QR_RESPONSE 1
|
||||
#define DNS_OPCODE_QUERY 0
|
||||
|
||||
enum class DNSReplyCode
|
||||
{
|
||||
NoError = 0,
|
||||
FormError = 1,
|
||||
ServerFailure = 2,
|
||||
NonExistentDomain = 3,
|
||||
NotImplemented = 4,
|
||||
Refused = 5,
|
||||
YXDomain = 6,
|
||||
YXRRSet = 7,
|
||||
NXRRSet = 8
|
||||
};
|
||||
|
||||
struct DNSHeader
|
||||
{
|
||||
uint16_t ID; // identification number
|
||||
unsigned char RD : 1; // recursion desired
|
||||
unsigned char TC : 1; // truncated message
|
||||
unsigned char AA : 1; // authoritive answer
|
||||
unsigned char OPCode : 4; // message_type
|
||||
unsigned char QR : 1; // query/response flag
|
||||
unsigned char RCode : 4; // response code
|
||||
unsigned char Z : 3; // its z! reserved
|
||||
unsigned char RA : 1; // recursion available
|
||||
uint16_t QDCount; // number of question entries
|
||||
uint16_t ANCount; // number of answer entries
|
||||
uint16_t NSCount; // number of authority entries
|
||||
uint16_t ARCount; // number of resource entries
|
||||
};
|
||||
|
||||
class DNSServer
|
||||
{
|
||||
public:
|
||||
DNSServer();
|
||||
void processNextRequest();
|
||||
void setErrorReplyCode(const DNSReplyCode &replyCode);
|
||||
void setTTL(const uint32_t &ttl);
|
||||
|
||||
// Returns true if successful, false if there are no sockets available
|
||||
bool start(const uint16_t &port,
|
||||
const String &domainName,
|
||||
const IPAddress &resolvedIP);
|
||||
// stops the DNS server
|
||||
void stop();
|
||||
|
||||
private:
|
||||
WiFiUDP _udp;
|
||||
uint16_t _port;
|
||||
String _domainName;
|
||||
unsigned char _resolvedIP[4];
|
||||
int _currentPacketSize;
|
||||
unsigned char* _buffer;
|
||||
DNSHeader* _dnsHeader;
|
||||
uint32_t _ttl;
|
||||
DNSReplyCode _errorReplyCode;
|
||||
|
||||
|
||||
void downcaseAndRemoveWwwPrefix(String &domainName);
|
||||
String getDomainNameWithoutWwwPrefix();
|
||||
bool requestIncludesOnlyOneQuestion();
|
||||
void replyWithIP();
|
||||
void replyWithCustomCode();
|
||||
};
|
||||
#endif
|
@ -33,6 +33,8 @@ extern "C" {
|
||||
#include "lwip/dns.h"
|
||||
}
|
||||
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiUdp.h"
|
||||
|
||||
extern "C" void esp_schedule();
|
||||
extern "C" void esp_yield();
|
||||
@ -42,6 +44,7 @@ ESP8266WiFiClass::ESP8266WiFiClass()
|
||||
, _useClientMode(false)
|
||||
, _useStaticIp(false)
|
||||
{
|
||||
wifi_set_event_handler_cb((wifi_event_handler_cb_t)&ESP8266WiFiClass::_eventCallback);
|
||||
}
|
||||
|
||||
void ESP8266WiFiClass::mode(WiFiMode m)
|
||||
@ -69,7 +72,7 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t ch
|
||||
mode(WIFI_STA);
|
||||
}
|
||||
|
||||
if(!ssid || strlen(ssid) > 31) {
|
||||
if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
|
||||
// fail SSID to long or missing!
|
||||
return WL_CONNECT_FAILED;
|
||||
}
|
||||
@ -104,8 +107,8 @@ int ESP8266WiFiClass::begin(const char* ssid, const char *passphrase, int32_t ch
|
||||
wifi_set_channel(channel);
|
||||
}
|
||||
|
||||
if(!_useStaticIp)
|
||||
wifi_station_dhcpc_start();
|
||||
if(!_useStaticIp)
|
||||
wifi_station_dhcpc_start();
|
||||
return status();
|
||||
}
|
||||
|
||||
@ -128,8 +131,8 @@ void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress s
|
||||
|
||||
wifi_station_dhcpc_stop();
|
||||
wifi_set_ip_info(STATION_IF, &info);
|
||||
|
||||
_useStaticIp = true;
|
||||
|
||||
_useStaticIp = true;
|
||||
}
|
||||
|
||||
void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress subnet, IPAddress dns)
|
||||
@ -146,8 +149,8 @@ void ESP8266WiFiClass::config(IPAddress local_ip, IPAddress gateway, IPAddress s
|
||||
ip_addr_t d;
|
||||
d.addr = static_cast<uint32_t>(dns);
|
||||
dns_setserver(0,&d);
|
||||
|
||||
_useStaticIp = true;
|
||||
|
||||
_useStaticIp = true;
|
||||
}
|
||||
|
||||
int ESP8266WiFiClass::disconnect()
|
||||
@ -178,7 +181,7 @@ void ESP8266WiFiClass::softAP(const char* ssid, const char* passphrase, int chan
|
||||
mode(WIFI_AP);
|
||||
}
|
||||
|
||||
if(!ssid || strlen(ssid) > 31) {
|
||||
if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
|
||||
// fail SSID to long or missing!
|
||||
return;
|
||||
}
|
||||
@ -588,6 +591,17 @@ void ESP8266WiFiClass::_smartConfigCallback(uint32_t st, void* result)
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266WiFiClass::_eventCallback(void* arg)
|
||||
{
|
||||
System_Event_t* event = reinterpret_cast<System_Event_t*>(arg);
|
||||
DEBUGV("wifi evt: %d\r\n", event->event);
|
||||
|
||||
if (event->event == EVENT_STAMODE_DISCONNECTED) {
|
||||
WiFiClient::stopAll();
|
||||
WiFiUDP::stopAll();
|
||||
}
|
||||
}
|
||||
|
||||
void ESP8266WiFiClass::printDiag(Print& p)
|
||||
{
|
||||
const char* modes[] = {"NULL", "STA", "AP", "STA+AP"};
|
||||
|
@ -313,6 +313,7 @@ protected:
|
||||
static void _scanDone(void* result, int status);
|
||||
void * _getScanInfoByIndex(int i);
|
||||
static void _smartConfigCallback(uint32_t status, void* result);
|
||||
static void _eventCallback(void *event);
|
||||
bool _smartConfigStarted = false;
|
||||
bool _smartConfigDone = false;
|
||||
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
#include "ESP8266WiFiMulti.h"
|
||||
#include <limits.h>
|
||||
#include <string.h>
|
||||
|
||||
ESP8266WiFiMulti::ESP8266WiFiMulti() {
|
||||
}
|
||||
@ -151,7 +152,7 @@ bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) {
|
||||
|
||||
WifiAPlist_t newAP;
|
||||
|
||||
if(!ssid || strlen(ssid) > 31) {
|
||||
if(!ssid || *ssid == 0x00 || strlen(ssid) > 31) {
|
||||
// fail SSID to long or missing!
|
||||
return false;
|
||||
}
|
||||
@ -161,21 +162,18 @@ bool ESP8266WiFiMulti::APlistAdd(const char* ssid, const char *passphrase) {
|
||||
return false;
|
||||
}
|
||||
|
||||
newAP.ssid = (char*) malloc((strlen(ssid) + 1));
|
||||
newAP.ssid = strdup(ssid);
|
||||
|
||||
if(!newAP.ssid) {
|
||||
return false;
|
||||
}
|
||||
|
||||
strcpy(newAP.ssid, ssid);
|
||||
|
||||
if(passphrase && *passphrase != 0x00) {
|
||||
newAP.passphrase = (char*) malloc((strlen(passphrase) + 1));
|
||||
newAP.passphrase = strdup(passphrase);
|
||||
if(!newAP.passphrase) {
|
||||
free(newAP.ssid);
|
||||
return false;
|
||||
}
|
||||
strcpy(newAP.passphrase, passphrase);
|
||||
}
|
||||
|
||||
APlist.push_back(newAP);
|
||||
|
@ -34,26 +34,35 @@ extern "C"
|
||||
#include "WiFiClient.h"
|
||||
#include "WiFiServer.h"
|
||||
#include "lwip/opt.h"
|
||||
#include "lwip/ip.h"
|
||||
#include "lwip/tcp.h"
|
||||
#include "lwip/inet.h"
|
||||
#include "lwip/netif.h"
|
||||
#include "cbuf.h"
|
||||
#include "include/ClientContext.h"
|
||||
#include "c_types.h"
|
||||
|
||||
uint16_t WiFiClient::_localPort = 0;
|
||||
|
||||
template<>
|
||||
WiFiClient* SList<WiFiClient>::_s_first = 0;
|
||||
|
||||
|
||||
WiFiClient::WiFiClient()
|
||||
: _client(0)
|
||||
{
|
||||
WiFiClient::_add(this);
|
||||
}
|
||||
|
||||
WiFiClient::WiFiClient(ClientContext* client) : _client(client)
|
||||
{
|
||||
_client->ref();
|
||||
WiFiClient::_add(this);
|
||||
}
|
||||
|
||||
WiFiClient::~WiFiClient()
|
||||
{
|
||||
WiFiClient::_remove(this);
|
||||
if (_client)
|
||||
_client->unref();
|
||||
}
|
||||
@ -63,6 +72,7 @@ WiFiClient::WiFiClient(const WiFiClient& other)
|
||||
_client = other._client;
|
||||
if (_client)
|
||||
_client->ref();
|
||||
WiFiClient::_add(this);
|
||||
}
|
||||
|
||||
WiFiClient& WiFiClient::operator=(const WiFiClient& other)
|
||||
@ -88,9 +98,21 @@ int WiFiClient::connect(const char* host, uint16_t port)
|
||||
|
||||
int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
{
|
||||
ip_addr_t addr;
|
||||
addr.addr = ip;
|
||||
|
||||
if (_client)
|
||||
stop();
|
||||
|
||||
// if the default interface is down, tcp_connect exits early without
|
||||
// ever calling tcp_err
|
||||
// http://lists.gnu.org/archive/html/lwip-devel/2010-05/msg00001.html
|
||||
netif* interface = ip_route(&addr);
|
||||
if (!interface) {
|
||||
DEBUGV("no route to host\r\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tcp_pcb* pcb = tcp_new();
|
||||
if (!pcb)
|
||||
return 0;
|
||||
@ -99,8 +121,6 @@ int WiFiClient::connect(IPAddress ip, uint16_t port)
|
||||
pcb->local_port = _localPort++;
|
||||
}
|
||||
|
||||
ip_addr_t addr;
|
||||
addr.addr = ip;
|
||||
tcp_arg(pcb, this);
|
||||
tcp_err(pcb, &WiFiClient::_s_err);
|
||||
tcp_connect(pcb, &addr, port, reinterpret_cast<tcp_connected_fn>(&WiFiClient::_s_connected));
|
||||
@ -257,3 +277,14 @@ void WiFiClient::_s_err(void* arg, int8_t err)
|
||||
reinterpret_cast<WiFiClient*>(arg)->_err(err);
|
||||
}
|
||||
|
||||
void WiFiClient::stopAll()
|
||||
{
|
||||
for (WiFiClient* it = _s_first; it; it = it->_next) {
|
||||
ClientContext* c = it->_client;
|
||||
if (c) {
|
||||
c->abort();
|
||||
c->unref();
|
||||
it->_client = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -26,11 +26,12 @@
|
||||
#include "Client.h"
|
||||
#include "IPAddress.h"
|
||||
#include <memory>
|
||||
#include "include/slist.h"
|
||||
|
||||
class ClientContext;
|
||||
class WiFiServer;
|
||||
|
||||
class WiFiClient : public Client {
|
||||
class WiFiClient : public Client, public SList<WiFiClient> {
|
||||
protected:
|
||||
WiFiClient(ClientContext* client);
|
||||
|
||||
@ -89,6 +90,8 @@ public:
|
||||
|
||||
using Print::write;
|
||||
|
||||
static void stopAll();
|
||||
|
||||
private:
|
||||
|
||||
static int8_t _s_connected(void* arg, void* tpcb, int8_t err);
|
||||
@ -99,7 +102,6 @@ private:
|
||||
|
||||
ClientContext* _client;
|
||||
static uint16_t _localPort;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -40,14 +40,22 @@ extern "C"
|
||||
#include "lwip/mem.h"
|
||||
#include "include/UdpContext.h"
|
||||
|
||||
|
||||
template<>
|
||||
WiFiUDP* SList<WiFiUDP>::_s_first = 0;
|
||||
|
||||
/* Constructor */
|
||||
WiFiUDP::WiFiUDP() : _ctx(0) {}
|
||||
WiFiUDP::WiFiUDP() : _ctx(0)
|
||||
{
|
||||
WiFiUDP::_add(this);
|
||||
}
|
||||
|
||||
WiFiUDP::WiFiUDP(const WiFiUDP& other)
|
||||
{
|
||||
_ctx = other._ctx;
|
||||
if (_ctx)
|
||||
_ctx->ref();
|
||||
WiFiUDP::_add(this);
|
||||
}
|
||||
|
||||
WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
|
||||
@ -60,6 +68,7 @@ WiFiUDP& WiFiUDP::operator=(const WiFiUDP& rhs)
|
||||
|
||||
WiFiUDP::~WiFiUDP()
|
||||
{
|
||||
WiFiUDP::_remove(this);
|
||||
if (_ctx)
|
||||
_ctx->unref();
|
||||
}
|
||||
@ -258,3 +267,11 @@ uint16_t WiFiUDP::localPort()
|
||||
|
||||
return _ctx->getLocalPort();
|
||||
}
|
||||
|
||||
void WiFiUDP::stopAll()
|
||||
{
|
||||
for (WiFiUDP* it = _s_first; it; it = it->_next) {
|
||||
it->stop();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,12 +23,13 @@
|
||||
#define WIFIUDP_H
|
||||
|
||||
#include <Udp.h>
|
||||
#include <include/slist.h>
|
||||
|
||||
#define UDP_TX_PACKET_MAX_SIZE 8192
|
||||
|
||||
class UdpContext;
|
||||
|
||||
class WiFiUDP : public UDP {
|
||||
class WiFiUDP : public UDP, public SList<WiFiUDP> {
|
||||
private:
|
||||
UdpContext* _ctx;
|
||||
|
||||
@ -103,6 +104,8 @@ public:
|
||||
// Return the local port for outgoing packets
|
||||
uint16_t localPort();
|
||||
|
||||
static void stopAll();
|
||||
|
||||
};
|
||||
|
||||
#endif //WIFIUDP_H
|
||||
|
@ -261,8 +261,17 @@ class ClientContext {
|
||||
}
|
||||
|
||||
void _error(err_t err) {
|
||||
DEBUGV(":er %d\r\n", err);
|
||||
close();
|
||||
DEBUGV(":er %d %d %d\r\n", err, _size_sent, _send_waiting);
|
||||
if (err != ERR_ABRT) {
|
||||
abort();
|
||||
}
|
||||
else {
|
||||
tcp_arg(_pcb, NULL);
|
||||
tcp_sent(_pcb, NULL);
|
||||
tcp_recv(_pcb, NULL);
|
||||
tcp_err(_pcb, NULL);
|
||||
_pcb = NULL;
|
||||
}
|
||||
if(_size_sent && _send_waiting) {
|
||||
esp_schedule();
|
||||
}
|
||||
|
38
libraries/ESP8266WiFi/src/include/slist.h
Normal file
38
libraries/ESP8266WiFi/src/include/slist.h
Normal file
@ -0,0 +1,38 @@
|
||||
#ifndef SLIST_H
|
||||
#define SLIST_H
|
||||
|
||||
template<typename T>
|
||||
class SList {
|
||||
public:
|
||||
SList() : _next(0) { }
|
||||
|
||||
protected:
|
||||
|
||||
static void _add(T* self) {
|
||||
T* tmp = _s_first;
|
||||
_s_first = self;
|
||||
self->_next = tmp;
|
||||
}
|
||||
|
||||
static void _remove(T* self) {
|
||||
if (_s_first == self) {
|
||||
_s_first = self->_next;
|
||||
self->_next = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
for (T* prev = _s_first; prev->_next; _s_first = _s_first->_next) {
|
||||
if (prev->_next == self) {
|
||||
prev->_next = self->_next;
|
||||
self->_next = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static T* _s_first;
|
||||
T* _next;
|
||||
};
|
||||
|
||||
|
||||
#endif //SLIST_H
|
Reference in New Issue
Block a user