using Microsoft.Extensions.Hosting;
using Microsoft.SqlServer.Server;
using ProxyApi.db_cotroller;
using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
public class TcpServerService : BackgroundService
{
private TcpListener _tcpListener;
private readonly IWebHostEnvironment _env;
public TcpServerService(IWebHostEnvironment env)
{
_env = env;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
string localIP = GetLocalIPAddress();
_tcpListener = new TcpListener(IPAddress.Parse(localIP), 9091); / Adjust the IP and port
_tcpListener.Start();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"HTTP LISTENER started listening on {localIP}:9091.");
Console.ResetColor();
while (!stoppingToken.IsCancellationRequested)
{
TcpClient client = await _tcpListener.AcceptTcpClientAsync();
_ = HandleClient(client);
}
}
public static string GetLocalIPAddress()
{
var networkInterfaces = NetworkInterface.GetAllNetworkInterfaces();
foreach (var networkInterface in networkInterfaces)
{
if (networkInterface.NetworkInterfaceType != NetworkInterfaceType.Wireless80211 &&
networkInterface.NetworkInterfaceType != NetworkInterfaceType.Loopback)
{
var ipProperties = networkInterface.GetIPProperties();
foreach (var ip in ipProperties.UnicastAddresses)
{
if (ip.Address.AddressFamily == AddressFamily.InterNetwork)
{
return ip.Address.ToString();
}
}
}
}
throw new Exception("No Ethernet network adapters with an IPv4 address in the system!");
}
private async Task HandleClient(TcpClient client)
{
string clientIP = ((IPEndPoint)client.Client.RemoteEndPoint).Address.ToString();
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"HTTP LISTENER: {clientIP} sending data.");
Console.ResetColor();
try
{
using (NetworkStream stream = client.GetStream())
{
MemoryStream memoryStream = new MemoryStream();
byte[] buffer = new byte[client.ReceiveBufferSize];
int bytesRead;
while ((bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
memoryStream.Write(buffer, 0, bytesRead);
}
byte[] requestData = memoryStream.ToArray();
string boundaryString = GetBoundary(requestData);
if (boundaryString == null)
{
Console.WriteLine("Boundary string not found in the request.");
return;
}
List<MultipartFormData> formDataList = ExtractFormData(requestData, boundaryString);
foreach (var formData in formDataList)
{
if (formData.IsImage)
{
string webRootPath = _env.WebRootPath;
string folderPath = Path.Combine(webRootPath, "images", "lpr_images");
Directory.CreateDirectory(folderPath);
string filePath = Path.Combine(folderPath, formData.Filename);
File.WriteAllBytes(filePath, formData.Content);
Console.WriteLine($"IMAGE: Saved {formData.Filename}");
}
else if (formData.ContentType.Equals("text/xml", StringComparison.OrdinalIgnoreCase))
{
string xmlContent = Encoding.UTF8.GetString(formData.Content);
XNamespace ns = "http://www.hikvision.com/ver20/XMLSchema";
XDocument xmlDoc = XDocument.Parse(xmlContent);
string eventType = xmlDoc.Root.Element(ns + "eventType")?.Value;
if (!string.Equals(eventType, "ANPR", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine("Skipping non-ANPR event.");
continue;
}
string ipAddress = xmlDoc.Root.Element(ns + "ipAddress")?.Value;
string dateTime = xmlDoc.Root.Element(ns + "dateTime")?.Value;
XElement anprElement = xmlDoc.Root.Element(ns + "ANPR");
string licensePlate = anprElement?.Element(ns + "licensePlate")?.Value;
string vehicleListName = anprElement?.Element(ns + "vehicleListName")?.Value;
string secondPIdValue = "";
if (anprElement != null)
{
XElement pictureInfoListElement = anprElement.Element(ns + "pictureInfoList");
if (pictureInfoListElement != null)
{
/ Select the second pId element by index (index 1) within the ANPR element
XElement secondPictureInfoElement = pictureInfoListElement.Elements(ns + "pictureInfo").ElementAtOrDefault(1);
if (secondPictureInfoElement != null)
{
XElement secondPIdElement = secondPictureInfoElement.Element(ns + "pId");
if (secondPIdElement != null)
{
secondPIdValue = secondPIdElement.Value + ".jpg";
}
}
}
/ Now you have the secondPIdValue
}
if (ipAddress == null || dateTime == null || licensePlate == null || vehicleListName == null || secondPIdValue == null)
{
Console.WriteLine("One or more required XML elements are missing.");
continue;
}
SaveLPRlogstoDB.SaveLprLogs(ipAddress, dateTime, licensePlate, vehicleListName, secondPIdValue);
}
}
byte[] responseBytes = Encoding.ASCII.GetBytes("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n");
await stream.WriteAsync(responseBytes, 0, responseBytes.Length);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("HTTP LISTENER: Data processed and response sent.");
Console.ResetColor();
}
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred while handling the client: {ex}");
}
}
static string GetBoundary(byte[] requestData)
{
string header = Encoding.UTF8.GetString(requestData);
Match match = Regex.Match(header, "boundary=(?<boundary>.+?)\r\n");
if (match.Success)
{
return "--" + match.Groups["boundary"].Value.Trim();
}
return null;
}
static List<MultipartFormData> ExtractFormData(byte[] requestData, string boundaryString)
{
List<MultipartFormData> formDataList = new List<MultipartFormData>();
byte[] boundaryBytes = Encoding.ASCII.GetBytes(boundaryString);
int currentIndex = 0;
while (currentIndex < requestData.Length)
{
int headerStartIndex = FindIndex(requestData, Encoding.ASCII.GetBytes("Content-Disposition: form-data;"), currentIndex);
if (headerStartIndex == -1) break;
int headerEndIndex = FindIndex(requestData, Encoding.ASCII.GetBytes("\r\n\r\n"), headerStartIndex);
if (headerEndIndex == -1) break;
string header = Encoding.ASCII.GetString(requestData, headerStartIndex, headerEndIndex - headerStartIndex);
var filenameMatch = Regex.Match(header, "filename=\"(?<filename>[^\"]+)\"");
var contentTypeMatch = Regex.Match(header, "Content-Type: (?<contentType>[^\r\n]+)");
string filename = filenameMatch.Groups["filename"].Value;
string contentType = contentTypeMatch.Success ? contentTypeMatch.Groups["contentType"].Value : "application/octet-stream"; / Default content type if none specified
int contentStartIndex = headerEndIndex + 4; / The start index of the content data
int boundaryIndex = FindIndex(requestData, boundaryBytes, contentStartIndex);
if (boundaryIndex == -1) boundaryIndex = requestData.Length;
int contentLength = boundaryIndex - contentStartIndex;
byte[] contentData = new byte[contentLength];
Array.Copy(requestData, contentStartIndex, contentData, 0, contentLength);
formDataList.Add(new MultipartFormData
{
ContentType = contentType,
Filename = filename,
Content = contentData
/ IsImage is a computed property based on ContentType; no need to set it explicitly
});
currentIndex = boundaryIndex + boundaryBytes.Length; / Set currentIndex to after the boundary for the next loop iteration
}
return formDataList;
}
static int FindIndex(byte[] data, byte[] pattern, int startIndex = 0)
{
for (int i = startIndex; i < data.Length - pattern.Length + 1; i++)
{
bool isMatch = true;
for (int j = 0; j < pattern.Length; j++)
{
if (data[i + j] != pattern[j])
{
isMatch = false;
break;
}
}
if (isMatch) return i;
}
return -1;
}
class MultipartFormData
{
public string ContentType { get; set; }
public string Filename { get; set; }
public byte[] Content { get; set; }
public bool IsImage => ContentType.StartsWith("image/", StringComparison.OrdinalIgnoreCase);
}
public override Task StopAsync(CancellationToken cancellationToken)
{
_tcpListener?.Stop();
return base.StopAsync(cancellationToken);
}
}