| #include?<stdio.h> #include?<stdlib.h> #include?<errno.h> #include?<string.h> #include?<sys/types.h> #include?<netinet/in.h> #include?<sys/socket.h> #include?<sys/wait.h> #include?<unistd.h> #include?<arpa/inet.h> #include?<openssl/ssl.h> #include?<openssl/err.h> #define?MAXBUF 1024 int?main(int?argc,?char?**argv) { ????int?sockfd,?new_fd; ????socklen_t?len; ????struct?sockaddr_in?my_addr,?their_addr; ????unsigned?int?myport,?lisnum; ????char?buf[MAXBUF?+?1]; ????SSL_CTX?*ctx; ????if?(argv[1]) ????????myport?=?atoi(argv[1]); ????else ????????myport?=?7838; ????if?(argv[2]) ????????lisnum?=?atoi(argv[2]); ????else ????????lisnum?=?2; ????/* SSL 庫初始化 */ ????SSL_library_init(); ????/* 載入所有 SSL 算法 */ ????OpenSSL_add_all_algorithms(); ????/* 載入所有 SSL 錯誤消息 */ ????SSL_load_error_strings(); ????/* 以 SSL V2 和 V3 標準兼容方式產生一個 SSL_CTX ,即 SSL Content Text */ ????ctx?=?SSL_CTX_new(SSLv23_server_method()); ????/* 也可以用 SSLv2_server_method() 或 SSLv3_server_method() 單獨表示 V2 或 V3標準 */ ????if?(ctx?==?NULL)?{ ????????ERR_print_errors_fp(stdout); ????????exit(1); ????} ????/* 載入用戶的數字證書, 此證書用來發送給客戶端。 證書里包含有公鑰 */ ????if?(SSL_CTX_use_certificate_file(ctx,?argv[3],?SSL_FILETYPE_PEM)?<=?0)?{ ????????ERR_print_errors_fp(stdout); ????????exit(1); ????} ????/* 載入用戶私鑰 */ ????if?(SSL_CTX_use_PrivateKey_file(ctx,?argv[4],?SSL_FILETYPE_PEM)?<=?0)?{ ????????ERR_print_errors_fp(stdout); ????????exit(1); ????} ????/* 檢查用戶私鑰是否正確 */ ????if?(!SSL_CTX_check_private_key(ctx))?{ ????????ERR_print_errors_fp(stdout); ????????exit(1); ????} ????/* 開啟一個 socket 監聽 */ ????if?((sockfd?=?socket(PF_INET,?SOCK_STREAM,?0))?==?-1)?{ ????????perror("socket"); ????????exit(1); ????}?else ????????printf("socket created\n"); ????bzero(&my_addr,?sizeof(my_addr)); ????my_addr.sin_family?=?PF_INET; ????my_addr.sin_port?=?htons(myport); ????my_addr.sin_addr.s_addr?=?INADDR_ANY; ????if?(bind(sockfd,?(struct?sockaddr?*)?&my_addr,?sizeof(struct?sockaddr)) ????????==?-1)?{ ????????perror("bind"); ????????exit(1); ????}?else ????????printf("binded\n"); ????if?(listen(sockfd,?lisnum)?==?-1)?{ ????????perror("listen"); ????????exit(1); ????}?else ????????printf("begin listen\n"); ????while?(1)?{ ????????SSL?*ssl; ????????len?=?sizeof(struct?sockaddr); ????????/* 等待客戶端連上來 */ ????????if?((new_fd?= ?????????????accept(sockfd,?(struct?sockaddr?*)?&their_addr, ????????????????????&len))?==?-1)?{ ????????????perror("accept"); ????????????exit(errno); ????????}?else ????????????printf("server: got connection from %s, port %d, socket %d\n", ???????????????????inet_ntoa(their_addr.sin_addr), ???????????????????ntohs(their_addr.sin_port),?new_fd); ????????/* 基于 ctx 產生一個新的 SSL */ ????????ssl?=?SSL_new(ctx); ????????/* 將連接用戶的 socket 加入到 SSL */ ????????SSL_set_fd(ssl,?new_fd); ????????/* 建立 SSL 連接 */ ????????if?(SSL_accept(ssl)?==?-1)?{ ????????????perror("accept"); ????????????close(new_fd); ????????????break; ????????} ????????/* 開始處理每個新連接上的數據收發 */ ????????bzero(buf,?MAXBUF?+?1); ????????strcpy(buf,?"server->client"); ????????/* 發消息給客戶端 */ ????????len?=?SSL_write(ssl,?buf,?strlen(buf)); ????????if?(len?<=?0)?{ ????????????printf ????????????????("消息'%s'發送失敗!錯誤代碼是%d,錯誤信息是'%s'\n", ?????????????????buf,?errno,?strerror(errno)); ????????????goto?finish; ????????}?else ????????????printf("消息'%s'發送成功,共發送了%d個字節!\n", ???????????????????buf,?len); ????????bzero(buf,?MAXBUF?+?1); ????????/* 接收客戶端的消息 */ ????????len?=?SSL_read(ssl,?buf,?MAXBUF); ????????if?(len?>?0) ????????????printf("接收消息成功:'%s',共%d個字節的數據\n", ???????????????????buf,?len); ????????else ????????????printf ????????????????("消息接收失敗!錯誤代碼是%d,錯誤信息是'%s'\n", ?????????????????errno,?strerror(errno)); ????????/* 處理每個新連接上的數據收發結束 */ ??????finish: ????????/* 關閉 SSL 連接 */ ????????SSL_shutdown(ssl); ????????/* 釋放 SSL */ ????????SSL_free(ssl); ????????/* 關閉 socket */ ????????close(new_fd); ????} ????/* 關閉監聽的 socket */ ????close(sockfd); ????/* 釋放 CTX */ ????SSL_CTX_free(ctx); ????return?0; } |