/* * Flash Socket Policy File Server * * Based upon 68user's echo-server-select.c * Copyright 2005 68user. All rights reserved. */ #include #include #include #include #include #include #include #include #include #include #include #define BUFSIZE 24 typedef struct CLIENT_INFO { int connected; char ipaddr[16]; #ifdef DEBUG int port; #endif time_t last_access; char buffer[BUFSIZE]; int read_size; } CLIENT_INFO; CLIENT_INFO client_info[FD_SETSIZE]; int listening_socket; struct sockaddr_in sockin; fd_set org_target_fds; int connected; int run = 1; #ifdef DEBUG int debug = 0; #endif char *filename = "fspfd.xml"; char *outbuf = NULL; int out_len; void sendbuf(int sock, char *buf, size_t size) { int ret; while (size) { ret = send(sock, buf, size, 0); if (ret == -1) { syslog(LOG_WARNING, "send: %s", strerror(errno)); return; } else { size -= ret; buf += ret; } } } void get_file() { struct stat statbuf; FILE *fp; if (stat(filename, &statbuf) != 0) { syslog(LOG_ERR, "%s: %s", filename, strerror(errno)); exit(EXIT_FAILURE); } out_len = statbuf.st_size + 1; outbuf = realloc(outbuf, out_len); if (outbuf == NULL) { syslog(LOG_ERR, "Couldnt get file buffer: %s", strerror(errno)); exit(EXIT_FAILURE); } memset(outbuf, 0, out_len); fp = fopen(filename, "rb"); fread(outbuf, 1, out_len, fp); fclose(fp); } int read_and_reply(int sock) { int read_size; char *inbuf = client_info[sock].buffer; read_size = recv(sock, inbuf + client_info[sock].read_size, BUFSIZE - client_info[sock].read_size, 0); client_info[sock].read_size += read_size; if (read_size == 0 || read_size == -1 || client_info[sock].read_size > 23) { close(sock); client_info[sock].last_access = 0; return read_size; } if (memcmp (inbuf, "", client_info[sock].read_size) != 0) { close(sock); client_info[sock].last_access = 0; return -1; } if (client_info[sock].read_size < 23) { time(&client_info[sock].last_access); return read_size; } #ifdef DEBUG if (debug) syslog(LOG_INFO, "Valid request.\n"); #endif sendbuf(sock, outbuf, out_len); close(sock); client_info[sock].last_access = 0; return -1; } int accept_new_client() { socklen_t len; int new_socket; int sock, cnt; struct sockaddr_in peer_sin; len = sizeof(sockin); new_socket = accept(listening_socket, (struct sockaddr *) &sockin, &len); if (new_socket < 0) { syslog(LOG_WARNING, "accept error\n"); return -1; } if (new_socket >= FD_SETSIZE) { syslog(LOG_WARNING, "accept without range: %d\n", new_socket); return -1; } /* for debug */ len = sizeof(peer_sin); getpeername(new_socket, (struct sockaddr *) &peer_sin, &len); memset(&client_info[new_socket], 0, sizeof(CLIENT_INFO)); connected++; client_info[new_socket].connected = 1; strncpy(client_info[new_socket].ipaddr, inet_ntoa(peer_sin.sin_addr), sizeof client_info[new_socket].ipaddr); time(&client_info[new_socket].last_access); #ifdef DEBUG if (debug) { client_info[new_socket].port = ntohs(peer_sin.sin_port); syslog(LOG_INFO, "New socket IP:%s port:%d desc:%d\n", client_info[new_socket].ipaddr, client_info[new_socket].port, new_socket); } #endif for (sock = 0, cnt = 0; sock < FD_SETSIZE && cnt < connected; sock++) { if (client_info[sock].connected == 0) continue; cnt++; /* Skip non-target and listening sockets */ if (!FD_ISSET(sock, &org_target_fds) || sock == listening_socket) continue; if (strcmp (client_info[sock].ipaddr, client_info[new_socket].ipaddr) == 0) { close(new_socket); client_info[new_socket].last_access = 0; return -1; } } return new_socket; } void onstop(int sig) { run = 0; } int main(int argc, char *argv[]) { int ret; fd_set target_fds; unsigned short port = 843; int sock_optval = 1; signal(SIGINT, onstop); openlog("fspfd", LOG_PID, LOG_DAEMON); #ifdef DEBUG if (argc > 1 && strncmp(argv[1], "--debug", 7) == 0) { debug = 1; } #endif get_file(); /* Create socket for incoming connections */ listening_socket = socket(AF_INET, SOCK_STREAM, 0); if (listening_socket < 0) { syslog(LOG_ERR, "socket: %s", strerror(errno)); exit(EXIT_FAILURE); } ret = setsockopt(listening_socket, SOL_SOCKET, SO_REUSEADDR, &sock_optval, sizeof(sock_optval)); if (ret < 0) { syslog(LOG_ERR, "setsockopt: %s", strerror(errno)); exit(EXIT_FAILURE); } /* Construct local address structure */ memset(&sockin, 0, sizeof(sockin)); sockin.sin_family = AF_INET; sockin.sin_port = htons(port); sockin.sin_addr.s_addr = htonl(INADDR_ANY); /* Bind to the local address */ ret = bind(listening_socket, (struct sockaddr *) &sockin, sizeof(sockin)); if (ret < 0) { syslog(LOG_ERR, "bind: %s", strerror(errno)); exit(EXIT_FAILURE); } /* Mark the socket so it will listen for incoming connections */ ret = listen(listening_socket, SOMAXCONN); if (ret < 0) { syslog(LOG_ERR, "listen: %s", strerror(errno)); exit(EXIT_FAILURE); } FD_ZERO(&org_target_fds); FD_SET(listening_socket, &org_target_fds); connected = 1; memset(&client_info, 0, sizeof(client_info)); client_info[listening_socket].connected = 1; #ifdef DEBUG if (debug) syslog(LOG_INFO, "Listening port:%d desc:%d\n", port, listening_socket); #endif while (run) { int sock, cnt; time_t timeout; struct timeval waitval; /* Wait 2.5 sec */ waitval.tv_sec = 2; waitval.tv_usec = 500; memcpy(&target_fds, &org_target_fds, sizeof(org_target_fds)); ret = select(FD_SETSIZE, &target_fds, NULL, NULL, &waitval); if (ret < 0) { syslog(LOG_ERR, "select: %s", strerror(errno)); exit(EXIT_FAILURE); } for (sock = 0, cnt = 0; sock < FD_SETSIZE && cnt < connected; sock++) { if (client_info[sock].connected == 0) continue; cnt++; if (FD_ISSET(sock, &target_fds)) { if (sock == listening_socket) { int new_sock; new_sock = accept_new_client(); if (new_sock != -1) { FD_SET(new_sock, &org_target_fds); } } else { #ifdef DEBUG if (debug) syslog(LOG_INFO, "Received IP:%s port:%d desc:%d\n", client_info[sock].ipaddr, client_info[sock].port, sock); #endif if (read_and_reply(sock) <= 0) { /* Delete disconnected socket from targets */ FD_CLR(sock, &org_target_fds); client_info[sock].connected = 0; connected--; } } } } time(&timeout); timeout -= 10; for (sock = 0, cnt = 0; sock < FD_SETSIZE && cnt < connected; sock++) { if (client_info[sock].connected == 0) continue; cnt++; /* Skip non-target and listening sockets */ if (!FD_ISSET(sock, &org_target_fds) || sock == listening_socket) continue; if (timeout > client_info[sock].last_access) { close(sock); /* Delete disconnected socket from targets */ FD_CLR(sock, &org_target_fds); client_info[sock].connected = 0; connected--; } } } close(listening_socket); return EXIT_SUCCESS; }