// // A simple file client application. // It connects to a file server // and sends commands to a server. // // Usage: // client [IP_address_of_server [port_of_server]] // where IP_address_of_server is either IP number of server // or a symbolic Internet name, default is "localhost"; // port_of_server is a port number, default is 1234. // #include #include #include #include #include #include #include #include #include #include "filesrv.h" static void usage(); static void initializeFrame(ProtocolFrame* frame); static void textMessage(const wchar_t* str); static void textNumMessage(const wchar_t* str, int n); static void netErrorMessage(const wchar_t* str); static void outputText(const wchar_t* str); class ProtocolException { public: const char *reason; ProtocolException(): reason("") {} ProtocolException(const char *cause): reason(cause) {} }; static int receiveFrame(int s, ProtocolFrame* frame); static void sendFrame(int s, const ProtocolFrame* frame) throw (ProtocolException); // Protocol commands static void pwd(int s) throw (ProtocolException); static void cd(int s, const wchar_t* path) throw (ProtocolException); static void ls(int s) throw (ProtocolException); static void put(int s, const wchar_t* path) throw (ProtocolException); static void get(int s, const wchar_t* path) throw (ProtocolException); static void logout(int s) throw (ProtocolException); static const int BLOCK_SIZE = 1024; static jmp_buf readCommandPoint; // Saved point for long jump int main(int argc, char *argv[]) { if (argc > 1 && *(argv[1]) == '-') { usage(); exit(1); } if (!SetConsoleOutputCP(CP_UTF8)) { printf( "Cannot set console output to UTF8: error %d\n", (int) GetLastError() ); } // Initialize Winsock DLL WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; int err = WSAStartup(wVersionRequested, &wsaData); if (err != 0) { netErrorMessage(L"WSAStartup failed"); exit(-1); } // Create a socket int s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { netErrorMessage(L"Cannot create a socket"); exit(-1); } // Fill in the address of server struct sockaddr_in peeraddr; memset(&peeraddr, 0, sizeof(peeraddr)); const char* peerHost = "localhost"; if (argc > 1) peerHost = argv[1]; // Resolve the server address (convert from symbolic name to IP number) struct hostent *host = gethostbyname(peerHost); if (host == NULL) { perror("Cannot define host address"); exit(1); } peeraddr.sin_family = AF_INET; short peerPort = 1234; if (argc >= 3) peerPort = (short) atoi(argv[2]); peeraddr.sin_port = htons(peerPort); // Print a resolved address of server (the first IP of the host) printf( "peer addr = %d.%d.%d.%d, port %d\n", host->h_addr_list[0][0] & 0xff, host->h_addr_list[0][1] & 0xff, host->h_addr_list[0][2] & 0xff, host->h_addr_list[0][3] & 0xff, (int) peerPort ); // Write resolved IP address of a server to the address structure memmove(&(peeraddr.sin_addr.s_addr), host->h_addr_list[0], 4); // Connect to a remote server int res = connect(s, (struct sockaddr*) &peeraddr, sizeof(peeraddr)); if (res < 0) { perror("Cannot connect"); exit(1); } textMessage(L"Connected."); try { ProtocolFrame frame; while (receiveFrame(s, &frame) >= 0 && frame.command != FSR_LOGOUT) { wchar_t line[256]; // Save an entry point for a long jump setjmp(readCommandPoint); LReadCommand: ; printf("Command>"); fflush(stdout); //... if (fgets(line, 254, stdin) == NULL) if (_getws(line) == NULL) break; // Parse a command line[254] = 0; int len = wcslen(line); if (len == 0) // Empty command goto LReadCommand; int i = 0; // Skip a space in beginning of line while (i < len && iswspace(line[i])) ++i; int commandBeg = i; while (i < len && iswalpha(line[i])) ++i; int commandEnd = i; int commandLen = commandEnd - commandBeg; if ( wcsncmp(L"pwd", line+commandBeg, commandLen) == 0 ) { pwd(s); } else if ( wcsncmp(L"cd", line+commandBeg, commandLen) == 0 ) { while (i < len && iswspace(line[i])) ++i; // Skip a space if (i >= len) { printf("Incorrect command.\n"); goto LReadCommand; } cd(s, line + i); } else if ( wcsncmp(L"ls", line+commandBeg, commandLen) == 0 ) { ls(s); } else if ( wcsncmp(L"put", line+commandBeg, commandLen) == 0 ) { while (i < len && iswspace(line[i])) ++i; // Skip a space if (i >= len) { printf("Incorrect command.\n"); goto LReadCommand; } put(s, line + i); } else if ( wcsncmp(L"get", line+commandBeg, commandLen) == 0 ) { while (i < len && iswspace(line[i])) ++i; // Skip a space if (i >= len) { printf("Incorrect command.\n"); goto LReadCommand; } get(s, line + i); } else if ( wcsncmp(L"logout", line+commandBeg, commandLen) == 0 || line[commandBeg] == L'q' || line[commandBeg] == L'Q' ) { logout(s); break; } else { printf("Incorrect command.\n"); goto LReadCommand; } } } catch (ProtocolException& e) { printf( "Protocol exception: %s\n", e.reason ); } WSACleanup(); closesocket(s); return 0; } static void usage() { printf( "A simple file client application.\n" "Usage:\n" " client [IP_address_of_server [port_of_server]]\n" " where IP_address_of_server is either IP number of server\n" " or a symbolic Internet name, default is \"localhost\";\n" " port_of_server is a port number, default is 1234.\n" ); } static void initializeFrame(ProtocolFrame* frame) { memset(frame, 0, sizeof(ProtocolFrame)); } static void sendFrame(int s, const ProtocolFrame* frame) throw (ProtocolException) { ssize_t res = send( s, (char *)frame, FSR_HEADERLEN + frame->length, 0 ); if (res < 0) throw ProtocolException("Write error on socket"); } static int receiveFrame(int s, ProtocolFrame* frame) { // Read frame header //???!!! ssize_t res = recv(s, frame, FSR_HEADERLEN, MSG_WAITALL); //??? #define MSG_WAITALL 0x8 ssize_t res = 0; int lh = 0; do { res = recv( s, ((char *)frame) + lh, FSR_HEADERLEN - lh, 0 ); if (res >= 0) lh += res; } while (res >= 0 && lh < FSR_HEADERLEN); if (lh < FSR_HEADERLEN) { netErrorMessage(L"Error reading from socket"); printf("Could not receive a frame header: len=%d\n", lh); fflush(stdout); return (-1); } int len = frame->length; if (len > FSR_MAXDATALEN) len = FSR_MAXDATALEN; char *pos = frame->data; while (len > 0) { int bytesToRead = len; if (bytesToRead > BLOCK_SIZE) bytesToRead = BLOCK_SIZE; res = recv(s, pos, bytesToRead, 0); if (res <= 0) return (-1); len -= res; pos += res; } return (FSR_HEADERLEN + frame->length); } static void pwd(int s) throw (ProtocolException) { ProtocolFrame frame; initializeFrame(&frame); frame.command = FSR_PWD; frame.length = 0; sendFrame(s, &frame); if (receiveFrame(s, &frame) < 0) { netErrorMessage(L"Disconnected"); exit(1); } if (frame.command == FSR_DATAEND) { char path[MAX_PATH + 2]; int len = frame.length; if (len > MAX_PATH) len = MAX_PATH; memmove(path, frame.data, len); path[len] = 0; path[len+1] = 0; textMessage((wchar_t *) path); } else if (frame.command == FSR_ERROR) { textMessage(L"Error:"); textMessage((wchar_t *) frame.data); } else { printf("Incorrect protocol.\n"); exit(1); } } static void cd(int s, const wchar_t* path) throw (ProtocolException) { ProtocolFrame frame; initializeFrame(&frame); frame.command = FSR_CD; int len = wcslen(path); if (len >= FSR_MAXDATALEN/2) len = FSR_MAXDATALEN/2 - 1; frame.length = 2*(len + 1); memmove(frame.data, path, 2*len); frame.data[2*len] = 0; frame.data[2*len + 1] = 0; sendFrame(s, &frame); if (receiveFrame(s, &frame) < 0) { netErrorMessage(L"Disconnected"); exit(-1); } if (frame.command == FSR_SUCCESS) { textMessage(L"OK"); } else if (frame.command == FSR_ERROR) { textMessage(L"Error:"); textMessage((wchar_t *) frame.data); } else { printf("Incorrect protocol.\n"); exit(-1); } } static void ls(int s) throw (ProtocolException) { // To do... printf("Not implemented.\n"); longjmp(readCommandPoint, 0); } static void put(int s, const wchar_t* path) throw (ProtocolException) { // To do... printf("Not implemented.\n"); longjmp(readCommandPoint, 0); } static void get(int s, const wchar_t* path) throw (ProtocolException) { // To do... printf("Not implemented.\n"); longjmp(readCommandPoint, 0); } static void logout(int s) throw (ProtocolException) { ProtocolFrame frame; initializeFrame(&frame); frame.command = FSR_LOGOUT; frame.length = 0; sendFrame(s, &frame); } static void outputText(const wchar_t* str) { // Define the length of converted string int bufferSize = WideCharToMultiByte( CP_UTF8, 0, str, -1, NULL, 0, NULL, NULL ); char txt[128]; char* line = txt; if (bufferSize >= 128) // if length is large line = new char[bufferSize + 2]; // allocate space // Convert a string to UTF8 line WideCharToMultiByte( CP_UTF8, 0, str, -1, line, bufferSize, NULL, NULL ); // Print the UTF8 line wprintf(L"%S", line); if (line != txt) delete[] line; } static void textMessage(const wchar_t* str) { outputText(str); outputText(L"\n"); fflush(stdout); } static void textNumMessage(const wchar_t* str, int n) { outputText(str); wchar_t num[32]; num[0] = L' '; swprintf(num + 1, L"%d", n); outputText(num); fflush(stdout); } static void netErrorMessage(const wchar_t* str) { outputText(str); textNumMessage(L": error", WSAGetLastError()); fflush(stdout); }