We are trying to write a multi-threaded web server but we don't know how to get the file name from each of the HTTP requests (web pages) to a simple server. We are also concerned about the size of each of these files as well. Any idea?
Here is our main for the server.c file:
int main(int argc, char *argv[])
{
int listenfd, connfd, port, clientlen;
struct sockaddr_in clientaddr;
getargs(&port, argc, argv);
listenfd = Open_listenfd(port);
thread_pool_init();
for(;;){
pthread_mutex_lock(&pool_lock);
while(buf_count == request_limit)
pthread_cond_wait(&signal_worker, &pool_lock);
clientlen = sizeof(clientaddr);
connfd = Accept(listenfd, (SA *)&clientaddr, (socklen_t *) &clientlen);
//get/parse html file name here
//get file size using stat
put(connfd);
pthread_cond_signal(&signal_worker);
pthread_mutex_unlock(&pool_lock);
}
Our open_connection code in client.c which sends HTTP requests to the server.c file, looks like this :
void * open_connection( ){
clientfd = Open_clientfd(host, port);
clientSend(clientfd, filename);
pthread_mutex_lock(&lock);
clientPrint(clientfd);
pthread_mutex_unlock(&lock);
Close(clientfd);
sem_post(&cond);
return NULL;
}
//Send an HTTP request for the specified file
void clientSend(int fd, char *filename)
{
char buf[MAXLINE];
char hostname[MAXLINE];
Gethostname(hostname, MAXLINE);
//Form and send the HTTP request
sprintf(buf, "GET %s HTTP/1.1\n", filename);
sprintf(buf, "%shost: %s\n\r\n", buf, hostname);
Rio_writen(fd, buf, strlen(buf));
}
Once you receive the HTTP request you need to parse it to retrieve the name of the file requested and then send the file back to the client.
I post a simple code that can be used to handle HTTP request which I have used in one of my experiment. It is really simple, it does not take into account a lot of different characteristics of the HTTP protocol, basically it works only with GET request, but it may be a good starting point.
The recv_request is a function that reads the request from the socket used to communicate with the client.
#define PORT 80
#define WEBROOT "/var/www/localhost/htdocs/"
void handle_connection(int sockfd, struct sockaddr_in *client_addr_ptr) {
unsigned char *ptr, request[REQUEST], resource[REQUEST];
int fd, length;
memset(request, 0, REQUEST);
memset(resource, 0, REQUEST);
length = recv_request(sockfd, request);
printf("Got request from %s:%d lenght: %d \n", inet_ntoa(client_addr_ptr->sin_addr), ntohs(client_addr_ptr->sin_port),length);
puts("--------------------------------\n");
printf("%.*s", 500, request);
puts("--------------------------------");
ptr = strstr(request, " HTTP/"); // search for valid looking request
if(ptr == NULL) { // then this isn't valid HTTP
printf(" NOT HTTP!\n");
} else {
*ptr = 0; // terminate the buffer at the end of the URL
ptr = NULL; // set ptr to NULL (used to flag for an invalid request)
if(strncmp(request, "GET ", 4) == 0) // get request
ptr = request+4; // ptr is the URL
if(strncmp(request, "HEAD ", 5) == 0) // head request
ptr = request+5; // ptr is the URL
if(ptr == NULL) { // then this is not a recognized request
printf("\tUNKNOWN REQUEST!\n");
} else { // valid request, with ptr pointing to the resource name
if (ptr[strlen(ptr) - 1] == '/') // for resources ending with '/'
strcat(ptr, "index.html"); // add 'index.html' to the end
strcpy(resource, WEBROOT); // begin resource with web root path
strcat(resource, ptr); // and join it with resource path
fd = open(resource, O_RDONLY, 0); // try to open the file
printf("Opening \'%s\'\t", resource);
if(fd == -1) { // if file is not found
printf(" 404 Not Found\n");
send_string(sockfd, "HTTP/1.0 404 NOT FOUND\r\n");
send_string(sockfd, "Server: Tiny webserver\r\n\r\n");
send_string(sockfd, "<html><head><title>404 Not Found</title></head>");
send_string(sockfd, "<body><h1>URL not found</h1></body></html>\r\n");
} else { // otherwise, serve up the file
printf(" 200 OK\n\n");
send_string(sockfd, "HTTP/1.0 200 OK\r\n");
send_string(sockfd, "Server: Tiny webserver\r\n\r\n");
if(ptr == request + 4) { // then this is a GET request
if( (length = get_file_size(fd)) == -1)
fatal("getting resource file size");
if( (ptr = (unsigned char *) malloc(length)) == NULL)
fatal("allocating memory for reading resource");
read(fd, ptr, length); // read the file into memory
write(sockfd, ptr, length); // send it to socket
free(ptr); // free file memory
}
close(fd); // close the file
} // end if block for file found/not found
} // end if block for valid request
} // end if block for valid HTTP
shutdown(sockfd, SHUT_RDWR); // close the socket gracefully
return;
}
You should give a look at the curl library.
Related
Why does this code result in 301 error when trying to access sites that has a .net suffix
void test(const char * host, const char *index)
{
BIO *bio, *out;
SSL_CTX * ctx;
SSL * ssl;
int len;
char tmpbuf[1024];
ERR_load_crypto_strings();
char ready[1204];
char format[] = "%s:http";
sprintf(ready, format , host);
char req_template[] = "GET %s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n";
char ready_request[1024];
sprintf(ready_request , req_template , index, host);
const SSL_METHOD * method = SSLv23_client_method();
if (!method)
exit(-1);
ctx = SSL_CTX_new(method);
if (!ctx)
exit(-1);
if (!SSL_CTX_load_verify_locations(ctx,"/etc/ssl/certs/ca-certificates.crt","/etc/ssl/certs/"))
{
SSL_CTX_free(ctx);
exit(-1);
}
bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, &ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
char temp[1024];
sprintf(temp, "%s:https",host);
if (BIO_set_conn_hostname(bio, temp) < 0)
{
memset(temp, 0, sizeof(temp));
sprintf(temp, "%s:http", host);
bio = BIO_new_connect(temp);
if (BIO_do_connect(bio) < 0 )
{
BIO_free_all(bio);
SSL_CTX_free(ctx);
exit(-1);
}
}
printf("###\n%s\n###\n",ready_request);
out = BIO_new_fp(stdout, BIO_NOCLOSE);
if(BIO_do_connect(bio) <= 0)
exit(-1);
BIO_puts(bio,ready_request);
for(;;)
{
len = BIO_read(bio, tmpbuf, 1024);
if(len <= 0) break;
BIO_write(out, tmpbuf, len);
}
BIO_free(bio);
BIO_free(out);
}
int main()
{
test("openssl.org", "/docs/manpages.html");
test("pastebin.com", "/raw/j0BnRwBw");
test("pastebin.com", "/j0BnRwBw");
}
for some reason that i can't figure out the first time test is called it returns a 301 status code but the two time test is called it returns the html code or the paste code with out any problems
Does this have anything to do with the fact that the websites use different technologies or if they have some sort of firewall, I believe pastebin uses cloudflare to protect it self, I also tried using User-Agent but still got the same result
Just add www. as a prefix to the host header and for BIO_set_conn_hostname you should use the format www.<hostname>.com:https or www.<host>.org:http for BIO_new_connect
for some reason, the docs do not mention this
void test(const char * host, const char *index)
{
BIO *bio, *out;
SSL_CTX * ctx;
SSL * ssl;
int len;
char tmpbuf[1024];
ERR_load_crypto_strings();
char req_template[] = "GET %s HTTP/1.1\r\nHost: www.%s\r\nConnection: close\r\n\r\n";
char ready_request[1024];
sprintf(ready_request , req_template , index, host);
const SSL_METHOD * method = SSLv23_client_method();
if (!method)
exit(-1);
ctx = SSL_CTX_new(method);
if (!ctx)
exit(-1);
if (!SSL_CTX_load_verify_locations(ctx,"/etc/ssl/certs/ca-certificates.crt","/etc/ssl/certs/"))
{
SSL_CTX_free(ctx);
exit(-1);
}
bio = BIO_new_ssl_connect(ctx);
BIO_get_ssl(bio, &ssl);
SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
char temp[1024];
sprintf(temp, "www.%s:https",host);
if (BIO_set_conn_hostname(bio, temp) < 0)
{
memset(temp, 0, sizeof(temp));
sprintf(temp, "www.%s:http", host);
bio = BIO_new_connect(temp);
if (BIO_do_connect(bio) < 0 )
{
BIO_free_all(bio);
SSL_CTX_free(ctx);
exit(-1);
}
}
printf("###\n%s\n###\n",ready_request);
out = BIO_new_fp(stdout, BIO_NOCLOSE);
if(BIO_do_connect(bio) <= 0)
exit(-1);
BIO_puts(bio,ready_request);
for(;;)
{
len = BIO_read(bio, tmpbuf, 1024);
if(len <= 0) break;
BIO_write(out, tmpbuf, len);
}
BIO_free(bio);
BIO_free(out);
}
The first request https://openssl.org/docs/manpages.html returns:
HTTP/1.1 301 Moved Permanently
...
Location: https://www.openssl.org/docs/manpages.html
...
You make another request to that url. To demonstrate it working, I changed your first test case to read:
test("www.openssl.org", "/docs/manpages.html");
// ^^^^
and the server now returns the response you were expecting:
HTTP/1.1 200 OK
...
I'm trying to use snprintf to write a request string into the buffer. The first iteration works fine, however, after the second iteration it the beginning of the string disappears.
The function which write into the buffer
char* http_get_request(url_info *info) {
char * request_buffer = (char *) malloc(100 + strlen(info->path) + strlen(info->host)); //malloc spaces for the request buffer pointer
memset(request_buffer, 0, sizeof(*request_buffer));
puts("http get request req_buf address:");
printf("%p\n", request_buffer);
// puts(info->path);
// puts("INFO PATH ADDRESS:");
// printf("%p\n",&info->path);
snprintf(request_buffer, 1024, "GET /%s HTTP/1.1\r\nHost: %s\r\nConnection: close\r\n\r\n",
info->path, info->host); //writes: "GET <PATH> HTTP/1.1\r\nHost: <HOSTNAME>\r\nConnection: close\r\n\r\n" into the buffer
return request_buffer;
}
Relevant part of the download_page function:
puts("REQUEST BUFFER");
printf("%p\n",request_buffer);
puts(request_buffer);
//retrieve request string
if (connect(mysocket, ptr-> ai_addr, ptr-> ai_addrlen)){
fprintf(stderr, "Could not connect: %s\n", strerror(errno));
return -1;
}
send(mysocket, request_buffer, strlen(request_buffer), 0);
//between receiving data from the server and storing in the buffer
//Some aribitrary big number for length of data buffer written into file
shutdown(mysocket, SHUT_WR); //further transmissions disallowed
free(request_buffer);
Relevant part which iterates are keeps on generating new requests.
// Let's first isolate the first line of the reply
char *status_line = next_line(reply->reply_buffer, reply->reply_buffer_length);
if (status_line == NULL) {
fprintf(stderr, "Could not find status\n");
return 5;
}
*status_line = '\0'; // Make the first line is a null-terminated string
// Now let's read the status (parsing the first line)
int status;
double http_version;
int rv = sscanf(reply->reply_buffer, "HTTP/%lf %d", &http_version, &status);
if (rv != 2) { // if there are not two values http_version and status then return error.
fprintf(stderr, "Could not parse http response first line (rv=%d, %s)\n", rv, reply->reply_buffer);
return 6;
}
int i = 0;
struct http_reply newReply;
url_info info;
while (status == 301 && i < 5){
char *buf = status_line + 2;
char *start = strstr(buf,"Location: ") +10;
char *end = strchr(start, '\r');
size_t diff = end - start +1;
char newUrl[diff];
strncpy(newUrl, start, diff);
printf("New Url:\n%s\n",newUrl);
printf("info pointer: %p\n", &info);
int ret = parse_url(newUrl, &info);
if (ret) {
fprintf(stderr, "Could not parse URL '%s': %s\n", newUrl, parse_url_errstr[ret]);
return 2;
}
ret = download_page(&info, &newReply);
if (ret) {
return 3;
}
char *status_line = next_line(newReply.reply_buffer, newReply.reply_buffer_length);
if (status_line == NULL) {
fprintf(stderr, "Could not find status\n");
return 5;
}
*status_line = '\0'; // Make the first line is a null-terminated string
// Now let's read the status (parsing the first line)
int status;
double http_version;
int rv = sscanf(newReply.reply_buffer, "HTTP/%lf %d", &http_version, &status);
//write to the reply->reply_buffer a reply value.
//seperate the first line, the http reply, then the headers then adat.
if (rv != 2) { // if there are not two values http_version and status then return error.
fprintf(stderr, "Could not parse http response first line (rv=%d, %s)\n", rv, newReply.reply_buffer);
return 6;
}
i++;
if (status == 301){
free(newReply.reply_buffer);
}
}
//if there was at least one redirect,
if (i!=0){
reply = &newReply;
}
if (status != 200) {
fprintf(stderr, "Server returned status %d (should be 200)\n", status);
return 0;
}
//check status redirect, send to the new location.
char *buf = status_line + 2;
char *ptr = reply->reply_buffer;
while(1 == 1){
status_line = next_line(ptr, reply->reply_buffer_length);
buf = status_line +2;
if (ptr+ 2 == buf) break;
ptr = buf;
}
write_data(file_name, buf, reply->reply_buffer + reply->reply_buffer_length - buf);
return 0;
}
This is the output:
Yis-MacBook-Pro:ex05-sockets yao$ ./wgetX http://redirect.epizeuxis.net/make
http get request req_buf address:
0x7fac3e6063c0
REQUEST BUFFER
0x7fac3e6063c0
GET /make HTTP/1.1
Host: redirect.epizeuxis.net
Connection: close
New Url:
http://info.cern.ch/
info pointer: 0x7ffee495a7e0
http get request req_buf address:
0x7fac3e6063c0
REQUEST BUFFER
0x7fac3e6063c0
HTTP/1.1
Host: info.cern.ch
Connection: close
New Url:
http://info.cern.ch/
info pointer: 0x7ffee495a7e0
http get request req_buf address:
0x7fac3e50fe70
REQUEST BUFFER
0x7fac3e50fe70
HTTP/1.1
Host: info.cern.ch
Connection: close
New Url:
http://info.cern.ch/
info pointer: 0x7ffee495a7e0
http get request req_buf address:
0x7fac3fa04080
REQUEST BUFFER
0x7fac3fa04080
HTTP/1.1
Host: info.cern.ch
Connection: close
New Url:
http://info.cern.ch/
info pointer: 0x7ffee495a7e0
http get request req_buf address:
0x7fac3e6063c0
REQUEST BUFFER
0x7fac3e6063c0
HTTP/1.1
Host: info.cern.ch
Connection: close
for one of my university courses I must realize a simple chat program in C that uses UDP Client-Server, this is the description that the teacher sent us:
You should develop a private chat environment to exchange
text messages between hosts. Message encryption is optional but not required.
The project should be composed by 2 main modules:
Server: receives and stores each message in a sort of chat database.
A very naive database would consist in a User struct,
that contains everything (login credentials, chats, ...).
Each Chat structure contains the actual messages.
Client: provides a very simple interface to select a
receiver for our message and then write the content of the message.
Login is required. If a receiver is not subscribed returns an error.
The project should be tested with at least 3 users :)
I managed to implement the authentication phase but then when trying to implement the message exchange phase I got stuck. When I try to send the linked_list of online users from the Server to the Client the execution freezes and not only that but it gives somewhat of random behavior, sometimes gets stuck on the first try sometimes on the second and so on. I also noticed that when I introduced a separated thread in the Client to handle the inbox of messages the situation got worst getting stuck more often then before. I will add the code of the functions responsible of sending and receiving the online users and also the link to my git repo where if you want you can find the complete code.
This is the code in the Server:
void Send_list(ListHead* head, int sockfd,struct sockaddr_in cliaddr, int size){
int written_bytes;
int len = sizeof(cliaddr);
char username[50];
if(head->size == 1){
return;
}
ListItem* aux = head->first;
for(int i=0;i<size;i++){
memset(username,0,sizeof(username));
UserListItem* uitem = (UserListItem*) aux;
strcpy(username,uitem->user.username);
do{
written_bytes = 0;
written_bytes = sendto(sockfd,(const char *)username,strlen(username),0,(const struct sockaddr*)&cliaddr,len);
}while(written_bytes != strlen(username));
printf("\nusername mandato: %s",username);
printf("\n");
if(aux->next){
aux = aux->next;
}
}
}
And this is the code in the Client:
int recv_list(int sockfd,struct sockaddr_in servaddr, ListHead* head,int size, char username[50]){
char onuser[50];
int len = sizeof(servaddr);
int read_bytes;
int idx = 1;
if(size == 1){
return 1;
}
for(int i=0;i<size;i++){
read_bytes = recvfrom(sockfd,(char *)onuser,sizeof(onuser),0,(struct sockaddr*)&servaddr,&len );
onuser[read_bytes] = '\0';
if(List_find_by_username(head,onuser) == 0 || strcmp(onuser,username)){
UserListItem* uitem = malloc(sizeof(UserListItem));
memset(uitem,0,sizeof(UserListItem));
UList_init(uitem,onuser);
uitem->idx = idx++;
ListItem* result = List_insert(head,head->last,(ListItem*)uitem);
assert(result);
}
memset(onuser,0,sizeof(onuser));
}
UserList_print(head);
return 0;
}
And this is the link to my git repo: https://gitlab.com/antonio_ciprani/so-progetto-20_21
I work in an Ubuntu based system.
I really hope that somebody can help me because this is driving me crazy :(
I also noticed that when I introduced a separated thread in the Client to handle the inbox of messages the situation got worst getting stuck more often then before.
Indeed the use of threads in your program does more harm than good. Especially that in the main loop you pthread_create a new reciving thread, which competes with the main thread for the incoming messages, disrupts the course of recv_list. Better don't use threads for your project - you'll avoid a lot of problems.
Let's first write two helper functions:
void store(thread_args_t *targs, Message *msg)
{ // code taken from your function "reciving"
if (!strcmp(targs->user->username, msg->reciver))
{
Inbox *mitem = malloc(sizeof (Inbox));
strcpy(mitem->msg.sender, msg->sender);
strcpy(mitem->msg.reciver, msg->reciver);
strcpy(mitem->msg.data, msg->data);
ListItem *result =
List_insert(targs->inbox, targs->inbox->last, (ListItem *)mitem);
assert(result);
}
}
char *input(thread_args_t *targs)
{ // wait for user input and store incoming messages
fflush(stdout);
fd_set fds, fdr;
FD_ZERO(&fds);
FD_SET(0, &fds); // add STDIN to the fd set
FD_SET(targs->sockfd, &fds); // add socket to the fd set
for (; ; )
{
if (fdr = fds, select(targs->sockfd+1, &fdr, NULL, NULL, NULL) < 0)
perror("select"), exit(1);
if (FD_ISSET(0, &fdr))
{ // this is the user's input
static char data[256];
if (!fgets(data, sizeof data, stdin)) return NULL; // no more user input
data[strlen(data)-1] = '\0';
return data;
}
// if no user input, then there's a message
Message msg;
socklen_t len = sizeof targs->servaddr;
if (recvfrom(targs->sockfd, &msg, sizeof msg, 0,
(struct sockaddr *)targs->servaddr, &len) < 0)
perror("recvfrom"), exit(1);
store(targs, &msg);
}
}
Now you can replace the main loop body in main with this:
int ret, op;
printf("\nPlease choose an option: ");
printf("\n1.Send a message!");
printf("\n2.Incoming messages!");
printf("\n3.Logout!");
printf("\nYour choice:\t");
char *str = input(&targs);
sscanf(str, "%d", &ret);
printf("\nqua bro?\n");
if (ret == 1)
{
printf("\nqua loz?\n");
int res, read_bytes, size, id;
op = 3;
socklen_t len = sizeof servaddr;
sendto(sockfd, &op, sizeof op, MSG_CONFIRM,
(struct sockaddr *)&servaddr, len);
printf("\nqua shiiis?\n");
// We cannot preclude that a message arrives here,
// therefore we must handle that case.
Message msg;
while ((read_bytes = recvfrom(sockfd, &msg, sizeof msg, 0,
(struct sockaddr *)&servaddr,
&len)) == sizeof msg)
store(&targs, &msg);
if (read_bytes == -1) perror("recvfrom"), exit(1);
size = *(int *)&msg;
printf("\nqua ci siamo?\n");
res = recv_list(sockfd, servaddr, &on_list, size, user.username);
printf("\nqua?\n");
if (res == 0)
{
printf("\nChoose whom you want to send a message to");
printf("\nYour choice:\t");
str = input(&targs);
sscanf(str, "%d", &id);
printf("\nWrite the message you want to send:\n");
str = input(&targs);
Init_msg(&msg, str, id, &on_list, user.username);
int written_bytes = sendto(sockfd, &msg, sizeof msg, MSG_CONFIRM,
(struct sockaddr *)&servaddr, len);
if (written_bytes == -1) perror("sendto"), exit(1);
// With your present server, a message cannot arrive here, but you
// possibly will want to change that, so let's handle it already.
while ((read_bytes = recvfrom(sockfd, &msg, sizeof msg, 0,
(struct sockaddr *)&servaddr,
&len)) == sizeof msg)
store(&targs, &msg);
if (read_bytes == -1) perror("recvfrom"), exit(1);
int sent = *(int *)&msg;
if (sent == 0) printf("\nMessage sent!");
else
if (sent == 1) printf("\nUser is offline :(");
}
else
if (res == 1) printf("\nNo online user :(");
}
else
if (ret == 2) Print_msg(&inbox);
The next thing you possibly want to improve is modifying the server function Forward_message so that it allows for incoming commands from another client while waiting for a message.
I have the following code, and I am getting SIGSEGV on the line:
if ( SSL_connect(ssl) == FAIL )
The fault Im getting is:
Program received signal SIGSEGV, Segmentation fault.
0x00007ffffe5a41e0 in __GI___libc_malloc (bytes=104) at malloc.c:2926
2926 malloc.c: No such file or directory.
The program basically is designed to take loads of data and push it into firebase.
The first one element, is to check if we are registered, the next bit is to actually do the registration.
Cutting the program back to basics, we have the following opening gambit:
int main(int argc, char *argv[]) {
int iRegistered = checkRegistered();
int result = registerCar();
}
If we swap those two lines, so we register before we check the registration, then we don't get a SIGSEGV.
Here's the checkRegistration function:
int checkRegistered() {
int firebaseRegistered = 0;
char *carId;
carId = (char *) malloc(256);
strcpy(carId, "aabbccddeeffgg" );
char *payload;
payload = (char *) malloc(1024);
sprintf(payload, "{ \"carid\": \"%s\" }", carId);
char *response;
response = (char *) malloc(1024);
int result = firebase("isCarRegistered", payload, &response);
if (result == 0) {
// Process JSON Response
cJSON *json = cJSON_Parse(response);
if (json == NULL) {
//
} else {
cJSON *json_registered = NULL;
json_registered = cJSON_GetObjectItemCaseSensitive(json, "registered");
firebaseRegistered = json_registered->valueint;
}
}
free(response);
free(payload);
free(carId);
return firebaseRegistered;
}
And the registerCar function.
They're basically mostly the same format - construct a message, send it to firebase, process the JSON response. We use cJSON to decompile the data returned from Firebase, though we could potentially use it to also compile. But one thing at a time.
You'll see a number of free() statements - I've been trying to work out how best to complete this - ie, generate a char* locally, pass by reference ** to a function, let the function perform the malloc/realloc based on the sizes it can calculate and then we can free it from the calling code once we have dealth with the data. Though I also get a SIGSEGV from that as well.
int registerCar() {
int iResponse = 0;
char *carId;
carId = (char *) malloc(256);
char *authCode;
authCode = (char *) malloc(12);
char *payload;
payload = (char *) malloc(1024);
sprintf(payload, "{ }");
char *response;
response = (char *) malloc(1024);
int result = firebase("registerCar", payload, &response);
if (result == 0) {
// Process JSON Response
cJSON *json = cJSON_Parse(response);
if (json == NULL) {
//
} else {
cJSON *json_auth = NULL;
cJSON *json_car = NULL;
json_auth = cJSON_GetObjectItemCaseSensitive(json, "authcode");
json_car = cJSON_GetObjectItemCaseSensitive(json, "carid");
iResponse = 1;
}
}
free(response);
free(payload);
return iResponse;
}
Here's the firebase routine, it takes a function, a payload and generates a response. Interestingly here, char firebaseLocal and charfirebaseMessage is not always null before the initial malloc.
int firebase(char *firebaseFunction, char *firebasePayload, char **firebaseResponse) {
char buf[1024];
char *firebaseLocal;
char *firebaseMessage;
firebaseMessage = (char *) malloc(1024);
SSL_CTX *ctx;
int server;
SSL *ssl;
int bytes;
ctx = InitCTX();
server = OpenConnection(HOST, atoi(PORT));
ssl = SSL_new(ctx); /* create new SSL connection state */
SSL_set_fd(ssl, server); /* attach the socket descriptor */
if ( SSL_connect(ssl) == FAIL ) /* perform the connection */
ERR_print_errors_fp(stderr);
else {
ShowCerts(ssl); /* get any certs */
char *firebasePost;
generatePostMessage(firebaseFunction, firebasePayload, &firebasePost);
SSL_write(ssl, firebasePost, strlen(firebasePost));
bytes = SSL_read(ssl, buf, sizeof(buf)); /* get reply & decrypt */
buf[bytes] = 0;
//SSL_free(ssl); /* release connection state */
strcpy(firebaseMessage, buf);
firebaseLocal = strstr(firebaseMessage, "\r\n\r\n");
if (firebaseLocal != NULL) {
firebaseLocal +=4;
}
strcpy(*firebaseResponse, firebaseLocal);
}
free(firebaseMessage);
close(server); /* close socket */
SSL_CTX_free(ctx); /* release context */
return 0;
}
This is from an implementation I found on secure sockets.
int OpenConnection(const char *hostname, int port)
{ int sd;
struct hostent *host;
struct sockaddr_in addr;
if ( (host = gethostbyname(hostname)) == NULL )
{
perror(hostname);
abort();
}
sd = socket(PF_INET, SOCK_STREAM, 0);
bzero(&addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
addr.sin_addr.s_addr = *(long*)(host->h_addr);
if ( connect(sd, (struct sockaddr*)&addr, sizeof(addr)) != 0 )
{
close(sd);
perror(hostname);
abort();
}
return sd;
}
This is from an implementation I found on secure sockets.
SSL_CTX* InitCTX(void)
{
SSL_METHOD *method;
SSL_CTX *ctx;
SSL_library_init();
OpenSSL_add_all_algorithms(); /* Load cryptos, et.al. */
SSL_load_error_strings(); /* Bring in and register error messages */
method = TLSv1_2_client_method(); /* Create new client-method instance */
ctx = SSL_CTX_new(method); /* Create new context */
if ( ctx == NULL )
{
ERR_print_errors_fp(stderr);
abort();
}
return ctx;
}
This is from an implementation I found on secure sockets.
void ShowCerts(SSL* ssl)
{ X509 *cert;
char *line;
cert = SSL_get_peer_certificate(ssl); /* get the server's certificate */
if ( cert != NULL )
{
printf("Server certificates:\n");
line = X509_NAME_oneline(X509_get_subject_name(cert), 0, 0);
printf("Subject: %s\n", line);
free(line); /* free the malloc'ed string */
line = X509_NAME_oneline(X509_get_issuer_name(cert), 0, 0);
printf("Issuer: %s\n", line);
free(line); /* free the malloc'ed string */
X509_free(cert); /* free the malloc'ed certificate copy */
}
else
printf("Info: No client certificates configured.\n");
}
This is something that I wrote to generate a post message from message
void generatePostMessage(char *firebaseFunction, char *firebaseMessage, char **response) {
int intPayloadSize = strlen(firebaseMessage);
char *charPayloadSize;
charPayloadSize = (char *) malloc(8);
sprintf(charPayloadSize, "%d", intPayloadSize);
char *postmessage = "POST /%s HTTP/1.1\r\n"
"Host: us-central1-carconnect-e763e.cloudfunctions.net\r\n"
"User-Agent: USER_AGENT\r\n"
"Content-Type: application/json\r\n"
"Accept: text/plain\r\n"
"Content-Length: %d\r\n\r\n"
"%s";
// Allocate size of postmessage less the inserts, plus the payload size, plus the payload size digits, plus null
int responseLength = (strlen(postmessage) - 4) + intPayloadSize + strlen(charPayloadSize)+1;
// Round up Four Bytes.
int responseIncrease = responseLength % 4;
if (responseIncrease > 0) {
responseLength += (4 - responseIncrease);
}
*response = (char *) malloc(responseLength);
sprintf(*response, postmessage, firebaseFunction, intPayloadSize, firebaseMessage);
}
As advised, whether the registration or registration check is called first, the first call works fine.
If I perform the registration before the check, then both commands work fine. Further testing also does confirm the problem is the registration check. I can perform registration several times without fail. The registration check and any follow up calls fail completely at the SSL_connect line. I don't know why.
The SSL_free command in the firebase connection always fails. I also get a SIGSEGV if I try to free(firebasePost) after the SSL_Write - which suggests I cannot free a pointer that has been passed by reference and mallocced in a function.
Part of me wonders whether any of this is caused by the fact Im debugging on Windows. I've always had problems with malloc() on Windows just not working the way I would expect.
The problem, or at least one of them, is in generatePostMessage. Not enough buffer is allocated for response. sprintf will then run off the end of the allocated buffer and cause heap corruption, which manifests itself on next invocation of malloc. Try:
int responseLength = strlen(firebaseFunction) + (strlen(postmessage) - 4) + intPayloadSize + strlen(charPayloadSize)+1;
I am doing a class project right now and it requires me to send data and image using socket. So far I have finished most of it. Data gets sent correctly, small images get sent correctly, but when it comes to large images, only half of it is shown. I checked the characters sent and all of them got sent. So I am not sure where I got wrong. This my function to handle get request. I have tested sending data and it worked, so I think most of this function works but probably just some small details I missed. Please help...thanks!
void handle_get(int sock, const char* url) {
FILE* pFILE;
int file, i;
//file = open(url, O_RDONLY);
pFILE = fopen(++url, "r");
char response_message[1024];
char buffer[1024];
char c;
char *header_type, *file_type;
long file_size;
//char *buffer;
if (pFILE == NULL){
snprintf (response_message, sizeof (response_message), not_found_response_template, url);
write (sock, response_message, strlen (response_message));
error("ERROR opening requested file");
}
file_type = strrchr (url, '.');
//return pointer to the last occurrance of '.'
if (!file_type)
file_type = "html";
else
file_type++;
if (strcasecmp (file_type, "jpg") == 0 || strcasecmp (file_type, "jpeg") == 0)
header_type = "image/jpeg";
else if (strcasecmp (file_type, "gif") == 0)
header_type = "image/gif";
else if (strcasecmp (file_type, "png") == 0)
header_type = "image/png";
else
header_type = "text/html";
snprintf (response_message, sizeof (response_message), ok_response, header_type);
write (sock, response_message, strlen (response_message));
puts(response_message);
int n = 0;
bzero(buffer, 1024);
while (n=fread(buffer, sizeof(char), 1024, pFILE)){
printf("n is %d\n", n);
send (sock, buffer, n, 0);
//write(sock, buffer, n);
bzero(buffer, 1024);
}
fclose (pFILE);
}