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 프로그램으로 구현해도 되겠죠.
댓글 달기