[C言語]メモリリーク

メモリリークとは、動的に割当てたメモリ領域を解放し忘れることで次第にメモリ資源を食い潰していき、いずれプログラムやシステムに異常をきたすという問題。
c言語のメモリ解放はmalloc()やfree()が使われてきた。
malloc()で割当てて、free()で解放する。
メモリの解放を忘れていると、プログラムが終了するまでメモリ資源を無駄に占有し続ける。

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>

int maikFile(char *fileName, int size){
	FILE *fp;
	char *pData;

	// メモリ解放
	pData = malloc(size);
	if(pData == NULL){
		return 1;
	}

	fp = fopen(fileName, "wb");
	if(fp == NULL){
		return 1;
	}

	memset(pData, 0x20, size);
	fwrite(pData, size, 1, fp);
	fclose(fp);

	free(pData);
	return 0;
}


int main(int argc, char** argv[]){

	return 0;

}

ファイルシステムオープンの失敗を繰り返すと、メモリは解放されずにreturn1となるのでメモリリークになる。

[C言語]ファイヤーウォール

ファイヤーウォールとはパケットの制御または破棄を行うソフトウェアである

特定のパケットとは、
– 特定のポートにアクセスするパケット
– 特定のIPアドレスからのパケット
– 特定の内容をもつパケット
などがある。

ファイヤーウォールを作成するには
– パケットの中身を見る
– パケットの転送可否を行う

### パケットキャプチャ
パケットの中身を見る
TCPやUDPはもとより、IPやEthernetレベルのデータリンク情報も解析する
一般的に tcpdump や wireshark などがある

#include <stdio.h>
#include <net/if.h> // ネットワークインターフェイス構造体 PF_PACKET
#include <net/ethernet.h> // ETH_P_ALL

void analyzePacket(u_char *buf){
	printEtherHeader(buf);
}

void printEtherHeader(u_char *buf){
	struct ether_header *eth;
	eth = (struct ether_header *)buf;
	printf("Dst MAC addr :%17s\n", mac_ntoa(eth->ether_dhost));
	printf("Src MAC addr :%17s\n", mac_ntoa(eth->ether_shost));
	printf("Ethernet Type :0x%04x\n", ntohs(ether_type));
}

char *mac_ntoa(u_char *d){
	static char str[18];
	sprintf(str,"%02x:%02x:%02x:%02x:%02x:%02x",d[0],d[1],d[2],d[3],d[4],d[5]);
	return str;
}

int main(int argc, char** argv[]){

	int soc;
	u_char buf[65535]; // u_charはunsigned char
	soc = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	while(1){
		read(soc,buf,sizeof(buf));
		analyzePacket(buf);
	}
	return 0;

}

int socket(int domain, int type, int protocol);
PF_PACKETを指定すると,データリンク層やネットワーク層の生データを扱える
通常はSOCK_STREAM(TCPの場合)やSOCK_DGRAM(UDPの場合)
ETHERNETとは、TCP/IPプロトコルのネットワークインターフェース層に対応する有線の規格

宛先MAC address(固有識別番号)、送信元MAC address, type, ip以降
ビッグエンディアン

[C言語]ICMP

ICMPとはInternet Control Message Protocol
Internet Protocolのデータグラム処理における誤りの通知や通信に関する情報の通知などのために使用される

#include <stdio.h>

#include <sys/socket.h> // Internet Protocol family
#include <netinet/in.h> // Internet Protocol family

#include <netinet/ip.h>  // IPヘッダ構造体
#include <netinet/ip_icmp.h> // ICMPヘッダ

unsigned short checksum(unsigned short *buf, int bufsz){

	unsigned long sum = 0;

	while(bufsz > 1){
		sum += *buf;
		buf++;
		bufsz -= 2;
	}

	if(bufsz == 1){
		sum += *(unsigned char *)buf;
	}

	sum = (sum & 0xffff) + (sum >> 16);
	sum = (sum & 0xffff) + (sum >> 16);

	return ~sum;
}

int main(int argc, char** argv[]){

	int sock;
	struct icmphdr hdr;
	struct sockaddr_in addr;
	int n;

	char buf[2000];
	struct icmphdr *icmphdrptr;
	struct iphdr *iphdrptr;

	if(argc != 2){
		printf("usage : %s IPADDR\n", argv[0]);
		return 1;
	}

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(argv[1]);

	sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
	if(sock < 0){
		perror("socket");
		return 1;
	}

	memset(&hdr, 0, sizeof(hdr));

	hdr.type = ICMP_ECHO;
	hdr.code = 0;
	hdr.checksum = 0;
	hdr.un.echo.id = 0;
	hdr.un.echo.sequence = 0;

	hdr.checksum = chechsum((unsigned short *)&hdr, sizeof(hdr));

	n = sendto(sock, (char *)&hdr, sizeof(hdr), 0, (struct sockaddr *)&addr, sizeof(addr));
	if (n < 1){
		perror("sendto");
	}

	memset(buf, 0, sizeof(buf));

	n = recv(sock, buf, sizeof(buf), 0);
	if(n < 1){
		perror("recv");
	}

	iphdrptr = (struct iphdr *) buf;

	icmphdrptr = (struct icmphdr *)(buf + (iphdrptr->ihl * 4));

	if(icmphdrptr->type == ICMP_ECHOREPLY){
		printf("received ICMP ECHO REPLY\n");
	} else {
		printf("received ICMP %d\n", icmphdrptr->type);
	}

	close(sock);
	

	return 0;

}

[C言語]UDP

UDPはデータが宛先に届いたかどうかを関知しない為、到着を保証しない
複数の相手に同時にデータを送信できる、TCPは1対1のユニキャストのみ
TCPよりリアルタイム性が高い
用途は映像、音楽のストリーミング、Voice Over IPなど

### UDP受信
– ソケットを作る
– bindするIPアドレスとポートを設定
– ソケットに名前をつける
– データを受け取る

#include <stdio.h>
#include <sys/types.h> // typedef シンボルおよび構造体のコレクション
#include <sys/socket.h> // Internet Protocol family
#include <netinet/in.h> // Internet Protocol family

int main(int argc, char** argv){

	int sock;
	struct sockaddr_in addr; // sockaddr_inはIPアドレスやポート番号を保持する為の構造体

	char buf[2048];

	sock = socket(AF_INET, SOCK_DGRAM, 0); // ソケットの作成

	addr.sin_family = AF_INET; // アドレスファミリ
	addr.sin_port = htons(12345); // ポート番号、 htonsはネットワークバイトオーダに変換
	addr.sin_addr.s_addr = INADDR_ANY; // IPアドレス

	bind(sock, (struct sockaddr *)&addr, sizeof(addr)); // sockはソケットとアドレスの結合

	memset(buf, 0, sizeof(buf)); // バイトメモリブロックのセット
	recv(sock, buf, sizeof(buf), 0); // ソケットからメッセージを受け取る

	printf("%s\n", buf);

	close(sock);

	return 0;

}

### UDP送信
– ソケットを作る
– 宛先を指定して送信

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

int main(){
	
	int sock;
	struct sockaddr_in addr;

	sock = socket(AF_INET, SOCK_DGRAM, 0);

	addr.sin_family = AF_INET;
	addr.sin_port = htons(12345);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");

	sendto(sock, "HELLO", 5, 0, (struct sockaddr *)&addr, sizeof(addr));

	close(sock);

	return 0;
}

TCP/IPはデータを切れ目のないストリームとして扱う、ストリームのイメージは固定された通信路
一方、UDPはデータグラム(塊)として扱う

TCPとUDPについてわかってきました。

[C言語]TCP/IP

サーバ側

#include 
#include 
#include 
#include 

int main(int argc, char** argv){
	int sd;
	int acc_sd;
	struct sockaddr_in addr;

	socklen_t sin_size = sizeof(struct sockaddr_in);
	struct sock_in from addr;

	char buf[2048];

	memset(buf, 0, sizeof(buf));

	if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
		perror("socket");
		return -1;
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(22222);
	addr.sin_addr.s_addr = INADDR_ANY;

	if(bind(sd, (struct sockaddr *)&addr, sizeof(addr)) < 0){
		perror("bind");
		return -1;
	}

	if(listen(sd, 10) < 0){
		perror("listen");
		return -1;
	}

	if((acc_sd) = accept(sd, (struct sockaddr *)&from_addr, &sin_size)) < 0 {
		perror("accept");
		return -1;
	}

	if(recv(acc_sc, buf, sizeof(buf), 0) < 0){
		perror("recv");
		return -1;
	}

	close(acc_sd);

	close(sd);

	printf("%s\n", buf);

	return 0;

}

client

#include 
#include 
#include 

int main(int argc, char** argv){
	int sd;
	struct sockaddr_in addr;

	if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0){
		perror("socket");
		return -1;
	}

	addr.sin_family = AF_INET;
	addr.sin_port = htons(22222);
	addr.sin_addr.s_addr = inet_addr("127.0.0.1");

	connect(sd, (struct sockaddr *)&addr, sizeof(struct sockaddr_in));

	if(send(sd, "sending process", 17, 0) < 0){
		perror("send");
		return -1;
	}

	close(sd);

	return 0;
}

[C言語]バイナリファイル

パケットフィルタリングとは、通信機器やコンピュータの持つネットワーク制御機能の一つで、外部から受信したデータを管理者が設定した一定の基準に従って通したり破棄したりすること
Berkeley Packet Filterとは、ユーザランドからのコードをカーネル内で安全に実行する為の仕組み

$ grep BPF /boot/config-`uname -r`
CONFIG_CGROUP_BPF=y
CONFIG_BPF=y
CONFIG_BPF_SYSCALL=y
CONFIG_BPF_JIT_ALWAYS_ON=y
CONFIG_NETFILTER_XT_MATCH_BPF=m
CONFIG_NET_CLS_BPF=m
CONFIG_NET_ACT_BPF=m
CONFIG_BPF_JIT=y
CONFIG_BPF_STREAM_PARSER=y
CONFIG_LWTUNNEL_BPF=y
CONFIG_HAVE_EBPF_JIT=y
CONFIG_BPF_EVENTS=y
CONFIG_TEST_BPF=m

#include 
#include 
#include 
#include 
#include "bpf_load.h"
#include "sock_example.h"
#include 
#include 

int main(int ac, char **argv){

	char filename[256];
	FILE *f;
	int i, sock;

	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);

	if(load_bpf_file(filename)){
		printf("%s", bpf_log_buf);
		return 1;
	}

	sock = open_raw_sock("lo");

	assert(setsockopt(sock, SQL_SOCKET, SO_ATTACH_BPF, prog_fd, sizeof(prog_fd[0])) == 0);

	f = popen("ping -c5 localhost", "r");
	(void) f;

	for(i = 0; i < 5; i++){
		long long tcp_cnt, udp_cnt, icmp_cnt;
		int key;

		key = IPPROTO_TCP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &tcp_cnt) == 0);

		key = IPPROTO_UDP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &udp_cnt) == 0);

		key = IPPROTO_ICMP;
		assert(bpf_map_lookup_elem(map_fd[0], &key, &icmp_cnt) == 0);

		printf("TCP %lld UDP %lld ICMP %lld bytes\n", tcp_cnt, udp_cnt, icmp_cnt);
		sleep(1);
	}

	return 0;
}

TCPとはIPと同様にインターネットにおいて標準的に利用されている プロトコル。TCPは、IPの上位プロトコルでトランスポート層で動作する。
ネットワーク層のIPとセッション層以上のプロトコル(HTTP、FTP、Telnetなど)の橋渡しをする

UDPはUser Datagram Protocolの略、アプリケーション同士が最小限の仕組みでデータを送受信するプロトコル、リアルタイム性が重要視される通信で使われる、送信者アドレスの偽装が容易であるためDNSなどを使ったDDoS攻撃で使われることも多い

ICMPはIPプロトコルの「エラー通知」や「制御メッセージ」を転送するためのプロトコル、TCP/IPが実装されたコンピュータ間で通信状態を確認するために使用

[C言語]バイナリファイル

0と1のビットの並びで表現されたファイルをバイナリファイルと呼ぶ。また、そのデータをバイナリデータと呼ぶ。
行を変えるという概念がない。

– エンディアン
2バイト以上あるデータをメモリ上に配置する時に、どのように並べるかというルールのことで、リトルエンディアンとビッグエンディアンがある。
「0x00 0x00 0x003 0x84」(ビッグエンディアン)と「0x84 0x003 0x00 0x00」(リトルエンディアン)
IntelのCPUはリトルエンディアン

#include <stdio.h>

int main(void){
	printf("%X\n", 'x');
	printf("%X\n", 'y');
	printf("%X\n", 'z');
}

– 読み書き
fopen関数に”b”を含む

#include
#include

int main(void){
FILE *fp = fopen(“test.bin”,”rb”);
if(fp == NULL){
fputs(“ファイルオープンに失敗しました。\n”, stderr);
exit(EXIT_FAILURE);
}

int num = 900;
double d = 7.85;
char str[] = “xyzxyz”;

if(fwrite(&num, sizeof(num), 1, fp) < 1){ fputs("1.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fwrite(&d, sizeof(d), 1, fp) < 1){ fputs("2.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fwrite(str, sizeof(str[0]),sizeof(str),fp) < sizeof(str)){ fputs("3.ファイル書き込みに失敗しました。\n", stderr); exit(EXIT_FAILURE); } if(fclose(fp) == EOF){ fputs("ファイルクローズに失敗しました。\n", stderr); exit(EXIT_FAILURE); } return 0; } [/code] $ ./test 1.ファイル書き込みに失敗しました。

[C言語]データベース

### 作り方
データを構造体配列にして検索で工夫する
データのレコードやデータベースの項目情報は動的メモリ確保されたメモリ領域にリスト構造で保持
そこから検索アルゴリズムでデータを取り出し、必要に応じてソート処理
データの保存・読み込みにはバイナリファイルの取り扱いノウハウが必要

### 必要知識
検索、リスト構造、ソート、ハッシュ、動的メモリ確保、バイナリファイルの取り扱い

### 構造体配列のサンプル

#include <stdio.h>

struct pop_dt {
	char region[20];
	long pop;
};

int main(void){

	struct pop_dt world[7] = {
		{"asia", 3769},
		{"north_america", 498},
		{"south_america", 357},
		{"europe", 725},
		{"africa", 832},
		{"oceania", 31},
		{"nowhere", 0}
	};

	int i;
	for(i=0; world[i].pop != 0; i++){
		printf("%-15s %6d\n", (world+i)->region, (world+i)->pop);
	}

	return 0;
}

$ ./main
asia 3769
north_america 498
south_america 357
europe 725
africa 832
oceania 31

一つの事をやろうとしたら、副次的に色々な事を学ばなければならない。その量がやたら多いように感じるのは実力がないからか。

[C言語]Webサーバー

IPv4とは?
-> データ通信規格。IPアドレスを32ビットのデータとして扱う
バイトストリームとは?
-> バイト単位のデジタルデータのひと続き

#include 
#include  // typedefシンボルおよび構造体のコレクションを定義
#include  // ソケットに使うためのヘッダファイル socket()
#include  // インターネット・プロトコル・ファミリーの定義


int main(void){

	int rsock, wsock;
	struct sockaddr_in addr, client;
	int len;
	int ret;

	// 通信をするためのソケット作成
	rsock = socket(AF_INET, SOCK_STREAM, 0); // AF_INETはIPv4接続、SOCK_STREAMはバイトストリーム

	if(rsock < 0){
		fprintf(stderr, "Error. Cannot make socket\n");
		return -1;
	}

	// socket設定
	addr.sin_family = AF_INET; // IPv4
	addr.sin_port = htons(8080); // 8080ポート
	addr.sin_addr.s_addr = INADDR_ANY;  // アドレス指定なし

	// binding socket
	bind(rsock, (struct sockaddr *)&addr, sizeof(addr));

	if(ret < 0){
		fprintf(stderr, "Error. Cannot bind socket\n");
		return -1;
	} 

	// socketの接続待ち
	listen(rsock, 5);

	// accept TCP connection from client
	len = sizeof(client);
	wsock = accept(rsock, (struct sockaddr *)&client, &len);

	// メッセージ送信
	write(wsock, "HTTP1.1 200 OK", 14);

	// TCPセッション終了
	close(wsock);
	close(rsock);

	return 0;
}

$ gcc -o main main.c
main.c: In function ‘main’:
main.c:43:2: warning: implicit declaration of function ‘write’; did you mean ‘fwrite’? [-Wimplicit-function-declaration]
write(wsock, "HTTP1.1 200 OK", 14);
^~~~~
fwrite
main.c:46:2: warning: implicit declaration of function ‘close’; did you mean ‘pclose’? [-Wimplicit-function-declaration]
close(wsock);
^~~~~
pclose

ソケットで通信していることはわかったが、よくわからん。

[Arduino]センサー等の種類

### Arduinoで使用できるセンサー等の種類
1.LED: ビジュアルアート、広告
1.7セグLED: 数字表現
2.赤外線: Rubyと合わせて赤外線リモコンなど
2.フォトリフレクタ: 物体があるかないかの判定、血流値の計測
3.光センサー(CdSセル):明るさに応じて抵抗値が変わる
4.温度センサー: 気温
5.湿度センサー: 湿度
6:モーター、モータードライバ: 動力系、ラジコン
7:超音波センサー: 物体との距離を計測
8:加速度センサー: 傾き、衝撃、振動
9:電圧スピーカー: 音
10:土壌センサー: 土の渇きを測定する
11.気圧センサー
12.地磁気センサー
13.近接照度センサー
14.カラーセンサー

### その他
1. 衣装の制御ボード: 2012紅白Perfume
2. イーサネットシールド: Webサーバなどネットワーク接続ができるようになる
3. SDカード
4. ソーラーパネル
5. OSC通信
6. WiFiモジュール
7. ステッピングモーター
8. ハンダ付け

なんだこれーーーーーーーーーーーーー
まだまだ絶対にやらなきゃいけない事たくさんあるのに、Arduinoだけでも、一通りマスターするのに1〜2年かかりそうじゃんか。。。🤮🤮🤮
甘く見過ぎてた、マジどうしよ。。 
結論は急がず、数日、よく考えよう。