MES3.0はLinuxの下位互換性であり、MES3.0のユーザープログラムは原則としてLinuxでも同じソースコードで動作します。
以下、MES3.0で動作確認されたLinuxとソースコード互換のTFTPクライアントの例です。
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <unistd.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netdb.h>
#define TFTP_SIZE 512
#define TFTP_NOFILE 0
#define TFTP_ACCESS 2
#define TFTP_ILLEGAL 4
#define TFTP_READREQ 1
#define TFTP_WRITEREQ 2
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
static int make_req_packet(char *packet, char *name, char command) {
int index;
short *data;
index = 0;
data = (short*)&packet[index];
data[0] = htons(command);
index += sizeof(short);
strcpy(&packet[index], name);
index += strlen(name) + 1;
strcpy(&packet[index], "octet");
index += strlen("octet") + 1;
return index;
}
static int ack_get(int sock,struct sockaddr_in *target) {
unsigned short ack[2];
int ret, addrlen;
ack[0] = 0;
ret = recvfrom(sock, (char*)ack, 4, 0, (struct sockaddr *)target, &addrlen);
if(ret == -1) return -1;
if(ntohs(ack[0]) == TFTP_ACK) return ntohs(ack[1]); // block number
return -1;
}
/*static void ack_put(int sock,struct sockaddr_in *target, unsigned short pnum) {
unsigned short ack[2];
ack[0] = htons(TFTP_ACK);
ack[1] = htons(pnum); // block number
sendto(sock, (char*)ack, 4, 0, (struct sockaddr *)&target, sizeof(target));
}*/
static int tftp_common(int ip, char *filename, char command, void (*func)()) {
int ack, i, c, sock, size, filesize, count;
int mode, fullsize, ret, retry, addrlen, len;
unsigned int myip, servip, mask;
unsigned char mac[6];
unsigned char *packet;
unsigned short *data, pnum;
const int on = 1;
FILE *fp;
struct sockaddr_in target;
struct timeval tv;
switch(command) {
case TFTP_WRITEREQ:
fullsize = TFTP_SIZE;
fp = fopen(filename, "rb");
break;
case TFTP_READREQ:
fullsize = TFTP_SIZE + 4;
fp = fopen(filename, "wb");
break;
default:
return -1;
}
if(fp == NULL) {
printf("Open error.\n");
return -1;
}
servip = ip;
packet = malloc(TFTP_SIZE + 4);
if(packet == 0) {
printf("malloc error.\n");
return -1;
}
sock = socket(AF_INET, SOCK_DGRAM, 0);
if(sock == -1) {
printf("socket error.\n");
free(packet);
return -1;
}
getsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, &len);
tv.tv_sec = 3;
tv.tv_usec = 0;
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
bzero(packet, TFTP_SIZE + 4);
target.sin_family = AF_INET;
target.sin_addr.s_addr = servip;
target.sin_port = htons(69);
bind(sock, (struct sockaddr *)&target, sizeof(target));
size = make_req_packet(packet, filename, command);
data = (short*)packet;
sendto(sock, packet, size, 0, (struct sockaddr *)&target, sizeof(target));
ack = 0;
if(command == TFTP_WRITEREQ) ack = ack_get(sock, &target);
ret = -1;
count = 0;
if(ack == 0) {
ret = 0;
pnum = 1;
do {
bzero(packet, TFTP_SIZE + 4);
switch(command) {
case TFTP_WRITEREQ:
size = fread(&packet[4], 1, TFTP_SIZE, fp);
for(retry = 0;retry < 4;retry++) {
if(command == TFTP_WRITEREQ) {
data[0] = htons(TFTP_DATA);
data[1] = htons(pnum);
sendto(sock, packet, size + 4, 0, (struct sockaddr *)&target, sizeof(target));
ack = ack_get(sock, &target);
// if(ntohs(target.sin_port) < 1024) continue;
if(ack == -1) ret = -1;
if(ack == pnum || ack == -1) break;
}
}
if(retry == 4) ret = -1;
break;
case TFTP_READREQ:
for(retry = 0;retry < 4;retry++) {
size = recvfrom(sock, packet, TFTP_SIZE + 4, 0, (struct sockaddr *)&target, &addrlen);
if(size == -1) {
ret = -1;
break;
}
// if(ntohs(target.sin_port) < 1024) continue;
if(pnum == ntohs(data[1])) {
data[0] = htons(TFTP_ACK);
sendto(sock, packet, 4, 0, (struct sockaddr *)&target, sizeof(target));
fwrite(&packet[4], 1, size - 4, fp);
break;
}
}
if(retry == 4) ret = -1;
break;
}
pnum++;
if((count++ % 10) == 0) if(func != 0) (*func)();
} while(size == fullsize && ret == 0);
}
fclose(fp);
close(sock);
free(packet);
return ret;
}
static int tftpsave(int ip, char *filename, void (*func)()) {
return tftp_common(ip, filename, TFTP_WRITEREQ, func);
}
static int tftpload(int ip, char *filename, void (*func)()) {
return tftp_common(ip, filename, TFTP_READREQ, func);
}
int main(int argc, char** argv) {
struct sockaddr_in addr, saddr;
struct hostent *hp;
int ip, ret;
char *name;
if((hp = gethostbyname(argv[1])) == NULL) {
if((hp = gethostbyname(argv[2])) == NULL) {
printf("host not found.\n");
return -1;
}
bcopy(hp->h_addr_list[0], &(addr.sin_addr), hp->h_length);
name = strrchr(argv[1], '/');
if(name == 0) name = argv[1];
if(tftpload(addr.sin_addr.s_addr, name, 0) == -1) {
printf("download error.\n");
return -1;
}
} else {
bcopy(hp->h_addr_list[0], &(addr.sin_addr), hp->h_length);
name = strrchr(argv[2], '/');
if(name == 0) name = argv[2];
if(tftpsave(addr.sin_addr.s_addr, name, 0) == -1) {
printf("upload error.\n");
return -1;
}
}
return 0;
}