// socksrv.cpp : Defines the entry point for the console application.
#include "stdafx.h"
#include <stdio.h>
#include <winsock2.h>
#include <list>
#include <algorithm>
#include <string.h>
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>

#define MAXCONN 5
#define BUFLEN 1023

using namespace std;

typedef list<SOCKET> ListCONN;
typedef list<SOCKET> ListConErr;

struct IpandPort
{
	char ip[20];
	USHORT port;
};
string getcont(string name, int *flag){
	ifstream t(name.c_str());
	stringstream buffer;
	if (!t){
		*flag = 0;
	}
	else{
		*flag = 1;
		buffer << t.rdbuf();
	}
	string contents(buffer.str());
	return contents;
}

void sendpic(SOCKET sock, string fname){
	FILE *p=NULL;
	char buffer[1000];
	int size = 1000;
	fopen_s(&p,fname.c_str(), "r");
	if (p == NULL){
		cout << "open file faild\n";
	}
	while (size==1000)
	{
		fread(buffer,sizeof(char),1000,p);
		send(sock, buffer, 1000, 0);
	}
	send(sock, buffer, size, 0);
	fclose(p);
}
char * ReadFile(char *pathpic, int &pic_len){
	//将文件读取出来
	FILE *fp = fopen(pathpic, "rb");     //打开文件
	if (!fp){
		cout<<"没有找到文件位置\n";
		return NULL;
	}
	fseek(fp, 0, SEEK_END);  //一直寻找到文件尾部
	pic_len = ftell(fp);  //得到文件的长度
	rewind(fp);  //rewind将文件指针指向开头
	char *pic_buf = new char[pic_len + 1];  //开辟一个空间在堆上
	memset(pic_buf, 0, pic_len + 1);  //清空文件指针
	//读取文件内容
	fread(pic_buf, sizeof(char), pic_len, fp);
	fclose(fp);
	return pic_buf;
}
void SplitString(const std::string& s, std::vector<std::string>& v, const std::string& c)
{
	std::string::size_type pos1, pos2;
	pos2 = s.find(c);
	pos1 = 0;
	while (std::string::npos != pos2)
	{
		v.push_back(s.substr(pos1, pos2 - pos1));

		pos1 = pos2 + c.size();
		pos2 = s.find(c, pos1);
	}
	if (pos1 != s.length())
		v.push_back(s.substr(pos1));
}
void main(int argc, char* argv[])
{
	WSADATA wsaData;
	int nRC,fflag=1;
	sockaddr_in srvAddr;
	sockaddr clientAddr;
	SOCKET srvSock, newSock;
	int nAddrLen = sizeof(sockaddr);
	char sendBuf[BUFLEN], recvBuf[BUFLEN];
	string sendbuf;
	ListCONN::iterator itor;
	ListConErr::iterator itor1;

	ListConErr conErrList;	//保存所有失效的会话SOCKET

	//初始化 winsock
	nRC = WSAStartup(0x0101, &wsaData);
	if (nRC)
	{
		printf("Server initialize winsock error!\n");
		return;
	}
	if (wsaData.wVersion != 0x0101)
	{
		printf("Server's winsock version error!\n");
		WSACleanup();
		return;
	}
	printf("Server's winsock initialized !\n");

	//创建 TCP socket
	srvSock = socket(AF_INET, SOCK_STREAM, 0);
	if (srvSock == INVALID_SOCKET)
	{
		printf("Server create socket error!\n");
		WSACleanup();
		return;
	}
	printf("Server TCP socket create OK!\n");

	//绑定 socket to Server's IP and port 5050
	srvAddr.sin_family = AF_INET;
	srvAddr.sin_port = htons(5050);
	srvAddr.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
	nRC = bind(srvSock, (LPSOCKADDR)&srvAddr, sizeof(srvAddr));
	if (nRC == SOCKET_ERROR)
	{
		printf("Server socket bind error!\n");
		closesocket(srvSock);
		WSACleanup();
		return;
	}
	printf("Server socket bind OK!\n");

	//开始监听过程，等待客户的连接
	nRC = listen(srvSock, MAXCONN);
	if (nRC == SOCKET_ERROR)
	{
		printf("Server socket listen error!\n");
		closesocket(srvSock);
		WSACleanup();
		return;
	}
	printf("Server socket listen OK!\n");


	while (1)
	{
		newSock = accept(srvSock, &clientAddr, &nAddrLen);
		printf("Server socket accept OK!\n");
		IpandPort info;
		// 将sockaddr强制转换为 sockaddr_in
		sockaddr_in sin;
		memcpy(&sin, &clientAddr, sizeof(sin));

		// 取得ip和端口号
		sprintf(info.ip, inet_ntoa(sin.sin_addr));
		cout<<"\t\t\tclient ip and port " << info.ip<<":" << info.port << endl;
		if (newSock == INVALID_SOCKET)
		{
			printf("Server accept connection request error!\n");
			closesocket(srvSock);
			WSACleanup();
			return;
		}
		//printf("Server socket accept OK!\n");
		nRC = recv(newSock, recvBuf, BUFLEN, 0);
		//printf("recv ok\n");
		if (nRC == SOCKET_ERROR)
		{
			printf("recv error\n");
			//接受数据错误，
		}
		else if (nRC == 0){
			cout << "null request!\n";
		}
		else {
			printf("recv succeed\n");
			//接收数据成功，保存在发送缓冲区中，
			//以发送到所有客户去
			//cout << recvBuf<<endl;
			//cout << nRC << endl;
			recvBuf[nRC] = '\0';
			printf("request content: \n%s", recvBuf);
			//printf_s("revid\n");
			vector <string> sv, sv0, ftype;
			//printf_s("revid1\n");
			SplitString(recvBuf, sv, "\n");
			//printf_s("revid2\n");
			SplitString(sv[0], sv0, " ");
			//printf("recvid3\n");
			if (sv0[0] == "GET") {
				//printf("is GET\n");
				sv0[1] = sv0[1].substr(1);//请求的文件
				for (vector<string>::size_type i = 0; i != sv0.size(); ++i)
					cout << i << " " << sv0[i] << "\n";
				if (sv0[1] == ""){
					sv0[1] = "index.html";
				}
				SplitString(sv0[1], ftype, ".");
				if (ftype[1] == "html" || ftype[1] == "htm" || ftype[1] == "txt"){//文本类型
					string tmp = getcont(sv0[1], &fflag);
					if (fflag == 1){//文件存在
						sendbuf = "HTTP/1.1 200 OK\n\
Content-Type : text/html;\n\
\n";

						sendbuf += tmp;
					}
					else{//文件不存在

						sendbuf = "HTTP/1.1 404 Not Found\n\
Content-Type : text/html;\n\
\n";
						string name = "notfound.html";
						tmp = getcont(name, &fflag);
						sendbuf += tmp;
						//cout << sendbuf << endl;
					}
					//cout << sendbuf.length()<<" bytes sent!" << endl;
					nRC = send(newSock, sendbuf.c_str(), sendbuf.length(), 0);//发送报文
				}
				else if (ftype[1] == "png" || ftype[1] == "jpg" || ftype[1] == "ico" || ftype[1] == "gif"){//图片类型

					//string tmp = getcont(sv0[1], &fflag);
					sendbuf = "HTTP/1.1 200 OK\n\
Content-Type : image/webp;\n\
\n";
					nRC = send(newSock, sendbuf.c_str(), sendbuf.length(), 0);
					//sendbuf += tmp;
					//cout << sendbuf << endl;
					//nRC = send(newSock, sendbuf.c_str(), sendbuf.length(), 0);
		//			sendpic(newSock, sv0[1]);
					int piclen;
					char *picbuf,name[255];
					strcpy(name, sv0[1].c_str());
					picbuf = ReadFile(name, piclen);
					nRC = send(newSock, picbuf, piclen, 0);
				}
				else if (ftype[1] == "mp3"){//音频类型
					//string tmp = getcont(sv0[1], &fflag);
					sendbuf = "HTTP/1.1 200 OK\n\
Content-Type : audio/mp3;\n\
\n";
					nRC = send(newSock, sendbuf.c_str(), sendbuf.length(), 0);
					//sendbuf += tmp;
					//cout << sendbuf << endl;
					//nRC = send(newSock, sendbuf.c_str(), sendbuf.length(), 0);
					//			sendpic(newSock, sv0[1]);
					int piclen;
					char *picbuf, name[255];
					strcpy(name, sv0[1].c_str());
					picbuf = ReadFile(name, piclen);
					nRC = send(newSock, picbuf, piclen, 0);
					//printf("\t\t%d bytes sent.\n\n\n",nRC);
				}
				cout << "\t\t\tsend OK : " << nRC << " bytes sent\n\n\n";
				closesocket(newSock);
				//cout << nRC << endl;
				//printf("%s", sendbuf.c_str());
				//printf("send OK\n");
				if (nRC == SOCKET_ERROR)
				{
					//发送数据错误，

				}
				else//发送数据成功，清空发送缓冲区
					memset(sendBuf, '\0', BUFLEN);
			}

		}
	}
	closesocket(srvSock);
	WSACleanup();
}
