#include #include #include #include #include #include #include #include #include #include "list.h" #include "tcp.h" #include "buffer.h" #include "textFile.h" #define CLIENT_LIMIT_BUFFER (4096+256) #define STR_PATH_SIZE 4096 #define STR_ARENA_NET_NAME_SIZE 256 #define BUFFER_SEND_FILE_SIZE 4096 #define NET_STATUS_OK 0 #define NET_STATUS_ZOMBIE 1 #define BUFFER_SIZE 256 #define PROTO_SIZE 256 static sock_tcp_t *sock_server_tcp; static list_t *listClient; static textFile_t *configFile; typedef struct { int status; FILE *file; int fileSize; int fileOffset; sock_tcp_t *socket; buffer_t *recvBuffer; buffer_t *sendBuffer; } client_t; static client_t *newClient(sock_tcp_t * sock) { client_t *new; new = malloc(sizeof(client_t)); new->socket = sock; new->status = NET_STATUS_OK; new->file = NULL; new->recvBuffer = newBuffer(CLIENT_LIMIT_BUFFER); new->sendBuffer = newBuffer(CLIENT_LIMIT_BUFFER); return new; } static void destroyClient(client_t * client) { if (client->file != NULL) fclose(client->file); closeTcpSocket(client->socket); destroyBuffer(client->recvBuffer); destroyBuffer(client->sendBuffer); free(client); } int getFileSize(char *s) { struct stat buf; if (lstat(s, &buf) < 0) { return -1; } return buf.st_size; } static char *getFileFromArenaNetName(char *s) { int i; for (i = 0; i < configFile->text->count; i++) { char path[STR_PATH_SIZE]; char arena[STR_ARENA_NET_NAME_SIZE]; char *line; int len; line = configFile->text->list[i]; sscanf(line, "%s %s", path, arena); len = strlen(arena); if (strncmp(arena, s, len) == 0) { return strdup(path); } } return NULL; } static void proto_getarena(client_t * client, char *msg) { char msg_out[PROTO_SIZE]; char *path; path = getFileFromArenaNetName(msg); if (path != NULL) { client->file = fopen(path, "rb"); client->fileSize = getFileSize(path); client->fileOffset = 0; free(path); if (client->file == NULL || client->fileSize < 0) { client->file = NULL; client->fileSize = 0; sprintf(msg_out, "ERR server has a problem!\n"); } else { sprintf(msg_out, "OK %d\n", client->fileSize); } } else { sprintf(msg_out, "ERR arena not found\n"); } addBuffer(client->sendBuffer, msg_out, strlen(msg_out)); } static void doProto(client_t * client, char *msg) { printf("hmm msg = %s\n", msg); if (strncmp(msg, "GETARENA", 8) == 0 && client->file == NULL) { proto_getarena(client, msg + 9); } } static int initDownServer(char *ip, int port) { sock_server_tcp = bindTcpSocket(ip, port, PROTO_TCPv4); listClient = newList(); configFile = loadTextFile("arena.conf"); return 0; } static void eventNewClient(sock_tcp_t * server_sock) { sock_tcp_t *sock; client_t *client; sock = getTcpNewClient(server_sock); setTcpSockNonBlock(sock); client = newClient(sock); addList(listClient, client); } static void eventRecvClient(client_t * client) { char buffer[BUFFER_SIZE]; char line[PROTO_SIZE]; int ret; memset(buffer, 0, BUFFER_SIZE); ret = readTcpSocket(client->socket, buffer, BUFFER_SIZE - 1); //printf("readTcpSocket = %d\n", ret); if (ret <= 0) { client->status = NET_STATUS_ZOMBIE; return; } if (addBuffer(client->recvBuffer, buffer, ret) < 0) { client->status = NET_STATUS_ZOMBIE; return; } while (getBufferLine(client->recvBuffer, line, PROTO_SIZE) >= 0) { doProto(client, line); } } static void eventSendClient(client_t * client) { void *data; int len; int res; len = getBufferSize(client->sendBuffer); if (len == 0) { return; } data = getBufferData(client->sendBuffer); res = writeTcpSocket(client->socket, data, len); //printf("send = %d\n", res); //printf("writeTcpSocket = %d\n", res); if (res < 0) { client->status = NET_STATUS_ZOMBIE; return; } cutBuffer(client->sendBuffer, res); } static void eventClient(client_t * client) { if (client->file != NULL && getBufferSize(client->sendBuffer) == 0) { char buffer[BUFFER_SEND_FILE_SIZE]; int count; int ret; count = client->fileSize - client->fileOffset; if (count > BUFFER_SEND_FILE_SIZE) { count = BUFFER_SEND_FILE_SIZE; } ret = fread(buffer, count, 1, client->file); //printf("read = %d\n", count); if (ret == 1) { if (addBuffer(client->sendBuffer, buffer, count) < 0) { client->status = NET_STATUS_ZOMBIE; return; } client->fileOffset += count; } else { client->status = NET_STATUS_ZOMBIE; } } } void startDownServer() { struct timeval tv; fd_set readfds; fd_set writefds; int max_fd; int ret; int i; tv.tv_sec = 1; tv.tv_usec = 0; FD_ZERO(&readfds); FD_ZERO(&writefds); max_fd = sock_server_tcp->sock; FD_SET(sock_server_tcp->sock, &readfds); for (i = 0; i < listClient->count; i++) { client_t *client; int sock; client = (client_t *) listClient->list[i]; if (client->status != NET_STATUS_ZOMBIE) { sock = client->socket->sock; if (sock > max_fd) { max_fd = sock; } FD_SET(sock, &readfds); if (getBufferSize(client->sendBuffer) > 0) { FD_SET(sock, &writefds); } } } ret = select(max_fd + 1, &readfds, &writefds, (fd_set *) NULL, &tv); if (ret > 0) { if (FD_ISSET(sock_server_tcp->sock, &readfds)) { eventNewClient(sock_server_tcp); } for (i = 0; i < listClient->count; i++) { client_t *client; int sock; client = (client_t *) listClient->list[i]; sock = client->socket->sock; if (FD_ISSET(sock, &readfds)) { eventRecvClient(client); } if (FD_ISSET(sock, &writefds)) { eventSendClient(client); } } } for (i = 0; i < listClient->count; i++) { client_t *client; client = (client_t *) listClient->list[i]; if (client->status == NET_STATUS_ZOMBIE) { delListItem(listClient, i, destroyClient); i--; continue; } eventClient(client); } } void quitDownServer() { closeTcpSocket(sock_server_tcp); destroyListItem(listClient, destroyClient); } int isFillPath(const char *path) { return 0; } int main(int argc, char **argv) { signal(SIGPIPE, SIG_IGN); initDownServer("0.0.0.0", 6800); while (1) { startDownServer(); } }