fcm 오픈소스에 관해 질문드립니다
c++에서 fcm 서버로 푸쉬메시지를 보내고 싶어서 찾던 중 오픈소스를 발견하였습니다
오픈소스의 내용은 함수 하나가 정의되어 있었습니다.
해당 함수를 호출하여 fcm서버로 메시지를 보내는것 같습니다.
bool send_a_push_notification(const string &gcm_key, const string *node_id, const string &payload, int type)
위의 함수에서 gcm_key는 api key인것 같고..payload는 보여줄 메시지인것 같고
나머지를 모르겠습니다...
혹시 몰라서 오픈소스도 같이 올립니다.
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "openssl/ssl.h"
#include "openssl/err.h"
#include "openssl/opensslconf.h"
// for convenience
using json = nlohmann::json;
void close_ssl(SSL *ssl , int fd){
	close(fd);
	SSL_shutdown(ssl);
	SSL_free(ssl);
	server_logger->info("Closing ssl: {}", fd);
}
bool send_a_push_notification(const string &gcm_key, const string *node_id, const string &payload, int type){
	if(gcm_key.empty()) return false;
	struct addrinfo hints, *result, *p;
	int ret;
	int fd = -1;
	memset(&hints, 0, sizeof(hints));
	hints.ai_family = AF_UNSPEC;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_flags = AI_NUMERICSERV;
	if ((ret = getaddrinfo("fcm.googleapis.com", "443", &hints, &result)) != 0){
	  server_logger->error("getaddrinfo failed for fcm {}", "fcm");
	  return false;
	}
//	https://fcm.googleapis.com/fcm/send
//	Content-Type:application/json
//	Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA
	for(p = result; p != NULL; p = p->ai_next){
		fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol);
		if (fd <0) { continue; }
		if (connect(fd, p->ai_addr, p->ai_addrlen)==0) {
			//print_addr_info(p);
			break;
		}
		close(fd);
		fd = -1;
	}
	freeaddrinfo(result);
	if(fd==-1){
		server_logger->error("failed to create connection to fcm");
		return false;
	}
	/*
	 * create auth_key from node id
	 */
	SSL* ssl = SSL_new(client_ssl_ctx);						/* create new SSL connection state */
	SSL_set_fd(ssl, fd);
	unique_ptr > fd_auto_close( ssl , boost::bind(&close_ssl, boost::placeholders::_1, fd ));//auto close on loop exit
	if(SSL_connect(ssl)<0){
		return false;
	}
	X509 *cert = SSL_get_peer_certificate(ssl);
	if(!cert){
		return false;
	}
	X509_free(cert);//i don't know why i am doing this
	//websocket headers
	char headers[1024];
	size_t s=0;
	memcpy(headers, "POST /fcm/send HTTP/1.1\r\n",25);s+=25;
	memcpy(headers+s, "Content-Type: application/json\r\n", 32);s+=32;
	memcpy(headers+s, "Connection: close\r\n", 19); s+=19;
	memcpy(headers+s, "Host: fcm.googleapis.com\r\n", 26); s+=26;
	memcpy(headers+s, "Authorization: key=", 19);s+=19;
	memcpy(headers+s, &(gcm_authorization_key)[0], gcm_authorization_key.length());s+=gcm_authorization_key.length();
	memcpy(headers+s, "\r\n", 2);s+=2;
	json data = {
			{"to", gcm_key},
			{"data", {
					{"type", type},
					{"payload",payload}
				}
			},
			{"notification", {
						{"body" ,payload},
						{"title" , "Message"}
					}
			}
	};
string json_data = data.dump();
	char content_length[10];
	int n_digits = itoa(json_data.length(), content_length, 10);
	memcpy(headers+s, "Content-Length: ", 16);s+=16;
	memcpy(headers+s, content_length, n_digits);s+=n_digits;
	memcpy(headers+s, "\r\n\r\n", 4);s+=4;
memcpy(headers+s, &json_data[0], json_data.length());s+=json_data.length();
	ssize_t headers_written =0;
	ERR_clear_error();
	while((headers_written = SSL_write(ssl, headers, s))<0){
		int ssl_err = SSL_get_error(ssl,headers_written);
		if((ssl_err == SSL_ERROR_WANT_WRITE || ssl_err == SSL_ERROR_WANT_READ)){
			//connection negotiation issues, connection in pending state.
			ERR_clear_error();
			continue;
		}
		break;
	}
	if(headers_written==s){
		//read the data from socket
		unique_ptr > header_buff( (char*)mem_recycler.get(2048) , boost::bind(&MemRecycler::recyle, &mem_recycler, boost::placeholders::_1, 2048));
		int pret;
		struct phr_header headers[100];
		size_t buflen = 0, prevbuflen = 0, method_len, num_headers;
		int minor_version;
		int status;
		const char *msg_buf;
		size_t msg_buf_len;
		while (true) {
				/* read the request */
				ERR_clear_error();
				ssize_t bytes_read = SSL_read( ssl, header_buff.get() + buflen, 2048-buflen );
				if (bytes_read <= 0){
					if(errno!=LIBCO_POLL_TIMEOUT){
						//ssl related error , handshaking in between
						int ssl_err = SSL_get_error(ssl,bytes_read);
						if((ssl_err == SSL_ERROR_WANT_WRITE || ssl_err == SSL_ERROR_WANT_READ)){
							//connection negotiation issues, connection in pending state.
							continue;
						}
					}
					// even if timeout , we break , because it should respond in timeout
					break;
				}
				prevbuflen = buflen;
				buflen+=bytes_read;
				/* parse the request */
				num_headers = sizeof(headers) / sizeof(headers[0]);
				pret = phr_parse_response(header_buff.get(), buflen, &minor_version , &status, &msg_buf, &msg_buf_len,
										headers, &num_headers, prevbuflen);
				if (pret > 0)
					break; /* successfully parsed the request */
				else if (pret == -1){
					break;
				}
				if (buflen >= 2048){
					break;
				}
				//pret == -2 continue looping.
		}
		if(pret>0){
			return true;
		}
		return false;
	}
	return false;
}


fcm을 직접 구현하시려면 굉장히 까다로우실 겁니다.
fcm을 직접 구현하시려면 굉장히 까다로우실 겁니다.
여건이 되신다면 curl 같은거로 fcm 요청을 호출하시는게 휠씬 간단하실 겁니다.
* http://www.irgroup.org/fcm-app-server-1/
* https://riptutorial.com/ko/firebase-cloud-messaging/example/26480/curl%EC%9D%84-%ED%86%B5%ED%95%B4-%EB%8B%A4%EC%9A%B4-%EC%8A%A4%ED%8A%B8%EB%A6%BC-%EB%A9%94%EC%8B%9C%EC%A7%80-%EB%B3%B4%EB%82%B4%EA%B8%B0
* https://blog.mestwin.net/send-your-test-fcm-push-notification-quickly-with-curl/
답변감사드립니다.
초보라서 잘모르겠습니다..
c++에서 curl이라는 것이 가능한것인가요?
curl에 대해 간략히 설명부탁드려도 될까요?
위 소스 코드가 하는 일은 https(http가 아닌
위 소스 코드가 하는 일은 https(http가 아닌) 요청을 하는 소스 코드입니다.
즉, fcm 이라는 것은 특정한/정해진 packet을 https로 요청하면 되는겁니다.
curl은 https 호출해 주는 console 프로그램입니다.
fcm과 curl로 검색을 해 보시면 curl로 fcm을 테스트하는 예제들이 꽤 있을 겁니다.
그렇게 테스트를 한 후에, 직접(소스 코딩) https 호출을 socket 프로그램으로 구현해도 되겠죠.
댓글 달기