/* struct linger zu ein- ausschalten von Lingering */ /* * Missing: * Can't handle multiple clients * UDP support * Client can't choose audio file * unbind/unconnect on signals * change send and receiver buffers for TCP/IP */ #include "mppdec.h" #ifndef _WIN32 # include # include /* gethostbyaddr() */ # include #endif #ifndef _WIN32 # include #endif #define PORT 1088 /* port of server */ #ifdef _WIN32 # define FILENAME "D:\\Archive\\1.mpc" /* default file */ #else # define FILENAME "/Archive/1.mpc" /* default file */ #endif #define BUFFERSIZE (40 * 1452) #define TIME_OUT 300 #undef REPORT #ifdef VERBOSE # define REPORT(x) (x) #else # define REPORT(x) #endif #ifdef _WIN32 static int InitWinSocket ( void ) { WORD VersionRequested; WSADATA wsaData; int err; VersionRequested = MAKEWORD (2, 2); err = WSAStartup ( VersionRequested, &wsaData ); if ( err != 0 ) { // Tell the user that we could not find a usable WinSock DLL fprintf ( stderr, "Can't find WinSock DLL\n"); return -1; } // Confirm that the WinSock DLL supports 2.2. // Note that if the DLL supports versions greater than 2.2 in addition to 2.2, // it will still return 2.2 in Version since that is the version we requested. if ( LOBYTE (wsaData.wVersion) != 2 || HIBYTE (wsaData.wVersion) != 2 ) { // Tell the user that we could not find a usable WinSock DLL. fprintf ( stderr, "Wrong version of WinSock DLL: %d.%d\n", HIBYTE (wsaData.wVersion), LOBYTE (wsaData.wVersion) ); WSACleanup (); return -1; } return 0; } #endif int rc, cs; static void handler ( int signalno ) { fprintf (stderr, "\nSignal %2d captured\a\n\n", signalno ); shutdown (cs, 2); shutdown (rc, 2); _exit (1); } int main ( int argc, char** argv ) { static char okay [] = "HTTP/1.0 200 OK\r\nContent-Type: application/octet-stream\r\n\r\n"; char timestring [sizeof("2000-00-00 00:00:00")]; int tries; /* used for timeout (2 min.) */ int socket_fd; /* socket descriptor */ #if 0 int cs; /* new connection's socket descriptor */ int rc; /* system calls return value storage */ #endif struct sockaddr_in sa; /* internet address struct */ struct sockaddr_in csa; /* client's address struct */ size_t size_csa; /* size of client's address struct */ struct hostent* entry; /* host entry */ time_t epoch; struct tm* tm; FILE* fp; const char* file; unsigned char buff1 [BUFFERSIZE]; unsigned char buff2 [1024]; ssize_t bytes_read; ssize_t bytes_wrote; Int64_t total_bytes_written; int state; #ifndef _WIN32 struct sigaction act; struct sigaction oact; #endif TIME_T start; TIME_T end; double dur; int opt; size_t len; #ifdef _WIN32 LINGER ling; #else struct linger ling; #endif #ifdef _WIN32 static int init = 0; if ( init == 0 && InitWinSocket () != 0 ) return -1; init = 1; #endif #ifndef _WIN32 act.sa_handler = handler; if ( 0 != sigaction (SIGPIPE, &act, &oact) ) { fprintf ( stderr, "*** Fatal Error: Installation of SIGPIPE handler failed.\n"); return -1; } act.sa_handler = handler; if ( 0 != sigaction (SIGINT, &act, &oact) ) { fprintf ( stderr, "*** Fatal Error: Installation of SIGINT handler failed.\n"); return -1; } #endif switch ( argc ) { case 1: file = FILENAME; break; case 2: file = argv[1]; break; default: fprintf ( stderr, "usage: %s [filename]\n", argv[0] ); return 1; } setvbuf ( stdout, NULL, _IONBF, 0 ); setvbuf ( stderr, NULL, _IONBF, 0 ); /* initiate machine's internet address structure */ memset ( &sa, 0, sizeof (sa) ); /* first clear out the struct, to avoid garbage */ sa.sin_family = AF_INET; /* using internet address family */ sa.sin_port = htons (PORT); /* copy port number in network byte order */ sa.sin_addr.s_addr = INADDR_ANY; /* we will accept connections coming through any IP address that belongs to our host, using the INADDR_ANY wild-card */ /* allocate a free socket, internet address family, stream socket */ tries = 120; while ( (socket_fd = socket (AF_INET, SOCK_STREAM, 0)) < 0 ) { perror ("socket: allocation failed"); sleep (1); if (--tries <= 0) return -1; } opt = 1; if (setsockopt ( socket_fd, IPPROTO_TCP, TCP_NODELAY, (const char*)&opt, sizeof(opt) ) != 0 ) { perror ("setsockopt NODELAY"); } opt = 1; if (setsockopt ( socket_fd, SOL_SOCKET, SO_REUSEADDR, (const char*)&opt, sizeof(opt) ) != 0 ) { perror ("setsockopt REUSE"); } #if 0 ling.l_onoff = 1; ling.l_linger = 1; if (setsockopt ( socket_fd, SOL_SOCKET, SO_LINGER, (const char*)&ling, sizeof(ling) ) != 0 ) { perror ("setsockopt LINGER"); } #endif opt = 1; if (setsockopt ( socket_fd, SOL_SOCKET, SO_KEEPALIVE, (const char*)&opt, sizeof(opt) ) != 0 ) { perror ("setsockopt KEEP"); } /* bind the socket to the newly formed address */ tries = 3600; while ( (rc = bind (socket_fd, (struct sockaddr*)&sa, sizeof (sa))) != 0 ) { perror ("bind"); sleep (1); if (--tries <= 0) return -1; } /* * ask the system to listen for incoming connections to the address we just bound. specify that up to 5 pending connection * requests will be queued by the system, if we are not directly awaiting them using the accept() system call, when they arrive. */ tries = 120; while ( (rc = listen (socket_fd, 5)) != 0 ) { perror ("listen"); sleep (1); if (--tries <= 0) return -1; } /* remember size for later usage */ size_csa = sizeof (csa); printf ( "Serving file '%s' at port %d.\n", file, PORT ); printf ( "Server running.\n\n"); while ( 1 ) { /* * the accept() system call will wait for a connection, and when one is established, a new socket will be created to form * it, and the csa variable will hold the address of the client that just connected to us. the old socket, s, will still * be available for future accept() statements. */ /* check for errors -- if any, enter accept mode again */ if ( (cs = accept (socket_fd, (struct sockaddr*)&csa, &size_csa)) < 0 ) { continue; } #if 1 len = READ_SOCKET (cs, buff2, sizeof(buff2) ); write (2, "-------------------------------------------------------------------------------\n", 80 ); write (2, buff2, len ); write (2, "-------------------------------------------------------------------------------\n", 80 ); #endif TIME ( start ); /* ok, we got a new connection. do the job ... */ time ( &epoch ); /* time since 1970 */ tm = localtime ( &epoch ); /* fill time-struct */ snprintf ( timestring, sizeof (timestring), "%04d-%02d-%02d %02d:%02d:%02d", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec ); /* log connection */ printf ( "%s Connection from %s ", timestring, inet_ntoa ( /*(struct in_addr)*/ csa.sin_addr ) ); /* get the host entry */ if ( NULL == ( entry = gethostbyaddr ( (char*)&csa.sin_addr, sizeof (csa.sin_addr), AF_INET ) ) ) { #ifdef __linux__ herror ("gethostbyaddr" ); #else printf ("(no host address info)."); #endif } else { printf ( "(%s) ... ", entry->h_name ); } WRITE_SOCKET ( cs, okay, sizeof (okay)-1 ); /* service connection */ total_bytes_written = 0; if ( ( fp = fopen (file, "rb") ) == NULL ) { fprintf (stderr, "*** Fatal Error: Could not open file %s.\n", file); } else { do { state = 0; bytes_read = fread (buff1, 1, sizeof (buff1), fp); if ( bytes_read > 0 ) { total_bytes_written += bytes_wrote = WRITE_SOCKET (cs, buff1, (size_t)bytes_read ); REPORT (fprintf (stderr, " %s: %lld bytes sent.\r", inet_ntoa ((struct in_addr)csa.sin_addr), total_bytes_written)); if (bytes_wrote == bytes_read) { state = 1; } else { REPORT (fprintf (stderr, " Connection closed by foreign host (%d out of %d written).\n", bytes_wrote, bytes_read )); } } } while ( state ); fclose (fp); } /* now close the connection */ shutdown (cs, 0); while ( READ_SOCKET (cs, buff2, sizeof(buff2)) > 0 ) ; close (cs); TIME ( end ); dur = DTIME (start, end); printf ("\b\b\b\b\b, done. (%ld KBytes sent in %.2f sec = %.2f KB/s)\a\n", (long)(total_bytes_written >> 10), dur, total_bytes_written / dur * 1.e-3 ); } return 0; } /* end of streamserver.c */