// Run like this: simple_client address port // Results in argv ["./simple_client", "address", "port"] #include #include #include #include #include #include #include #include #include using namespace std; struct lurk_version_message { uint8_t type, major, minor; uint16_t extension_length; bool read(int skt){ ssize_t readlen; readlen = recv(skt, &type, 1, MSG_PEEK); if(readlen < 1 || type != 14){ printf("Failed to read version\n"); return false; } readlen = recv(skt, &type, 5, MSG_WAITALL); return readlen == 5; } } __attribute__((packed)); ostream& operator<<(ostream& out, const lurk_version_message &lvm){ out << "Type: " << (int)lvm.type << endl; out << "Version: " << (int)lvm.major << "." << (int)lvm.minor << endl; out << "Extension Length: " << lvm.extension_length << endl; return out; } struct lurk_game_message { uint8_t type; uint16_t initial_points, stat_limit, description_length; char *description = 0; bool read(int skt) { ssize_t readlen = recv(skt, this, 7, MSG_WAITALL); if(readlen < 7){ printf("Failed to read first 7 bytes, giving up!\n"); return false; } description = (char*)malloc(description_length + 1); description[description_length] = 0; readlen = recv(skt, description, description_length, MSG_WAITALL); if(readlen != description_length){ printf("Failed to read description, giving up\n"); free(description); description = 0; return false; } return true; } ~lurk_game_message(){ if(description) free(description); } } __attribute__((packed)); // Otherwise the compiler will leave padding ostream& operator<<(ostream& out, const lurk_game_message &lgm){ out << "Type: " << (int)lgm.type << endl; out << "Initial Points: " << lgm.initial_points << endl; out << "Stat Limit: " << lgm.stat_limit << endl; out << "Description Length: " << lgm.description_length << endl; out << "Description: " << lgm.description << endl; return out; } int main(int argc, char ** argv){ if(argc < 3){ printf("Usage: %s hostname port\n", argv[0]); return 1; } struct sockaddr_in sad; sad.sin_port = htons(atoi(argv[2])); sad.sin_family = AF_INET; int skt = socket(AF_INET, SOCK_STREAM, 0); // do a dns lookup struct hostent* entry = gethostbyname(argv[1]); if(!entry){ if(h_errno == HOST_NOT_FOUND){ printf("This is our own message that says the host wasn't found\n"); } herror("gethostbyname"); return 1; } struct in_addr **addr_list = (struct in_addr**)entry->h_addr_list; struct in_addr* c_addr = addr_list[0]; char* ip_string = inet_ntoa(*c_addr); sad.sin_addr = *c_addr; // copy the address we found into sad // Finally done with DNS! printf("Connecting to: %s\n", ip_string); if( connect(skt, (struct sockaddr*)&sad, sizeof(struct sockaddr_in)) ){ perror("connect"); return 1; } // New assumption: We don't know if the server will send a version or not! struct lurk_version_message lvm; if(lvm.read(skt)) cout << lvm << endl; else cout << "No version sent\n"; struct lurk_game_message lgm; lgm.read(skt); cout << lgm << endl; close(skt); return 0; }