summaryrefslogtreecommitdiffhomepage
path: root/NetEx
diff options
context:
space:
mode:
authormilo24x7@gmail.com <milo24x7@gmail.com@076cb2c4-205e-83fd-5cf3-1be9aa105544>2013-07-07 21:40:05 +0000
committermilo24x7@gmail.com <milo24x7@gmail.com@076cb2c4-205e-83fd-5cf3-1be9aa105544>2013-07-07 21:40:05 +0000
commit7943704cfe4e7d6c853ddca82f2d0f3365fb2c88 (patch)
treed520b8e84e9ce5ad843c8bef47bd67fae7a2c01f /NetEx
parent2c1c5595efec1db63c142accda59e83079af217e (diff)
downloadstarshatter-7943704cfe4e7d6c853ddca82f2d0f3365fb2c88.zip
starshatter-7943704cfe4e7d6c853ddca82f2d0f3365fb2c88.tar.gz
starshatter-7943704cfe4e7d6c853ddca82f2d0f3365fb2c88.tar.bz2
Updated open source license declaration and fixed some formatting issues.
Diffstat (limited to 'NetEx')
-rw-r--r--NetEx/HttpClient.cpp158
-rw-r--r--NetEx/HttpClient.h108
-rw-r--r--NetEx/HttpServer.cpp2030
-rw-r--r--NetEx/HttpServer.h456
-rw-r--r--NetEx/HttpServlet.cpp470
-rw-r--r--NetEx/HttpServlet.h192
-rw-r--r--NetEx/HttpServletExec.cpp489
-rw-r--r--NetEx/HttpServletExec.h136
-rw-r--r--NetEx/NetAddr.cpp238
-rw-r--r--NetEx/NetAddr.h138
-rw-r--r--NetEx/NetClient.cpp256
-rw-r--r--NetEx/NetClient.h228
-rw-r--r--NetEx/NetGram.cpp246
-rw-r--r--NetEx/NetGram.h182
-rw-r--r--NetEx/NetHost.cpp228
-rw-r--r--NetEx/NetHost.h122
-rw-r--r--NetEx/NetLayer.cpp210
-rw-r--r--NetEx/NetLayer.h112
-rw-r--r--NetEx/NetLink.cpp998
-rw-r--r--NetEx/NetLink.h248
-rw-r--r--NetEx/NetMsg.cpp202
-rw-r--r--NetEx/NetMsg.h186
-rw-r--r--NetEx/NetPeer.cpp904
-rw-r--r--NetEx/NetPeer.h218
-rw-r--r--NetEx/NetServer.cpp544
-rw-r--r--NetEx/NetServer.h152
-rw-r--r--NetEx/NetSock.cpp708
-rw-r--r--NetEx/NetSock.h168
28 files changed, 5499 insertions, 4828 deletions
diff --git a/NetEx/HttpClient.cpp b/NetEx/HttpClient.cpp
index 3f7e204..a9cef50 100644
--- a/NetEx/HttpClient.cpp
+++ b/NetEx/HttpClient.cpp
@@ -1,68 +1,92 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: HttpClient.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#include "MemDebug.h"
-#include "HttpClient.h"
-#include "NetHost.h"
-#include "NetLayer.h"
-#include <mmsystem.h>
-
-// +-------------------------------------------------------------------+
-
-HttpClient::HttpClient(const NetAddr& server_addr)
- : NetClient(server_addr)
-{
-}
-
-HttpClient::~HttpClient()
-{
- cookies.destroy();
-}
-
-HttpResponse*
-HttpClient::DoRequest(HttpRequest& request)
-{
- // add existing cookies to request before sending:
- CombineCookies(request.GetCookies(), cookies);
-
- Text req = request.operator Text();
- Text msg = SendRecv(req);
- HttpResponse* response = new(__FILE__,__LINE__) HttpResponse(msg);
-
- if (response) {
- // save cookies returned in response:
- CombineCookies(cookies, response->GetCookies());
- }
-
- return response;
-}
-
-void
-HttpClient::CombineCookies(List<HttpParam>& dst, List<HttpParam>& src)
-{
- for (int i = 0; i < src.size(); i++) {
- HttpParam* s = src[i];
- HttpParam* d = dst.find(s);
-
- if (d) {
- d->value = s->value;
- }
- else {
- HttpParam* cookie = new(__FILE__,__LINE__) HttpParam(s->name, s->value);
- if (cookie)
- dst.append(cookie);
- }
- }
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: HttpClient.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#include "MemDebug.h"
+#include "HttpClient.h"
+#include "NetHost.h"
+#include "NetLayer.h"
+#include <mmsystem.h>
+
+// +-------------------------------------------------------------------+
+
+HttpClient::HttpClient(const NetAddr& server_addr)
+ : NetClient(server_addr)
+{
+}
+
+HttpClient::~HttpClient()
+{
+ cookies.destroy();
+}
+
+HttpResponse*
+HttpClient::DoRequest(HttpRequest& request)
+{
+ // add existing cookies to request before sending:
+ CombineCookies(request.GetCookies(), cookies);
+
+ Text req = request.operator Text();
+ Text msg = SendRecv(req);
+ HttpResponse* response = new(__FILE__,__LINE__) HttpResponse(msg);
+
+ if (response) {
+ // save cookies returned in response:
+ CombineCookies(cookies, response->GetCookies());
+ }
+
+ return response;
+}
+
+void
+HttpClient::CombineCookies(List<HttpParam>& dst, List<HttpParam>& src)
+{
+ for (int i = 0; i < src.size(); i++) {
+ HttpParam* s = src[i];
+ HttpParam* d = dst.find(s);
+
+ if (d) {
+ d->value = s->value;
+ }
+ else {
+ HttpParam* cookie = new(__FILE__,__LINE__) HttpParam(s->name, s->value);
+ if (cookie)
+ dst.append(cookie);
+ }
+ }
} \ No newline at end of file
diff --git a/NetEx/HttpClient.h b/NetEx/HttpClient.h
index 51ea161..e9b84b9 100644
--- a/NetEx/HttpClient.h
+++ b/NetEx/HttpClient.h
@@ -1,43 +1,67 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: HttpClient.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- HTTP/1.1 client class
-*/
-
-
-#ifndef HttpClient_h
-#define HttpClient_h
-
-#include "NetClient.h"
-#include "HttpServer.h"
-
-// +-------------------------------------------------------------------+
-
-class HttpClient : public NetClient
-{
-public:
- static const char* TYPENAME() { return "HttpClient"; }
-
- HttpClient(const NetAddr& server_addr);
- virtual ~HttpClient();
-
- int operator == (const HttpClient& c) const { return this == &c; }
-
- HttpResponse* DoRequest(HttpRequest& request);
-
-protected:
- void CombineCookies(List<HttpParam>& dst, List<HttpParam>& src);
-
- List<HttpParam> cookies;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: HttpClient.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ HTTP/1.1 client class
+*/
+
+
+#ifndef HttpClient_h
+#define HttpClient_h
+
+#include "NetClient.h"
+#include "HttpServer.h"
+
+// +-------------------------------------------------------------------+
+
+class HttpClient : public NetClient
+{
+public:
+ static const char* TYPENAME() { return "HttpClient"; }
+
+ HttpClient(const NetAddr& server_addr);
+ virtual ~HttpClient();
+
+ int operator == (const HttpClient& c) const { return this == &c; }
+
+ HttpResponse* DoRequest(HttpRequest& request);
+
+protected:
+ void CombineCookies(List<HttpParam>& dst, List<HttpParam>& src);
+
+ List<HttpParam> cookies;
+};
+
+
#endif HttpClient_h \ No newline at end of file
diff --git a/NetEx/HttpServer.cpp b/NetEx/HttpServer.cpp
index 5926a25..92a13b2 100644
--- a/NetEx/HttpServer.cpp
+++ b/NetEx/HttpServer.cpp
@@ -1,1003 +1,1027 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: HttpServer.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#include "MemDebug.h"
-#include "HttpServer.h"
-#include "NetLayer.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-
-// +-------------------------------------------------------------------+
-
-HttpServer::HttpServer(WORD port, int poolsize)
- : NetServer(port, poolsize)
-{
- http_server_name = "Generic HttpServer 1.0";
-}
-
-HttpServer::~HttpServer()
-{ }
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpServer::ProcessRequest(Text msg, const NetAddr& addr)
-{
- HttpRequest request(msg);
- HttpResponse response;
-
- request.SetClientAddr(addr);
-
- switch (request.Method()) {
- case HttpRequest::HTTP_GET:
- if (DoGet(request, response))
- return response;
-
- case HttpRequest::HTTP_POST:
- if (DoPost(request, response))
- return response;
-
- case HttpRequest::HTTP_HEAD:
- if (DoHead(request, response))
- return response;
- }
-
- return ErrorResponse();
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpServer::GetServerName()
-{
- return http_server_name;
-}
-
-void
-HttpServer::SetServerName(const char* name)
-{
- http_server_name = name;
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpServer::DefaultResponse()
-{
- Text response = "HTTP/1.1 200 OK\nServer: ";
- response += http_server_name;
- response += "\nMIME-Version: 1.0\nContent-Type: text/html\nConnection: close\n\n";
-
- return response;
-}
-
-Text
-HttpServer::ErrorResponse()
-{
- Text response = "HTTP/1.1 500 Internal Server Error\nServer:";
- response += http_server_name;
- response += "\nMIME-Version: 1.0\nContent-Type: text/html\nConnection: close\n\n";
-
- response += "<html><head><title>";
- response += http_server_name;
- response += " Error</title></head>\n";
- response += "<body bgcolor=\"black\" text=\"white\">\n<h1>";
- response += http_server_name;
- response += "</h1>\n<p>Veruca... sweetheart... angel... I'm not a magician!\n";
- response += "</body></html>\n\n";
-
- return response;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-HttpServer::DoGet(HttpRequest& request, HttpResponse& response)
-{
- char buffer[1024];
- Text content;
-
- content = "<html><head><title>";
- content += http_server_name;
- content += "</title></head>\n";
- content += "<body bgcolor=\"white\" text=\"black\">\n<h1>";
- content += http_server_name;
- content += "</h1>\n";
- content += "<br><h3>Client Address:</h3><p>\n";
-
- sprintf_s(buffer, "%d.%d.%d.%d:%d<br><br>\n",
- client_addr.B1(),
- client_addr.B2(),
- client_addr.B3(),
- client_addr.B4(),
- client_addr.Port());
-
- content += buffer;
- content += "<h3>Request Method:</h3><p>\n";
-
- switch (request.Method()) {
- case HttpRequest::HTTP_GET:
- content += "GET";
- break;
-
- case HttpRequest::HTTP_POST:
- content += "POST";
- break;
-
- case HttpRequest::HTTP_HEAD:
- content += "HEAD";
- break;
-
- default:
- content += "(unsupported?)";
- break;
- }
-
- content += "<br>\n";
- content += "<br><h3>URI Requested:</h3><p>\n";
- content += request.URI();
- content += "<br>\n";
-
- if (request.GetQuery().size() > 0) {
- content += "<br><h3>Query Parameters:</h3>\n";
-
- ListIter<HttpParam> q_iter = request.GetQuery();
- while (++q_iter) {
- HttpParam* q = q_iter.value();
- sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", q->name.data(), q->value.data());
- content += buffer;
- }
- }
-
- content += "<br><h3>Request Headers:</h3>\n";
- ListIter<HttpParam> h_iter = request.GetHeaders();
- while (++h_iter) {
- HttpParam* h = h_iter.value();
- sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", h->name.data(), h->value.data());
- content += buffer;
- }
-
- content += "</body></html>\n\n";
-
- response.SetStatus(HttpResponse::SC_OK);
- response.AddHeader("Server", http_server_name);
- response.AddHeader("MIME-Version", "1.0");
- response.AddHeader("Content-Type", "text/html");
- response.SetContent(content);
-
- return true;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-HttpServer::DoPost(HttpRequest& request, HttpResponse& response)
-{
- return DoGet(request, response);
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-HttpServer::DoHead(HttpRequest& request, HttpResponse& response)
-{
- if (DoGet(request, response)) {
- int len = response.Content().length();
-
- char buffer[256];
- sprintf_s(buffer, "%d", len);
- response.SetHeader("Content-Length", buffer);
- response.SetContent("");
-
- return true;
- }
-
- return false;
-}
-
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-
-HttpRequest::HttpRequest(const char* r)
- : method(0)
-{
- if (r && *r)
- ParseRequest(r);
-}
-
-HttpRequest::~HttpRequest()
-{
- query.destroy();
- headers.destroy();
- cookies.destroy();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-HttpRequest::ParseRequest(Text request)
-{
- if (request.length() <= 8)
- return;
-
- const char* pReq = 0;
- const char* pURI = 0;
- const char* pQuery = 0;
-
- switch (request[0]) {
- case 'G':
- if (request.indexOf("GET") == 0)
- method = HTTP_GET;
- break;
-
- case 'P':
- if (request.indexOf("POST") == 0)
- method = HTTP_POST;
- break;
-
- case 'H':
- if (request.indexOf("HEAD") == 0)
- method = HTTP_HEAD;
- break;
-
- default:
- break;
- }
-
- if (!method) return;
-
- char buffer[1024];
- int i = 0;
-
- // save the request line:
- pReq = request.data();
- while (*pReq && *pReq != '\n')
- buffer[i++] = *pReq++;
- buffer[i] = 0;
-
- request_line = buffer;
- i = 0;
-
- // find the URI:
- pURI = request.data();
- while (*pURI && !isspace(*pURI))
- pURI++;
-
- while (*pURI && isspace(*pURI))
- pURI++;
-
- // copy the URI and find the query string:
- while (*pURI && *pURI != '?' && !isspace(*pURI)) {
- buffer[i++] = *pURI++;
- }
-
- buffer[i] = 0;
- uri = buffer;
- pQuery = pURI;
-
- // parse the query string:
- if (*pQuery == '?') {
- pQuery++;
-
- while (*pQuery && !isspace(*pQuery)) {
- char name_buf[1024];
- char value_buf[1024];
-
- i = 0;
- while (*pQuery && *pQuery != '=' && !isspace(*pQuery))
- name_buf[i++] = *pQuery++;
- name_buf[i] = 0;
-
- if (*pQuery == '=')
- pQuery++;
-
- i = 0;
- while (*pQuery && *pQuery != '&' && !isspace(*pQuery))
- value_buf[i++] = *pQuery++;
- value_buf[i] = 0;
-
- if (*pQuery == '&')
- pQuery++;
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, DecodeParam(value_buf));
- if (param)
- query.append(param);
- }
- }
-
- // get the headers:
- const char* p = request.data();
- while (*p && *p != '\n')
- p++;
-
- if (*p == '\n') p++;
-
- while (*p && *p != '\r' && *p != '\n') {
- char name_buf[1024];
- char value_buf[1024];
-
- i = 0;
- while (*p && *p != ':')
- name_buf[i++] = *p++;
- name_buf[i] = 0;
-
- p++; // skip ':'
- while (isspace(*p)) p++; // skip spaces
-
- i = 0;
- while (*p && *p != '\r' && *p != '\n') // read to end of header line
- value_buf[i++] = *p++;
- value_buf[i] = 0;
-
- if (!_stricmp(name_buf, "Cookie")) {
- ParseCookie(value_buf);
- }
- else {
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, value_buf);
- if (param)
- headers.append(param);
- }
-
- while (*p && *p != '\n')
- p++;
-
- if (*p == '\n') p++;
- }
-
- if (method == HTTP_POST && *p) {
- while (*p == '\n' || *p == '\r')
- p++;
-
- content = *p;
- pQuery = p;
-
- while (*pQuery && !isspace(*pQuery)) {
- char name_buf[1024];
- char value_buf[1024];
-
- i = 0;
- while (*pQuery && *pQuery != '=' && !isspace(*pQuery))
- name_buf[i++] = *pQuery++;
- name_buf[i] = 0;
-
- if (*pQuery == '=')
- pQuery++;
-
- i = 0;
- while (*pQuery && *pQuery != '&' && !isspace(*pQuery))
- value_buf[i++] = *pQuery++;
- value_buf[i] = 0;
-
- if (*pQuery == '&')
- pQuery++;
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, DecodeParam(value_buf));
- if (param)
- query.append(param);
- }
- }
-}
-
-void
-HttpRequest::ParseCookie(const char* param)
-{
- const char* p = param;
-
- while (p && *p) {
- while (isspace(*p)) p++;
-
- // just ignore reserved attributes
- if (*p == '$') {
- while (*p && !isspace(*p) && *p != ';') p++;
-
- if (*p == ';')
- p++;
- }
-
- // found a cookie!
- else if (isalpha(*p)) {
- char name[1024];
- char data[1024];
-
- char* d = name;
- while (*p && *p != '=')
- *d++ = *p++;
- *d = 0;
-
- if (*p == '=')
- p++;
-
- if (*p == '"')
- p++;
-
- d = data;
- while (*p && *p != '"' && *p != ';')
- *d++ = *p++;
- *d = 0;
-
- if (*p == '"')
- p++;
-
- if (*p == ';')
- p++;
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, data);
- if (param)
- cookies.append(param);
- }
-
- // this shouldn't happen - abandon the parse
- else {
- return;
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpRequest::GetParam(const char* name)
-{
- ListIter<HttpParam> iter = query;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name)
- return p->value;
- }
-
- return Text();
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpRequest::GetHeader(const char* name)
-{
- ListIter<HttpParam> iter = headers;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name)
- return p->value;
- }
-
- return Text();
-}
-
-void
-HttpRequest::SetHeader(const char* name, const char* value)
-{
- ListIter<HttpParam> iter = headers;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name) {
- p->value = value;
- return;
- }
- }
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- headers.append(param);
-}
-
-void
-HttpRequest::AddHeader(const char* name, const char* value)
-{
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- headers.append(param);
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpRequest::GetCookie(const char* name)
-{
- ListIter<HttpParam> iter = cookies;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name)
- return p->value;
- }
-
- return Text();
-}
-
-void
-HttpRequest::SetCookie(const char* name, const char* value)
-{
- ListIter<HttpParam> iter = cookies;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name) {
- p->value = value;
- return;
- }
- }
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- cookies.append(param);
-}
-
-void
-HttpRequest::AddCookie(const char* name, const char* value)
-{
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- cookies.append(param);
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpRequest::DecodeParam(const char* value)
-{
- if (!value || !*value) return "";
-
- int size = strlen(value);
- char val = 0;
- char code[4];
- char sbuf[256];
- char* lbuf = 0;
-
- char* dst = sbuf;
- char* p = sbuf;
-
- if (size > 255) {
- lbuf = new(__FILE__,__LINE__) char[size+1];
- dst = lbuf;
- p = lbuf;
- }
-
- if (p) {
- while (*value) {
- switch (*value) {
- default: *p++ = *value; break;
- case '+': *p++ = ' '; break;
-
- case '%':
- value++;
- code[0] = *value++;
- code[1] = *value;
- code[2] = 0;
-
- val = (char) strtol(code, 0, 16);
- *p++ = val;
- break;
- }
-
- value++;
- }
-
- *p = 0;
- }
-
- Text result = dst;
-
- if (lbuf)
- delete [] lbuf;
-
- return result;
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpRequest::EncodeParam(const char* value)
-{
- if (!value || !*value) return "";
-
- int size = strlen(value);
- char hex1 = 0;
- char hex2 = 0;
-
- char sbuf[1024];
- char* lbuf = 0;
-
- char* dst = sbuf;
- char* p = sbuf;
-
- if (size > 255) {
- lbuf = new(__FILE__,__LINE__) char[4*size+1];
- dst = lbuf;
- p = lbuf;
- }
-
- if (p) {
- while (*value) {
- switch (*value) {
- default: *p++ = *value; break;
- case ' ': *p++ = '+'; break;
-
- case '?': *p++ = '%'; *p++ = '3'; *p++ = 'F'; break;
- case '&': *p++ = '%'; *p++ = '2'; *p++ = '6'; break;
- case ':': *p++ = '%'; *p++ = '3'; *p++ = 'A'; break;
- case '/': *p++ = '%'; *p++ = '2'; *p++ = 'F'; break;
- case '\\': *p++ = '%'; *p++ = '5'; *p++ = 'C'; break;
- case '%': *p++ = '%'; *p++ = '2'; *p++ = '5'; break;
- case '|': *p++ = '%'; *p++ = '7'; *p++ = 'C'; break;
- case '<': *p++ = '%'; *p++ = '3'; *p++ = 'C'; break;
- case '>': *p++ = '%'; *p++ = '3'; *p++ = 'E'; break;
- case '[': *p++ = '%'; *p++ = '5'; *p++ = 'B'; break;
- case ']': *p++ = '%'; *p++ = '5'; *p++ = 'D'; break;
- case '{': *p++ = '%'; *p++ = '7'; *p++ = 'B'; break;
- case '}': *p++ = '%'; *p++ = '7'; *p++ = 'D'; break;
- case '"': *p++ = '%'; *p++ = '2'; *p++ = '2'; break;
- case '^': *p++ = '%'; *p++ = '5'; *p++ = 'E'; break;
- case '`': *p++ = '%'; *p++ = '6'; *p++ = '0'; break;
- case '\n': break;
- case '\r': break;
- case '\t': break;
- }
-
- value++;
- }
-
- *p = 0;
- }
-
- Text result = dst;
-
- if (lbuf)
- delete [] lbuf;
-
- return result;
-}
-
-// +--------------------------------------------------------------------+
-
-HttpRequest::operator Text()
-{
- Text response = request_line.data();
- response += "\n";
-
- for (int i = 0; i < headers.size(); i++) {
- HttpParam* h = headers[i];
- response += h->name;
- response += ": ";
- response += h->value;
- response += "\n";
- }
-
- for (int i = 0; i < cookies.size(); i++) {
- HttpParam* c = cookies[i];
- response += "Cookie: ";
- response += c->name;
- response += "=\"";
- response += c->value;
- response += "\"\n";
- }
-
- response += "Connection: close\n\n";
- response += content;
-
- return response;
-}
-
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-
-HttpResponse::HttpResponse(int stat, const char* data)
- : status(stat), content(data)
-{ }
-
-HttpResponse::HttpResponse(const char* r)
- : status(0), content(r)
-{
- if (r && *r)
- ParseResponse(r);
-}
-
-HttpResponse::~HttpResponse()
-{
- headers.destroy();
- cookies.destroy();
-}
-
-// +--------------------------------------------------------------------+
-
-HttpResponse::operator Text()
-{
- Text response;
-
- switch (status) {
- case SC_CONTINUE : response = "HTTP/1.1 100 Continue\n"; break;
- case SC_SWITCHING_PROTOCOLS : response = "HTTP/1.1 101 Switching Protocols\n"; break;
-
- case SC_OK : response = "HTTP/1.1 200 OK\n"; break;
- case SC_CREATED : response = "HTTP/1.1 201 Created\n"; break;
- case SC_ACCEPTED : response = "HTTP/1.1 202 Accepted\n"; break;
- case SC_NON_AUTHORITATIVE : response = "HTTP/1.1 203 Non Authoritative\n"; break;
- case SC_NO_CONTENT : response = "HTTP/1.1 204 No Content\n"; break;
- case SC_RESET_CONTENT : response = "HTTP/1.1 205 Reset Content\n"; break;
- case SC_PARTIAL_CONTENT : response = "HTTP/1.1 206 Partial Content\n"; break;
-
- case SC_MULTIPLE_CHOICES : response = "HTTP/1.1 300 Multiple Choices\n"; break;
- case SC_MOVED_PERMANENTLY : response = "HTTP/1.1 301 Moved Permanently\n"; break;
- case SC_FOUND : response = "HTTP/1.1 302 Found\n"; break;
- case SC_SEE_OTHER : response = "HTTP/1.1 303 See Other\n"; break;
- case SC_NOT_MODIFIED : response = "HTTP/1.1 304 Not Modified\n"; break;
- case SC_USE_PROXY : response = "HTTP/1.1 305 Use Proxy\n"; break;
- case SC_TEMPORARY_REDIRECT : response = "HTTP/1.1 307 Temporary Redirect\n"; break;
-
- case SC_BAD_REQUEST : response = "HTTP/1.1 400 Bad Request\n"; break;
- case SC_UNAUTHORIZED : response = "HTTP/1.1 401 Unauthorized\n"; break;
- case SC_PAYMENT_REQUIRED : response = "HTTP/1.1 402 Payment Required\n"; break;
- case SC_FORBIDDEN : response = "HTTP/1.1 403 Forbidden\n"; break;
- case SC_NOT_FOUND : response = "HTTP/1.1 404 Not Found\n"; break;
- case SC_METHOD_NOT_ALLOWED : response = "HTTP/1.1 405 Method Not Allowed\n"; break;
- case SC_NOT_ACCEPTABLE : response = "HTTP/1.1 406 Not Acceptable\n"; break;
- case SC_PROXY_AUTH_REQ : response = "HTTP/1.1 407 Proxy Authorization Req\n"; break;
- case SC_REQUEST_TIME_OUT : response = "HTTP/1.1 408 Request Timeout\n"; break;
- case SC_CONFLICT : response = "HTTP/1.1 409 Conflict\n"; break;
- case SC_GONE : response = "HTTP/1.1 410 Gone\n"; break;
- case SC_LENGTH_REQUIRED : response = "HTTP/1.1 411 Length Required\n"; break;
-
- default:
- case SC_SERVER_ERROR : response = "HTTP/1.1 500 Internal Server Error\n"; break;
- case SC_NOT_IMPLEMENTED : response = "HTTP/1.1 501 Not Implemented\n"; break;
- case SC_BAD_GATEWAY : response = "HTTP/1.1 502 Bad Gateway\n"; break;
- case SC_SERVICE_UNAVAILABLE : response = "HTTP/1.1 503 Service Unavailable\n"; break;
- case SC_GATEWAY_TIMEOUT : response = "HTTP/1.1 504 Gateway Timeout\n"; break;
- case SC_VERSION_NOT_SUPPORTED: response = "HTTP/1.1 505 HTTP Version Not Supported\n"; break;
- }
-
- SetHeader("Connection", "close");
-
- char buffer[256];
-
- if (content.length()) {
- sprintf_s(buffer, "%d", content.length());
- SetHeader("Content-Length", buffer);
- }
-
- for (int i = 0; i < cookies.size(); i++) {
- HttpParam* cookie = cookies.at(i);
- sprintf_s(buffer, "%s=\"%s\"; Version=\"1\"", cookie->name.data(), cookie->value.data());
-
- AddHeader("Set-Cookie", buffer);
- }
-
- for (int i = 0; i < headers.size(); i++) {
- const HttpParam* p = headers.at(i);
- sprintf_s(buffer, "%s: %s\n", p->name.data(), p->value.data());
- response += buffer;
- }
-
- response += "\n";
- response += content;
-
- return response;
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpResponse::GetHeader(const char* name)
-{
- ListIter<HttpParam> iter = headers;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name)
- return p->value;
- }
-
- return Text();
-}
-
-void
-HttpResponse::SetHeader(const char* name, const char* value)
-{
- ListIter<HttpParam> iter = headers;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name) {
- p->value = value;
- return;
- }
- }
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- headers.append(param);
-}
-
-void
-HttpResponse::AddHeader(const char* name, const char* value)
-{
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- headers.append(param);
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpResponse::GetCookie(const char* name)
-{
- ListIter<HttpParam> iter = cookies;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name)
- return p->value;
- }
-
- return Text();
-}
-
-void
-HttpResponse::SetCookie(const char* name, const char* value)
-{
- ListIter<HttpParam> iter = cookies;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name) {
- p->value = value;
- return;
- }
- }
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- cookies.append(param);
-}
-
-void
-HttpResponse::AddCookie(const char* name, const char* value)
-{
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- cookies.append(param);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-HttpResponse::SendRedirect(const char* url)
-{
- status = SC_TEMPORARY_REDIRECT;
- SetHeader("Location", url);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-HttpResponse::ParseResponse(Text response)
-{
- if (response.length() <= 12 || response.indexOf("HTTP/1.") != 0)
- return;
-
- const char* pStatus = response.data() + 9;
-
- sscanf_s(pStatus, "%d", &status);
- if (!status) return;
-
- int i = 0;
-
- // get the headers:
- const char* p = response.data();
- while (*p && *p != '\n')
- p++;
-
- if (*p == '\n') p++;
-
- while (*p && *p != '\r' && *p != '\n') {
- char name_buf[1024];
- char value_buf[1024];
-
- i = 0;
- while (*p && *p != ':')
- name_buf[i++] = *p++;
- name_buf[i] = 0;
-
- p++; // skip ':'
- while (isspace(*p)) p++; // skip spaces
-
- i = 0;
- while (*p && *p != '\r' && *p != '\n') // read to end of header line
- value_buf[i++] = *p++;
- value_buf[i] = 0;
-
- if (!_stricmp(name_buf, "Set-Cookie")) {
- ParseCookie(value_buf);
- }
- else {
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, value_buf);
- if (param)
- headers.append(param);
- }
-
- while (*p && *p != '\n')
- p++;
-
- if (*p == '\n') p++;
- }
-
- if (*p == '\n') p++;
- content = p;
-}
-
-void
-HttpResponse::ParseCookie(const char* param)
-{
- const char* p = param;
-
- while (p && *p) {
- while (isspace(*p)) p++;
-
- // just ignore reserved attributes
- if (*p == '$') {
- while (*p && !isspace(*p) && *p != ';') p++;
-
- if (*p == ';')
- p++;
- }
-
- // found a cookie!
- else if (isalpha(*p)) {
- char name[1024];
- char data[1024];
-
- char* d = name;
- while (*p && *p != '=')
- *d++ = *p++;
- *d = 0;
-
- if (*p == '=')
- p++;
-
- if (*p == '"')
- p++;
-
- d = data;
- while (*p && *p != '"' && *p != ';')
- *d++ = *p++;
- *d = 0;
-
- if (*p == '"')
- p++;
-
- if (*p == ';')
- p++;
-
- // ignore the version attribute
- if (_stricmp(name, "version")) {
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, data);
- if (param)
- cookies.append(param);
- }
- }
-
- // this shouldn't happen - abandon the parse
- else {
- return;
- }
- }
-}
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: HttpServer.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#include "MemDebug.h"
+#include "HttpServer.h"
+#include "NetLayer.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+// +-------------------------------------------------------------------+
+
+HttpServer::HttpServer(WORD port, int poolsize)
+ : NetServer(port, poolsize)
+{
+ http_server_name = "Generic HttpServer 1.0";
+}
+
+HttpServer::~HttpServer()
+{ }
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpServer::ProcessRequest(Text msg, const NetAddr& addr)
+{
+ HttpRequest request(msg);
+ HttpResponse response;
+
+ request.SetClientAddr(addr);
+
+ switch (request.Method()) {
+ case HttpRequest::HTTP_GET:
+ if (DoGet(request, response))
+ return response;
+
+ case HttpRequest::HTTP_POST:
+ if (DoPost(request, response))
+ return response;
+
+ case HttpRequest::HTTP_HEAD:
+ if (DoHead(request, response))
+ return response;
+ }
+
+ return ErrorResponse();
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpServer::GetServerName()
+{
+ return http_server_name;
+}
+
+void
+HttpServer::SetServerName(const char* name)
+{
+ http_server_name = name;
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpServer::DefaultResponse()
+{
+ Text response = "HTTP/1.1 200 OK\nServer: ";
+ response += http_server_name;
+ response += "\nMIME-Version: 1.0\nContent-Type: text/html\nConnection: close\n\n";
+
+ return response;
+}
+
+Text
+HttpServer::ErrorResponse()
+{
+ Text response = "HTTP/1.1 500 Internal Server Error\nServer:";
+ response += http_server_name;
+ response += "\nMIME-Version: 1.0\nContent-Type: text/html\nConnection: close\n\n";
+
+ response += "<html><head><title>";
+ response += http_server_name;
+ response += " Error</title></head>\n";
+ response += "<body bgcolor=\"black\" text=\"white\">\n<h1>";
+ response += http_server_name;
+ response += "</h1>\n<p>Veruca... sweetheart... angel... I'm not a magician!\n";
+ response += "</body></html>\n\n";
+
+ return response;
+}
+
+// +--------------------------------------------------------------------+
+
+bool
+HttpServer::DoGet(HttpRequest& request, HttpResponse& response)
+{
+ char buffer[1024];
+ Text content;
+
+ content = "<html><head><title>";
+ content += http_server_name;
+ content += "</title></head>\n";
+ content += "<body bgcolor=\"white\" text=\"black\">\n<h1>";
+ content += http_server_name;
+ content += "</h1>\n";
+ content += "<br><h3>Client Address:</h3><p>\n";
+
+ sprintf_s(buffer, "%d.%d.%d.%d:%d<br><br>\n",
+ client_addr.B1(),
+ client_addr.B2(),
+ client_addr.B3(),
+ client_addr.B4(),
+ client_addr.Port());
+
+ content += buffer;
+ content += "<h3>Request Method:</h3><p>\n";
+
+ switch (request.Method()) {
+ case HttpRequest::HTTP_GET:
+ content += "GET";
+ break;
+
+ case HttpRequest::HTTP_POST:
+ content += "POST";
+ break;
+
+ case HttpRequest::HTTP_HEAD:
+ content += "HEAD";
+ break;
+
+ default:
+ content += "(unsupported?)";
+ break;
+ }
+
+ content += "<br>\n";
+ content += "<br><h3>URI Requested:</h3><p>\n";
+ content += request.URI();
+ content += "<br>\n";
+
+ if (request.GetQuery().size() > 0) {
+ content += "<br><h3>Query Parameters:</h3>\n";
+
+ ListIter<HttpParam> q_iter = request.GetQuery();
+ while (++q_iter) {
+ HttpParam* q = q_iter.value();
+ sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", q->name.data(), q->value.data());
+ content += buffer;
+ }
+ }
+
+ content += "<br><h3>Request Headers:</h3>\n";
+ ListIter<HttpParam> h_iter = request.GetHeaders();
+ while (++h_iter) {
+ HttpParam* h = h_iter.value();
+ sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", h->name.data(), h->value.data());
+ content += buffer;
+ }
+
+ content += "</body></html>\n\n";
+
+ response.SetStatus(HttpResponse::SC_OK);
+ response.AddHeader("Server", http_server_name);
+ response.AddHeader("MIME-Version", "1.0");
+ response.AddHeader("Content-Type", "text/html");
+ response.SetContent(content);
+
+ return true;
+}
+
+// +--------------------------------------------------------------------+
+
+bool
+HttpServer::DoPost(HttpRequest& request, HttpResponse& response)
+{
+ return DoGet(request, response);
+}
+
+// +--------------------------------------------------------------------+
+
+bool
+HttpServer::DoHead(HttpRequest& request, HttpResponse& response)
+{
+ if (DoGet(request, response)) {
+ int len = response.Content().length();
+
+ char buffer[256];
+ sprintf_s(buffer, "%d", len);
+ response.SetHeader("Content-Length", buffer);
+ response.SetContent("");
+
+ return true;
+ }
+
+ return false;
+}
+
+// +--------------------------------------------------------------------+
+// +--------------------------------------------------------------------+
+// +--------------------------------------------------------------------+
+
+HttpRequest::HttpRequest(const char* r)
+ : method(0)
+{
+ if (r && *r)
+ ParseRequest(r);
+}
+
+HttpRequest::~HttpRequest()
+{
+ query.destroy();
+ headers.destroy();
+ cookies.destroy();
+}
+
+// +--------------------------------------------------------------------+
+
+void
+HttpRequest::ParseRequest(Text request)
+{
+ if (request.length() <= 8)
+ return;
+
+ const char* pReq = 0;
+ const char* pURI = 0;
+ const char* pQuery = 0;
+
+ switch (request[0]) {
+ case 'G':
+ if (request.indexOf("GET") == 0)
+ method = HTTP_GET;
+ break;
+
+ case 'P':
+ if (request.indexOf("POST") == 0)
+ method = HTTP_POST;
+ break;
+
+ case 'H':
+ if (request.indexOf("HEAD") == 0)
+ method = HTTP_HEAD;
+ break;
+
+ default:
+ break;
+ }
+
+ if (!method) return;
+
+ char buffer[1024];
+ int i = 0;
+
+ // save the request line:
+ pReq = request.data();
+ while (*pReq && *pReq != '\n')
+ buffer[i++] = *pReq++;
+ buffer[i] = 0;
+
+ request_line = buffer;
+ i = 0;
+
+ // find the URI:
+ pURI = request.data();
+ while (*pURI && !isspace(*pURI))
+ pURI++;
+
+ while (*pURI && isspace(*pURI))
+ pURI++;
+
+ // copy the URI and find the query string:
+ while (*pURI && *pURI != '?' && !isspace(*pURI)) {
+ buffer[i++] = *pURI++;
+ }
+
+ buffer[i] = 0;
+ uri = buffer;
+ pQuery = pURI;
+
+ // parse the query string:
+ if (*pQuery == '?') {
+ pQuery++;
+
+ while (*pQuery && !isspace(*pQuery)) {
+ char name_buf[1024];
+ char value_buf[1024];
+
+ i = 0;
+ while (*pQuery && *pQuery != '=' && !isspace(*pQuery))
+ name_buf[i++] = *pQuery++;
+ name_buf[i] = 0;
+
+ if (*pQuery == '=')
+ pQuery++;
+
+ i = 0;
+ while (*pQuery && *pQuery != '&' && !isspace(*pQuery))
+ value_buf[i++] = *pQuery++;
+ value_buf[i] = 0;
+
+ if (*pQuery == '&')
+ pQuery++;
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, DecodeParam(value_buf));
+ if (param)
+ query.append(param);
+ }
+ }
+
+ // get the headers:
+ const char* p = request.data();
+ while (*p && *p != '\n')
+ p++;
+
+ if (*p == '\n') p++;
+
+ while (*p && *p != '\r' && *p != '\n') {
+ char name_buf[1024];
+ char value_buf[1024];
+
+ i = 0;
+ while (*p && *p != ':')
+ name_buf[i++] = *p++;
+ name_buf[i] = 0;
+
+ p++; // skip ':'
+ while (isspace(*p)) p++; // skip spaces
+
+ i = 0;
+ while (*p && *p != '\r' && *p != '\n') // read to end of header line
+ value_buf[i++] = *p++;
+ value_buf[i] = 0;
+
+ if (!_stricmp(name_buf, "Cookie")) {
+ ParseCookie(value_buf);
+ }
+ else {
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, value_buf);
+ if (param)
+ headers.append(param);
+ }
+
+ while (*p && *p != '\n')
+ p++;
+
+ if (*p == '\n') p++;
+ }
+
+ if (method == HTTP_POST && *p) {
+ while (*p == '\n' || *p == '\r')
+ p++;
+
+ content = *p;
+ pQuery = p;
+
+ while (*pQuery && !isspace(*pQuery)) {
+ char name_buf[1024];
+ char value_buf[1024];
+
+ i = 0;
+ while (*pQuery && *pQuery != '=' && !isspace(*pQuery))
+ name_buf[i++] = *pQuery++;
+ name_buf[i] = 0;
+
+ if (*pQuery == '=')
+ pQuery++;
+
+ i = 0;
+ while (*pQuery && *pQuery != '&' && !isspace(*pQuery))
+ value_buf[i++] = *pQuery++;
+ value_buf[i] = 0;
+
+ if (*pQuery == '&')
+ pQuery++;
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, DecodeParam(value_buf));
+ if (param)
+ query.append(param);
+ }
+ }
+}
+
+void
+HttpRequest::ParseCookie(const char* param)
+{
+ const char* p = param;
+
+ while (p && *p) {
+ while (isspace(*p)) p++;
+
+ // just ignore reserved attributes
+ if (*p == '$') {
+ while (*p && !isspace(*p) && *p != ';') p++;
+
+ if (*p == ';')
+ p++;
+ }
+
+ // found a cookie!
+ else if (isalpha(*p)) {
+ char name[1024];
+ char data[1024];
+
+ char* d = name;
+ while (*p && *p != '=')
+ *d++ = *p++;
+ *d = 0;
+
+ if (*p == '=')
+ p++;
+
+ if (*p == '"')
+ p++;
+
+ d = data;
+ while (*p && *p != '"' && *p != ';')
+ *d++ = *p++;
+ *d = 0;
+
+ if (*p == '"')
+ p++;
+
+ if (*p == ';')
+ p++;
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, data);
+ if (param)
+ cookies.append(param);
+ }
+
+ // this shouldn't happen - abandon the parse
+ else {
+ return;
+ }
+ }
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpRequest::GetParam(const char* name)
+{
+ ListIter<HttpParam> iter = query;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name)
+ return p->value;
+ }
+
+ return Text();
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpRequest::GetHeader(const char* name)
+{
+ ListIter<HttpParam> iter = headers;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name)
+ return p->value;
+ }
+
+ return Text();
+}
+
+void
+HttpRequest::SetHeader(const char* name, const char* value)
+{
+ ListIter<HttpParam> iter = headers;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name) {
+ p->value = value;
+ return;
+ }
+ }
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ headers.append(param);
+}
+
+void
+HttpRequest::AddHeader(const char* name, const char* value)
+{
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ headers.append(param);
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpRequest::GetCookie(const char* name)
+{
+ ListIter<HttpParam> iter = cookies;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name)
+ return p->value;
+ }
+
+ return Text();
+}
+
+void
+HttpRequest::SetCookie(const char* name, const char* value)
+{
+ ListIter<HttpParam> iter = cookies;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name) {
+ p->value = value;
+ return;
+ }
+ }
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ cookies.append(param);
+}
+
+void
+HttpRequest::AddCookie(const char* name, const char* value)
+{
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ cookies.append(param);
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpRequest::DecodeParam(const char* value)
+{
+ if (!value || !*value) return "";
+
+ int size = strlen(value);
+ char val = 0;
+ char code[4];
+ char sbuf[256];
+ char* lbuf = 0;
+
+ char* dst = sbuf;
+ char* p = sbuf;
+
+ if (size > 255) {
+ lbuf = new(__FILE__,__LINE__) char[size+1];
+ dst = lbuf;
+ p = lbuf;
+ }
+
+ if (p) {
+ while (*value) {
+ switch (*value) {
+ default: *p++ = *value; break;
+ case '+': *p++ = ' '; break;
+
+ case '%':
+ value++;
+ code[0] = *value++;
+ code[1] = *value;
+ code[2] = 0;
+
+ val = (char) strtol(code, 0, 16);
+ *p++ = val;
+ break;
+ }
+
+ value++;
+ }
+
+ *p = 0;
+ }
+
+ Text result = dst;
+
+ if (lbuf)
+ delete [] lbuf;
+
+ return result;
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpRequest::EncodeParam(const char* value)
+{
+ if (!value || !*value) return "";
+
+ int size = strlen(value);
+ char hex1 = 0;
+ char hex2 = 0;
+
+ char sbuf[1024];
+ char* lbuf = 0;
+
+ char* dst = sbuf;
+ char* p = sbuf;
+
+ if (size > 255) {
+ lbuf = new(__FILE__,__LINE__) char[4*size+1];
+ dst = lbuf;
+ p = lbuf;
+ }
+
+ if (p) {
+ while (*value) {
+ switch (*value) {
+ default: *p++ = *value; break;
+ case ' ': *p++ = '+'; break;
+
+ case '?': *p++ = '%'; *p++ = '3'; *p++ = 'F'; break;
+ case '&': *p++ = '%'; *p++ = '2'; *p++ = '6'; break;
+ case ':': *p++ = '%'; *p++ = '3'; *p++ = 'A'; break;
+ case '/': *p++ = '%'; *p++ = '2'; *p++ = 'F'; break;
+ case '\\': *p++ = '%'; *p++ = '5'; *p++ = 'C'; break;
+ case '%': *p++ = '%'; *p++ = '2'; *p++ = '5'; break;
+ case '|': *p++ = '%'; *p++ = '7'; *p++ = 'C'; break;
+ case '<': *p++ = '%'; *p++ = '3'; *p++ = 'C'; break;
+ case '>': *p++ = '%'; *p++ = '3'; *p++ = 'E'; break;
+ case '[': *p++ = '%'; *p++ = '5'; *p++ = 'B'; break;
+ case ']': *p++ = '%'; *p++ = '5'; *p++ = 'D'; break;
+ case '{': *p++ = '%'; *p++ = '7'; *p++ = 'B'; break;
+ case '}': *p++ = '%'; *p++ = '7'; *p++ = 'D'; break;
+ case '"': *p++ = '%'; *p++ = '2'; *p++ = '2'; break;
+ case '^': *p++ = '%'; *p++ = '5'; *p++ = 'E'; break;
+ case '`': *p++ = '%'; *p++ = '6'; *p++ = '0'; break;
+ case '\n': break;
+ case '\r': break;
+ case '\t': break;
+ }
+
+ value++;
+ }
+
+ *p = 0;
+ }
+
+ Text result = dst;
+
+ if (lbuf)
+ delete [] lbuf;
+
+ return result;
+}
+
+// +--------------------------------------------------------------------+
+
+HttpRequest::operator Text()
+{
+ Text response = request_line.data();
+ response += "\n";
+
+ for (int i = 0; i < headers.size(); i++) {
+ HttpParam* h = headers[i];
+ response += h->name;
+ response += ": ";
+ response += h->value;
+ response += "\n";
+ }
+
+ for (int i = 0; i < cookies.size(); i++) {
+ HttpParam* c = cookies[i];
+ response += "Cookie: ";
+ response += c->name;
+ response += "=\"";
+ response += c->value;
+ response += "\"\n";
+ }
+
+ response += "Connection: close\n\n";
+ response += content;
+
+ return response;
+}
+
+// +--------------------------------------------------------------------+
+// +--------------------------------------------------------------------+
+// +--------------------------------------------------------------------+
+
+HttpResponse::HttpResponse(int stat, const char* data)
+ : status(stat), content(data)
+{ }
+
+HttpResponse::HttpResponse(const char* r)
+ : status(0), content(r)
+{
+ if (r && *r)
+ ParseResponse(r);
+}
+
+HttpResponse::~HttpResponse()
+{
+ headers.destroy();
+ cookies.destroy();
+}
+
+// +--------------------------------------------------------------------+
+
+HttpResponse::operator Text()
+{
+ Text response;
+
+ switch (status) {
+ case SC_CONTINUE : response = "HTTP/1.1 100 Continue\n"; break;
+ case SC_SWITCHING_PROTOCOLS : response = "HTTP/1.1 101 Switching Protocols\n"; break;
+
+ case SC_OK : response = "HTTP/1.1 200 OK\n"; break;
+ case SC_CREATED : response = "HTTP/1.1 201 Created\n"; break;
+ case SC_ACCEPTED : response = "HTTP/1.1 202 Accepted\n"; break;
+ case SC_NON_AUTHORITATIVE : response = "HTTP/1.1 203 Non Authoritative\n"; break;
+ case SC_NO_CONTENT : response = "HTTP/1.1 204 No Content\n"; break;
+ case SC_RESET_CONTENT : response = "HTTP/1.1 205 Reset Content\n"; break;
+ case SC_PARTIAL_CONTENT : response = "HTTP/1.1 206 Partial Content\n"; break;
+
+ case SC_MULTIPLE_CHOICES : response = "HTTP/1.1 300 Multiple Choices\n"; break;
+ case SC_MOVED_PERMANENTLY : response = "HTTP/1.1 301 Moved Permanently\n"; break;
+ case SC_FOUND : response = "HTTP/1.1 302 Found\n"; break;
+ case SC_SEE_OTHER : response = "HTTP/1.1 303 See Other\n"; break;
+ case SC_NOT_MODIFIED : response = "HTTP/1.1 304 Not Modified\n"; break;
+ case SC_USE_PROXY : response = "HTTP/1.1 305 Use Proxy\n"; break;
+ case SC_TEMPORARY_REDIRECT : response = "HTTP/1.1 307 Temporary Redirect\n"; break;
+
+ case SC_BAD_REQUEST : response = "HTTP/1.1 400 Bad Request\n"; break;
+ case SC_UNAUTHORIZED : response = "HTTP/1.1 401 Unauthorized\n"; break;
+ case SC_PAYMENT_REQUIRED : response = "HTTP/1.1 402 Payment Required\n"; break;
+ case SC_FORBIDDEN : response = "HTTP/1.1 403 Forbidden\n"; break;
+ case SC_NOT_FOUND : response = "HTTP/1.1 404 Not Found\n"; break;
+ case SC_METHOD_NOT_ALLOWED : response = "HTTP/1.1 405 Method Not Allowed\n"; break;
+ case SC_NOT_ACCEPTABLE : response = "HTTP/1.1 406 Not Acceptable\n"; break;
+ case SC_PROXY_AUTH_REQ : response = "HTTP/1.1 407 Proxy Authorization Req\n"; break;
+ case SC_REQUEST_TIME_OUT : response = "HTTP/1.1 408 Request Timeout\n"; break;
+ case SC_CONFLICT : response = "HTTP/1.1 409 Conflict\n"; break;
+ case SC_GONE : response = "HTTP/1.1 410 Gone\n"; break;
+ case SC_LENGTH_REQUIRED : response = "HTTP/1.1 411 Length Required\n"; break;
+
+ default:
+ case SC_SERVER_ERROR : response = "HTTP/1.1 500 Internal Server Error\n"; break;
+ case SC_NOT_IMPLEMENTED : response = "HTTP/1.1 501 Not Implemented\n"; break;
+ case SC_BAD_GATEWAY : response = "HTTP/1.1 502 Bad Gateway\n"; break;
+ case SC_SERVICE_UNAVAILABLE : response = "HTTP/1.1 503 Service Unavailable\n"; break;
+ case SC_GATEWAY_TIMEOUT : response = "HTTP/1.1 504 Gateway Timeout\n"; break;
+ case SC_VERSION_NOT_SUPPORTED: response = "HTTP/1.1 505 HTTP Version Not Supported\n"; break;
+ }
+
+ SetHeader("Connection", "close");
+
+ char buffer[256];
+
+ if (content.length()) {
+ sprintf_s(buffer, "%d", content.length());
+ SetHeader("Content-Length", buffer);
+ }
+
+ for (int i = 0; i < cookies.size(); i++) {
+ HttpParam* cookie = cookies.at(i);
+ sprintf_s(buffer, "%s=\"%s\"; Version=\"1\"", cookie->name.data(), cookie->value.data());
+
+ AddHeader("Set-Cookie", buffer);
+ }
+
+ for (int i = 0; i < headers.size(); i++) {
+ const HttpParam* p = headers.at(i);
+ sprintf_s(buffer, "%s: %s\n", p->name.data(), p->value.data());
+ response += buffer;
+ }
+
+ response += "\n";
+ response += content;
+
+ return response;
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpResponse::GetHeader(const char* name)
+{
+ ListIter<HttpParam> iter = headers;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name)
+ return p->value;
+ }
+
+ return Text();
+}
+
+void
+HttpResponse::SetHeader(const char* name, const char* value)
+{
+ ListIter<HttpParam> iter = headers;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name) {
+ p->value = value;
+ return;
+ }
+ }
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ headers.append(param);
+}
+
+void
+HttpResponse::AddHeader(const char* name, const char* value)
+{
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ headers.append(param);
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpResponse::GetCookie(const char* name)
+{
+ ListIter<HttpParam> iter = cookies;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name)
+ return p->value;
+ }
+
+ return Text();
+}
+
+void
+HttpResponse::SetCookie(const char* name, const char* value)
+{
+ ListIter<HttpParam> iter = cookies;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name) {
+ p->value = value;
+ return;
+ }
+ }
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ cookies.append(param);
+}
+
+void
+HttpResponse::AddCookie(const char* name, const char* value)
+{
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ cookies.append(param);
+}
+
+// +--------------------------------------------------------------------+
+
+void
+HttpResponse::SendRedirect(const char* url)
+{
+ status = SC_TEMPORARY_REDIRECT;
+ SetHeader("Location", url);
+}
+
+// +--------------------------------------------------------------------+
+
+void
+HttpResponse::ParseResponse(Text response)
+{
+ if (response.length() <= 12 || response.indexOf("HTTP/1.") != 0)
+ return;
+
+ const char* pStatus = response.data() + 9;
+
+ sscanf_s(pStatus, "%d", &status);
+ if (!status) return;
+
+ int i = 0;
+
+ // get the headers:
+ const char* p = response.data();
+ while (*p && *p != '\n')
+ p++;
+
+ if (*p == '\n') p++;
+
+ while (*p && *p != '\r' && *p != '\n') {
+ char name_buf[1024];
+ char value_buf[1024];
+
+ i = 0;
+ while (*p && *p != ':')
+ name_buf[i++] = *p++;
+ name_buf[i] = 0;
+
+ p++; // skip ':'
+ while (isspace(*p)) p++; // skip spaces
+
+ i = 0;
+ while (*p && *p != '\r' && *p != '\n') // read to end of header line
+ value_buf[i++] = *p++;
+ value_buf[i] = 0;
+
+ if (!_stricmp(name_buf, "Set-Cookie")) {
+ ParseCookie(value_buf);
+ }
+ else {
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name_buf, value_buf);
+ if (param)
+ headers.append(param);
+ }
+
+ while (*p && *p != '\n')
+ p++;
+
+ if (*p == '\n') p++;
+ }
+
+ if (*p == '\n') p++;
+ content = p;
+}
+
+void
+HttpResponse::ParseCookie(const char* param)
+{
+ const char* p = param;
+
+ while (p && *p) {
+ while (isspace(*p)) p++;
+
+ // just ignore reserved attributes
+ if (*p == '$') {
+ while (*p && !isspace(*p) && *p != ';') p++;
+
+ if (*p == ';')
+ p++;
+ }
+
+ // found a cookie!
+ else if (isalpha(*p)) {
+ char name[1024];
+ char data[1024];
+
+ char* d = name;
+ while (*p && *p != '=')
+ *d++ = *p++;
+ *d = 0;
+
+ if (*p == '=')
+ p++;
+
+ if (*p == '"')
+ p++;
+
+ d = data;
+ while (*p && *p != '"' && *p != ';')
+ *d++ = *p++;
+ *d = 0;
+
+ if (*p == '"')
+ p++;
+
+ if (*p == ';')
+ p++;
+
+ // ignore the version attribute
+ if (_stricmp(name, "version")) {
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, data);
+ if (param)
+ cookies.append(param);
+ }
+ }
+
+ // this shouldn't happen - abandon the parse
+ else {
+ return;
+ }
+ }
+}
+
diff --git a/NetEx/HttpServer.h b/NetEx/HttpServer.h
index fe811b3..fb74fbc 100644
--- a/NetEx/HttpServer.h
+++ b/NetEx/HttpServer.h
@@ -1,217 +1,241 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: HttpServer.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#ifndef HttpServer_h
-#define HttpServer_h
-
-#include "NetServer.h"
-
-// +-------------------------------------------------------------------+
-
-class HttpParam;
-class HttpRequest;
-class HttpResponse;
-
-// +-------------------------------------------------------------------+
-
-class HttpServer : public NetServer
-{
-public:
- static const char* TYPENAME() { return "HttpServer"; }
-
- HttpServer(WORD port, int poolsize=1);
- virtual ~HttpServer();
-
- int operator == (const HttpServer& l) const { return addr == l.addr; }
-
- virtual Text ProcessRequest(Text request, const NetAddr& addr);
- virtual Text DefaultResponse();
- virtual Text ErrorResponse();
-
- virtual bool DoGet(HttpRequest& request, HttpResponse& response);
- virtual bool DoPost(HttpRequest& request, HttpResponse& response);
- virtual bool DoHead(HttpRequest& request, HttpResponse& response);
-
- virtual Text GetServerName();
- virtual void SetServerName(const char* name);
-
-protected:
- Text http_server_name;
-};
-
-// +-------------------------------------------------------------------+
-
-class HttpParam
-{
-public:
- static const char* TYPENAME() { return "HttpParam"; }
-
- HttpParam(const char* n, const char* v) : name(n), value(v) { }
-
- int operator == (const HttpParam& p) const { return name == p.name; }
-
- Text name;
- Text value;
-};
-
-// +-------------------------------------------------------------------+
-
-class HttpRequest
-{
-public:
- static const char* TYPENAME() { return "HttpRequest"; }
-
- enum METHOD {
- HTTP_OPTIONS,
- HTTP_GET,
- HTTP_HEAD,
- HTTP_POST,
- HTTP_PUT,
- HTTP_DELETE,
- HTTP_TRACE,
- HTTP_CONNECT
- };
-
- HttpRequest(const char* request=0);
- ~HttpRequest();
-
- operator Text();
-
- void ParseRequest(Text request);
- void ParseCookie(const char* param);
-
- int Method() const { return method; }
- Text URI() const { return uri; }
- Text Content() const { return content; }
- Text RequestLine() const { return request_line; }
-
- List<HttpParam>& GetQuery() { return query; }
- List<HttpParam>& GetHeaders() { return headers; }
- List<HttpParam>& GetCookies() { return cookies; }
-
- NetAddr GetClientAddr() const { return client_addr; }
- void SetClientAddr(const NetAddr& a) { client_addr = a; }
-
- Text GetParam(const char* name);
-
- Text GetHeader(const char* name);
- void SetHeader(const char* name, const char* value);
- void AddHeader(const char* name, const char* value);
- Text GetCookie(const char* name);
- void SetCookie(const char* name, const char* value);
- void AddCookie(const char* name, const char* value);
-
- Text DecodeParam(const char* value);
- static Text EncodeParam(const char* value);
-
-private:
- int method;
- Text uri;
- Text content;
- Text request_line;
- NetAddr client_addr;
-
- List<HttpParam> query;
- List<HttpParam> headers;
- List<HttpParam> cookies;
-};
-
-// +-------------------------------------------------------------------+
-
-class HttpResponse
-{
-public:
- static const char* TYPENAME() { return "HttpResponse"; }
-
- enum STATUS {
- SC_CONTINUE = 100,
- SC_SWITCHING_PROTOCOLS = 101,
-
- SC_OK = 200,
- SC_CREATED = 201,
- SC_ACCEPTED = 202,
- SC_NON_AUTHORITATIVE = 203,
- SC_NO_CONTENT = 204,
- SC_RESET_CONTENT = 205,
- SC_PARTIAL_CONTENT = 206,
-
- SC_MULTIPLE_CHOICES = 300,
- SC_MOVED_PERMANENTLY = 301,
- SC_FOUND = 302,
- SC_SEE_OTHER = 303,
- SC_NOT_MODIFIED = 304,
- SC_USE_PROXY = 305,
- SC_TEMPORARY_REDIRECT = 307,
-
- SC_BAD_REQUEST = 400,
- SC_UNAUTHORIZED = 401,
- SC_PAYMENT_REQUIRED = 402,
- SC_FORBIDDEN = 403,
- SC_NOT_FOUND = 404,
- SC_METHOD_NOT_ALLOWED = 405,
- SC_NOT_ACCEPTABLE = 406,
- SC_PROXY_AUTH_REQ = 407,
- SC_REQUEST_TIME_OUT = 408,
- SC_CONFLICT = 409,
- SC_GONE = 410,
- SC_LENGTH_REQUIRED = 411,
-
- SC_SERVER_ERROR = 500,
- SC_NOT_IMPLEMENTED = 501,
- SC_BAD_GATEWAY = 502,
- SC_SERVICE_UNAVAILABLE = 503,
- SC_GATEWAY_TIMEOUT = 504,
- SC_VERSION_NOT_SUPPORTED= 505
- };
-
-
- HttpResponse(int status=500, const char* content=0);
- HttpResponse(const char* response);
- ~HttpResponse();
-
- operator Text();
-
- void ParseResponse(Text request);
- void ParseCookie(const char* param);
-
- int Status() const { return status; }
- void SetStatus(int s) { status = s; }
-
- Text Content() const { return content; }
- void SetContent(Text t) { content = t; }
- void AddContent(Text t) { content += t; }
-
- List<HttpParam>& GetHeaders() { return headers; }
- List<HttpParam>& GetCookies() { return cookies; }
-
- Text GetHeader(const char* name);
- void SetHeader(const char* name, const char* value);
- void AddHeader(const char* name, const char* value);
- Text GetCookie(const char* name);
- void SetCookie(const char* name, const char* value);
- void AddCookie(const char* name, const char* value);
-
- void SendRedirect(const char* url);
-
-private:
- int status;
- Text content;
-
- List<HttpParam> headers;
- List<HttpParam> cookies;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: HttpServer.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#ifndef HttpServer_h
+#define HttpServer_h
+
+#include "NetServer.h"
+
+// +-------------------------------------------------------------------+
+
+class HttpParam;
+class HttpRequest;
+class HttpResponse;
+
+// +-------------------------------------------------------------------+
+
+class HttpServer : public NetServer
+{
+public:
+ static const char* TYPENAME() { return "HttpServer"; }
+
+ HttpServer(WORD port, int poolsize=1);
+ virtual ~HttpServer();
+
+ int operator == (const HttpServer& l) const { return addr == l.addr; }
+
+ virtual Text ProcessRequest(Text request, const NetAddr& addr);
+ virtual Text DefaultResponse();
+ virtual Text ErrorResponse();
+
+ virtual bool DoGet(HttpRequest& request, HttpResponse& response);
+ virtual bool DoPost(HttpRequest& request, HttpResponse& response);
+ virtual bool DoHead(HttpRequest& request, HttpResponse& response);
+
+ virtual Text GetServerName();
+ virtual void SetServerName(const char* name);
+
+protected:
+ Text http_server_name;
+};
+
+// +-------------------------------------------------------------------+
+
+class HttpParam
+{
+public:
+ static const char* TYPENAME() { return "HttpParam"; }
+
+ HttpParam(const char* n, const char* v) : name(n), value(v) { }
+
+ int operator == (const HttpParam& p) const { return name == p.name; }
+
+ Text name;
+ Text value;
+};
+
+// +-------------------------------------------------------------------+
+
+class HttpRequest
+{
+public:
+ static const char* TYPENAME() { return "HttpRequest"; }
+
+ enum METHOD {
+ HTTP_OPTIONS,
+ HTTP_GET,
+ HTTP_HEAD,
+ HTTP_POST,
+ HTTP_PUT,
+ HTTP_DELETE,
+ HTTP_TRACE,
+ HTTP_CONNECT
+ };
+
+ HttpRequest(const char* request=0);
+ ~HttpRequest();
+
+ operator Text();
+
+ void ParseRequest(Text request);
+ void ParseCookie(const char* param);
+
+ int Method() const { return method; }
+ Text URI() const { return uri; }
+ Text Content() const { return content; }
+ Text RequestLine() const { return request_line; }
+
+ List<HttpParam>& GetQuery() { return query; }
+ List<HttpParam>& GetHeaders() { return headers; }
+ List<HttpParam>& GetCookies() { return cookies; }
+
+ NetAddr GetClientAddr() const { return client_addr; }
+ void SetClientAddr(const NetAddr& a) { client_addr = a; }
+
+ Text GetParam(const char* name);
+
+ Text GetHeader(const char* name);
+ void SetHeader(const char* name, const char* value);
+ void AddHeader(const char* name, const char* value);
+ Text GetCookie(const char* name);
+ void SetCookie(const char* name, const char* value);
+ void AddCookie(const char* name, const char* value);
+
+ Text DecodeParam(const char* value);
+ static Text EncodeParam(const char* value);
+
+private:
+ int method;
+ Text uri;
+ Text content;
+ Text request_line;
+ NetAddr client_addr;
+
+ List<HttpParam> query;
+ List<HttpParam> headers;
+ List<HttpParam> cookies;
+};
+
+// +-------------------------------------------------------------------+
+
+class HttpResponse
+{
+public:
+ static const char* TYPENAME() { return "HttpResponse"; }
+
+ enum STATUS {
+ SC_CONTINUE = 100,
+ SC_SWITCHING_PROTOCOLS = 101,
+
+ SC_OK = 200,
+ SC_CREATED = 201,
+ SC_ACCEPTED = 202,
+ SC_NON_AUTHORITATIVE = 203,
+ SC_NO_CONTENT = 204,
+ SC_RESET_CONTENT = 205,
+ SC_PARTIAL_CONTENT = 206,
+
+ SC_MULTIPLE_CHOICES = 300,
+ SC_MOVED_PERMANENTLY = 301,
+ SC_FOUND = 302,
+ SC_SEE_OTHER = 303,
+ SC_NOT_MODIFIED = 304,
+ SC_USE_PROXY = 305,
+ SC_TEMPORARY_REDIRECT = 307,
+
+ SC_BAD_REQUEST = 400,
+ SC_UNAUTHORIZED = 401,
+ SC_PAYMENT_REQUIRED = 402,
+ SC_FORBIDDEN = 403,
+ SC_NOT_FOUND = 404,
+ SC_METHOD_NOT_ALLOWED = 405,
+ SC_NOT_ACCEPTABLE = 406,
+ SC_PROXY_AUTH_REQ = 407,
+ SC_REQUEST_TIME_OUT = 408,
+ SC_CONFLICT = 409,
+ SC_GONE = 410,
+ SC_LENGTH_REQUIRED = 411,
+
+ SC_SERVER_ERROR = 500,
+ SC_NOT_IMPLEMENTED = 501,
+ SC_BAD_GATEWAY = 502,
+ SC_SERVICE_UNAVAILABLE = 503,
+ SC_GATEWAY_TIMEOUT = 504,
+ SC_VERSION_NOT_SUPPORTED= 505
+ };
+
+
+ HttpResponse(int status=500, const char* content=0);
+ HttpResponse(const char* response);
+ ~HttpResponse();
+
+ operator Text();
+
+ void ParseResponse(Text request);
+ void ParseCookie(const char* param);
+
+ int Status() const { return status; }
+ void SetStatus(int s) { status = s; }
+
+ Text Content() const { return content; }
+ void SetContent(Text t) { content = t; }
+ void AddContent(Text t) { content += t; }
+
+ List<HttpParam>& GetHeaders() { return headers; }
+ List<HttpParam>& GetCookies() { return cookies; }
+
+ Text GetHeader(const char* name);
+ void SetHeader(const char* name, const char* value);
+ void AddHeader(const char* name, const char* value);
+ Text GetCookie(const char* name);
+ void SetCookie(const char* name, const char* value);
+ void AddCookie(const char* name, const char* value);
+
+ void SendRedirect(const char* url);
+
+private:
+ int status;
+ Text content;
+
+ List<HttpParam> headers;
+ List<HttpParam> cookies;
+};
+
+
#endif HttpServer_h \ No newline at end of file
diff --git a/NetEx/HttpServlet.cpp b/NetEx/HttpServlet.cpp
index 504f2fa..17f5084 100644
--- a/NetEx/HttpServlet.cpp
+++ b/NetEx/HttpServlet.cpp
@@ -1,223 +1,247 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: HttpServlet.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#include "MemDebug.h"
-#include "HttpServlet.h"
-#include "NetLayer.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-
-// +-------------------------------------------------------------------+
-
-HttpServlet::HttpServlet()
- : session(0)
-{ }
-
-HttpServlet::~HttpServlet()
-{ }
-
-// +--------------------------------------------------------------------+
-
-bool
-HttpServlet::Service(HttpRequest& request, HttpResponse& response)
-{
- bool result = false;
-
- switch (request.Method()) {
- case HttpRequest::HTTP_GET:
- result = DoGet(request, response);
- break;
-
- case HttpRequest::HTTP_POST:
- result = DoPost(request, response);
- break;
-
- case HttpRequest::HTTP_HEAD:
- result = DoHead(request, response);
- break;
-
- default:
- break;
- }
-
- return result;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-HttpServlet::DoGet(HttpRequest& request, HttpResponse& response)
-{
- return false;
-}
-
-bool
-HttpServlet::DoPost(HttpRequest& request, HttpResponse& response)
-{
- return DoGet(request, response);
-}
-
-bool
-HttpServlet::DoHead(HttpRequest& request, HttpResponse& response)
-{
- if (DoGet(request, response)) {
- int len = response.Content().length();
-
- char buffer[256];
- sprintf(buffer, "%d", len);
- response.SetHeader("Content-Length", buffer);
- response.SetContent("");
-
- return true;
- }
-
- return false;
-}
-
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-// +--------------------------------------------------------------------+
-
-HttpSession::HttpSession()
-{
- id = GenerateUniqueID();
- access_time = NetLayer::GetUTC();
-}
-
-HttpSession::~HttpSession()
-{
- attributes.destroy();
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpSession::GetAttribute(const char* name)
-{
- ListIter<HttpParam> iter = attributes;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name)
- return p->value;
- }
-
- return Text();
-}
-
-void
-HttpSession::SetAttribute(const char* name, const char* value)
-{
- ListIter<HttpParam> iter = attributes;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name) {
- p->value = value;
- return;
- }
- }
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
- if (param)
- attributes.append(param);
-}
-
-void
-HttpSession::DelAttribute(const char* name)
-{
- ListIter<HttpParam> iter = attributes;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name) {
- delete iter.removeItem();
- return;
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-int
-HttpSession::GetIntAttribute(const char* name)
-{
- ListIter<HttpParam> iter = attributes;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name) {
- int result = ::atoi(p->value.data());
- return result;
- }
- }
-
- return 0;
-}
-
-void
-HttpSession::SetIntAttribute(const char* name, int value)
-{
- char buf[32];
- sprintf(buf, "%d", value);
-
- ListIter<HttpParam> iter = attributes;
- while (++iter) {
- HttpParam* p = iter.value();
-
- if (p->name == name) {
- p->value = buf;
- return;
- }
- }
-
- HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, buf);
- if (param)
- attributes.append(param);
-}
-
-void
-HttpSession::DelIntAttribute(const char* name)
-{
- DelAttribute(name);
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-HttpSession::GenerateUniqueID()
-{
- char unique[17];
-
- for (int i = 0; i < 16; i++) {
- char c = rand() % 25 + 'a';
- unique[i] = c;
- }
-
- unique[16] = 0;
- return unique;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-HttpSession::Access()
-{
- access_time = NetLayer::GetUTC();
-}
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: HttpServlet.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#include "MemDebug.h"
+#include "HttpServlet.h"
+#include "NetLayer.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+// +-------------------------------------------------------------------+
+
+HttpServlet::HttpServlet()
+ : session(0)
+{ }
+
+HttpServlet::~HttpServlet()
+{ }
+
+// +--------------------------------------------------------------------+
+
+bool
+HttpServlet::Service(HttpRequest& request, HttpResponse& response)
+{
+ bool result = false;
+
+ switch (request.Method()) {
+ case HttpRequest::HTTP_GET:
+ result = DoGet(request, response);
+ break;
+
+ case HttpRequest::HTTP_POST:
+ result = DoPost(request, response);
+ break;
+
+ case HttpRequest::HTTP_HEAD:
+ result = DoHead(request, response);
+ break;
+
+ default:
+ break;
+ }
+
+ return result;
+}
+
+// +--------------------------------------------------------------------+
+
+bool
+HttpServlet::DoGet(HttpRequest& request, HttpResponse& response)
+{
+ return false;
+}
+
+bool
+HttpServlet::DoPost(HttpRequest& request, HttpResponse& response)
+{
+ return DoGet(request, response);
+}
+
+bool
+HttpServlet::DoHead(HttpRequest& request, HttpResponse& response)
+{
+ if (DoGet(request, response)) {
+ int len = response.Content().length();
+
+ char buffer[256];
+ sprintf(buffer, "%d", len);
+ response.SetHeader("Content-Length", buffer);
+ response.SetContent("");
+
+ return true;
+ }
+
+ return false;
+}
+
+// +--------------------------------------------------------------------+
+// +--------------------------------------------------------------------+
+// +--------------------------------------------------------------------+
+
+HttpSession::HttpSession()
+{
+ id = GenerateUniqueID();
+ access_time = NetLayer::GetUTC();
+}
+
+HttpSession::~HttpSession()
+{
+ attributes.destroy();
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpSession::GetAttribute(const char* name)
+{
+ ListIter<HttpParam> iter = attributes;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name)
+ return p->value;
+ }
+
+ return Text();
+}
+
+void
+HttpSession::SetAttribute(const char* name, const char* value)
+{
+ ListIter<HttpParam> iter = attributes;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name) {
+ p->value = value;
+ return;
+ }
+ }
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, value);
+ if (param)
+ attributes.append(param);
+}
+
+void
+HttpSession::DelAttribute(const char* name)
+{
+ ListIter<HttpParam> iter = attributes;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name) {
+ delete iter.removeItem();
+ return;
+ }
+ }
+}
+
+// +--------------------------------------------------------------------+
+
+int
+HttpSession::GetIntAttribute(const char* name)
+{
+ ListIter<HttpParam> iter = attributes;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name) {
+ int result = ::atoi(p->value.data());
+ return result;
+ }
+ }
+
+ return 0;
+}
+
+void
+HttpSession::SetIntAttribute(const char* name, int value)
+{
+ char buf[32];
+ sprintf(buf, "%d", value);
+
+ ListIter<HttpParam> iter = attributes;
+ while (++iter) {
+ HttpParam* p = iter.value();
+
+ if (p->name == name) {
+ p->value = buf;
+ return;
+ }
+ }
+
+ HttpParam* param = new(__FILE__,__LINE__) HttpParam(name, buf);
+ if (param)
+ attributes.append(param);
+}
+
+void
+HttpSession::DelIntAttribute(const char* name)
+{
+ DelAttribute(name);
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+HttpSession::GenerateUniqueID()
+{
+ char unique[17];
+
+ for (int i = 0; i < 16; i++) {
+ char c = rand() % 25 + 'a';
+ unique[i] = c;
+ }
+
+ unique[16] = 0;
+ return unique;
+}
+
+// +--------------------------------------------------------------------+
+
+void
+HttpSession::Access()
+{
+ access_time = NetLayer::GetUTC();
+}
+
+
diff --git a/NetEx/HttpServlet.h b/NetEx/HttpServlet.h
index 99ac06d..e209671 100644
--- a/NetEx/HttpServlet.h
+++ b/NetEx/HttpServlet.h
@@ -1,85 +1,109 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: HttpServlet.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#ifndef HttpServlet_h
-#define HttpServlet_h
-
-#include "HttpServer.h"
-
-// +-------------------------------------------------------------------+
-
-class HttpServlet;
-class HttpSession;
-
-// +-------------------------------------------------------------------+
-
-class HttpServlet
-{
-public:
- static const char* TYPENAME() { return "HttpServlet"; }
-
- HttpServlet();
- virtual ~HttpServlet();
-
- virtual bool Service(HttpRequest& request, HttpResponse& response);
-
- virtual bool DoGet(HttpRequest& request, HttpResponse& response);
- virtual bool DoPost(HttpRequest& request, HttpResponse& response);
- virtual bool DoHead(HttpRequest& request, HttpResponse& response);
-
- virtual HttpSession* GetSession() { return session; }
- virtual void SetSession(HttpSession* s) { session = s; }
-
-protected:
- HttpSession* session;
-};
-
-// +-------------------------------------------------------------------+
-
-class HttpSession
-{
-public:
- static const char* TYPENAME() { return "HttpSession"; }
-
- HttpSession();
- virtual ~HttpSession();
-
- int operator == (const HttpSession& s) const { return id == s.id; }
-
- Text GenerateUniqueID();
-
- Text GetID() const { return id; }
- void SetID(const char* i) { id = i; }
- int GetLastAccess() const { return access_time;}
- void Access();
-
- List<HttpParam>& GetAttributes() { return attributes; }
-
- Text GetAttribute(const char* name);
- void SetAttribute(const char* name, const char* value);
- void DelAttribute(const char* name);
-
- int GetIntAttribute(const char* name);
- void SetIntAttribute(const char* name, int value);
- void DelIntAttribute(const char* name);
-
-protected:
- Text id;
- int access_time;
- List<HttpParam> attributes;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: HttpServlet.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#ifndef HttpServlet_h
+#define HttpServlet_h
+
+#include "HttpServer.h"
+
+// +-------------------------------------------------------------------+
+
+class HttpServlet;
+class HttpSession;
+
+// +-------------------------------------------------------------------+
+
+class HttpServlet
+{
+public:
+ static const char* TYPENAME() { return "HttpServlet"; }
+
+ HttpServlet();
+ virtual ~HttpServlet();
+
+ virtual bool Service(HttpRequest& request, HttpResponse& response);
+
+ virtual bool DoGet(HttpRequest& request, HttpResponse& response);
+ virtual bool DoPost(HttpRequest& request, HttpResponse& response);
+ virtual bool DoHead(HttpRequest& request, HttpResponse& response);
+
+ virtual HttpSession* GetSession() { return session; }
+ virtual void SetSession(HttpSession* s) { session = s; }
+
+protected:
+ HttpSession* session;
+};
+
+// +-------------------------------------------------------------------+
+
+class HttpSession
+{
+public:
+ static const char* TYPENAME() { return "HttpSession"; }
+
+ HttpSession();
+ virtual ~HttpSession();
+
+ int operator == (const HttpSession& s) const { return id == s.id; }
+
+ Text GenerateUniqueID();
+
+ Text GetID() const { return id; }
+ void SetID(const char* i) { id = i; }
+ int GetLastAccess() const { return access_time;}
+ void Access();
+
+ List<HttpParam>& GetAttributes() { return attributes; }
+
+ Text GetAttribute(const char* name);
+ void SetAttribute(const char* name, const char* value);
+ void DelAttribute(const char* name);
+
+ int GetIntAttribute(const char* name);
+ void SetIntAttribute(const char* name, int value);
+ void DelIntAttribute(const char* name);
+
+protected:
+ Text id;
+ int access_time;
+ List<HttpParam> attributes;
+};
+
+
#endif HttpServlet_h \ No newline at end of file
diff --git a/NetEx/HttpServletExec.cpp b/NetEx/HttpServletExec.cpp
index bd71149..0027fe0 100644
--- a/NetEx/HttpServletExec.cpp
+++ b/NetEx/HttpServletExec.cpp
@@ -1,233 +1,256 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: HttpServletExec.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#include "MemDebug.h"
-#include "HttpServletExec.h"
-#include "HttpServlet.h"
-#include "NetLayer.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-
-// +-------------------------------------------------------------------+
-
-class HttpTestServlet : public HttpServlet
-{
-public:
- HttpTestServlet() { }
- virtual ~HttpTestServlet() { }
-
- virtual bool DoGet(HttpRequest& request, HttpResponse& response)
- {
- char buffer[1024];
- Text content;
-
- content = "<html><head><title>HttpTestServlet</title></head>\n";
- content += "<body bgcolor=\"#c0c0c0\" text=\"black\">\n<h1>HttpTestServlet</h1>\n";
-
- content += "<br><h3>HttpSessionId:</h3><p>\n";
- if (session)
- content += session->GetID();
- else
- content += "No Session Found";
- content += "<br>\n";
-
- content += "<br><h3>URI Requested:</h3><p>\n";
- content += request.URI();
- content += "<br>\n";
-
- if (request.GetQuery().size() > 0) {
- content += "<br><h3>Query Parameters:</h3>\n";
-
- ListIter<HttpParam> q_iter = request.GetQuery();
- while (++q_iter) {
- HttpParam* q = q_iter.value();
- sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", q->name.data(), q->value.data());
- content += buffer;
- }
- }
-
- content += "<br><h3>Request Headers:</h3>\n";
- ListIter<HttpParam> h_iter = request.GetHeaders();
- while (++h_iter) {
- HttpParam* h = h_iter.value();
- sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", h->name.data(), h->value.data());
- content += buffer;
- }
-
- if (request.GetCookies().size() > 0) {
- content += "<br><h3>Cookies:</h3>\n";
- ListIter<HttpParam> c_iter = request.GetCookies();
- while (++c_iter) {
- HttpParam* c = c_iter.value();
- sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", c->name.data(), c->value.data());
- content += buffer;
- }
- }
-
- content += "</body></html>\n\n";
-
- response.SetStatus(HttpResponse::SC_OK);
- response.AddHeader("MIME-Version", "1.0");
- response.AddHeader("Content-Type", "text/html");
- response.SetContent(content);
-
- return true;
- }
-};
-
-// +-------------------------------------------------------------------+
-// +-------------------------------------------------------------------+
-// +-------------------------------------------------------------------+
-
-DWORD WINAPI HttpServletExecSessionProc(LPVOID link);
-
-HttpServletExec::HttpServletExec(WORD port, int poolsize)
- : HttpServer(port, poolsize), session_timeout(60), exec_shutdown(false)
-{
- http_server_name = "Generic HttpServletExec 1.0";
-
- DWORD thread_id = 0;
- hsession = CreateThread(0, 4096, HttpServletExecSessionProc,
- (LPVOID) this, 0, &thread_id);
-}
-
-HttpServletExec::~HttpServletExec()
-{
- if (!exec_shutdown)
- exec_shutdown = true;
-
- WaitForSingleObject(hsession, 1000);
- CloseHandle(hsession);
- hsession = 0;
-
- sessions.destroy();
-}
-
-// +--------------------------------------------------------------------+
-
-HttpServlet*
-HttpServletExec::GetServlet(HttpRequest& request)
-{
- return new(__FILE__,__LINE__) HttpTestServlet;
-}
-
-// +--------------------------------------------------------------------+
-
-HttpSession*
-HttpServletExec::GetSession(HttpRequest& request)
-{
- HttpSession* session = 0;
- Text reqID = request.GetCookie("SessionID");
-
- if (reqID.length() > 0) {
- ListIter<HttpSession> iter = sessions;
- while (++iter && !session) {
- HttpSession* s = iter.value();
-
- if (s->GetID() == reqID) {
- session = s;
- session->Access();
- }
- }
- }
-
- if (!session) {
- session = new(__FILE__,__LINE__) HttpSession;
- if (session) {
- sessions.append(session);
-
- ::Print("HttpServletExec created new session '%s' for request '%s'\n",
- (const char*) session->GetID(),
- (const char*) request.RequestLine());
- }
- else {
- ::Print("HttpServletExec out of memory for request '%s'\n",
- (const char*) request.RequestLine());
- }
- }
-
- return session;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-HttpServletExec::DoGet(HttpRequest& request, HttpResponse& response)
-{
- bool result = false;
- HttpSession* session = GetSession(request);
- HttpServlet* servlet = GetServlet(request);
-
- if (servlet) {
- servlet->SetSession(session);
- result = servlet->Service(request, response);
- delete servlet;
- }
-
- if (result) {
- response.SetHeader("Server", http_server_name);
-
- if (session)
- response.SetCookie("SessionID", session->GetID());
- }
-
- return result;
-}
-
-// +--------------------------------------------------------------------+
-
-DWORD WINAPI HttpServletExecSessionProc(LPVOID link)
-{
- HttpServletExec* exec = (HttpServletExec*) link;
-
- if (exec)
- return exec->CheckSessions();
-
- return (DWORD) E_POINTER;
-}
-
-DWORD
-HttpServletExec::CheckSessions()
-{
- while (!exec_shutdown) {
- sync.acquire();
-
- if (sessions.size()) {
- ListIter<HttpSession> iter = sessions;
- while (++iter) {
- HttpSession* s = iter.value();
-
- if (NetLayer::GetUTC() - s->GetLastAccess() > session_timeout) {
- ::Print("HttpServletExec deleting expired session '%s'\n", (const char*) s->GetID());
- delete iter.removeItem();
- }
- }
- }
-
- DoSyncedCheck();
-
- sync.release();
- Sleep(100);
- }
-
- return 0;
-}
-
-void
-HttpServletExec::DoSyncedCheck()
-{
-} \ No newline at end of file
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: HttpServletExec.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#include "MemDebug.h"
+#include "HttpServletExec.h"
+#include "HttpServlet.h"
+#include "NetLayer.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+// +-------------------------------------------------------------------+
+
+class HttpTestServlet : public HttpServlet
+{
+public:
+ HttpTestServlet() { }
+ virtual ~HttpTestServlet() { }
+
+ virtual bool DoGet(HttpRequest& request, HttpResponse& response)
+ {
+ char buffer[1024];
+ Text content;
+
+ content = "<html><head><title>HttpTestServlet</title></head>\n";
+ content += "<body bgcolor=\"#c0c0c0\" text=\"black\">\n<h1>HttpTestServlet</h1>\n";
+
+ content += "<br><h3>HttpSessionId:</h3><p>\n";
+ if (session)
+ content += session->GetID();
+ else
+ content += "No Session Found";
+ content += "<br>\n";
+
+ content += "<br><h3>URI Requested:</h3><p>\n";
+ content += request.URI();
+ content += "<br>\n";
+
+ if (request.GetQuery().size() > 0) {
+ content += "<br><h3>Query Parameters:</h3>\n";
+
+ ListIter<HttpParam> q_iter = request.GetQuery();
+ while (++q_iter) {
+ HttpParam* q = q_iter.value();
+ sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", q->name.data(), q->value.data());
+ content += buffer;
+ }
+ }
+
+ content += "<br><h3>Request Headers:</h3>\n";
+ ListIter<HttpParam> h_iter = request.GetHeaders();
+ while (++h_iter) {
+ HttpParam* h = h_iter.value();
+ sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", h->name.data(), h->value.data());
+ content += buffer;
+ }
+
+ if (request.GetCookies().size() > 0) {
+ content += "<br><h3>Cookies:</h3>\n";
+ ListIter<HttpParam> c_iter = request.GetCookies();
+ while (++c_iter) {
+ HttpParam* c = c_iter.value();
+ sprintf_s(buffer, "<b>%s:</b> <i>%s</i><br>\n", c->name.data(), c->value.data());
+ content += buffer;
+ }
+ }
+
+ content += "</body></html>\n\n";
+
+ response.SetStatus(HttpResponse::SC_OK);
+ response.AddHeader("MIME-Version", "1.0");
+ response.AddHeader("Content-Type", "text/html");
+ response.SetContent(content);
+
+ return true;
+ }
+};
+
+// +-------------------------------------------------------------------+
+// +-------------------------------------------------------------------+
+// +-------------------------------------------------------------------+
+
+DWORD WINAPI HttpServletExecSessionProc(LPVOID link);
+
+HttpServletExec::HttpServletExec(WORD port, int poolsize)
+ : HttpServer(port, poolsize), session_timeout(60), exec_shutdown(false)
+{
+ http_server_name = "Generic HttpServletExec 1.0";
+
+ DWORD thread_id = 0;
+ hsession = CreateThread(0, 4096, HttpServletExecSessionProc, (LPVOID) this, 0, &thread_id);
+}
+
+HttpServletExec::~HttpServletExec()
+{
+ if (!exec_shutdown)
+ exec_shutdown = true;
+
+ WaitForSingleObject(hsession, 1000);
+ CloseHandle(hsession);
+ hsession = 0;
+
+ sessions.destroy();
+}
+
+// +--------------------------------------------------------------------+
+
+HttpServlet*
+HttpServletExec::GetServlet(HttpRequest& request)
+{
+ return new(__FILE__,__LINE__) HttpTestServlet;
+}
+
+// +--------------------------------------------------------------------+
+
+HttpSession*
+HttpServletExec::GetSession(HttpRequest& request)
+{
+ HttpSession* session = 0;
+ Text reqID = request.GetCookie("SessionID");
+
+ if (reqID.length() > 0) {
+ ListIter<HttpSession> iter = sessions;
+ while (++iter && !session) {
+ HttpSession* s = iter.value();
+
+ if (s->GetID() == reqID) {
+ session = s;
+ session->Access();
+ }
+ }
+ }
+
+ if (!session) {
+ session = new(__FILE__,__LINE__) HttpSession;
+ if (session) {
+ sessions.append(session);
+
+ ::Print("HttpServletExec created new session '%s' for request '%s'\n",
+ (const char*) session->GetID(),
+ (const char*) request.RequestLine());
+ }
+ else {
+ ::Print("HttpServletExec out of memory for request '%s'\n",
+ (const char*) request.RequestLine());
+ }
+ }
+
+ return session;
+}
+
+// +--------------------------------------------------------------------+
+
+bool
+HttpServletExec::DoGet(HttpRequest& request, HttpResponse& response)
+{
+ bool result = false;
+ HttpSession* session = GetSession(request);
+ HttpServlet* servlet = GetServlet(request);
+
+ if (servlet) {
+ servlet->SetSession(session);
+ result = servlet->Service(request, response);
+ delete servlet;
+ }
+
+ if (result) {
+ response.SetHeader("Server", http_server_name);
+
+ if (session)
+ response.SetCookie("SessionID", session->GetID());
+ }
+
+ return result;
+}
+
+// +--------------------------------------------------------------------+
+
+DWORD WINAPI HttpServletExecSessionProc(LPVOID link)
+{
+ HttpServletExec* exec = (HttpServletExec*) link;
+
+ if (exec)
+ return exec->CheckSessions();
+
+ return (DWORD) E_POINTER;
+}
+
+DWORD
+HttpServletExec::CheckSessions()
+{
+ while (!exec_shutdown) {
+ sync.acquire();
+
+ if (sessions.size()) {
+ ListIter<HttpSession> iter = sessions;
+ while (++iter) {
+ HttpSession* s = iter.value();
+
+ if (NetLayer::GetUTC() - s->GetLastAccess() > session_timeout) {
+ ::Print("HttpServletExec deleting expired session '%s'\n", (const char*) s->GetID());
+ delete iter.removeItem();
+ }
+ }
+ }
+
+ DoSyncedCheck();
+
+ sync.release();
+ Sleep(100);
+ }
+
+ return 0;
+}
+
+void
+HttpServletExec::DoSyncedCheck()
+{
+}
diff --git a/NetEx/HttpServletExec.h b/NetEx/HttpServletExec.h
index bead257..3ae1be1 100644
--- a/NetEx/HttpServletExec.h
+++ b/NetEx/HttpServletExec.h
@@ -1,57 +1,81 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: HttpServletExec.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#ifndef HttpServletExec_h
-#define HttpServletExec_h
-
-#include "HttpServer.h"
-
-// +-------------------------------------------------------------------+
-
-class HttpServlet;
-class HttpSession;
-
-// +-------------------------------------------------------------------+
-
-class HttpServletExec : public HttpServer
-{
-public:
- static const char* TYPENAME() { return "HttpServletExec"; }
-
- HttpServletExec(WORD port, int poolsize=1);
- virtual ~HttpServletExec();
-
- int operator == (const HttpServletExec& l) const { return addr == l.addr; }
-
- virtual bool DoGet(HttpRequest& request, HttpResponse& response);
-
- virtual HttpServlet* GetServlet(HttpRequest& request);
- virtual HttpSession* GetSession(HttpRequest& request);
-
- virtual DWORD CheckSessions();
-
- virtual int GetSessionTimeout() const { return session_timeout; }
- virtual void SetSessionTimeout(int t) { session_timeout = t; }
-
-protected:
- virtual void DoSyncedCheck();
-
- List<HttpSession> sessions;
- int session_timeout;
- HANDLE hsession;
- bool exec_shutdown;
-};
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: HttpServletExec.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#ifndef HttpServletExec_h
+#define HttpServletExec_h
+
+#include "HttpServer.h"
+
+// +-------------------------------------------------------------------+
+
+class HttpServlet;
+class HttpSession;
+
+// +-------------------------------------------------------------------+
+
+class HttpServletExec : public HttpServer
+{
+public:
+ static const char* TYPENAME() { return "HttpServletExec"; }
+
+ HttpServletExec(WORD port, int poolsize=1);
+ virtual ~HttpServletExec();
+
+ int operator == (const HttpServletExec& l) const { return addr == l.addr; }
+
+ virtual bool DoGet(HttpRequest& request, HttpResponse& response);
+
+ virtual HttpServlet* GetServlet(HttpRequest& request);
+ virtual HttpSession* GetSession(HttpRequest& request);
+
+ virtual DWORD CheckSessions();
+
+ virtual int GetSessionTimeout() const { return session_timeout; }
+ virtual void SetSessionTimeout(int t) { session_timeout = t; }
+
+protected:
+ virtual void DoSyncedCheck();
+
+ List<HttpSession> sessions;
+ int session_timeout;
+ HANDLE hsession;
+ bool exec_shutdown;
+};
+
#endif HttpServletExec_h \ No newline at end of file
diff --git a/NetEx/NetAddr.cpp b/NetEx/NetAddr.cpp
index 53d6c79..ea26f0a 100644
--- a/NetEx/NetAddr.cpp
+++ b/NetEx/NetAddr.cpp
@@ -1,107 +1,131 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetAddr.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Address
-*/
-
-
-#include "MemDebug.h"
-#include "NetAddr.h"
-#include "NetHost.h"
-#include "NetLayer.h"
-#include <ctype.h>
-
-NetAddr::NetAddr(const char* host_name, WORD p)
- : addr(0), port(p)
-{
- if (host_name && *host_name) {
- HOSTENT* h = 0;
-
- if (isdigit(*host_name)) {
- DWORD a = inet_addr(host_name);
- h = gethostbyaddr((const char*) &a, 4, AF_INET);
- }
- else {
- h = gethostbyname(host_name);
- }
-
- if (h) {
- if (h->h_addr_list) {
- addr = **(DWORD**) (h->h_addr_list);
- }
- }
- }
-
- Init();
-}
-
-NetAddr::NetAddr(DWORD a, WORD p)
- : addr(a), port(p)
-{
- Init();
-}
-
-NetAddr::NetAddr(const NetAddr& n)
- : addr(n.addr), port(n.port)
-{
- Init();
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NetAddr::Init()
-{
- ZeroMemory(&sadr, sizeof(sadr));
-
- sadr.sin_family = AF_INET;
- sadr.sin_port = ::htons(port);
- sadr.sin_addr.s_addr = addr;
-}
-
-void
-NetAddr::InitFromSockAddr()
-{
- addr = sadr.sin_addr.s_addr;
- port = ::ntohs(sadr.sin_port);
-}
-
-// +--------------------------------------------------------------------+
-
-sockaddr*
-NetAddr::GetSockAddr() const
-{
- return (sockaddr*) &sadr;
-}
-
-size_t
-NetAddr::GetSockAddrLength() const
-{
- return sizeof(sadr);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NetAddr::SetSockAddr(sockaddr* s, int size)
-{
- if (s) {
- ZeroMemory(&sadr, sizeof(sadr));
-
- if (size > sizeof(sadr))
- CopyMemory(&sadr, s, sizeof(sadr));
- else
- CopyMemory(&sadr, s, size);
-
- InitFromSockAddr();
- }
-}
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetAddr.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Address
+*/
+
+
+#include "MemDebug.h"
+#include "NetAddr.h"
+#include "NetHost.h"
+#include "NetLayer.h"
+#include <ctype.h>
+
+NetAddr::NetAddr(const char* host_name, WORD p)
+ : addr(0), port(p)
+{
+ if (host_name && *host_name) {
+ HOSTENT* h = 0;
+
+ if (isdigit(*host_name)) {
+ DWORD a = inet_addr(host_name);
+ h = gethostbyaddr((const char*) &a, 4, AF_INET);
+ }
+ else {
+ h = gethostbyname(host_name);
+ }
+
+ if (h) {
+ if (h->h_addr_list) {
+ addr = **(DWORD**) (h->h_addr_list);
+ }
+ }
+ }
+
+ Init();
+}
+
+NetAddr::NetAddr(DWORD a, WORD p)
+ : addr(a), port(p)
+{
+ Init();
+}
+
+NetAddr::NetAddr(const NetAddr& n)
+ : addr(n.addr), port(n.port)
+{
+ Init();
+}
+
+// +--------------------------------------------------------------------+
+
+void
+NetAddr::Init()
+{
+ ZeroMemory(&sadr, sizeof(sadr));
+
+ sadr.sin_family = AF_INET;
+ sadr.sin_port = ::htons(port);
+ sadr.sin_addr.s_addr = addr;
+}
+
+void
+NetAddr::InitFromSockAddr()
+{
+ addr = sadr.sin_addr.s_addr;
+ port = ::ntohs(sadr.sin_port);
+}
+
+// +--------------------------------------------------------------------+
+
+sockaddr*
+NetAddr::GetSockAddr() const
+{
+ return (sockaddr*) &sadr;
+}
+
+size_t
+NetAddr::GetSockAddrLength() const
+{
+ return sizeof(sadr);
+}
+
+// +--------------------------------------------------------------------+
+
+void
+NetAddr::SetSockAddr(sockaddr* s, int size)
+{
+ if (s) {
+ ZeroMemory(&sadr, sizeof(sadr));
+
+ if (size > sizeof(sadr))
+ CopyMemory(&sadr, s, sizeof(sadr));
+ else
+ CopyMemory(&sadr, s, size);
+
+ InitFromSockAddr();
+ }
+}
+
diff --git a/NetEx/NetAddr.h b/NetEx/NetAddr.h
index 562dc64..58e6b9c 100644
--- a/NetEx/NetAddr.h
+++ b/NetEx/NetAddr.h
@@ -1,58 +1,82 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetAddr.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Address (specifically, Internet Protocol)
-*/
-
-
-#ifndef NetAddr_h
-#define NetAddr_h
-
-#include <windows.h>
-
-// +-------------------------------------------------------------------+
-
-class NetAddr
-{
-public:
- static const char* TYPENAME() { return "NetAddr"; }
-
- NetAddr(const char* a, WORD p=0);
- NetAddr(DWORD a=0, WORD p=0);
- NetAddr(const NetAddr& n);
-
- int operator == (const NetAddr& a) const { return addr==a.addr && port==a.port; }
-
- DWORD IPAddr() const { return addr; }
- BYTE B4() const { return (BYTE) ((addr & 0xff000000) >> 24); }
- BYTE B3() const { return (BYTE) ((addr & 0x00ff0000) >> 16); }
- BYTE B2() const { return (BYTE) ((addr & 0x0000ff00) >> 8); }
- BYTE B1() const { return (BYTE) ((addr & 0x000000ff) ); }
-
- WORD Port() const { return port; }
- void SetPort(WORD p) { port = p; }
-
- sockaddr* GetSockAddr() const;
- size_t GetSockAddrLength() const;
-
- void SetSockAddr(sockaddr* s, int size);
- void InitFromSockAddr();
-
-private:
- void Init();
-
- DWORD addr; // IP addr in host byte order
- WORD port; // IP port in host byte order
- sockaddr_in sadr;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetAddr.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Address (specifically, Internet Protocol)
+*/
+
+
+#ifndef NetAddr_h
+#define NetAddr_h
+
+#include <windows.h>
+
+// +-------------------------------------------------------------------+
+
+class NetAddr
+{
+public:
+ static const char* TYPENAME() { return "NetAddr"; }
+
+ NetAddr(const char* a, WORD p=0);
+ NetAddr(DWORD a=0, WORD p=0);
+ NetAddr(const NetAddr& n);
+
+ int operator == (const NetAddr& a) const { return addr==a.addr && port==a.port; }
+
+ DWORD IPAddr() const { return addr; }
+ BYTE B4() const { return (BYTE) ((addr & 0xff000000) >> 24); }
+ BYTE B3() const { return (BYTE) ((addr & 0x00ff0000) >> 16); }
+ BYTE B2() const { return (BYTE) ((addr & 0x0000ff00) >> 8); }
+ BYTE B1() const { return (BYTE) ((addr & 0x000000ff) ); }
+
+ WORD Port() const { return port; }
+ void SetPort(WORD p) { port = p; }
+
+ sockaddr* GetSockAddr() const;
+ size_t GetSockAddrLength() const;
+
+ void SetSockAddr(sockaddr* s, int size);
+ void InitFromSockAddr();
+
+private:
+ void Init();
+
+ DWORD addr; // IP addr in host byte order
+ WORD port; // IP port in host byte order
+ sockaddr_in sadr;
+};
+
+
#endif NetAddr_h \ No newline at end of file
diff --git a/NetEx/NetClient.cpp b/NetEx/NetClient.cpp
index 4f831fb..f31b881 100644
--- a/NetEx/NetClient.cpp
+++ b/NetEx/NetClient.cpp
@@ -1,116 +1,140 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetClient.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#include "MemDebug.h"
-#include "NetClient.h"
-#include "NetHost.h"
-#include "NetLayer.h"
-#include <mmsystem.h>
-
-// +-------------------------------------------------------------------+
-
-NetClient::NetClient(const NetAddr& server_addr)
- : addr(server_addr), sock(0), delta(0), time(0), err(0)
-{
-}
-
-NetClient::~NetClient()
-{
- delete sock;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-NetClient::Send(Text msg)
-{
- if (msg.length() > 0) {
- if (sock)
- delete sock;
-
- sock = new(__FILE__,__LINE__) NetSock(addr, true);
- delta = 0;
- time = timeGetTime();
-
- if (!sock) {
- err = ERR_NOBUFS;
- return false;
- }
-
- err = sock->send(msg);
- if (err < 0) {
- err = NetLayer::GetLastError();
- return false;
- }
-
- err = sock->shutdown_output();
- if (err < 0) {
- err = NetLayer::GetLastError();
- return false;
- }
-
- return true;
- }
-
- else {
- delete sock;
- sock = 0;
- }
-
- return false;
-}
-
-Text
-NetClient::Recv()
-{
- Text response;
-
- if (sock) {
- int ready = sock->select();
-
- while (!ready && timeGetTime() - time < 2000) {
- Sleep(5);
- ready = sock->select();
- }
-
- if (ready) {
- Text msg = sock->recv();
-
- while (msg.length() > 0) {
- response += msg;
- msg = sock->recv();
- }
-
- delta = timeGetTime() - time;
- }
-
- delete sock;
- sock = 0;
- }
-
- return response;
-}
-
-Text
-NetClient::SendRecv(Text msg)
-{
- Text response;
-
- if (msg.length() > 0 && Send(msg)) {
- response = Recv();
- }
-
- return response;
-}
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetClient.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#include "MemDebug.h"
+#include "NetClient.h"
+#include "NetHost.h"
+#include "NetLayer.h"
+#include <mmsystem.h>
+
+// +-------------------------------------------------------------------+
+
+NetClient::NetClient(const NetAddr& server_addr)
+ : addr(server_addr), sock(0), delta(0), time(0), err(0)
+{
+}
+
+NetClient::~NetClient()
+{
+ delete sock;
+}
+
+// +--------------------------------------------------------------------+
+
+bool
+NetClient::Send(Text msg)
+{
+ if (msg.length() > 0) {
+ if (sock)
+ delete sock;
+
+ sock = new(__FILE__,__LINE__) NetSock(addr, true);
+ delta = 0;
+ time = timeGetTime();
+
+ if (!sock) {
+ err = ERR_NOBUFS;
+ return false;
+ }
+
+ err = sock->send(msg);
+ if (err < 0) {
+ err = NetLayer::GetLastError();
+ return false;
+ }
+
+ err = sock->shutdown_output();
+ if (err < 0) {
+ err = NetLayer::GetLastError();
+ return false;
+ }
+
+ return true;
+ }
+
+ else {
+ delete sock;
+ sock = 0;
+ }
+
+ return false;
+}
+
+Text
+NetClient::Recv()
+{
+ Text response;
+
+ if (sock) {
+ int ready = sock->select();
+
+ while (!ready && timeGetTime() - time < 2000) {
+ Sleep(5);
+ ready = sock->select();
+ }
+
+ if (ready) {
+ Text msg = sock->recv();
+
+ while (msg.length() > 0) {
+ response += msg;
+ msg = sock->recv();
+ }
+
+ delta = timeGetTime() - time;
+ }
+
+ delete sock;
+ sock = 0;
+ }
+
+ return response;
+}
+
+Text
+NetClient::SendRecv(Text msg)
+{
+ Text response;
+
+ if (msg.length() > 0 && Send(msg)) {
+ response = Recv();
+ }
+
+ return response;
+}
diff --git a/NetEx/NetClient.h b/NetEx/NetClient.h
index bbc668a..932847c 100644
--- a/NetEx/NetClient.h
+++ b/NetEx/NetClient.h
@@ -1,103 +1,127 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetClient.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Stream-oriented network client class
-*/
-
-
-#ifndef NetClient_h
-#define NetClient_h
-
-#include <windows.h>
-#include "NetAddr.h"
-#include "NetGram.h"
-#include "NetSock.h"
-#include "List.h"
-
-// +-------------------------------------------------------------------+
-
-class NetClient
-{
-public:
- static const char* TYPENAME() { return "NetClient"; }
-
- NetClient(const NetAddr& server_addr);
- virtual ~NetClient();
-
- int operator == (const NetClient& c) const { return this == &c; }
-
- NetAddr GetServerAddr() const { return addr; }
-
- bool Send(Text msg);
- Text Recv();
- Text SendRecv(Text msg);
-
- int GetLastError() const { return err; }
- DWORD GetTime() const { return delta; }
-
-protected:
- NetAddr addr;
- NetSock* sock;
- DWORD delta;
- DWORD time;
- int err;
-
-public:
- enum ERRS {
- ERR_INTR = 10004,
- ERR_BADF = 10009,
- ERR_ACCES = 10013,
- ERR_FAULT = 10014,
- ERR_INVAL = 10022,
- ERR_MFILE = 10024,
-
- ERR_WOULDBLOCK = 10035,
- ERR_INPROGRESS = 10036,
- ERR_ALREADY = 10037,
- ERR_NOTSOCK = 10038,
- ERR_DESTADDRREQ = 10039,
- ERR_MSGSIZE = 10040,
- ERR_PROTOTYPE = 10041,
- ERR_NOPROTOOPT = 10042,
- ERR_PROTONOSUPPORT = 10043,
- ERR_SOCKTNOSUPPORT = 10044,
- ERR_OPNOTSUPP = 10045,
- ERR_PFNOSUPPORT = 10046,
- ERR_AFNOSUPPORT = 10047,
- ERR_ADDRINUSE = 10048,
- ERR_ADDRNOTAVAIL = 10049,
- ERR_NETDOWN = 10050,
- ERR_NETUNREACH = 10051,
- ERR_NETRESET = 10052,
- ERR_CONNABORTED = 10053,
- ERR_CONNRESET = 10054,
- ERR_NOBUFS = 10055,
- ERR_ISCONN = 10056,
- ERR_NOTCONN = 10057,
- ERR_SHUTDOWN = 10058,
- ERR_TOOMANYREFS = 10059,
- ERR_TIMEDOUT = 10060,
- ERR_CONNREFUSED = 10061,
- ERR_LOOP = 10062,
- ERR_NAMETOOLONG = 10063,
- ERR_HOSTDOWN = 10064,
- ERR_HOSTUNREACH = 10065,
- ERR_NOTEMPTY = 10066,
- ERR_PROCLIM = 10067,
- ERR_USERS = 10068,
- ERR_DQUOT = 10069,
- ERR_STALE = 10070,
- ERR_REMOTE = 10071
- };
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetClient.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Stream-oriented network client class
+*/
+
+
+#ifndef NetClient_h
+#define NetClient_h
+
+#include <windows.h>
+#include "NetAddr.h"
+#include "NetGram.h"
+#include "NetSock.h"
+#include "List.h"
+
+// +-------------------------------------------------------------------+
+
+class NetClient
+{
+public:
+ static const char* TYPENAME() { return "NetClient"; }
+
+ NetClient(const NetAddr& server_addr);
+ virtual ~NetClient();
+
+ int operator == (const NetClient& c) const { return this == &c; }
+
+ NetAddr GetServerAddr() const { return addr; }
+
+ bool Send(Text msg);
+ Text Recv();
+ Text SendRecv(Text msg);
+
+ int GetLastError() const { return err; }
+ DWORD GetTime() const { return delta; }
+
+protected:
+ NetAddr addr;
+ NetSock* sock;
+ DWORD delta;
+ DWORD time;
+ int err;
+
+public:
+ enum ERRS {
+ ERR_INTR = 10004,
+ ERR_BADF = 10009,
+ ERR_ACCES = 10013,
+ ERR_FAULT = 10014,
+ ERR_INVAL = 10022,
+ ERR_MFILE = 10024,
+
+ ERR_WOULDBLOCK = 10035,
+ ERR_INPROGRESS = 10036,
+ ERR_ALREADY = 10037,
+ ERR_NOTSOCK = 10038,
+ ERR_DESTADDRREQ = 10039,
+ ERR_MSGSIZE = 10040,
+ ERR_PROTOTYPE = 10041,
+ ERR_NOPROTOOPT = 10042,
+ ERR_PROTONOSUPPORT = 10043,
+ ERR_SOCKTNOSUPPORT = 10044,
+ ERR_OPNOTSUPP = 10045,
+ ERR_PFNOSUPPORT = 10046,
+ ERR_AFNOSUPPORT = 10047,
+ ERR_ADDRINUSE = 10048,
+ ERR_ADDRNOTAVAIL = 10049,
+ ERR_NETDOWN = 10050,
+ ERR_NETUNREACH = 10051,
+ ERR_NETRESET = 10052,
+ ERR_CONNABORTED = 10053,
+ ERR_CONNRESET = 10054,
+ ERR_NOBUFS = 10055,
+ ERR_ISCONN = 10056,
+ ERR_NOTCONN = 10057,
+ ERR_SHUTDOWN = 10058,
+ ERR_TOOMANYREFS = 10059,
+ ERR_TIMEDOUT = 10060,
+ ERR_CONNREFUSED = 10061,
+ ERR_LOOP = 10062,
+ ERR_NAMETOOLONG = 10063,
+ ERR_HOSTDOWN = 10064,
+ ERR_HOSTUNREACH = 10065,
+ ERR_NOTEMPTY = 10066,
+ ERR_PROCLIM = 10067,
+ ERR_USERS = 10068,
+ ERR_DQUOT = 10069,
+ ERR_STALE = 10070,
+ ERR_REMOTE = 10071
+ };
+};
+
+
#endif NetClient_h \ No newline at end of file
diff --git a/NetEx/NetGram.cpp b/NetEx/NetGram.cpp
index 94e1ca2..3bb8f2a 100644
--- a/NetEx/NetGram.cpp
+++ b/NetEx/NetGram.cpp
@@ -1,111 +1,135 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetGram.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Generic Network Packet (Datagram) Implementation
-*/
-
-
-#include "MemDebug.h"
-#include "NetGram.h"
-#include "NetLayer.h"
-
-// +-------------------------------------------------------------------+
-
-static DWORD net_gram_sequence = 1;
-
-// +-------------------------------------------------------------------+
-
-/**
- * NetGram constructor for ACK packets
- */
-NetGram::NetGram()
- : retries(0), packet_id(0), send_time(0)
-{ }
-
-/**
- * NetGram constructor for receiving packets from remote hosts
- */
-NetGram::NetGram(const NetAddr& src, Text msg)
- : addr(src), retries(0), send_time(0)
-{
- body = msg;
-
- if (body.length() >= NET_GRAM_HEADER_SIZE) {
- BYTE* data = (BYTE*) body.data();
-
- packet_id = (((DWORD) data[0]) << 24) +
- (((DWORD) data[1]) << 16) +
- (((DWORD) data[2]) << 8) +
- ((DWORD) data[3]);
- }
-}
-
-/**
- * NetGram constructor for composing packets to send to remote hosts
- */
-NetGram::NetGram(const NetAddr& dst, Text user_data, int r)
- : addr(dst), retries(r)
-{
- send_time = NetLayer::GetTime();
- packet_id = net_gram_sequence++;
-
- if (retries)
- packet_id |= NET_GRAM_RELIABLE;
-
- static BYTE buf[NET_GRAM_MAX_SIZE];
- buf[0] = (BYTE) (packet_id >> 24) & 0xff;
- buf[1] = (BYTE) (packet_id >> 16) & 0xff;
- buf[2] = (BYTE) (packet_id >> 8) & 0xff;
- buf[3] = (BYTE) (packet_id) & 0xff;
-
- int len = user_data.length();
- if (len >= NET_GRAM_MAX_SIZE - NET_GRAM_HEADER_SIZE)
- len = NET_GRAM_MAX_SIZE - NET_GRAM_HEADER_SIZE - 1;
-
- CopyMemory(buf+NET_GRAM_HEADER_SIZE, user_data.data(), len);
-
- body = Text((char*) buf, len+NET_GRAM_HEADER_SIZE);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NetGram::Retry()
-{
- if (retries > 0) {
- retries--;
- send_time = NetLayer::GetTime();
- }
-}
-
-// +--------------------------------------------------------------------+
-
-NetGram
-NetGram::Ack()
-{
- NetGram ack;
-
- ack.packet_id = packet_id | NET_GRAM_ACK;
- ack.send_time = NetLayer::GetTime();
-
- static BYTE buf[NET_GRAM_HEADER_SIZE];
- buf[0] = (BYTE) (ack.packet_id >> 24) & 0xff;
- buf[1] = (BYTE) (ack.packet_id >> 16) & 0xff;
- buf[2] = (BYTE) (ack.packet_id >> 8) & 0xff;
- buf[3] = (BYTE) (ack.packet_id) & 0xff;
-
- ack.body = Text((char*) buf, NET_GRAM_HEADER_SIZE);
-
- return ack;
-}
-
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetGram.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Generic Network Packet (Datagram) Implementation
+*/
+
+
+#include "MemDebug.h"
+#include "NetGram.h"
+#include "NetLayer.h"
+
+// +-------------------------------------------------------------------+
+
+static DWORD net_gram_sequence = 1;
+
+// +-------------------------------------------------------------------+
+
+/**
+ * NetGram constructor for ACK packets
+ */
+NetGram::NetGram()
+ : retries(0), packet_id(0), send_time(0)
+{ }
+
+/**
+ * NetGram constructor for receiving packets from remote hosts
+ */
+NetGram::NetGram(const NetAddr& src, Text msg)
+ : addr(src), retries(0), send_time(0)
+{
+ body = msg;
+
+ if (body.length() >= NET_GRAM_HEADER_SIZE) {
+ BYTE* data = (BYTE*) body.data();
+
+ packet_id = (((DWORD) data[0]) << 24) +
+ (((DWORD) data[1]) << 16) +
+ (((DWORD) data[2]) << 8) +
+ ((DWORD) data[3]);
+ }
+}
+
+/**
+ * NetGram constructor for composing packets to send to remote hosts
+ */
+NetGram::NetGram(const NetAddr& dst, Text user_data, int r)
+ : addr(dst), retries(r)
+{
+ send_time = NetLayer::GetTime();
+ packet_id = net_gram_sequence++;
+
+ if (retries)
+ packet_id |= NET_GRAM_RELIABLE;
+
+ static BYTE buf[NET_GRAM_MAX_SIZE];
+ buf[0] = (BYTE) (packet_id >> 24) & 0xff;
+ buf[1] = (BYTE) (packet_id >> 16) & 0xff;
+ buf[2] = (BYTE) (packet_id >> 8) & 0xff;
+ buf[3] = (BYTE) (packet_id) & 0xff;
+
+ int len = user_data.length();
+ if (len >= NET_GRAM_MAX_SIZE - NET_GRAM_HEADER_SIZE)
+ len = NET_GRAM_MAX_SIZE - NET_GRAM_HEADER_SIZE - 1;
+
+ CopyMemory(buf+NET_GRAM_HEADER_SIZE, user_data.data(), len);
+
+ body = Text((char*) buf, len+NET_GRAM_HEADER_SIZE);
+}
+
+// +--------------------------------------------------------------------+
+
+void
+NetGram::Retry()
+{
+ if (retries > 0) {
+ retries--;
+ send_time = NetLayer::GetTime();
+ }
+}
+
+// +--------------------------------------------------------------------+
+
+NetGram
+NetGram::Ack()
+{
+ NetGram ack;
+
+ ack.packet_id = packet_id | NET_GRAM_ACK;
+ ack.send_time = NetLayer::GetTime();
+
+ static BYTE buf[NET_GRAM_HEADER_SIZE];
+ buf[0] = (BYTE) (ack.packet_id >> 24) & 0xff;
+ buf[1] = (BYTE) (ack.packet_id >> 16) & 0xff;
+ buf[2] = (BYTE) (ack.packet_id >> 8) & 0xff;
+ buf[3] = (BYTE) (ack.packet_id) & 0xff;
+
+ ack.body = Text((char*) buf, NET_GRAM_HEADER_SIZE);
+
+ return ack;
+}
+
+
+
diff --git a/NetEx/NetGram.h b/NetEx/NetGram.h
index e836e8d..d1831b4 100644
--- a/NetEx/NetGram.h
+++ b/NetEx/NetGram.h
@@ -1,79 +1,103 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetGram.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Datagram (UDP) packet that implements the basic
- packet-oriented network protocol.
-*/
-
-
-#ifndef NetGram_h
-#define NetGram_h
-
-#include <windows.h>
-#include "NetAddr.h"
-#include "Text.h"
-
-// +-------------------------------------------------------------------+
-
-const int NET_GRAM_ACK = 0x80000000;
-const int NET_GRAM_RELIABLE = 0x40000000;
-const int NET_GRAM_SEQ_MASK = 0x3fffffff;
-
-const int NET_GRAM_HEADER_SIZE = 4;
-const int NET_GRAM_MAX_SIZE = 1024;
-
-// +-------------------------------------------------------------------+
-
-class NetGram
-{
-public:
- static const char* TYPENAME() { return "NetGram"; }
-
- // for receiving packets from remote hosts:
- NetGram(const NetAddr& src, Text msg);
-
- // for composing packets to send to remote hosts:
- NetGram(const NetAddr& dst, Text user_data, int retries);
-
- int operator == (const NetGram& g) const { return packet_id == g.packet_id &&
- addr == g.addr; }
- int operator < (const NetGram& g) const { return Sequence() < g.Sequence(); }
-
- DWORD PacketID() const { return packet_id; }
- DWORD Sequence() const { return packet_id & NET_GRAM_SEQ_MASK; }
- DWORD SendTime() const { return send_time; }
- BYTE* Data() const { return (BYTE*) body.data(); }
- BYTE* UserData() const { return (BYTE*) body.data() + NET_GRAM_HEADER_SIZE; }
- int Size() const { return body.length(); }
- const Text& Body() const { return body; }
- const NetAddr& Address() const { return addr; }
-
- bool IsAck() const { return packet_id & NET_GRAM_ACK ? true : false; }
- bool IsReliable() const { return packet_id & NET_GRAM_RELIABLE ? true : false; }
- int Retries() const { return retries; }
-
- void Retry();
- NetGram Ack();
- void ClearAck() { packet_id &= ~NET_GRAM_ACK; }
-
-protected:
- NetGram();
-
- NetAddr addr; // network address of remote host
- int retries; // number of retries remaining (reliable packets only)
- DWORD send_time; // time in msec of most recent send attempt
-
- DWORD packet_id; // copy of packet id from header in body
- Text body; // header plus user data
-};
-
-
-#endif NetGram_h \ No newline at end of file
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetGram.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Datagram (UDP) packet that implements the basic
+ packet-oriented network protocol.
+*/
+
+
+#ifndef NetGram_h
+#define NetGram_h
+
+#include <windows.h>
+#include "NetAddr.h"
+#include "Text.h"
+
+// +-------------------------------------------------------------------+
+
+const int NET_GRAM_ACK = 0x80000000;
+const int NET_GRAM_RELIABLE = 0x40000000;
+const int NET_GRAM_SEQ_MASK = 0x3fffffff;
+
+const int NET_GRAM_HEADER_SIZE = 4;
+const int NET_GRAM_MAX_SIZE = 1024;
+
+// +-------------------------------------------------------------------+
+
+class NetGram
+{
+public:
+ static const char* TYPENAME() { return "NetGram"; }
+
+ // for receiving packets from remote hosts:
+ NetGram(const NetAddr& src, Text msg);
+
+ // for composing packets to send to remote hosts:
+ NetGram(const NetAddr& dst, Text user_data, int retries);
+
+ int operator == (const NetGram& g) const { return packet_id == g.packet_id &&
+ addr == g.addr; }
+ int operator < (const NetGram& g) const { return Sequence() < g.Sequence(); }
+
+ DWORD PacketID() const { return packet_id; }
+ DWORD Sequence() const { return packet_id & NET_GRAM_SEQ_MASK; }
+ DWORD SendTime() const { return send_time; }
+ BYTE* Data() const { return (BYTE*) body.data(); }
+ BYTE* UserData() const { return (BYTE*) body.data() + NET_GRAM_HEADER_SIZE; }
+ int Size() const { return body.length(); }
+ const Text& Body() const { return body; }
+ const NetAddr& Address() const { return addr; }
+
+ bool IsAck() const { return packet_id & NET_GRAM_ACK ? true : false; }
+ bool IsReliable() const { return packet_id & NET_GRAM_RELIABLE ? true : false; }
+ int Retries() const { return retries; }
+
+ void Retry();
+ NetGram Ack();
+ void ClearAck() { packet_id &= ~NET_GRAM_ACK; }
+
+protected:
+ NetGram();
+
+ NetAddr addr; // network address of remote host
+ int retries; // number of retries remaining (reliable packets only)
+ DWORD send_time; // time in msec of most recent send attempt
+
+ DWORD packet_id; // copy of packet id from header in body
+ Text body; // header plus user data
+};
+
+
+#endif NetGram_h
diff --git a/NetEx/NetHost.cpp b/NetEx/NetHost.cpp
index d42ec2a..03330f0 100644
--- a/NetEx/NetHost.cpp
+++ b/NetEx/NetHost.cpp
@@ -1,103 +1,127 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetHost.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Host
-*/
-
-
-#include "MemDebug.h"
-#include "NetHost.h"
-#include "NetLayer.h"
-#include <ctype.h>
-
-NetHost::NetHost()
-{
- char host_name[256];
- gethostname(host_name, sizeof(host_name));
-
- Init(host_name);
-}
-
-NetHost::NetHost(const char* host_name)
-{
- Init(host_name);
-}
-
-void NetHost::Init(const char* host_name)
-{
- if (host_name && *host_name) {
- HOSTENT* h = 0;
-
- if (isdigit(*host_name)) {
- DWORD addr = inet_addr(host_name);
- h = gethostbyaddr((const char*) &addr, 4, AF_INET);
- }
- else {
- h = gethostbyname(host_name);
- }
-
- if (h) {
- name = h->h_name;
-
- char** alias = h->h_aliases;
- while (*alias) {
- aliases.append(new Text(*alias));
- alias++;
- }
-
- char** addr = h->h_addr_list;
- while (*addr) {
- NetAddr* pna = new(__FILE__,__LINE__) NetAddr(**(DWORD**) addr);
- if (pna)
- addresses.append(pna);
- addr++;
- }
- }
- }
-}
-
-NetHost::NetHost(const NetHost& n)
-{
- if (&n != this) {
- NetHost& nh = (NetHost&) n;
-
- name = nh.name;
-
- ListIter<Text> alias = nh.aliases;
- while (++alias)
- aliases.append(new Text(*alias.value()));
-
- ListIter<NetAddr> addr = nh.addresses;
- while (++addr)
- addresses.append(new NetAddr(*addr.value()));
- }
-}
-
-NetHost::~NetHost()
-{
- aliases.destroy();
- addresses.destroy();
-}
-
-const char*
-NetHost::Name()
-{
- return name;
-}
-
-NetAddr
-NetHost::Address()
-{
- if (addresses.size())
- return *(addresses[0]);
-
- return NetAddr((DWORD) 0);
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetHost.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Host
+*/
+
+
+#include "MemDebug.h"
+#include "NetHost.h"
+#include "NetLayer.h"
+#include <ctype.h>
+
+NetHost::NetHost()
+{
+ char host_name[256];
+ gethostname(host_name, sizeof(host_name));
+
+ Init(host_name);
+}
+
+NetHost::NetHost(const char* host_name)
+{
+ Init(host_name);
+}
+
+void NetHost::Init(const char* host_name)
+{
+ if (host_name && *host_name) {
+ HOSTENT* h = 0;
+
+ if (isdigit(*host_name)) {
+ DWORD addr = inet_addr(host_name);
+ h = gethostbyaddr((const char*) &addr, 4, AF_INET);
+ }
+ else {
+ h = gethostbyname(host_name);
+ }
+
+ if (h) {
+ name = h->h_name;
+
+ char** alias = h->h_aliases;
+ while (*alias) {
+ aliases.append(new Text(*alias));
+ alias++;
+ }
+
+ char** addr = h->h_addr_list;
+ while (*addr) {
+ NetAddr* pna = new(__FILE__,__LINE__) NetAddr(**(DWORD**) addr);
+ if (pna)
+ addresses.append(pna);
+ addr++;
+ }
+ }
+ }
+}
+
+NetHost::NetHost(const NetHost& n)
+{
+ if (&n != this) {
+ NetHost& nh = (NetHost&) n;
+
+ name = nh.name;
+
+ ListIter<Text> alias = nh.aliases;
+ while (++alias)
+ aliases.append(new Text(*alias.value()));
+
+ ListIter<NetAddr> addr = nh.addresses;
+ while (++addr)
+ addresses.append(new NetAddr(*addr.value()));
+ }
+}
+
+NetHost::~NetHost()
+{
+ aliases.destroy();
+ addresses.destroy();
+}
+
+const char*
+NetHost::Name()
+{
+ return name;
+}
+
+NetAddr
+NetHost::Address()
+{
+ if (addresses.size())
+ return *(addresses[0]);
+
+ return NetAddr((DWORD) 0);
} \ No newline at end of file
diff --git a/NetEx/NetHost.h b/NetEx/NetHost.h
index 2240eab..cf6c255 100644
--- a/NetEx/NetHost.h
+++ b/NetEx/NetHost.h
@@ -1,50 +1,74 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetHost.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Host
-*/
-
-#ifndef NET_HOST_H
-#define NET_HOST_H
-
-#include <windows.h>
-#include "NetAddr.h"
-#include "Text.h"
-#include "List.h"
-
-// +-------------------------------------------------------------------+
-
-class NetHost
-{
-public:
- static const char* TYPENAME() { return "NetHost"; }
-
- NetHost();
- NetHost(const char* host_addr);
- NetHost(const NetHost& n);
- ~NetHost();
-
- const char* Name();
- NetAddr Address();
-
- List<Text>& Aliases() { return aliases; }
- List<NetAddr>& AddressList() { return addresses; }
-
-private:
- void Init(const char* host_name);
-
- Text name;
- List<Text> aliases;
- List<NetAddr> addresses;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetHost.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Host
+*/
+
+#ifndef NET_HOST_H
+#define NET_HOST_H
+
+#include <windows.h>
+#include "NetAddr.h"
+#include "Text.h"
+#include "List.h"
+
+// +-------------------------------------------------------------------+
+
+class NetHost
+{
+public:
+ static const char* TYPENAME() { return "NetHost"; }
+
+ NetHost();
+ NetHost(const char* host_addr);
+ NetHost(const NetHost& n);
+ ~NetHost();
+
+ const char* Name();
+ NetAddr Address();
+
+ List<Text>& Aliases() { return aliases; }
+ List<NetAddr>& AddressList() { return addresses; }
+
+private:
+ void Init(const char* host_name);
+
+ Text name;
+ List<Text> aliases;
+ List<NetAddr> addresses;
+};
+
+
#endif // NET_HOST_H \ No newline at end of file
diff --git a/NetEx/NetLayer.cpp b/NetEx/NetLayer.cpp
index 8494f72..573fe45 100644
--- a/NetEx/NetLayer.cpp
+++ b/NetEx/NetLayer.cpp
@@ -1,93 +1,117 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetLayer.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Wrapper for WinSock Library
-*/
-
-
-#include "MemDebug.h"
-#include <windows.h>
-#include "NetLayer.h"
-
-#include <mmsystem.h>
-#include <time.h>
-
-// +-------------------------------------------------------------------+
-
-static DWORD baseTime = timeGetTime();
-
-// +-------------------------------------------------------------------+
-
-NetLayer::NetLayer()
-{
- fail = false;
- ZeroMemory(&info, sizeof(info));
-
- WORD ver = MAKEWORD(2,2);
- int err = WSAStartup(ver, &info);
-
- if (err)
- fail = true;
-}
-
-NetLayer::~NetLayer()
-{
- WSACleanup();
-}
-
-bool
-NetLayer::OK() const
-{
- return !fail;
-}
-
-const char*
-NetLayer::Description() const
-{
- return info.szDescription;
-}
-
-int
-NetLayer::GetLastError()
-{
- return WSAGetLastError();
-}
-
-DWORD
-NetLayer::GetTime()
-{
- DWORD msec = timeGetTime();
-
- if (msec >= baseTime) {
- return msec - baseTime;
- }
-
- else {
- DWORD extra = 0xffffffff;
- return msec + extra - baseTime;
- }
-}
-
-long
-NetLayer::GetUTC()
-{
- return (long) time(0);
-}
-
-Text
-NetLayer::GetHostName()
-{
- char hostname[256];
- ZeroMemory(hostname, sizeof(hostname));
- ::gethostname(hostname, sizeof(hostname));
-
- return hostname;
-}
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetLayer.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Wrapper for WinSock Library
+*/
+
+
+#include "MemDebug.h"
+#include <windows.h>
+#include "NetLayer.h"
+
+#include <mmsystem.h>
+#include <time.h>
+
+// +-------------------------------------------------------------------+
+
+static DWORD baseTime = timeGetTime();
+
+// +-------------------------------------------------------------------+
+
+NetLayer::NetLayer()
+{
+ fail = false;
+ ZeroMemory(&info, sizeof(info));
+
+ WORD ver = MAKEWORD(2,2);
+ int err = WSAStartup(ver, &info);
+
+ if (err)
+ fail = true;
+}
+
+NetLayer::~NetLayer()
+{
+ WSACleanup();
+}
+
+bool
+NetLayer::OK() const
+{
+ return !fail;
+}
+
+const char*
+NetLayer::Description() const
+{
+ return info.szDescription;
+}
+
+int
+NetLayer::GetLastError()
+{
+ return WSAGetLastError();
+}
+
+DWORD
+NetLayer::GetTime()
+{
+ DWORD msec = timeGetTime();
+
+ if (msec >= baseTime) {
+ return msec - baseTime;
+ }
+
+ else {
+ DWORD extra = 0xffffffff;
+ return msec + extra - baseTime;
+ }
+}
+
+long
+NetLayer::GetUTC()
+{
+ return (long) time(0);
+}
+
+Text
+NetLayer::GetHostName()
+{
+ char hostname[256];
+ ZeroMemory(hostname, sizeof(hostname));
+ ::gethostname(hostname, sizeof(hostname));
+
+ return hostname;
+}
diff --git a/NetEx/NetLayer.h b/NetEx/NetLayer.h
index fbb2b52..66b9c9d 100644
--- a/NetEx/NetLayer.h
+++ b/NetEx/NetLayer.h
@@ -1,45 +1,69 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetLayer.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Wrapper for WinSock Library
-*/
-
-#ifndef NetLayer_h
-#define NetLayer_h
-
-#include <windows.h>
-#include "Text.h"
-
-// +-------------------------------------------------------------------+
-
-class NetLayer
-{
-public:
- static const char* TYPENAME() { return "NetLayer"; }
-
- NetLayer();
- ~NetLayer();
-
- bool OK() const;
- const char* Description() const;
-
- static int GetLastError();
- static DWORD GetTime();
- static long GetUTC();
- static Text GetHostName();
-
-private:
- WSADATA info;
- bool fail;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetLayer.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Wrapper for WinSock Library
+*/
+
+#ifndef NetLayer_h
+#define NetLayer_h
+
+#include <windows.h>
+#include "Text.h"
+
+// +-------------------------------------------------------------------+
+
+class NetLayer
+{
+public:
+ static const char* TYPENAME() { return "NetLayer"; }
+
+ NetLayer();
+ ~NetLayer();
+
+ bool OK() const;
+ const char* Description() const;
+
+ static int GetLastError();
+ static DWORD GetTime();
+ static long GetUTC();
+ static Text GetHostName();
+
+private:
+ WSADATA info;
+ bool fail;
+};
+
+
#endif NetLayer_h \ No newline at end of file
diff --git a/NetEx/NetLink.cpp b/NetEx/NetLink.cpp
index 7cd6f4e..05c486a 100644
--- a/NetEx/NetLink.cpp
+++ b/NetEx/NetLink.cpp
@@ -1,487 +1,511 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetLink.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network (IP) Socket Wrapper Implementation
-*/
-
-
-#include "MemDebug.h"
-#include "NetLink.h"
-#include "NetGram.h"
-#include "NetMsg.h"
-#include "NetPeer.h"
-#include "NetLayer.h"
-
-// +-------------------------------------------------------------------+
-
-DWORD WINAPI NetLinkProc(LPVOID link);
-
-const DWORD UDP_HEADER_SIZE = 34;
-
-// +-------------------------------------------------------------------+
-// client-side ctor
-NetLink::NetLink()
- : hnet(0), shutdown(false), traffic_time(50), resend_time(300),
- packets_sent(0), packets_recv(0), bytes_sent(0), bytes_recv(0), retries(0), drops(0), lag(100)
-{
- ZeroMemory(lag_samples, sizeof(lag_samples));
- lag_index = 0;
-
- DWORD thread_id = 0;
- hnet = CreateThread(0, 4096, NetLinkProc, (LPVOID) this, 0, &thread_id);
-}
-
-// server-side ctor
-NetLink::NetLink(NetAddr& a)
- : addr(a), hnet(0), shutdown(false), traffic_time(50), resend_time(300),
- packets_sent(0), packets_recv(0), bytes_sent(0), bytes_recv(0), retries(0), drops(0), lag(100)
-{
- ZeroMemory(lag_samples, sizeof(lag_samples));
- lag_index = 0;
-
- sock.bind(addr);
- DWORD thread_id = 0;
- hnet = CreateThread(0, 4096, NetLinkProc, (LPVOID) this, 0, &thread_id);
-}
-
-NetLink::~NetLink()
-{
- if (!shutdown) {
- shutdown = true;
- }
-
- if (hnet) {
- WaitForSingleObject(hnet, 2000);
- CloseHandle(hnet);
- }
-
- send_list.destroy(); // packets waiting to be ack'ed must be destroyed
- recv_list.clear(); // received messages are owned by the peers
- peer_list.destroy(); // but the net link owns the peers!
-}
-
-// +--------------------------------------------------------------------+
-
-static DWORD base_netid = 1000;
-
-DWORD
-NetLink::AddPeer(const char* a, WORD p)
-{
- return AddPeer(NetAddr(a, p));
-}
-
-DWORD
-NetLink::AddPeer(DWORD a, WORD p)
-{
- return AddPeer(NetAddr(a, p));
-}
-
-DWORD
-NetLink::AddPeer(const NetAddr& a)
-{
- if (!a.IPAddr())
- return 0;
-
- AutoThreadSync auto_sync(sync);
-
- NetPeer* peer = FindPeer(a);
-
- if (!peer) {
- peer = new(__FILE__, __LINE__) NetPeer(a, base_netid++);
- if (peer)
- peer_list.append(peer);
- }
-
- if (peer)
- return peer->NetID();
-
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-bool
-NetLink::SendMessage(DWORD nid, void* d, int l, BYTE f)
-{
- return SendMessage(new(__FILE__,__LINE__) NetMsg(nid, d, l, f));
-}
-
-bool
-NetLink::SendMessage(DWORD nid, BYTE type, const char* text, int len, BYTE f)
-{
- return SendMessage(new(__FILE__,__LINE__) NetMsg(nid, type, text, len, f));
-}
-
-bool
-NetLink::SendMessage(NetMsg* msg)
-{
- if (msg) {
- if (msg->Type() != NetMsg::INVALID &&
- msg->Type() < NetMsg::RESERVED &&
- msg->NetID()) {
-
- NetPeer* p = FindPeer(msg->NetID());
- if (p)
- return p->SendMessage(msg);
- }
-
- delete msg;
- }
-
- return false;
-}
-
-// +--------------------------------------------------------------------+
-
-NetMsg*
-NetLink::GetMessage(DWORD netid)
-{
- NetMsg* msg = 0;
-
- // receive from specific host:
- if (netid) {
- NetPeer* p = FindPeer(netid);
- if (p) {
- msg = p->GetMessage();
-
- sync.acquire();
- recv_list.remove(msg);
- sync.release();
- }
- }
-
- return msg;
-}
-
-// +--------------------------------------------------------------------+
-
-NetMsg*
-NetLink::GetMessage()
-{
- NetMsg* msg = 0;
-
- // get first available packet:
-
- // Double-checked locking:
- if (recv_list.size()) {
- sync.acquire();
- if (recv_list.size()) {
- msg = recv_list.removeIndex(0);
- }
- sync.release();
-
- if (msg && msg->NetID()) {
- NetPeer* p = FindPeer(msg->NetID());
- if (p) {
- p->GetMessage(); // remove message from peer's list
- // don't do this inside of sync block -
- // it might cause a deadlock
- }
- }
- }
-
- return msg;
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NetLink::Shutdown()
-{
- shutdown = true;
-}
-
-// +--------------------------------------------------------------------+
-
-DWORD WINAPI NetLinkProc(LPVOID link)
-{
- NetLink* netlink = (NetLink*) link;
-
- if (netlink)
- return netlink->DoSendRecv();
-
- return (DWORD) E_POINTER;
-}
-
-DWORD
-NetLink::DoSendRecv()
-{
- while (!shutdown) {
- ReadPackets();
- SendPackets();
-
- // discard reeeeally old peers:
- sync.acquire();
-
- ListIter<NetPeer> iter = peer_list;
- while (!shutdown && ++iter) {
- NetPeer* peer = iter.value();
-
- if ((NetLayer::GetUTC() - peer->LastReceiveTime()) > 300)
- delete iter.removeItem();
- }
-
- sync.release();
- Sleep(traffic_time);
- }
-
- return 0;
-}
-
-void
-NetLink::ReadPackets()
-{
- while (!shutdown && sock.select(NetSock::SELECT_READ) > 0) {
- NetGram* gram = RecvNetGram();
-
- if (gram && gram->IsReliable()) {
- if (gram->IsAck()) {
- ProcessAck(gram);
- delete gram;
- }
- else {
- AckNetGram(gram);
- QueueNetGram(gram);
- }
- }
- else {
- QueueNetGram(gram);
- }
- }
-}
-
-void
-NetLink::SendPackets()
-{
- if (shutdown)
- return;
-
- if (sock.select(NetSock::SELECT_WRITE) > 0) {
- DoRetries();
- }
-
- AutoThreadSync auto_sync(sync);
-
- ListIter<NetPeer> iter = peer_list;
- while (!shutdown && ++iter) {
- NetPeer* p = iter.value();
- NetGram* g = 0;
-
- do {
- if (sock.select(NetSock::SELECT_WRITE) > 0) {
- g = p->ComposeGram();
- if (g) {
- SendNetGram(g);
- }
- }
- else {
- g = 0;
- }
- }
- while (!shutdown && g);
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NetLink::SendNetGram(NetGram* gram)
-{
- if (gram) {
- if (gram->IsReliable()) {
- send_list.append(gram);
- }
-
- int err = sock.sendto(gram->Body(), gram->Address());
-
- if (err < 0) {
- err = NetLayer::GetLastError();
- }
- else {
- packets_sent += 1;
- bytes_sent += gram->Size() + UDP_HEADER_SIZE;
- }
-
- if (!gram->IsReliable())
- delete gram;
- }
-}
-
-NetGram*
-NetLink::RecvNetGram()
-{
- NetAddr from;
- Text msg = sock.recvfrom(&from);
-
- packets_recv += 1;
- bytes_recv += msg.length() + UDP_HEADER_SIZE;
-
- return new(__FILE__, __LINE__) NetGram(from, msg);
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NetLink::AckNetGram(NetGram* gram)
-{
- if (gram) {
- NetGram ack = gram->Ack();
-
- int err = sock.sendto(ack.Body(), gram->Address());
- if (err < 0)
- err = NetLayer::GetLastError();
- }
- else {
- Print("NetLink::AckNetGram( NULL!!! )\n");
- }
-}
-
-void
-NetLink::ProcessAck(NetGram* gram)
-{
- if (!shutdown && send_list.size()) {
- AutoThreadSync auto_sync(sync);
-
- // remove the ack flag:
- gram->ClearAck();
-
- // find a matching outgoing packet:
- int sent = send_list.index(gram);
- if (sent >= 0) {
- NetGram* orig = send_list.removeIndex(sent);
- DWORD time = NetLayer::GetTime();
- DWORD msec = time - orig->SendTime();
- double dlag = 0.75 * lag + 0.25 * msec;
-
- if (lag_index >= 10) lag_index = 0;
- lag_samples[lag_index++] = msec;
-
- NetPeer* peer = FindPeer(orig->Address());
- if (peer)
- peer->SetLastReceiveTime(NetLayer::GetUTC());
-
- delete orig;
-
- lag = (DWORD) dlag;
-
- if (lag > 100)
- resend_time = 3 * lag;
- else
- resend_time = 300;
- }
- }
-}
-
-void
-NetLink::QueueNetGram(NetGram* gram)
-{
- if (!shutdown) {
- AutoThreadSync auto_sync(sync);
-
- DWORD sequence = 0;
- NetPeer* peer = FindPeer(gram->Address());
-
- if (peer) {
- sequence = peer->Sequence();
- }
- else {
- peer = new(__FILE__, __LINE__) NetPeer(gram->Address(), base_netid++);
- if (peer)
- peer_list.append(peer);
- }
-
- if (!gram->IsReliable()) {
- if (gram->Sequence() < sequence) { // discard, too old
- delete gram;
- return;
- }
- }
-
- // sort this gram into the recv list(s) based on sequence:
- if (peer) {
- peer->ReceiveGram(gram, &recv_list);
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NetLink::DoRetries()
-{
- if (!shutdown) {
- AutoThreadSync auto_sync(sync);
-
- if (send_list.size()) {
- int time = (int) NetLayer::GetTime();
-
- ListIter<NetGram> iter = send_list;
- while (!shutdown && ++iter) {
- NetGram* gram = iter.value();
-
- // still trying ?
- if (gram->Retries() > 0) {
- DWORD last_send = gram->SendTime();
- DWORD delta = time - last_send;
-
- if (delta > resend_time) {
- gram->Retry();
- sock.sendto(gram->Body(), gram->Address());
- retries++;
- }
- }
-
- // oh, give it up:
- else {
- iter.removeItem();
- delete gram;
- drops++;
- }
- }
- }
- }
-}
-
-// +--------------------------------------------------------------------+
-
-NetPeer*
-NetLink::FindPeer(DWORD netid)
-{
- AutoThreadSync auto_sync(sync);
- NetPeer* peer = 0;
-
- ListIter<NetPeer> iter = peer_list;
- while (++iter && !peer) {
- NetPeer* p = iter.value();
-
- if (p->NetID() == netid)
- peer = p;
- }
-
- return peer;
-}
-
-NetPeer*
-NetLink::FindPeer(const NetAddr& a)
-{
- AutoThreadSync auto_sync(sync);
- NetPeer* peer = 0;
-
- ListIter<NetPeer> iter = peer_list;
- while (++iter && !peer) {
- NetPeer* p = iter.value();
-
- if (p->Address() == a)
- peer = p;
- }
-
- return peer;
-}
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetLink.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network (IP) Socket Wrapper Implementation
+*/
+
+
+#include "MemDebug.h"
+#include "NetLink.h"
+#include "NetGram.h"
+#include "NetMsg.h"
+#include "NetPeer.h"
+#include "NetLayer.h"
+
+// +-------------------------------------------------------------------+
+
+DWORD WINAPI NetLinkProc(LPVOID link);
+
+const DWORD UDP_HEADER_SIZE = 34;
+
+// +-------------------------------------------------------------------+
+// client-side ctor
+NetLink::NetLink()
+ : hnet(0), shutdown(false), traffic_time(50), resend_time(300),
+ packets_sent(0), packets_recv(0), bytes_sent(0), bytes_recv(0), retries(0), drops(0), lag(100)
+{
+ ZeroMemory(lag_samples, sizeof(lag_samples));
+ lag_index = 0;
+
+ DWORD thread_id = 0;
+ hnet = CreateThread(0, 4096, NetLinkProc, (LPVOID) this, 0, &thread_id);
+}
+
+// server-side ctor
+NetLink::NetLink(NetAddr& a)
+ : addr(a), hnet(0), shutdown(false), traffic_time(50), resend_time(300),
+ packets_sent(0), packets_recv(0), bytes_sent(0), bytes_recv(0), retries(0), drops(0), lag(100)
+{
+ ZeroMemory(lag_samples, sizeof(lag_samples));
+ lag_index = 0;
+
+ sock.bind(addr);
+ DWORD thread_id = 0;
+ hnet = CreateThread(0, 4096, NetLinkProc, (LPVOID) this, 0, &thread_id);
+}
+
+NetLink::~NetLink()
+{
+ if (!shutdown) {
+ shutdown = true;
+ }
+
+ if (hnet) {
+ WaitForSingleObject(hnet, 2000);
+ CloseHandle(hnet);
+ }
+
+ send_list.destroy(); // packets waiting to be ack'ed must be destroyed
+ recv_list.clear(); // received messages are owned by the peers
+ peer_list.destroy(); // but the net link owns the peers!
+}
+
+// +--------------------------------------------------------------------+
+
+static DWORD base_netid = 1000;
+
+DWORD
+NetLink::AddPeer(const char* a, WORD p)
+{
+ return AddPeer(NetAddr(a, p));
+}
+
+DWORD
+NetLink::AddPeer(DWORD a, WORD p)
+{
+ return AddPeer(NetAddr(a, p));
+}
+
+DWORD
+NetLink::AddPeer(const NetAddr& a)
+{
+ if (!a.IPAddr())
+ return 0;
+
+ AutoThreadSync auto_sync(sync);
+
+ NetPeer* peer = FindPeer(a);
+
+ if (!peer) {
+ peer = new(__FILE__, __LINE__) NetPeer(a, base_netid++);
+ if (peer)
+ peer_list.append(peer);
+ }
+
+ if (peer)
+ return peer->NetID();
+
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+bool
+NetLink::SendMessage(DWORD nid, void* d, int l, BYTE f)
+{
+ return SendMessage(new(__FILE__,__LINE__) NetMsg(nid, d, l, f));
+}
+
+bool
+NetLink::SendMessage(DWORD nid, BYTE type, const char* text, int len, BYTE f)
+{
+ return SendMessage(new(__FILE__,__LINE__) NetMsg(nid, type, text, len, f));
+}
+
+bool
+NetLink::SendMessage(NetMsg* msg)
+{
+ if (msg) {
+ if (msg->Type() != NetMsg::INVALID &&
+ msg->Type() < NetMsg::RESERVED &&
+ msg->NetID()) {
+
+ NetPeer* p = FindPeer(msg->NetID());
+ if (p)
+ return p->SendMessage(msg);
+ }
+
+ delete msg;
+ }
+
+ return false;
+}
+
+// +--------------------------------------------------------------------+
+
+NetMsg*
+NetLink::GetMessage(DWORD netid)
+{
+ NetMsg* msg = 0;
+
+ // receive from specific host:
+ if (netid) {
+ NetPeer* p = FindPeer(netid);
+ if (p) {
+ msg = p->GetMessage();
+
+ sync.acquire();
+ recv_list.remove(msg);
+ sync.release();
+ }
+ }
+
+ return msg;
+}
+
+// +--------------------------------------------------------------------+
+
+NetMsg*
+NetLink::GetMessage()
+{
+ NetMsg* msg = 0;
+
+ // get first available packet:
+
+ // Double-checked locking:
+ if (recv_list.size()) {
+ sync.acquire();
+ if (recv_list.size()) {
+ msg = recv_list.removeIndex(0);
+ }
+ sync.release();
+
+ if (msg && msg->NetID()) {
+ NetPeer* p = FindPeer(msg->NetID());
+ if (p) {
+ p->GetMessage(); // remove message from peer's list
+ // don't do this inside of sync block -
+ // it might cause a deadlock
+ }
+ }
+ }
+
+ return msg;
+}
+
+// +--------------------------------------------------------------------+
+
+void
+NetLink::Shutdown()
+{
+ shutdown = true;
+}
+
+// +--------------------------------------------------------------------+
+
+DWORD WINAPI NetLinkProc(LPVOID link)
+{
+ NetLink* netlink = (NetLink*) link;
+
+ if (netlink)
+ return netlink->DoSendRecv();
+
+ return (DWORD) E_POINTER;
+}
+
+DWORD
+NetLink::DoSendRecv()
+{
+ while (!shutdown) {
+ ReadPackets();
+ SendPackets();
+
+ // discard reeeeally old peers:
+ sync.acquire();
+
+ ListIter<NetPeer> iter = peer_list;
+ while (!shutdown && ++iter) {
+ NetPeer* peer = iter.value();
+
+ if ((NetLayer::GetUTC() - peer->LastReceiveTime()) > 300)
+ delete iter.removeItem();
+ }
+
+ sync.release();
+ Sleep(traffic_time);
+ }
+
+ return 0;
+}
+
+void
+NetLink::ReadPackets()
+{
+ while (!shutdown && sock.select(NetSock::SELECT_READ) > 0) {
+ NetGram* gram = RecvNetGram();
+
+ if (gram && gram->IsReliable()) {
+ if (gram->IsAck()) {
+ ProcessAck(gram);
+ delete gram;
+ }
+ else {
+ AckNetGram(gram);
+ QueueNetGram(gram);
+ }
+ }
+ else {
+ QueueNetGram(gram);
+ }
+ }
+}
+
+void
+NetLink::SendPackets()
+{
+ if (shutdown)
+ return;
+
+ if (sock.select(NetSock::SELECT_WRITE) > 0) {
+ DoRetries();
+ }
+
+ AutoThreadSync auto_sync(sync);
+
+ ListIter<NetPeer> iter = peer_list;
+ while (!shutdown && ++iter) {
+ NetPeer* p = iter.value();
+ NetGram* g = 0;
+
+ do {
+ if (sock.select(NetSock::SELECT_WRITE) > 0) {
+ g = p->ComposeGram();
+ if (g) {
+ SendNetGram(g);
+ }
+ }
+ else {
+ g = 0;
+ }
+ }
+ while (!shutdown && g);
+ }
+}
+
+// +--------------------------------------------------------------------+
+
+void
+NetLink::SendNetGram(NetGram* gram)
+{
+ if (gram) {
+ if (gram->IsReliable()) {
+ send_list.append(gram);
+ }
+
+ int err = sock.sendto(gram->Body(), gram->Address());
+
+ if (err < 0) {
+ err = NetLayer::GetLastError();
+ }
+ else {
+ packets_sent += 1;
+ bytes_sent += gram->Size() + UDP_HEADER_SIZE;
+ }
+
+ if (!gram->IsReliable())
+ delete gram;
+ }
+}
+
+NetGram*
+NetLink::RecvNetGram()
+{
+ NetAddr from;
+ Text msg = sock.recvfrom(&from);
+
+ packets_recv += 1;
+ bytes_recv += msg.length() + UDP_HEADER_SIZE;
+
+ return new(__FILE__, __LINE__) NetGram(from, msg);
+}
+
+// +--------------------------------------------------------------------+
+
+void
+NetLink::AckNetGram(NetGram* gram)
+{
+ if (gram) {
+ NetGram ack = gram->Ack();
+
+ int err = sock.sendto(ack.Body(), gram->Address());
+ if (err < 0)
+ err = NetLayer::GetLastError();
+ }
+ else {
+ Print("NetLink::AckNetGram( NULL!!! )\n");
+ }
+}
+
+void
+NetLink::ProcessAck(NetGram* gram)
+{
+ if (!shutdown && send_list.size()) {
+ AutoThreadSync auto_sync(sync);
+
+ // remove the ack flag:
+ gram->ClearAck();
+
+ // find a matching outgoing packet:
+ int sent = send_list.index(gram);
+ if (sent >= 0) {
+ NetGram* orig = send_list.removeIndex(sent);
+ DWORD time = NetLayer::GetTime();
+ DWORD msec = time - orig->SendTime();
+ double dlag = 0.75 * lag + 0.25 * msec;
+
+ if (lag_index >= 10) lag_index = 0;
+ lag_samples[lag_index++] = msec;
+
+ NetPeer* peer = FindPeer(orig->Address());
+ if (peer)
+ peer->SetLastReceiveTime(NetLayer::GetUTC());
+
+ delete orig;
+
+ lag = (DWORD) dlag;
+
+ if (lag > 100)
+ resend_time = 3 * lag;
+ else
+ resend_time = 300;
+ }
+ }
+}
+
+void
+NetLink::QueueNetGram(NetGram* gram)
+{
+ if (!shutdown) {
+ AutoThreadSync auto_sync(sync);
+
+ DWORD sequence = 0;
+ NetPeer* peer = FindPeer(gram->Address());
+
+ if (peer) {
+ sequence = peer->Sequence();
+ }
+ else {
+ peer = new(__FILE__, __LINE__) NetPeer(gram->Address(), base_netid++);
+ if (peer)
+ peer_list.append(peer);
+ }
+
+ if (!gram->IsReliable()) {
+ if (gram->Sequence() < sequence) { // discard, too old
+ delete gram;
+ return;
+ }
+ }
+
+ // sort this gram into the recv list(s) based on sequence:
+ if (peer) {
+ peer->ReceiveGram(gram, &recv_list);
+ }
+ }
+}
+
+// +--------------------------------------------------------------------+
+
+void
+NetLink::DoRetries()
+{
+ if (!shutdown) {
+ AutoThreadSync auto_sync(sync);
+
+ if (send_list.size()) {
+ int time = (int) NetLayer::GetTime();
+
+ ListIter<NetGram> iter = send_list;
+ while (!shutdown && ++iter) {
+ NetGram* gram = iter.value();
+
+ // still trying ?
+ if (gram->Retries() > 0) {
+ DWORD last_send = gram->SendTime();
+ DWORD delta = time - last_send;
+
+ if (delta > resend_time) {
+ gram->Retry();
+ sock.sendto(gram->Body(), gram->Address());
+ retries++;
+ }
+ }
+
+ // oh, give it up:
+ else {
+ iter.removeItem();
+ delete gram;
+ drops++;
+ }
+ }
+ }
+ }
+}
+
+// +--------------------------------------------------------------------+
+
+NetPeer*
+NetLink::FindPeer(DWORD netid)
+{
+ AutoThreadSync auto_sync(sync);
+ NetPeer* peer = 0;
+
+ ListIter<NetPeer> iter = peer_list;
+ while (++iter && !peer) {
+ NetPeer* p = iter.value();
+
+ if (p->NetID() == netid)
+ peer = p;
+ }
+
+ return peer;
+}
+
+NetPeer*
+NetLink::FindPeer(const NetAddr& a)
+{
+ AutoThreadSync auto_sync(sync);
+ NetPeer* peer = 0;
+
+ ListIter<NetPeer> iter = peer_list;
+ while (++iter && !peer) {
+ NetPeer* p = iter.value();
+
+ if (p->Address() == a)
+ peer = p;
+ }
+
+ return peer;
+}
diff --git a/NetEx/NetLink.h b/NetEx/NetLink.h
index 8d83ced..c39a32e 100644
--- a/NetEx/NetLink.h
+++ b/NetEx/NetLink.h
@@ -1,113 +1,137 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetLink.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Link for Remote Player
-*/
-
-
-#ifndef NetLink_h
-#define NetLink_h
-
-#include <windows.h>
-#include "NetAddr.h"
-#include "NetSock.h"
-#include "List.h"
-#include "ThreadSync.h"
-
-// +-------------------------------------------------------------------+
-
-class NetGram;
-class NetMsg;
-class NetPeer;
-
-// +-------------------------------------------------------------------+
-
-class NetLink
-{
-public:
- static const char* TYPENAME() { return "NetLink"; }
-
- NetLink();
- NetLink(NetAddr& a);
- virtual ~NetLink();
-
- int operator == (const NetLink& that) const { return this == &that; }
-
- const NetAddr& GetAddress() const { return addr; }
-
- DWORD AddPeer(const char* a, WORD p=12345);
- DWORD AddPeer(DWORD a, WORD p=12345);
- DWORD AddPeer(const NetAddr& a);
-
- bool SendMessage(DWORD nid, void* d, int l, BYTE f=0);
- bool SendMessage(DWORD nid, BYTE type, const char* text, int len, BYTE f=0);
- bool SendMessage(NetMsg* msg);
-
- NetMsg* GetMessage();
- NetMsg* GetMessage(DWORD netid);
-
- virtual void Shutdown();
- DWORD DoSendRecv();
-
- DWORD GetResendInterval() const { return resend_time; }
- void SetResendInterval(DWORD t) { resend_time = t; }
- DWORD GetTrafficInterval() const { return traffic_time; }
- void SetTrafficInterval(DWORD t) { traffic_time = t; }
-
- DWORD GetPacketsSent() const { return packets_sent; }
- DWORD GetPacketsRecv() const { return packets_recv; }
- DWORD GetBytesSent() const { return bytes_sent; }
- DWORD GetBytesRecv() const { return bytes_recv; }
- DWORD GetRetries() const { return retries; }
- DWORD GetDrops() const { return drops; }
- DWORD GetLag() const { return lag; }
-
- NetPeer* FindPeer(const NetAddr& a);
- NetPeer* FindPeer(DWORD netid);
-
-protected:
- void SendNetGram(NetGram* g);
- NetGram* RecvNetGram();
- void AckNetGram(NetGram* gram);
- void ProcessAck(NetGram* gram);
- void QueueNetGram(NetGram* gram);
-
- void ReadPackets();
- void SendPackets();
- void DoRetries();
-
- NetAddr addr;
- NetSock sock;
- List<NetGram> send_list;
- List<NetMsg> recv_list;
- List<NetPeer> peer_list;
-
- HANDLE hnet;
- bool shutdown;
- ThreadSync sync;
-
- DWORD resend_time;
- DWORD traffic_time;
-
- DWORD packets_sent;
- DWORD packets_recv;
- DWORD bytes_sent;
- DWORD bytes_recv;
- DWORD retries;
- DWORD drops;
- DWORD lag;
-
- DWORD lag_samples[10];
- int lag_index;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetLink.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Link for Remote Player
+*/
+
+
+#ifndef NetLink_h
+#define NetLink_h
+
+#include <windows.h>
+#include "NetAddr.h"
+#include "NetSock.h"
+#include "List.h"
+#include "ThreadSync.h"
+
+// +-------------------------------------------------------------------+
+
+class NetGram;
+class NetMsg;
+class NetPeer;
+
+// +-------------------------------------------------------------------+
+
+class NetLink
+{
+public:
+ static const char* TYPENAME() { return "NetLink"; }
+
+ NetLink();
+ NetLink(NetAddr& a);
+ virtual ~NetLink();
+
+ int operator == (const NetLink& that) const { return this == &that; }
+
+ const NetAddr& GetAddress() const { return addr; }
+
+ DWORD AddPeer(const char* a, WORD p=12345);
+ DWORD AddPeer(DWORD a, WORD p=12345);
+ DWORD AddPeer(const NetAddr& a);
+
+ bool SendMessage(DWORD nid, void* d, int l, BYTE f=0);
+ bool SendMessage(DWORD nid, BYTE type, const char* text, int len, BYTE f=0);
+ bool SendMessage(NetMsg* msg);
+
+ NetMsg* GetMessage();
+ NetMsg* GetMessage(DWORD netid);
+
+ virtual void Shutdown();
+ DWORD DoSendRecv();
+
+ DWORD GetResendInterval() const { return resend_time; }
+ void SetResendInterval(DWORD t) { resend_time = t; }
+ DWORD GetTrafficInterval() const { return traffic_time; }
+ void SetTrafficInterval(DWORD t) { traffic_time = t; }
+
+ DWORD GetPacketsSent() const { return packets_sent; }
+ DWORD GetPacketsRecv() const { return packets_recv; }
+ DWORD GetBytesSent() const { return bytes_sent; }
+ DWORD GetBytesRecv() const { return bytes_recv; }
+ DWORD GetRetries() const { return retries; }
+ DWORD GetDrops() const { return drops; }
+ DWORD GetLag() const { return lag; }
+
+ NetPeer* FindPeer(const NetAddr& a);
+ NetPeer* FindPeer(DWORD netid);
+
+protected:
+ void SendNetGram(NetGram* g);
+ NetGram* RecvNetGram();
+ void AckNetGram(NetGram* gram);
+ void ProcessAck(NetGram* gram);
+ void QueueNetGram(NetGram* gram);
+
+ void ReadPackets();
+ void SendPackets();
+ void DoRetries();
+
+ NetAddr addr;
+ NetSock sock;
+ List<NetGram> send_list;
+ List<NetMsg> recv_list;
+ List<NetPeer> peer_list;
+
+ HANDLE hnet;
+ bool shutdown;
+ ThreadSync sync;
+
+ DWORD resend_time;
+ DWORD traffic_time;
+
+ DWORD packets_sent;
+ DWORD packets_recv;
+ DWORD bytes_sent;
+ DWORD bytes_recv;
+ DWORD retries;
+ DWORD drops;
+ DWORD lag;
+
+ DWORD lag_samples[10];
+ int lag_index;
+};
+
+
#endif NetLink_h \ No newline at end of file
diff --git a/NetEx/NetMsg.cpp b/NetEx/NetMsg.cpp
index dec0bfd..e326d3a 100644
--- a/NetEx/NetMsg.cpp
+++ b/NetEx/NetMsg.cpp
@@ -1,89 +1,113 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetMsg.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- User level network message
-*/
-
-
-#include "MemDebug.h"
-#include <windows.h>
-#include "NetMsg.h"
-
-// +-------------------------------------------------------------------+
-
-static DWORD net_msg_sequence = 1;
-
-// +-------------------------------------------------------------------+
-
-NetMsg::NetMsg(DWORD nid, void* d, int l, BYTE f)
- : msgid(net_msg_sequence++), netid(nid), len(l), flags(f)
-{
- data = new(__FILE__,__LINE__) BYTE[len];
-
- if (data) {
- CopyMemory(data, d, len);
-
- if (len < MAX_SIZE)
- data[1] = len;
- else
- data[1] = 0;
- }
- else {
- len = 0;
- }
-}
-
-// +-------------------------------------------------------------------+
-
-NetMsg::NetMsg(DWORD nid, BYTE type, const char* text, int l, BYTE f)
- : msgid(net_msg_sequence++), netid(nid), len(2+l), flags(f)
-{
- data = new(__FILE__,__LINE__) BYTE[len];
-
- if (data) {
- data[0] = type;
-
- if (len < MAX_SIZE)
- data[1] = len;
- else
- data[1] = 0;
-
- if (len > 2)
- CopyMemory(data+2, text, len-2);
- }
- else {
- len = 0;
- }
-}
-
-// +-------------------------------------------------------------------+
-
-NetMsg::~NetMsg()
-{
- delete [] data;
-}
-
-// +-------------------------------------------------------------------+
-
-int NetMsg::operator < (const NetMsg& m) const
-{
- if (data[0] == MULTIPART && m.data[0] == MULTIPART) {
- NetMsgMultipart* p1 = (NetMsgMultipart*) data;
- NetMsgMultipart* p2 = (NetMsgMultipart*) m.data;
-
- if (p1->msgid == p2->msgid)
- return p1->partno < p2->partno;
-
- return p1->msgid < p2->msgid;
- }
-
- return msgid < m.msgid;
-}
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetMsg.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ User level network message
+*/
+
+
+#include "MemDebug.h"
+#include <windows.h>
+#include "NetMsg.h"
+
+// +-------------------------------------------------------------------+
+
+static DWORD net_msg_sequence = 1;
+
+// +-------------------------------------------------------------------+
+
+NetMsg::NetMsg(DWORD nid, void* d, int l, BYTE f)
+ : msgid(net_msg_sequence++), netid(nid), len(l), flags(f)
+{
+ data = new(__FILE__,__LINE__) BYTE[len];
+
+ if (data) {
+ CopyMemory(data, d, len);
+
+ if (len < MAX_SIZE)
+ data[1] = len;
+ else
+ data[1] = 0;
+ }
+ else {
+ len = 0;
+ }
+}
+
+// +-------------------------------------------------------------------+
+
+NetMsg::NetMsg(DWORD nid, BYTE type, const char* text, int l, BYTE f)
+ : msgid(net_msg_sequence++), netid(nid), len(2+l), flags(f)
+{
+ data = new(__FILE__,__LINE__) BYTE[len];
+
+ if (data) {
+ data[0] = type;
+
+ if (len < MAX_SIZE)
+ data[1] = len;
+ else
+ data[1] = 0;
+
+ if (len > 2)
+ CopyMemory(data+2, text, len-2);
+ }
+ else {
+ len = 0;
+ }
+}
+
+// +-------------------------------------------------------------------+
+
+NetMsg::~NetMsg()
+{
+ delete [] data;
+}
+
+// +-------------------------------------------------------------------+
+
+int NetMsg::operator < (const NetMsg& m) const
+{
+ if (data[0] == MULTIPART && m.data[0] == MULTIPART) {
+ NetMsgMultipart* p1 = (NetMsgMultipart*) data;
+ NetMsgMultipart* p2 = (NetMsgMultipart*) m.data;
+
+ if (p1->msgid == p2->msgid)
+ return p1->partno < p2->partno;
+
+ return p1->msgid < p2->msgid;
+ }
+
+ return msgid < m.msgid;
+}
diff --git a/NetEx/NetMsg.h b/NetEx/NetMsg.h
index 1c2a91a..072886b 100644
--- a/NetEx/NetMsg.h
+++ b/NetEx/NetMsg.h
@@ -1,81 +1,105 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetMsg.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- User level network message
-*/
-
-
-#ifndef NetMsg_h
-#define NetMsg_h
-
-#include <windows.h>
-#include "NetAddr.h"
-#include "NetGram.h"
-#include "NetSock.h"
-#include "List.h"
-
-// +-------------------------------------------------------------------+
-
-class NetMsg
-{
-public:
- static const char* TYPENAME() { return "NetMsg"; }
-
- enum FLAGS { RELIABLE = 0x01, PRIORITY = 0x02, SCATTER = 0x04 };
- enum TYPES { INVALID = 0,
- RESERVED = 0xF0,
- MULTIPART = 0xF1
- };
- enum { MAX_SIZE = 250 };
-
- NetMsg(DWORD nid, void* d, int l, BYTE f=0);
- NetMsg(DWORD nid, BYTE type, const char* text, int len, BYTE f=0);
- ~NetMsg();
-
- int operator == (const NetMsg& m) const { return msgid == m.msgid &&
- netid == m.netid; }
- int operator < (const NetMsg& m) const;
-
- DWORD Sequence() const { return msgid; }
- DWORD NetID() const { return netid; }
- const BYTE* Data() const { return data; }
- BYTE Type() const { return data ? *data : 0; }
- int Length() const { return len; }
- BYTE Flags() const { return flags; }
-
- bool IsReliable() const { return flags & RELIABLE ? true : false; }
- bool IsPriority() const { return flags & PRIORITY ? true : false; }
- bool IsScatter() const { return flags & SCATTER ? true : false; }
-
- void SetSequence(DWORD s) { msgid = s; }
-
-private:
- DWORD msgid;
- DWORD netid;
- BYTE* data;
- int len;
- BYTE flags;
-};
-
-// +-------------------------------------------------------------------+
-
-struct NetMsgMultipart {
- BYTE type;
- BYTE len;
- DWORD msgid;
- DWORD partno;
- DWORD nparts;
- BYTE payload[256];
-};
-
-// +-------------------------------------------------------------------+
-
-#endif NetMsg_h \ No newline at end of file
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetMsg.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ User level network message
+*/
+
+
+#ifndef NetMsg_h
+#define NetMsg_h
+
+#include <windows.h>
+#include "NetAddr.h"
+#include "NetGram.h"
+#include "NetSock.h"
+#include "List.h"
+
+// +-------------------------------------------------------------------+
+
+class NetMsg
+{
+public:
+ static const char* TYPENAME() { return "NetMsg"; }
+
+ enum FLAGS { RELIABLE = 0x01, PRIORITY = 0x02, SCATTER = 0x04 };
+ enum TYPES { INVALID = 0,
+ RESERVED = 0xF0,
+ MULTIPART = 0xF1
+ };
+ enum { MAX_SIZE = 250 };
+
+ NetMsg(DWORD nid, void* d, int l, BYTE f=0);
+ NetMsg(DWORD nid, BYTE type, const char* text, int len, BYTE f=0);
+ ~NetMsg();
+
+ int operator == (const NetMsg& m) const { return msgid == m.msgid &&
+ netid == m.netid; }
+ int operator < (const NetMsg& m) const;
+
+ DWORD Sequence() const { return msgid; }
+ DWORD NetID() const { return netid; }
+ const BYTE* Data() const { return data; }
+ BYTE Type() const { return data ? *data : 0; }
+ int Length() const { return len; }
+ BYTE Flags() const { return flags; }
+
+ bool IsReliable() const { return flags & RELIABLE ? true : false; }
+ bool IsPriority() const { return flags & PRIORITY ? true : false; }
+ bool IsScatter() const { return flags & SCATTER ? true : false; }
+
+ void SetSequence(DWORD s) { msgid = s; }
+
+private:
+ DWORD msgid;
+ DWORD netid;
+ BYTE* data;
+ int len;
+ BYTE flags;
+};
+
+// +-------------------------------------------------------------------+
+
+struct NetMsgMultipart {
+ BYTE type;
+ BYTE len;
+ DWORD msgid;
+ DWORD partno;
+ DWORD nparts;
+ BYTE payload[256];
+};
+
+// +-------------------------------------------------------------------+
+
+#endif NetMsg_h
diff --git a/NetEx/NetPeer.cpp b/NetEx/NetPeer.cpp
index 6ead8a4..94f68a5 100644
--- a/NetEx/NetPeer.cpp
+++ b/NetEx/NetPeer.cpp
@@ -1,440 +1,464 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetPeer.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- One side of a UDP net link connection
-*/
-
-
-#include "MemDebug.h"
-#include <windows.h>
-#include "NetPeer.h"
-#include "NetGram.h"
-#include "NetMsg.h"
-#include "NetLayer.h"
-
-#include <stdio.h>
-
-// +-------------------------------------------------------------------+
-
-const int MULTIPART_CHUNKSIZE = 232;
-const int MULTIPART_HEADER = 16;
-const int UDP_HEADER_SIZE = 34;
-
-static NetMsgMultipart multi_part_buffer;
-static DWORD multi_msg_sequence = 1;
-
-// +-------------------------------------------------------------------+
-
-NetPeer::NetPeer(const NetAddr& a, DWORD id)
- : addr(a), netid(id), sequence(0), pps(0), bps(0), max_qsize(0),
- status(OK), hist_indx(0), send_size(0), recv_size(0),
- chunk_size(MULTIPART_CHUNKSIZE)
-{
- ZeroMemory(hist_time, sizeof(hist_time));
- ZeroMemory(hist_size, sizeof(hist_size));
-
- last_recv_time = NetLayer::GetUTC();
-}
-
-NetPeer::~NetPeer()
-{
- send_list.destroy();
- recv_list.destroy();
-
- multi_send_list.destroy();
- multi_recv_list.destroy();
-}
-
-// +-------------------------------------------------------------------+
-
-bool
-NetPeer::SendMessage(NetMsg* msg)
-{
- if (msg) {
- if (max_qsize > 0 && msg->Length() + send_size > max_qsize) {
- status = SEND_OVERFLOW;
- delete msg;
- return false;
- }
-
- // simple message
- if (msg->Length() <= (int) chunk_size) {
- if (msg->IsPriority())
- send_list.insert(msg);
- else
- send_list.append(msg);
-
- send_size += msg->Length();
- }
-
- // multipart message
- else {
- List<NetMsg>* list = &send_list;
-
- if (msg->IsScatter())
- list = &multi_send_list;
-
- DWORD nparts = msg->Length() / chunk_size;
- DWORD extra = msg->Length() % chunk_size;
-
- if (extra > 0) nparts++;
-
- multi_part_buffer.type = NetMsg::MULTIPART;
- multi_part_buffer.msgid = multi_msg_sequence++;
- multi_part_buffer.nparts = nparts;
-
- DWORD header_size = (DWORD) (&multi_part_buffer.payload) -
- (DWORD) (&multi_part_buffer);
-
- const BYTE* p = msg->Data();
-
- for (DWORD i = 0; i < nparts; i++) {
- multi_part_buffer.partno = i;
- NetMsg* part = 0;
- DWORD part_size = chunk_size;
-
- if (i == nparts-1 && extra > 0) // last partial payload
- part_size = extra;
-
- CopyMemory(multi_part_buffer.payload, p, part_size);
- p += part_size;
- part = new(__FILE__,__LINE__) NetMsg(msg->NetID(),
- &multi_part_buffer,
- header_size + part_size,
- msg->Flags());
-
- if (part) {
- list->append(part);
- send_size += part->Length();
- }
- }
- }
-
- return true;
- }
-
- return false;
-}
-
-// +-------------------------------------------------------------------+
-
-NetMsg*
-NetPeer::GetMessage()
-{
- if (recv_list.size() > 0) {
- NetMsg* msg = recv_list.removeIndex(0);
- recv_size -= msg->Length();
- return msg;
- }
-
- return 0;
-}
-
-// +-------------------------------------------------------------------+
-
-NetGram*
-NetPeer::ComposeGram()
-{
- NetGram* g = 0;
-
- if ((send_list.size() || multi_send_list.size()) && OKtoSend()) {
- AutoThreadSync auto_sync(sync);
-
- int xmit_size = send_size;
- int nmsg = send_list.size();
- int limit = NET_GRAM_MAX_SIZE;
- bool reliable = false;
- bool is_multi = false;
-
- NetMsg* multi_msg = 0;
- List<NetMsg>* list = &send_list;
-
- if (xmit_size > limit) {
- xmit_size = 0;
- nmsg = 0;
-
- if (send_list.size() > 0) {
-
- // if there is regular traffic, and multipart traffic
- if (multi_send_list.size()) {
- // just send one multipart message in this packet
- multi_msg = multi_send_list.removeIndex(0);
- limit -= multi_msg->Length();
- reliable = true;
- is_multi = true;
- }
-
- for (int i = 0; i < send_list.size(); i++) {
- NetMsg* msg = send_list[i];
-
- if (xmit_size + msg->Length() < limit) {
- xmit_size += msg->Length();
- nmsg++;
- }
- else {
- break;
- }
- }
- }
- else {
- // if there is only multipart traffic,
- // send as many multipart messages as will fit:
- list = &multi_send_list;
- reliable = true;
- is_multi = true;
-
- for (int i = 0; i < multi_send_list.size(); i++) {
- NetMsg* msg = multi_send_list[i];
-
- if (xmit_size + msg->Length() < limit) {
- xmit_size += msg->Length();
- nmsg++;
- }
- else {
- break;
- }
- }
- }
- }
-
- if (xmit_size > 0 && nmsg > 0) {
- BYTE* buffer = new(__FILE__,__LINE__) BYTE[xmit_size];
- BYTE* p = buffer;
-
- if (multi_msg) {
- if (buffer) {
- CopyMemory(p, multi_msg->Data(), multi_msg->Length());
- p[1] = multi_msg->Length();
- p += multi_msg->Length();
- }
- delete multi_msg;
- }
-
- while (nmsg-- && p < buffer + xmit_size) {
- NetMsg* msg = list->removeIndex(0);
-
- if (msg) {
- if (msg->IsReliable()) reliable = true;
- if (buffer) {
- CopyMemory(p, msg->Data(), msg->Length());
- p[1] = msg->Length();
- p += msg->Length();
- }
- delete msg;
- }
- }
-
- if (buffer) {
- Text user_data((const char*) buffer, xmit_size);
- int retries = 0;
-
- if (reliable)
- retries = 5;
-
- if (is_multi)
- retries = 10;
-
- send_size -= xmit_size;
-
- hist_size[hist_indx] = xmit_size + UDP_HEADER_SIZE;
- hist_time[hist_indx] = NetLayer::GetTime();
- hist_indx++;
-
- if (hist_indx >= HIST_SIZE)
- hist_indx = 0;
-
- g = new(__FILE__,__LINE__) NetGram(addr, user_data, retries);
- delete[] buffer;
- }
- }
-
- // the next msg is too big to fit in a single packet
- else {
- NetMsg* m = send_list.removeIndex(0);
- send_size -= m->Length();
- delete m;
- }
- }
-
- return g;
-}
-
-// +-------------------------------------------------------------------+
-
-bool
-NetPeer::ReceiveGram(NetGram* g, List<NetMsg>* q)
-{
- if (g) {
- if (max_qsize > 0 && recv_size + g->Size() > max_qsize) {
- status = RECV_OVERFLOW;
- delete g;
- return false;
- }
-
- sequence = g->Sequence();
- recv_size += g->Size() - NET_GRAM_HEADER_SIZE;
-
- // PARSE THE BLOCKS:
- BYTE* p = g->UserData();
-
- while (p < g->Data() + g->Size()) {
- BYTE block_type = p[0];
- BYTE block_size = p[1];
-
- if (!block_type || !block_size)
- break;
-
- NetMsg* msg = new(__FILE__,__LINE__) NetMsg(netid, p, block_size);
-
- if (msg) {
- if (msg->Type() < NetMsg::RESERVED) {
- msg->SetSequence(sequence);
-
- recv_list.insertSort(msg);
-
- if (q)
- q->insertSort(msg);
-
- p += block_size;
- }
-
- else if (msg->Type() == NetMsg::MULTIPART) {
- multi_recv_list.insertSort(msg);
- p += block_size;
-
- CheckMultiRecv(q);
- }
- }
- }
-
- last_recv_time = NetLayer::GetUTC();
-
- delete g;
- return true;
- }
-
- return false;
-}
-
-// +-------------------------------------------------------------------+
-
-bool
-NetPeer::OKtoSend() const
-{
- if (pps || bps) {
- DWORD hist_total = 0;
- DWORD hist_count = 0;
- DWORD now = NetLayer::GetTime();
- DWORD hist_oldest = now;
- DWORD hist_newest = 0;
-
- for (int i = 0; i < HIST_SIZE; i++) {
- if (hist_size[i] > 0) {
- hist_total += hist_size[i];
- hist_count++;
- }
-
- if (hist_time[i] > 0) {
- if (hist_time[i] < hist_oldest)
- hist_oldest = hist_time[i];
-
- if (hist_time[i] > hist_newest)
- hist_newest = hist_time[i];
- }
- }
-
- if (now - hist_newest < (DWORD) pps)
- return false;
-
- DWORD delta = now - hist_oldest;
- DWORD avg_bps = hist_total / delta;
-
- if (bps > 0 && avg_bps > (DWORD) bps)
- return false;
- }
-
- return true;
-}
-
-// +-------------------------------------------------------------------+
-
-struct PacketAssembly {
- DWORD msgid;
- DWORD netid;
- int nreq;
- int nparts;
- int nbytes;
-};
-
-void
-NetPeer::CheckMultiRecv(List<NetMsg>* q)
-{
- const int MAX_SIMULTANEOUS_MULTI_SEQUENCES = 8;
-
- PacketAssembly assy[MAX_SIMULTANEOUS_MULTI_SEQUENCES];
- ZeroMemory(assy, sizeof(assy));
-
- DWORD header_size = (DWORD) (&multi_part_buffer.payload) -
- (DWORD) (&multi_part_buffer);
-
- // Catalog how much of each multipart sequence has been received:
- for (int i = 0; i < multi_recv_list.size(); i++) {
- NetMsg* msg = multi_recv_list[i];
- NetMsgMultipart* m = (NetMsgMultipart*) msg->Data();
-
- for (int n = 0; n < MAX_SIMULTANEOUS_MULTI_SEQUENCES; n++) {
- PacketAssembly* a = assy + n;
-
- if (a->msgid == 0 || (a->msgid == m->msgid && a->netid == msg->NetID())) {
- a->msgid = m->msgid;
- a->netid = msg->NetID();
- a->nreq = m->nparts;
- a->nparts += 1;
- a->nbytes += m->len - header_size;
- break;
- }
- }
- }
-
- for (int n = 0; n < MAX_SIMULTANEOUS_MULTI_SEQUENCES; n++) {
- PacketAssembly* a = assy + n;
-
- // is this sequence complete?
- if (a->msgid && a->nparts == a->nreq) {
- BYTE* buffer = new BYTE[a->nbytes];
- BYTE* p = buffer;
- WORD nid = 0;
-
- ListIter<NetMsg> iter = multi_recv_list;
- while (++iter) {
- netid = iter->NetID();
- NetMsgMultipart* m = (NetMsgMultipart*) iter->Data();
-
- // found part of the sequence
- if (m->msgid == a->msgid && netid == a->netid) {
- // copy it into the buffer
- CopyMemory(p, m->payload, m->len - header_size);
- p += m->len - header_size;
-
- delete iter.removeItem();
- }
- }
-
- NetMsg* msg = new(__FILE__,__LINE__) NetMsg(netid, buffer, a->nbytes, NetMsg::RELIABLE);
- if (msg) {
- recv_list.insertSort(msg);
-
- if (q)
- q->insertSort(msg);
- }
- }
- }
-}
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetPeer.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ One side of a UDP net link connection
+*/
+
+
+#include "MemDebug.h"
+#include <windows.h>
+#include "NetPeer.h"
+#include "NetGram.h"
+#include "NetMsg.h"
+#include "NetLayer.h"
+
+#include <stdio.h>
+
+// +-------------------------------------------------------------------+
+
+const int MULTIPART_CHUNKSIZE = 232;
+const int MULTIPART_HEADER = 16;
+const int UDP_HEADER_SIZE = 34;
+
+static NetMsgMultipart multi_part_buffer;
+static DWORD multi_msg_sequence = 1;
+
+// +-------------------------------------------------------------------+
+
+NetPeer::NetPeer(const NetAddr& a, DWORD id)
+ : addr(a), netid(id), sequence(0), pps(0), bps(0), max_qsize(0),
+ status(OK), hist_indx(0), send_size(0), recv_size(0),
+ chunk_size(MULTIPART_CHUNKSIZE)
+{
+ ZeroMemory(hist_time, sizeof(hist_time));
+ ZeroMemory(hist_size, sizeof(hist_size));
+
+ last_recv_time = NetLayer::GetUTC();
+}
+
+NetPeer::~NetPeer()
+{
+ send_list.destroy();
+ recv_list.destroy();
+
+ multi_send_list.destroy();
+ multi_recv_list.destroy();
+}
+
+// +-------------------------------------------------------------------+
+
+bool
+NetPeer::SendMessage(NetMsg* msg)
+{
+ if (msg) {
+ if (max_qsize > 0 && msg->Length() + send_size > max_qsize) {
+ status = SEND_OVERFLOW;
+ delete msg;
+ return false;
+ }
+
+ // simple message
+ if (msg->Length() <= (int) chunk_size) {
+ if (msg->IsPriority())
+ send_list.insert(msg);
+ else
+ send_list.append(msg);
+
+ send_size += msg->Length();
+ }
+
+ // multipart message
+ else {
+ List<NetMsg>* list = &send_list;
+
+ if (msg->IsScatter())
+ list = &multi_send_list;
+
+ DWORD nparts = msg->Length() / chunk_size;
+ DWORD extra = msg->Length() % chunk_size;
+
+ if (extra > 0) nparts++;
+
+ multi_part_buffer.type = NetMsg::MULTIPART;
+ multi_part_buffer.msgid = multi_msg_sequence++;
+ multi_part_buffer.nparts = nparts;
+
+ DWORD header_size = (DWORD) (&multi_part_buffer.payload) -
+ (DWORD) (&multi_part_buffer);
+
+ const BYTE* p = msg->Data();
+
+ for (DWORD i = 0; i < nparts; i++) {
+ multi_part_buffer.partno = i;
+ NetMsg* part = 0;
+ DWORD part_size = chunk_size;
+
+ if (i == nparts-1 && extra > 0) // last partial payload
+ part_size = extra;
+
+ CopyMemory(multi_part_buffer.payload, p, part_size);
+ p += part_size;
+ part = new(__FILE__,__LINE__) NetMsg(msg->NetID(),
+ &multi_part_buffer,
+ header_size + part_size,
+ msg->Flags());
+
+ if (part) {
+ list->append(part);
+ send_size += part->Length();
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+// +-------------------------------------------------------------------+
+
+NetMsg*
+NetPeer::GetMessage()
+{
+ if (recv_list.size() > 0) {
+ NetMsg* msg = recv_list.removeIndex(0);
+ recv_size -= msg->Length();
+ return msg;
+ }
+
+ return 0;
+}
+
+// +-------------------------------------------------------------------+
+
+NetGram*
+NetPeer::ComposeGram()
+{
+ NetGram* g = 0;
+
+ if ((send_list.size() || multi_send_list.size()) && OKtoSend()) {
+ AutoThreadSync auto_sync(sync);
+
+ int xmit_size = send_size;
+ int nmsg = send_list.size();
+ int limit = NET_GRAM_MAX_SIZE;
+ bool reliable = false;
+ bool is_multi = false;
+
+ NetMsg* multi_msg = 0;
+ List<NetMsg>* list = &send_list;
+
+ if (xmit_size > limit) {
+ xmit_size = 0;
+ nmsg = 0;
+
+ if (send_list.size() > 0) {
+
+ // if there is regular traffic, and multipart traffic
+ if (multi_send_list.size()) {
+ // just send one multipart message in this packet
+ multi_msg = multi_send_list.removeIndex(0);
+ limit -= multi_msg->Length();
+ reliable = true;
+ is_multi = true;
+ }
+
+ for (int i = 0; i < send_list.size(); i++) {
+ NetMsg* msg = send_list[i];
+
+ if (xmit_size + msg->Length() < limit) {
+ xmit_size += msg->Length();
+ nmsg++;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ else {
+ // if there is only multipart traffic,
+ // send as many multipart messages as will fit:
+ list = &multi_send_list;
+ reliable = true;
+ is_multi = true;
+
+ for (int i = 0; i < multi_send_list.size(); i++) {
+ NetMsg* msg = multi_send_list[i];
+
+ if (xmit_size + msg->Length() < limit) {
+ xmit_size += msg->Length();
+ nmsg++;
+ }
+ else {
+ break;
+ }
+ }
+ }
+ }
+
+ if (xmit_size > 0 && nmsg > 0) {
+ BYTE* buffer = new(__FILE__,__LINE__) BYTE[xmit_size];
+ BYTE* p = buffer;
+
+ if (multi_msg) {
+ if (buffer) {
+ CopyMemory(p, multi_msg->Data(), multi_msg->Length());
+ p[1] = multi_msg->Length();
+ p += multi_msg->Length();
+ }
+ delete multi_msg;
+ }
+
+ while (nmsg-- && p < buffer + xmit_size) {
+ NetMsg* msg = list->removeIndex(0);
+
+ if (msg) {
+ if (msg->IsReliable()) reliable = true;
+ if (buffer) {
+ CopyMemory(p, msg->Data(), msg->Length());
+ p[1] = msg->Length();
+ p += msg->Length();
+ }
+ delete msg;
+ }
+ }
+
+ if (buffer) {
+ Text user_data((const char*) buffer, xmit_size);
+ int retries = 0;
+
+ if (reliable)
+ retries = 5;
+
+ if (is_multi)
+ retries = 10;
+
+ send_size -= xmit_size;
+
+ hist_size[hist_indx] = xmit_size + UDP_HEADER_SIZE;
+ hist_time[hist_indx] = NetLayer::GetTime();
+ hist_indx++;
+
+ if (hist_indx >= HIST_SIZE)
+ hist_indx = 0;
+
+ g = new(__FILE__,__LINE__) NetGram(addr, user_data, retries);
+ delete[] buffer;
+ }
+ }
+
+ // the next msg is too big to fit in a single packet
+ else {
+ NetMsg* m = send_list.removeIndex(0);
+ send_size -= m->Length();
+ delete m;
+ }
+ }
+
+ return g;
+}
+
+// +-------------------------------------------------------------------+
+
+bool
+NetPeer::ReceiveGram(NetGram* g, List<NetMsg>* q)
+{
+ if (g) {
+ if (max_qsize > 0 && recv_size + g->Size() > max_qsize) {
+ status = RECV_OVERFLOW;
+ delete g;
+ return false;
+ }
+
+ sequence = g->Sequence();
+ recv_size += g->Size() - NET_GRAM_HEADER_SIZE;
+
+ // PARSE THE BLOCKS:
+ BYTE* p = g->UserData();
+
+ while (p < g->Data() + g->Size()) {
+ BYTE block_type = p[0];
+ BYTE block_size = p[1];
+
+ if (!block_type || !block_size)
+ break;
+
+ NetMsg* msg = new(__FILE__,__LINE__) NetMsg(netid, p, block_size);
+
+ if (msg) {
+ if (msg->Type() < NetMsg::RESERVED) {
+ msg->SetSequence(sequence);
+
+ recv_list.insertSort(msg);
+
+ if (q)
+ q->insertSort(msg);
+
+ p += block_size;
+ }
+
+ else if (msg->Type() == NetMsg::MULTIPART) {
+ multi_recv_list.insertSort(msg);
+ p += block_size;
+
+ CheckMultiRecv(q);
+ }
+ }
+ }
+
+ last_recv_time = NetLayer::GetUTC();
+
+ delete g;
+ return true;
+ }
+
+ return false;
+}
+
+// +-------------------------------------------------------------------+
+
+bool
+NetPeer::OKtoSend() const
+{
+ if (pps || bps) {
+ DWORD hist_total = 0;
+ DWORD hist_count = 0;
+ DWORD now = NetLayer::GetTime();
+ DWORD hist_oldest = now;
+ DWORD hist_newest = 0;
+
+ for (int i = 0; i < HIST_SIZE; i++) {
+ if (hist_size[i] > 0) {
+ hist_total += hist_size[i];
+ hist_count++;
+ }
+
+ if (hist_time[i] > 0) {
+ if (hist_time[i] < hist_oldest)
+ hist_oldest = hist_time[i];
+
+ if (hist_time[i] > hist_newest)
+ hist_newest = hist_time[i];
+ }
+ }
+
+ if (now - hist_newest < (DWORD) pps)
+ return false;
+
+ DWORD delta = now - hist_oldest;
+ DWORD avg_bps = hist_total / delta;
+
+ if (bps > 0 && avg_bps > (DWORD) bps)
+ return false;
+ }
+
+ return true;
+}
+
+// +-------------------------------------------------------------------+
+
+struct PacketAssembly {
+ DWORD msgid;
+ DWORD netid;
+ int nreq;
+ int nparts;
+ int nbytes;
+};
+
+void
+NetPeer::CheckMultiRecv(List<NetMsg>* q)
+{
+ const int MAX_SIMULTANEOUS_MULTI_SEQUENCES = 8;
+
+ PacketAssembly assy[MAX_SIMULTANEOUS_MULTI_SEQUENCES];
+ ZeroMemory(assy, sizeof(assy));
+
+ DWORD header_size = (DWORD) (&multi_part_buffer.payload) -
+ (DWORD) (&multi_part_buffer);
+
+ // Catalog how much of each multipart sequence has been received:
+ for (int i = 0; i < multi_recv_list.size(); i++) {
+ NetMsg* msg = multi_recv_list[i];
+ NetMsgMultipart* m = (NetMsgMultipart*) msg->Data();
+
+ for (int n = 0; n < MAX_SIMULTANEOUS_MULTI_SEQUENCES; n++) {
+ PacketAssembly* a = assy + n;
+
+ if (a->msgid == 0 || (a->msgid == m->msgid && a->netid == msg->NetID())) {
+ a->msgid = m->msgid;
+ a->netid = msg->NetID();
+ a->nreq = m->nparts;
+ a->nparts += 1;
+ a->nbytes += m->len - header_size;
+ break;
+ }
+ }
+ }
+
+ for (int n = 0; n < MAX_SIMULTANEOUS_MULTI_SEQUENCES; n++) {
+ PacketAssembly* a = assy + n;
+
+ // is this sequence complete?
+ if (a->msgid && a->nparts == a->nreq) {
+ BYTE* buffer = new BYTE[a->nbytes];
+ BYTE* p = buffer;
+ WORD nid = 0;
+
+ ListIter<NetMsg> iter = multi_recv_list;
+ while (++iter) {
+ netid = iter->NetID();
+ NetMsgMultipart* m = (NetMsgMultipart*) iter->Data();
+
+ // found part of the sequence
+ if (m->msgid == a->msgid && netid == a->netid) {
+ // copy it into the buffer
+ CopyMemory(p, m->payload, m->len - header_size);
+ p += m->len - header_size;
+
+ delete iter.removeItem();
+ }
+ }
+
+ NetMsg* msg = new(__FILE__,__LINE__) NetMsg(netid, buffer, a->nbytes, NetMsg::RELIABLE);
+ if (msg) {
+ recv_list.insertSort(msg);
+
+ if (q)
+ q->insertSort(msg);
+ }
+ }
+ }
+}
diff --git a/NetEx/NetPeer.h b/NetEx/NetPeer.h
index b2ec882..4849f2f 100644
--- a/NetEx/NetPeer.h
+++ b/NetEx/NetPeer.h
@@ -1,98 +1,122 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetPeer.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- One side of a UDP net link connection
-*/
-
-
-#ifndef NetPeer_h
-#define NetPeer_h
-
-#include <windows.h>
-#include "NetAddr.h"
-#include "List.h"
-#include "ThreadSync.h"
-
-// +-------------------------------------------------------------------+
-
-class NetGram;
-class NetMsg;
-
-// +-------------------------------------------------------------------+
-
-class NetPeer
-{
-public:
- static const char* TYPENAME() { return "NetPeer"; }
-
- enum STATUS { OK, SEND_OVERFLOW, RECV_OVERFLOW };
-
- NetPeer(const NetAddr& addr, DWORD id);
- ~NetPeer();
-
- int operator == (const NetPeer& p) const { return netid == p.netid; }
-
- bool SendMessage(NetMsg* msg);
- NetMsg* GetMessage();
-
- NetGram* ComposeGram();
- bool ReceiveGram(NetGram* g, List<NetMsg>* q=0);
-
- const NetAddr& Address() const { return addr; }
- DWORD NetID() const { return netid; }
- DWORD Sequence() const { return sequence; }
-
- int GetMaxPPS() const { return pps; }
- void SetMaxPPS(int p) { pps = p; }
- int GetMaxBPS() const { return bps; }
- void SetMaxBPS(int b) { bps = b; }
- int GetMaxQSize() const { return max_qsize; }
- void SetMaxQSize(int q) { max_qsize = q; }
-
- DWORD GetChunkSize() const { return chunk_size; }
- void SetChunkSize(DWORD s) { chunk_size = s; }
-
- DWORD LastReceiveTime() const { return last_recv_time; }
- void SetLastReceiveTime(DWORD t) { last_recv_time = t; }
-
-private:
- bool OKtoSend() const;
- void CheckMultiRecv(List<NetMsg>* q);
-
- NetAddr addr; // remote network address
- DWORD sequence; // highest packet id received
- DWORD netid; // unique id for this peer
- int pps; // max packets per second
- int bps; // max bits per second
- int max_qsize; // max bytes in either queue
- int status; // ok or error code
- DWORD chunk_size; // size of multipart message chunk
-
- enum HIST { HIST_SIZE=8 };
-
- DWORD last_recv_time; // time of last received packet
- DWORD hist_time[HIST_SIZE]; // history for pps check
- DWORD hist_size[HIST_SIZE]; // history for bps check
- int hist_indx; // index into history
-
- int send_size; // total bytes in send list
- int recv_size; // total bytes in recv list
- List<NetMsg> send_list; // queue of messages waiting to be sent
- List<NetMsg> recv_list; // queue of messages waiting to be read
-
- List<NetMsg> multi_send_list;
- List<NetMsg> multi_recv_list;
-
- ThreadSync sync;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetPeer.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ One side of a UDP net link connection
+*/
+
+
+#ifndef NetPeer_h
+#define NetPeer_h
+
+#include <windows.h>
+#include "NetAddr.h"
+#include "List.h"
+#include "ThreadSync.h"
+
+// +-------------------------------------------------------------------+
+
+class NetGram;
+class NetMsg;
+
+// +-------------------------------------------------------------------+
+
+class NetPeer
+{
+public:
+ static const char* TYPENAME() { return "NetPeer"; }
+
+ enum STATUS { OK, SEND_OVERFLOW, RECV_OVERFLOW };
+
+ NetPeer(const NetAddr& addr, DWORD id);
+ ~NetPeer();
+
+ int operator == (const NetPeer& p) const { return netid == p.netid; }
+
+ bool SendMessage(NetMsg* msg);
+ NetMsg* GetMessage();
+
+ NetGram* ComposeGram();
+ bool ReceiveGram(NetGram* g, List<NetMsg>* q=0);
+
+ const NetAddr& Address() const { return addr; }
+ DWORD NetID() const { return netid; }
+ DWORD Sequence() const { return sequence; }
+
+ int GetMaxPPS() const { return pps; }
+ void SetMaxPPS(int p) { pps = p; }
+ int GetMaxBPS() const { return bps; }
+ void SetMaxBPS(int b) { bps = b; }
+ int GetMaxQSize() const { return max_qsize; }
+ void SetMaxQSize(int q) { max_qsize = q; }
+
+ DWORD GetChunkSize() const { return chunk_size; }
+ void SetChunkSize(DWORD s) { chunk_size = s; }
+
+ DWORD LastReceiveTime() const { return last_recv_time; }
+ void SetLastReceiveTime(DWORD t) { last_recv_time = t; }
+
+private:
+ bool OKtoSend() const;
+ void CheckMultiRecv(List<NetMsg>* q);
+
+ NetAddr addr; // remote network address
+ DWORD sequence; // highest packet id received
+ DWORD netid; // unique id for this peer
+ int pps; // max packets per second
+ int bps; // max bits per second
+ int max_qsize; // max bytes in either queue
+ int status; // ok or error code
+ DWORD chunk_size; // size of multipart message chunk
+
+ enum HIST { HIST_SIZE=8 };
+
+ DWORD last_recv_time; // time of last received packet
+ DWORD hist_time[HIST_SIZE]; // history for pps check
+ DWORD hist_size[HIST_SIZE]; // history for bps check
+ int hist_indx; // index into history
+
+ int send_size; // total bytes in send list
+ int recv_size; // total bytes in recv list
+ List<NetMsg> send_list; // queue of messages waiting to be sent
+ List<NetMsg> recv_list; // queue of messages waiting to be read
+
+ List<NetMsg> multi_send_list;
+ List<NetMsg> multi_recv_list;
+
+ ThreadSync sync;
+};
+
+
#endif NetPeer_h \ No newline at end of file
diff --git a/NetEx/NetServer.cpp b/NetEx/NetServer.cpp
index 6534202..1ec45fd 100644
--- a/NetEx/NetServer.cpp
+++ b/NetEx/NetServer.cpp
@@ -1,260 +1,284 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetServer.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#include "MemDebug.h"
-#include "NetServer.h"
-#include "NetHost.h"
-#include "NetLayer.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <mmsystem.h>
-
-// +-------------------------------------------------------------------+
-
-DWORD WINAPI NetServerListenerProc(LPVOID link);
-DWORD WINAPI NetServerReaderProc(LPVOID link);
-
-struct PoolItem { NetServer* server; int thread_index; };
-
-// +-------------------------------------------------------------------+
-
-NetServer::NetServer(WORD port, int nthreads)
- : sock(true), pool(0), conn(0), poolsize(nthreads), err(0),
- server_shutdown(false), hreader(0)
-{
- NetHost host;
- addr = NetAddr(host.Address().IPAddr(), port);
-
- sock.bind(addr);
- sock.listen(3);
-
- if (poolsize < 1) poolsize = 1;
-
- pool = new(__FILE__,__LINE__) HANDLE[poolsize];
- conn = new(__FILE__,__LINE__) NetSock*[poolsize];
- clients = new(__FILE__,__LINE__) NetAddr[poolsize];
-
- if (pool && conn && clients) {
- ZeroMemory(pool, poolsize * sizeof(HANDLE));
- ZeroMemory(conn, poolsize * sizeof(NetSock*));
-
- DWORD thread_id = 0;
-
- for (int i = 0; i < poolsize; i++) {
- thread_id = 0;
- PoolItem* item = new PoolItem;
- item->server = this;
- item->thread_index = i;
-
- pool[i] = CreateThread(0, 4096, NetServerReaderProc, (LPVOID) item, 0, &thread_id);
- }
-
- thread_id = 0;
- hreader = CreateThread(0, 4096, NetServerListenerProc, (LPVOID) this, 0, &thread_id);
- }
-}
-
-NetServer::~NetServer()
-{
- if (!server_shutdown) {
- server_shutdown = true;
- sock.close();
- }
-
- if (hreader) {
- WaitForSingleObject(hreader, 1000);
- CloseHandle(hreader);
- }
-
- if (pool && poolsize) {
- for (int i = 0; i < poolsize; i++) {
- WaitForSingleObject(pool[i], 1000);
- CloseHandle(pool[i]);
- delete conn[i];
- conn[i] = 0;
- }
-
- delete [] pool;
- delete [] conn;
- delete [] clients;
- }
-}
-
-// +--------------------------------------------------------------------+
-
-void
-NetServer::Shutdown()
-{
- server_shutdown = true;
-}
-
-// +--------------------------------------------------------------------+
-
-DWORD WINAPI NetServerListenerProc(LPVOID link)
-{
- NetServer* net_server = (NetServer*) link;
-
- if (net_server)
- return net_server->Listener();
-
- return (DWORD) E_POINTER;
-}
-
-DWORD
-NetServer::Listener()
-{
- while (!server_shutdown) {
- NetSock* s = sock.accept(&client_addr);
-
- while (s) {
- sync.acquire();
-
- for (int i = 0; i < poolsize; i++) {
- if (conn[i] == 0) {
- conn[i] = s;
- clients[i] = client_addr;
- s = 0;
- break;
- }
- }
-
- sync.release();
-
- // wait for a thread to become not busy
- if (s)
- Sleep(10);
- }
- }
-
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-DWORD WINAPI NetServerReaderProc(LPVOID link)
-{
- if (!link) return (DWORD) E_POINTER;
-
- PoolItem* item = (PoolItem*) link;
- NetServer* net_server = item->server;
- int index = item->thread_index;
-
- delete item;
-
- if (net_server)
- return net_server->Reader(index);
-
- return (DWORD) E_POINTER;
-}
-
-DWORD
-NetServer::Reader(int index)
-{
- // init random seed for this thread:
- srand(timeGetTime());
-
- while (!server_shutdown) {
- sync.acquire();
- NetSock* s = conn[index];
- sync.release();
-
- if (s) {
- const int MAX_REQUEST = 4096;
- Text request;
-
- /***
- *** NOT SURE WHY, BUT THIS DOESN'T WORK FOR SHIT
- ***
- *** Setting the socket timeout to 2 seconds caused it
- *** to wait for two seconds, read nothing, and give up
- *** with a WSAETIMEDOUT error. Meanwhile, the client
- *** immediately registered a failure (during the 2 sec
- *** delay) and aborted the request.
- ***
-
- s->set_timeout(2000);
- Text msg = s->recv();
-
- while (msg.length() > 0 && request.length() < MAX_REQUEST) {
- request += msg;
- msg = s->recv();
- }
-
- ***/
-
- request = s->recv();
-
- if (request.length() > 0 && !s->is_closed()) {
- Text response = ProcessRequest(request, clients[index]);
- err = s->send(response);
- if (err < 0) {
- err = NetLayer::GetLastError();
- }
- }
-
- sync.acquire();
- delete conn[index];
- conn[index] = 0;
- sync.release();
- }
- else {
- Sleep(5);
- }
- }
-
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-Text
-NetServer::ProcessRequest(Text msg, const NetAddr& addr)
-{
- if (msg.indexOf("GET ") == 0)
- return DefaultResponse();
-
- return ErrorResponse();
-}
-
-Text
-NetServer::DefaultResponse()
-{
- Text response =
- "HTTP/1.0 200 OK\nServer: Generic NetServer 1.0\nMIME-Version: 1.0\nContent-type: text/html\n\n";
-
- response += "<html><head><title>Generic NetServer 1.0</title></head>\n\n";
- response += "<body bgcolor=\"black\" text=\"white\">\n";
- response += "<h1>Generic NetServer 1.0</h1>\n";
- response += "<p>Didn't think I could do it, did ya?\n";
- response += "</body></html>\n\n";
-
- return response;
-}
-
-Text
-NetServer::ErrorResponse()
-{
- Text response =
- "HTTP/1.0 501 Not Implemented\nServer: Generic NetServer 1.0\nMIME-Version: 1.0\nContent-type: text/html\n\n";
-
- response += "<html><head><title>Generic NetServer 1.0</title></head>\n\n";
- response += "<body bgcolor=\"black\" text=\"white\">\n";
- response += "<h1>Generic NetServer 1.0</h1>\n";
- response += "<p>Sorry charlie... I'm not a magician.\n";
- response += "</body></html>\n\n";
-
- return response;
-}
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetServer.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#include "MemDebug.h"
+#include "NetServer.h"
+#include "NetHost.h"
+#include "NetLayer.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <mmsystem.h>
+
+// +-------------------------------------------------------------------+
+
+DWORD WINAPI NetServerListenerProc(LPVOID link);
+DWORD WINAPI NetServerReaderProc(LPVOID link);
+
+struct PoolItem { NetServer* server; int thread_index; };
+
+// +-------------------------------------------------------------------+
+
+NetServer::NetServer(WORD port, int nthreads)
+ : sock(true), pool(0), conn(0), poolsize(nthreads), err(0),
+ server_shutdown(false), hreader(0)
+{
+ NetHost host;
+ addr = NetAddr(host.Address().IPAddr(), port);
+
+ sock.bind(addr);
+ sock.listen(3);
+
+ if (poolsize < 1) poolsize = 1;
+
+ pool = new(__FILE__,__LINE__) HANDLE[poolsize];
+ conn = new(__FILE__,__LINE__) NetSock*[poolsize];
+ clients = new(__FILE__,__LINE__) NetAddr[poolsize];
+
+ if (pool && conn && clients) {
+ ZeroMemory(pool, poolsize * sizeof(HANDLE));
+ ZeroMemory(conn, poolsize * sizeof(NetSock*));
+
+ DWORD thread_id = 0;
+
+ for (int i = 0; i < poolsize; i++) {
+ thread_id = 0;
+ PoolItem* item = new PoolItem;
+ item->server = this;
+ item->thread_index = i;
+
+ pool[i] = CreateThread(0, 4096, NetServerReaderProc, (LPVOID) item, 0, &thread_id);
+ }
+
+ thread_id = 0;
+ hreader = CreateThread(0, 4096, NetServerListenerProc, (LPVOID) this, 0, &thread_id);
+ }
+}
+
+NetServer::~NetServer()
+{
+ if (!server_shutdown) {
+ server_shutdown = true;
+ sock.close();
+ }
+
+ if (hreader) {
+ WaitForSingleObject(hreader, 1000);
+ CloseHandle(hreader);
+ }
+
+ if (pool && poolsize) {
+ for (int i = 0; i < poolsize; i++) {
+ WaitForSingleObject(pool[i], 1000);
+ CloseHandle(pool[i]);
+ delete conn[i];
+ conn[i] = 0;
+ }
+
+ delete [] pool;
+ delete [] conn;
+ delete [] clients;
+ }
+}
+
+// +--------------------------------------------------------------------+
+
+void
+NetServer::Shutdown()
+{
+ server_shutdown = true;
+}
+
+// +--------------------------------------------------------------------+
+
+DWORD WINAPI NetServerListenerProc(LPVOID link)
+{
+ NetServer* net_server = (NetServer*) link;
+
+ if (net_server)
+ return net_server->Listener();
+
+ return (DWORD) E_POINTER;
+}
+
+DWORD
+NetServer::Listener()
+{
+ while (!server_shutdown) {
+ NetSock* s = sock.accept(&client_addr);
+
+ while (s) {
+ sync.acquire();
+
+ for (int i = 0; i < poolsize; i++) {
+ if (conn[i] == 0) {
+ conn[i] = s;
+ clients[i] = client_addr;
+ s = 0;
+ break;
+ }
+ }
+
+ sync.release();
+
+ // wait for a thread to become not busy
+ if (s)
+ Sleep(10);
+ }
+ }
+
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+DWORD WINAPI NetServerReaderProc(LPVOID link)
+{
+ if (!link) return (DWORD) E_POINTER;
+
+ PoolItem* item = (PoolItem*) link;
+ NetServer* net_server = item->server;
+ int index = item->thread_index;
+
+ delete item;
+
+ if (net_server)
+ return net_server->Reader(index);
+
+ return (DWORD) E_POINTER;
+}
+
+DWORD
+NetServer::Reader(int index)
+{
+ // init random seed for this thread:
+ srand(timeGetTime());
+
+ while (!server_shutdown) {
+ sync.acquire();
+ NetSock* s = conn[index];
+ sync.release();
+
+ if (s) {
+ const int MAX_REQUEST = 4096;
+ Text request;
+
+ /***
+ *** NOT SURE WHY, BUT THIS DOESN'T WORK FOR SHIT
+ ***
+ *** Setting the socket timeout to 2 seconds caused it
+ *** to wait for two seconds, read nothing, and give up
+ *** with a WSAETIMEDOUT error. Meanwhile, the client
+ *** immediately registered a failure (during the 2 sec
+ *** delay) and aborted the request.
+ ***
+
+ s->set_timeout(2000);
+ Text msg = s->recv();
+
+ while (msg.length() > 0 && request.length() < MAX_REQUEST) {
+ request += msg;
+ msg = s->recv();
+ }
+
+ ***/
+
+ request = s->recv();
+
+ if (request.length() > 0 && !s->is_closed()) {
+ Text response = ProcessRequest(request, clients[index]);
+ err = s->send(response);
+ if (err < 0) {
+ err = NetLayer::GetLastError();
+ }
+ }
+
+ sync.acquire();
+ delete conn[index];
+ conn[index] = 0;
+ sync.release();
+ }
+ else {
+ Sleep(5);
+ }
+ }
+
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+Text
+NetServer::ProcessRequest(Text msg, const NetAddr& addr)
+{
+ if (msg.indexOf("GET ") == 0)
+ return DefaultResponse();
+
+ return ErrorResponse();
+}
+
+Text
+NetServer::DefaultResponse()
+{
+ Text response =
+ "HTTP/1.0 200 OK\nServer: Generic NetServer 1.0\nMIME-Version: 1.0\nContent-type: text/html\n\n";
+
+ response += "<html><head><title>Generic NetServer 1.0</title></head>\n\n";
+ response += "<body bgcolor=\"black\" text=\"white\">\n";
+ response += "<h1>Generic NetServer 1.0</h1>\n";
+ response += "<p>Didn't think I could do it, did ya?\n";
+ response += "</body></html>\n\n";
+
+ return response;
+}
+
+Text
+NetServer::ErrorResponse()
+{
+ Text response =
+ "HTTP/1.0 501 Not Implemented\nServer: Generic NetServer 1.0\nMIME-Version: 1.0\nContent-type: text/html\n\n";
+
+ response += "<html><head><title>Generic NetServer 1.0</title></head>\n\n";
+ response += "<body bgcolor=\"black\" text=\"white\">\n";
+ response += "<h1>Generic NetServer 1.0</h1>\n";
+ response += "<p>Sorry charlie... I'm not a magician.\n";
+ response += "</body></html>\n\n";
+
+ return response;
+}
diff --git a/NetEx/NetServer.h b/NetEx/NetServer.h
index d8996d7..f0b261f 100644
--- a/NetEx/NetServer.h
+++ b/NetEx/NetServer.h
@@ -1,65 +1,89 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetServer.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network Server Pump for HTTP Server
-*/
-
-
-#ifndef NetServer_h
-#define NetServer_h
-
-#include <windows.h>
-#include "NetAddr.h"
-#include "NetGram.h"
-#include "NetSock.h"
-#include "List.h"
-
-// +-------------------------------------------------------------------+
-
-class NetServer
-{
-public:
- static const char* TYPENAME() { return "NetServer"; }
-
- NetServer(WORD port, int poolsize=1);
- virtual ~NetServer();
-
- int operator == (const NetServer& l) const { return addr == l.addr; }
-
- virtual void Shutdown();
- virtual DWORD Listener();
- virtual DWORD Reader(int index);
-
- virtual Text ProcessRequest(Text request, const NetAddr& addr);
- virtual Text DefaultResponse();
- virtual Text ErrorResponse();
-
- const NetAddr& GetAddress() const { return addr; }
- int GetLastError() const { return err; }
-
-protected:
- NetAddr addr;
- NetSock sock;
- NetAddr client_addr;
-
- int poolsize;
- HANDLE hreader;
- HANDLE* pool;
- NetSock** conn;
- NetAddr* clients;
- int err;
- bool server_shutdown;
-
- ThreadSync sync;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetServer.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network Server Pump for HTTP Server
+*/
+
+
+#ifndef NetServer_h
+#define NetServer_h
+
+#include <windows.h>
+#include "NetAddr.h"
+#include "NetGram.h"
+#include "NetSock.h"
+#include "List.h"
+
+// +-------------------------------------------------------------------+
+
+class NetServer
+{
+public:
+ static const char* TYPENAME() { return "NetServer"; }
+
+ NetServer(WORD port, int poolsize=1);
+ virtual ~NetServer();
+
+ int operator == (const NetServer& l) const { return addr == l.addr; }
+
+ virtual void Shutdown();
+ virtual DWORD Listener();
+ virtual DWORD Reader(int index);
+
+ virtual Text ProcessRequest(Text request, const NetAddr& addr);
+ virtual Text DefaultResponse();
+ virtual Text ErrorResponse();
+
+ const NetAddr& GetAddress() const { return addr; }
+ int GetLastError() const { return err; }
+
+protected:
+ NetAddr addr;
+ NetSock sock;
+ NetAddr client_addr;
+
+ int poolsize;
+ HANDLE hreader;
+ HANDLE* pool;
+ NetSock** conn;
+ NetAddr* clients;
+ int err;
+ bool server_shutdown;
+
+ ThreadSync sync;
+};
+
+
#endif NetServer_h \ No newline at end of file
diff --git a/NetEx/NetSock.cpp b/NetEx/NetSock.cpp
index 47c50d8..0fb1081 100644
--- a/NetEx/NetSock.cpp
+++ b/NetEx/NetSock.cpp
@@ -1,342 +1,366 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetSock.cpp
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network (IP) Socket Wrapper Implementation
-*/
-
-
-// WINSOCK2.H MUST COME FIRST!!
-#include <winsock2.h>
-
-#include "MemDebug.h"
-#include "NetSock.h"
-#include "NetLayer.h"
-
-// +-------------------------------------------------------------------+
-
-/**
- * Server-side socket constructor
- */
-NetSock::NetSock(bool str)
- : stream(str), closed(false), stat(0), current_timeout(9999)
-{
- if (stream)
- s = ::socket(AF_INET, SOCK_STREAM, 0);
- else
- s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-}
-
-/**
- * Server-side socket constructor
- *
- * PRIVATE: used only by the accept call to build a socket for
- * a client connection to this server
- */
-NetSock::NetSock(SOCKET sock, bool str)
- : s(sock), stream(str), closed(false), stat(0), current_timeout(9999)
-{ }
-
-/**
- * Client-side socket constructor
- *
- * Will connect to server at "addr"
- */
-NetSock::NetSock(const NetAddr& addr, bool str)
- : stream(str), closed(false), stat(0), current_timeout(9999)
-{
- if (stream)
- s = ::socket(AF_INET, SOCK_STREAM, 0);
- else
- s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
-
- connect(addr);
-}
-
-NetSock::~NetSock()
-{
- close();
-}
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::bind(const NetAddr& addr)
-{
- if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
- return stat = ::bind(s, addr.GetSockAddr(), addr.GetSockAddrLength());
-}
-
-int
-NetSock::connect(const NetAddr& addr)
-{
- if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
- return stat = ::connect(s, addr.GetSockAddr(), addr.GetSockAddrLength());
-}
-
-int
-NetSock::listen(int max_connections)
-{
- if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
- return stat = ::listen(s, max_connections);
-}
-
-NetSock*
-NetSock::accept(NetAddr* addr)
-{
- if (closed || s == INVALID_SOCKET) return 0;
-
- SOCKET conn = INVALID_SOCKET;
-
- if (addr) {
- sockaddr a;
- int asize = sizeof(a);
-
- conn = ::accept(s, &a, &asize);
-
- if (conn != INVALID_SOCKET && asize > 0) {
- addr->SetSockAddr(&a, asize);
- }
- }
- else {
- conn = ::accept(s, 0, 0);
- }
-
- if (conn == INVALID_SOCKET)
- return 0;
-
- return new(__FILE__,__LINE__) NetSock(conn, stream);
-}
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::available()
-{
- if (closed || s == INVALID_SOCKET) return 0;
-
- DWORD nbytes = 0;
- if (::ioctlsocket(s, FIONREAD, &nbytes) == 0)
- return (int) nbytes;
-
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::send(Text msg)
-{
- if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
- return stat = ::send(s, msg.data(), msg.length(), 0);
-}
-
-Text
-NetSock::recv()
-{
- if (closed || s == INVALID_SOCKET) return "";
-
- static char rbuf[8192];
- int rlen = -1;
-
- if (stream) {
- rlen = ::recv(s, rbuf, sizeof(rbuf), 0);
- }
- else {
- rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, 0, 0);
- }
-
- if (rlen < 0) {
- stat = NetLayer::GetLastError();
-
- switch (stat) {
- case WSAENETDOWN:
- case WSAENETRESET:
- case WSAEINTR:
- case WSAESHUTDOWN:
- case WSAECONNABORTED:
- case WSAECONNRESET:
- case WSAETIMEDOUT:
- close();
- break;
-
- case WSAEWOULDBLOCK:
- stat = WSAEWOULDBLOCK;
- break;
- }
-
- return Text();
- }
-
- else if (rlen == 0) {
- return Text();
- }
-
- return Text(rbuf, rlen);
-}
-
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::sendto(Text msg, const NetAddr& dest)
-{
- if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
- return stat = ::sendto(s, msg.data(), msg.length(),
- 0, dest.GetSockAddr(), dest.GetSockAddrLength());
-}
-
-Text
-NetSock::recvfrom(NetAddr* a)
-{
- if (closed || s == INVALID_SOCKET) return "";
-
- static char rbuf[4096];
- int rlen = 0;
-
- if (a) {
- int addrlen = a->GetSockAddrLength();
- rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, a->GetSockAddr(), &addrlen);
- a->InitFromSockAddr();
- }
- else {
- rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, 0, 0);
- }
-
- if (rlen < 0) {
- stat = NetLayer::GetLastError();
- return Text();
- }
-
- else if (rlen == 0) {
- return Text();
- }
-
- return Text(rbuf, rlen);
-}
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::select(SELECT_TYPE t, long seconds, long microseconds)
-{
- if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
-
- FD_SET fd;
- ZeroMemory(&fd, sizeof(fd));
-
- FD_SET(s, &fd);
- TIMEVAL timeval = {seconds, microseconds};
- TIMEVAL* timeout = &timeval;
-
- if (t == SELECT_READ)
- return stat = ::select(1, &fd, 0, 0, timeout);
-
- else if (t == SELECT_WRITE)
- return stat = ::select(1, 0, &fd, 0, timeout);
-
- else if (t == (SELECT_READ|SELECT_WRITE))
- return stat = ::select(1, &fd, &fd, 0, timeout);
-
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::set_timeout(int msecs)
-{
- if (closed || s == INVALID_SOCKET) return 0;
- if (msecs == current_timeout) return 1;
-
- // zero timeout means non-blocking
- if (msecs == 0) {
- u_long nonblocking = 1;
- if (::ioctlsocket(s, FIONBIO, &nonblocking) == SOCKET_ERROR) {
- stat = NetLayer::GetLastError();
- return stat;
- }
- }
-
- // non-zero timeout means blocking
- else {
- if (current_timeout == 0) {
- u_long nonblocking = 0; // disable non-blocking
- if (::ioctlsocket(s, FIONBIO, &nonblocking) == SOCKET_ERROR) {
- stat = NetLayer::GetLastError();
- return stat;
- }
- }
-
- // max timeout means infinite wait
- if (msecs >= NET_MAX_TIMEOUT) {
- int maxto = 0;
- ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*) &maxto, sizeof(maxto));
- ::setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*) &maxto, sizeof(maxto));
- }
-
- // otherwise, set the timeout
- else {
- ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*) &msecs, sizeof(msecs));
- ::setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*) &msecs, sizeof(msecs));
- }
- }
-
- current_timeout = msecs;
- return 1;
-}
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::shutdown_input()
-{
- if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
- ::shutdown(s, SD_RECEIVE);
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::shutdown_output()
-{
- if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
- ::shutdown(s, SD_SEND);
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-int
-NetSock::close()
-{
- if (s != INVALID_SOCKET && !closed) {
- ::shutdown(s, SD_BOTH);
- ::closesocket(s);
-
- closed = true;
- }
-
- return 0;
-}
-
-// +--------------------------------------------------------------------+
-
-DWORD
-NetSock::max_packet_size() const
-{
- DWORD size = 0;
- int len = sizeof(size);
-
- ::getsockopt(s, SOL_SOCKET, 0x2003, (char*) &size, &len);
-
- return size;
-} \ No newline at end of file
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetSock.cpp
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network (IP) Socket Wrapper Implementation
+*/
+
+
+// WINSOCK2.H MUST COME FIRST!!
+#include <winsock2.h>
+
+#include "MemDebug.h"
+#include "NetSock.h"
+#include "NetLayer.h"
+
+// +-------------------------------------------------------------------+
+
+/**
+ * Server-side socket constructor
+ */
+NetSock::NetSock(bool str)
+ : stream(str), closed(false), stat(0), current_timeout(9999)
+{
+ if (stream)
+ s = ::socket(AF_INET, SOCK_STREAM, 0);
+ else
+ s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+}
+
+/**
+ * Server-side socket constructor
+ *
+ * PRIVATE: used only by the accept call to build a socket for
+ * a client connection to this server
+ */
+NetSock::NetSock(SOCKET sock, bool str)
+ : s(sock), stream(str), closed(false), stat(0), current_timeout(9999)
+{ }
+
+/**
+ * Client-side socket constructor
+ *
+ * Will connect to server at "addr"
+ */
+NetSock::NetSock(const NetAddr& addr, bool str)
+ : stream(str), closed(false), stat(0), current_timeout(9999)
+{
+ if (stream)
+ s = ::socket(AF_INET, SOCK_STREAM, 0);
+ else
+ s = ::socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+
+ connect(addr);
+}
+
+NetSock::~NetSock()
+{
+ close();
+}
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::bind(const NetAddr& addr)
+{
+ if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
+ return stat = ::bind(s, addr.GetSockAddr(), addr.GetSockAddrLength());
+}
+
+int
+NetSock::connect(const NetAddr& addr)
+{
+ if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
+ return stat = ::connect(s, addr.GetSockAddr(), addr.GetSockAddrLength());
+}
+
+int
+NetSock::listen(int max_connections)
+{
+ if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
+ return stat = ::listen(s, max_connections);
+}
+
+NetSock*
+NetSock::accept(NetAddr* addr)
+{
+ if (closed || s == INVALID_SOCKET) return 0;
+
+ SOCKET conn = INVALID_SOCKET;
+
+ if (addr) {
+ sockaddr a;
+ int asize = sizeof(a);
+
+ conn = ::accept(s, &a, &asize);
+
+ if (conn != INVALID_SOCKET && asize > 0) {
+ addr->SetSockAddr(&a, asize);
+ }
+ }
+ else {
+ conn = ::accept(s, 0, 0);
+ }
+
+ if (conn == INVALID_SOCKET)
+ return 0;
+
+ return new(__FILE__,__LINE__) NetSock(conn, stream);
+}
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::available()
+{
+ if (closed || s == INVALID_SOCKET) return 0;
+
+ DWORD nbytes = 0;
+ if (::ioctlsocket(s, FIONREAD, &nbytes) == 0)
+ return (int) nbytes;
+
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::send(Text msg)
+{
+ if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
+ return stat = ::send(s, msg.data(), msg.length(), 0);
+}
+
+Text
+NetSock::recv()
+{
+ if (closed || s == INVALID_SOCKET) return "";
+
+ static char rbuf[8192];
+ int rlen = -1;
+
+ if (stream) {
+ rlen = ::recv(s, rbuf, sizeof(rbuf), 0);
+ }
+ else {
+ rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, 0, 0);
+ }
+
+ if (rlen < 0) {
+ stat = NetLayer::GetLastError();
+
+ switch (stat) {
+ case WSAENETDOWN:
+ case WSAENETRESET:
+ case WSAEINTR:
+ case WSAESHUTDOWN:
+ case WSAECONNABORTED:
+ case WSAECONNRESET:
+ case WSAETIMEDOUT:
+ close();
+ break;
+
+ case WSAEWOULDBLOCK:
+ stat = WSAEWOULDBLOCK;
+ break;
+ }
+
+ return Text();
+ }
+
+ else if (rlen == 0) {
+ return Text();
+ }
+
+ return Text(rbuf, rlen);
+}
+
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::sendto(Text msg, const NetAddr& dest)
+{
+ if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
+ return stat = ::sendto(s, msg.data(), msg.length(),
+ 0, dest.GetSockAddr(), dest.GetSockAddrLength());
+}
+
+Text
+NetSock::recvfrom(NetAddr* a)
+{
+ if (closed || s == INVALID_SOCKET) return "";
+
+ static char rbuf[4096];
+ int rlen = 0;
+
+ if (a) {
+ int addrlen = a->GetSockAddrLength();
+ rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, a->GetSockAddr(), &addrlen);
+ a->InitFromSockAddr();
+ }
+ else {
+ rlen = ::recvfrom(s, rbuf, sizeof(rbuf), 0, 0, 0);
+ }
+
+ if (rlen < 0) {
+ stat = NetLayer::GetLastError();
+ return Text();
+ }
+
+ else if (rlen == 0) {
+ return Text();
+ }
+
+ return Text(rbuf, rlen);
+}
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::select(SELECT_TYPE t, long seconds, long microseconds)
+{
+ if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
+
+ FD_SET fd;
+ ZeroMemory(&fd, sizeof(fd));
+
+ FD_SET(s, &fd);
+ TIMEVAL timeval = {seconds, microseconds};
+ TIMEVAL* timeout = &timeval;
+
+ if (t == SELECT_READ)
+ return stat = ::select(1, &fd, 0, 0, timeout);
+
+ else if (t == SELECT_WRITE)
+ return stat = ::select(1, 0, &fd, 0, timeout);
+
+ else if (t == (SELECT_READ|SELECT_WRITE))
+ return stat = ::select(1, &fd, &fd, 0, timeout);
+
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::set_timeout(int msecs)
+{
+ if (closed || s == INVALID_SOCKET) return 0;
+ if (msecs == current_timeout) return 1;
+
+ // zero timeout means non-blocking
+ if (msecs == 0) {
+ u_long nonblocking = 1;
+ if (::ioctlsocket(s, FIONBIO, &nonblocking) == SOCKET_ERROR) {
+ stat = NetLayer::GetLastError();
+ return stat;
+ }
+ }
+
+ // non-zero timeout means blocking
+ else {
+ if (current_timeout == 0) {
+ u_long nonblocking = 0; // disable non-blocking
+ if (::ioctlsocket(s, FIONBIO, &nonblocking) == SOCKET_ERROR) {
+ stat = NetLayer::GetLastError();
+ return stat;
+ }
+ }
+
+ // max timeout means infinite wait
+ if (msecs >= NET_MAX_TIMEOUT) {
+ int maxto = 0;
+ ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*) &maxto, sizeof(maxto));
+ ::setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*) &maxto, sizeof(maxto));
+ }
+
+ // otherwise, set the timeout
+ else {
+ ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (char*) &msecs, sizeof(msecs));
+ ::setsockopt(s, SOL_SOCKET, SO_SNDTIMEO, (char*) &msecs, sizeof(msecs));
+ }
+ }
+
+ current_timeout = msecs;
+ return 1;
+}
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::shutdown_input()
+{
+ if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
+ ::shutdown(s, SD_RECEIVE);
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::shutdown_output()
+{
+ if (closed || s == INVALID_SOCKET) return INVALID_SOCKET;
+ ::shutdown(s, SD_SEND);
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+int
+NetSock::close()
+{
+ if (s != INVALID_SOCKET && !closed) {
+ ::shutdown(s, SD_BOTH);
+ ::closesocket(s);
+
+ closed = true;
+ }
+
+ return 0;
+}
+
+// +--------------------------------------------------------------------+
+
+DWORD
+NetSock::max_packet_size() const
+{
+ DWORD size = 0;
+ int len = sizeof(size);
+
+ ::getsockopt(s, SOL_SOCKET, 0x2003, (char*) &size, &len);
+
+ return size;
+}
diff --git a/NetEx/NetSock.h b/NetEx/NetSock.h
index 826d80c..00444f0 100644
--- a/NetEx/NetSock.h
+++ b/NetEx/NetSock.h
@@ -1,73 +1,97 @@
-/* Project nGenEx
- Destroyer Studios LLC
- Copyright © 1997-2004. All Rights Reserved.
-
- SUBSYSTEM: NetEx.lib
- FILE: NetSock.h
- AUTHOR: John DiCamillo
-
-
- OVERVIEW
- ========
- Network (IP) Socket
-*/
-
-#ifndef NetSock_h
-#define NetSock_h
-
-#include <windows.h>
-#include "NetAddr.h"
-#include "Text.h"
-
-// +-------------------------------------------------------------------+
-
-#define NET_MAX_TIMEOUT 1e9
-
-class NetSock
-{
-public:
- static const char* TYPENAME() { return "NetSock"; }
-
- enum SELECT_TYPE {
- SELECT_READ = 1,
- SELECT_WRITE = 2
- };
-
- NetSock(bool stream=false);
- NetSock(const NetAddr& addr, bool stream=false);
- ~NetSock();
-
- int bind(const NetAddr& addr);
- int connect(const NetAddr& addr);
- int listen(int max_connections=5);
- NetSock* accept(NetAddr* addr=0);
- int available();
- int send(Text msg);
- Text recv();
- int sendto(Text msg, const NetAddr& dest);
- Text recvfrom(NetAddr* a=0);
- int select(SELECT_TYPE t=SELECT_READ,
- long seconds=0, long microseconds=0);
-
- int shutdown_input();
- int shutdown_output();
- int set_timeout(int msecs);
- int close();
-
- DWORD max_packet_size() const;
- bool is_stream() const { return stream; }
- bool is_closed() const { return closed; }
- int status() const { return stat; }
-
-private:
- NetSock(SOCKET s, bool stream);
-
- SOCKET s;
- bool stream;
- bool closed;
- int stat;
- int current_timeout;
-};
-
-
+/* Starshatter OpenSource Distribution
+ Copyright (c) 1997-2004, Destroyer Studios LLC.
+ 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.
+ * Neither the name "Destroyer Studios" 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 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.
+
+ SUBSYSTEM: NetEx.lib
+ FILE: NetSock.h
+ AUTHOR: John DiCamillo
+
+
+ OVERVIEW
+ ========
+ Network (IP) Socket
+*/
+
+#ifndef NetSock_h
+#define NetSock_h
+
+#include <windows.h>
+#include "NetAddr.h"
+#include "Text.h"
+
+// +-------------------------------------------------------------------+
+
+#define NET_MAX_TIMEOUT 1e9
+
+class NetSock
+{
+public:
+ static const char* TYPENAME() { return "NetSock"; }
+
+ enum SELECT_TYPE {
+ SELECT_READ = 1,
+ SELECT_WRITE = 2
+ };
+
+ NetSock(bool stream=false);
+ NetSock(const NetAddr& addr, bool stream=false);
+ ~NetSock();
+
+ int bind(const NetAddr& addr);
+ int connect(const NetAddr& addr);
+ int listen(int max_connections=5);
+ NetSock* accept(NetAddr* addr=0);
+ int available();
+ int send(Text msg);
+ Text recv();
+ int sendto(Text msg, const NetAddr& dest);
+ Text recvfrom(NetAddr* a=0);
+ int select(SELECT_TYPE t=SELECT_READ,
+ long seconds=0, long microseconds=0);
+
+ int shutdown_input();
+ int shutdown_output();
+ int set_timeout(int msecs);
+ int close();
+
+ DWORD max_packet_size() const;
+ bool is_stream() const { return stream; }
+ bool is_closed() const { return closed; }
+ int status() const { return stat; }
+
+private:
+ NetSock(SOCKET s, bool stream);
+
+ SOCKET s;
+ bool stream;
+ bool closed;
+ int stat;
+ int current_timeout;
+};
+
+
#endif NetSock_h \ No newline at end of file