| 1 | #include <sys/socket.h> |
| 2 | #include <netinet/in.h> |
| 3 | #include <arpa/inet.h> /* inet_aton,inet_ntoa */ |
| 4 | #include <unistd.h> /* read,write,close */ |
| 5 | #include <string.h> /* memset */ |
| 6 | #include <stdlib.h> /* malloc */ |
| 7 | #include <stdio.h> /* FILE,fprintf */ |
| 8 | |
| 9 | #define FILE_READ_MAX_SIZE 655000 |
| 10 | #define FILE_ONE_PAGE_SIZE 64000 |
| 11 | |
| 12 | #define SDRAM_MAX_LENGTH 640000 |
| 13 | #define TOTAL_SETTINGS_SIZE 4096 |
| 14 | |
| 15 | #define TCP_DOWNLOAD_SIZE 128 |
| 16 | #define TCP_DOWNLOAD_PORT 0x2223 // 8739 |
| 17 | |
| 18 | #define DATA_HINT "dh" |
| 19 | #define SETTINGS_HINT "sh" |
| 20 | |
| 21 | /* |
| 22 | * Download protocol (from PalmToolDlg.cpp): |
| 23 | * Step1. PC make a TCP connection to Palm1's page0 program |
| 24 | * Step2. PC sends 2 bytes to Palm1 for data "dh" or settings "sh" hints |
| 25 | * Palm1 sends back 128 byte of data |
| 26 | * Repeat step2 until the whole data has been received |
| 27 | * Step3. PC close the TCP connection indicate the download is over |
| 28 | */ |
| 29 | int download(int sd, char *buffer, size_t length, const char *hint) { |
| 30 | fprintf(stdout, "Downloading... "); |
| 31 | // receiving data |
| 32 | while (length > 0) { |
| 33 | write(sd, hint, strlen(hint)); |
| 34 | read(sd, buffer, TCP_DOWNLOAD_SIZE); |
| 35 | // FIXME: should check for errors! |
| 36 | fprintf(stdout, "%10d\b\b\b\b\b\b\b\b\b\b", length); |
| 37 | buffer += TCP_DOWNLOAD_SIZE; |
| 38 | length -= TCP_DOWNLOAD_SIZE; |
| 39 | } |
| 40 | fprintf(stdout, "Done. \n"); |
| 41 | return 0; |
| 42 | } |
| 43 | |
| 44 | int main(int argc, const char *argv[]) { |
| 45 | const char *progname, *filename, *extension, *hint, *ipaddr; |
| 46 | FILE *filehandle; |
| 47 | size_t length, length_padded; |
| 48 | char *buffer; |
| 49 | struct in_addr sin_addr; |
| 50 | int sd; |
| 51 | struct sockaddr_in sin; |
| 52 | |
| 53 | // check arguments count |
| 54 | progname = argv[0]; |
| 55 | if (argc != 3) { |
| 56 | fprintf(stderr, "Syntax: %s <filename> <IPv4-address>\n", progname); |
| 57 | return 1; |
| 58 | } |
| 59 | filename = argv[1]; |
| 60 | ipaddr = argv[2]; |
| 61 | |
| 62 | // check first argument (filename) |
| 63 | filehandle = fopen(filename, "wb"); |
| 64 | if (filehandle == NULL) { |
| 65 | fprintf(stderr, "Unable to open '%s' !\n", filename); |
| 66 | return 2; |
| 67 | } |
| 68 | fprintf(stdout, "File name: %s\n", filename); |
| 69 | |
| 70 | // check file type (by extension, for now...) |
| 71 | extension = strrchr(filename, '.'); |
| 72 | if (extension && !strcasecmp(extension, ".dh")) { |
| 73 | hint = DATA_HINT; |
| 74 | length = SDRAM_MAX_LENGTH; // < FILE_READ_MAX_SIZE |
| 75 | } else if (extension && !strcasecmp(extension, ".sh")) { |
| 76 | hint = SETTINGS_HINT; |
| 77 | length = TOTAL_SETTINGS_SIZE; // < FILE_ONE_PAGE_SIZE |
| 78 | } else { |
| 79 | fprintf(stderr, "Unknown file type!\n"); |
| 80 | return 2; |
| 81 | } |
| 82 | |
| 83 | // normalize file size |
| 84 | length_padded = length + TCP_DOWNLOAD_SIZE*2 - 1; |
| 85 | length_padded /= TCP_DOWNLOAD_SIZE*2; |
| 86 | length_padded *= TCP_DOWNLOAD_SIZE*2; |
| 87 | |
| 88 | // prepare to load data into memory |
| 89 | fprintf(stdout, "File length: %d bytes", length); |
| 90 | if (length_padded > length) { |
| 91 | fprintf(stdout, " (padding to %d bytes)", length_padded); |
| 92 | } |
| 93 | fprintf(stdout, "\n"); |
| 94 | buffer = malloc(length_padded); |
| 95 | if (buffer == NULL) { |
| 96 | fprintf(stderr, "Unable to allocate enough (%d bytes) memory!\n", length_padded); |
| 97 | return 4; |
| 98 | } |
| 99 | |
| 100 | // check second argument (IPv4 address) |
| 101 | if (!inet_aton(ipaddr, &sin_addr)) { |
| 102 | fprintf(stderr, "'%s' is an invalid IPv4 address!\n", ipaddr); |
| 103 | return 6; |
| 104 | } |
| 105 | fprintf(stdout, "IPv4 address: %s\n", inet_ntoa(sin_addr)); |
| 106 | |
| 107 | // connect to the host |
| 108 | sd = socket(PF_INET, SOCK_STREAM, 0); |
| 109 | if (sd < 0) { |
| 110 | fprintf(stderr, "Unable to create a socket!\n"); |
| 111 | return 7; |
| 112 | } |
| 113 | memset(&sin, 0, sizeof(sin)); |
| 114 | sin.sin_family = AF_INET; |
| 115 | sin.sin_port = htons(TCP_DOWNLOAD_PORT); |
| 116 | memcpy(&sin.sin_addr, &sin_addr, sizeof(sin.sin_addr)); |
| 117 | if (connect(sd, (struct sockaddr *)&sin, sizeof(sin))) { |
| 118 | fprintf(stderr, "Unable to connect to host!\n"); |
| 119 | return 8; |
| 120 | } |
| 121 | |
| 122 | // do the upgrade process |
| 123 | setbuf(stdout, NULL); |
| 124 | if (download(sd, buffer, length_padded, hint)) return 9; |
| 125 | |
| 126 | // save to file |
| 127 | //if (length < length_padded) { |
| 128 | // memset(buffer + length, 0, length_padded - length); |
| 129 | //} |
| 130 | if (fwrite(buffer, length, 1, filehandle) != 1) { // XXX: length_padded? |
| 131 | fprintf(stderr, "Unable to write the whole file content!\n"); |
| 132 | return 5; |
| 133 | } |
| 134 | fclose(filehandle); |
| 135 | |
| 136 | // cleaning |
| 137 | close(sd); |
| 138 | return 0; |
| 139 | } |