I'm trying to write a simple client in C that will interface with the Google Search API and return search results. I am able to send a search request and get a response back with a 200 OK code and some header text, but there are no search results. Am I doing something wrong?
Here is my code:
#include sys/socket.h
#include sys/types.h
#include netinet/in.h
#include netdb.h
#include stdio.h
#include string.h
#include stdlib.h
#include unistd.h
#include errno.h
#include openssl/rand.h
#include openssl/ssl.h
#include openssl/err.h
// Simple structure to keep track of the handle, and
// of what needs to be freed later.
typedef struct {
int socket;
SSL *sslHandle;
SSL_CTX *sslContext;
} connection;
// For this example, we'll be testing on openssl.org
#define KEY "/customsearch/v1?key=AIzaSyAOdB5MgAEmvzglw05rR1OPYEYgFuZrT9o&cx=003397780648636422832:u25rx3s92ro&q="
#define SERVER "www.googleapis.com"
#define PORT 443
// Establish a regular tcp connection
int tcpConnect ()
{
int error, handle;
struct hostent *host;
struct sockaddr_in server;
host = gethostbyname (SERVER);
handle = socket (AF_INET, SOCK_STREAM, 0);
if (handle == -1)
{
perror ("Socket");
handle = 0;
}
else
{
server.sin_family = AF_INET;
server.sin_port = htons (PORT);
server.sin_addr = *((struct in_addr *) host->h_addr);
bzero (&(server.sin_zero), 8);
error = connect (handle, (struct sockaddr *) &server,
sizeof (struct sockaddr));
if (error == -1)
{
perror ("Connect");
handle = 0;
}
}
return handle;
}
// Establish a connection using an SSL layer
connection *sslConnect (void)
{
connection *c;
c = malloc (sizeof (connection));
c->sslHandle = NULL;
c->sslContext = NULL;
c->socket = tcpConnect ();
if (c->socket)
{
// Register the error strings for libcrypto & libssl
SSL_load_error_strings ();
// Register the available ciphers and digests
SSL_library_init ();
// New context saying we are a client, and using SSL 2 or 3
c->sslContext = SSL_CTX_new (SSLv23_client_method ());
if (c->sslContext == NULL)
ERR_print_errors_fp (stderr);
// Create an SSL struct for the connection
c->sslHandle = SSL_new (c->sslContext);
if (c->sslHandle == NULL)
ERR_print_errors_fp (stderr);
// Connect the SSL struct to our connection
if (!SSL_set_fd (c->sslHandle, c->socket))
ERR_print_errors_fp (stderr);
// Initiate SSL handshake
if (SSL_connect (c->sslHandle) != 1)
ERR_print_errors_fp (stderr);
}
else
{
perror ("Connect failed");
}
return c;
}
// Disconnect & free connection struct
void sslDisconnect (connection *c)
{
if (c->socket)
close (c->socket);
if (c->sslHandle)
{
SSL_shutdown (c->sslHandle);
SSL_free (c->sslHandle);
}
if (c->sslContext)
SSL_CTX_free (c->sslContext);
free (c);
}
// Read all available text from the connection
char *sslRead (connection *c)
{
const int readSize = 2048;
char *rc = NULL;
int received, count = 0;
char buffer[2048];
if (c)
{
while (1)
{
if (!rc)
rc = malloc (readSize * sizeof (char) + 1);
else
rc = realloc (rc, (count + 1) *
readSize * sizeof (char) + 1);
received = SSL_read (c->sslHandle, buffer, readSize);
buffer[received] = '\0';
if (received > 0)
strcat (rc, buffer);
if (received < readSize)
break;
count++;
}
}
return rc;
}
// Write text to the connection
void sslWrite (connection *c, char *text)
{
if (c)
SSL_write (c->sslHandle, text, strlen (text)
}
// Very basic main: we send GET / and print the response.
int main (int argc, char **argv)
{
connection *c;
char *response;
char request[512]="";
c = sslConnect ();
sprintf(request, "GET https://%s%s%s\r\n\r\n", SERVER, KEY, argv[1]);
printf("%s", request);
sslWrite (c, request);
response = sslRead (c);
printf ("%s\n", response);
sslDisconnect (c);
free (response);
return 0;
}
Here are my results (running "app_name stove"):
¸h ÆÁ*HTTP/1.0 200 OK
Expires: Wed, 23 May 2012 05:49:58 GMT
Date: Wed, 23 May 2012 05:49:58 GMT
Cache-Control: private, max-age=0, must-revalidate, no-transform
ETag: "ewDGMApuuzSJ2mUepyXm8PLTiIU/uPd2cbC0DjaL0y0Y6HiAvzSqSts"
Content-Type: application/json; charset=UTF-8
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
Server: GSE
There must certainly more information than nothing out there about stoves, right?
The two problems in the above code are #1) the start of rc is not initialized to zero after the malloc and before using strcat -- which results in the garbage characters, and #2) the line if (received < readSize) should be if (received == 0), since servers can potentially send the header and content as separate chunks.
Related
I have the following code that I have written which is suppose to send a simple http request over a TCP socket, I get a response but as soon as I try to read in the loop it hangs, in the 2nd read operation (tried it manually)
if anyone has an idea of why this might fail I will appreciate it a lot
attached below is the entire code
I am running the program like this: ./http_client yahoo.com
I get this response text at first:
HTTP/1.1 301 Moved Permanently
Date: Sat, 06 Aug 2022 08:07:11 GMT
Connection: keep-alive
Server: ATS
Cache-Control: no-store, no-cache
Content-Type: text/html
Content-Language: en
X-Frame-Options: SAMEORIGIN
Location: https://www.yahoo.com/
Content-Length: 8
redirect
and then it hangs and closes the socket, it shouldn't hang at all, it should run and exit without a delay or anything
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char *argv[]) {
int sockfd;
struct sockaddr_in cli_name;
struct sockaddr_in *saddr;
char *hostname;
struct addrinfo *res;
int port = 80;
if (argc != 2) {
perror("Usage: establish tcp connection to: <hostname>\n");
exit(1);
}
hostname = argv[1];
printf("Client is alive and establishing socket connection %s.\n", hostname);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
perror("Error opening channel");
close(sockfd);
exit(1);
}
if (0 != getaddrinfo(hostname, NULL, NULL, &res)) {
fprintf(stderr, "Error in resolving hostname %s\n", hostname);
exit(1);
}
bzero(&cli_name, sizeof(cli_name));
cli_name.sin_family = AF_INET;
saddr = (struct sockaddr_in *) res->ai_addr;
cli_name.sin_addr.s_addr = inet_addr(inet_ntoa(saddr->sin_addr));
cli_name.sin_port = htons(port);
fflush(stdout);
if (connect(sockfd, (struct sockaddr *) &cli_name, sizeof(cli_name)) < 0) {
perror("Error establishing communications");
close(sockfd);
exit(1);
}
char header[100];
int cx;
char buf[2056];
size_t byte_count = 0;
size_t sent_byte_count = 0;
cx = snprintf(header, 100, "GET / HTTP/1.1\r\nHost: %s:%d\r\n\r\n", hostname, port);
size_t total = strlen(header);
size_t sent = 0;
do {
sent_byte_count = write(sockfd, header + sent, total - sent);
if (sent_byte_count < 0)
printf("ERROR writing message to socket");
if (sent_byte_count == 0)
break;
sent += sent_byte_count;
} while (sent < total);
memset(buf,0,sizeof(buf));
while ((byte_count = read(sockfd, buf, 2054)) > 0) {
buf[byte_count] = '\0';
printf("%s", buf); // <-- give printf() the actual data size
fflush(stdout);
}
printf("Exiting now.\n");
close(sockfd);
exit(0);
}
I made a simple client program with C that sends HTTP request to a host. The last part of the code, where the client receives HTTP response from server looks like this:
int main(int argc, char *argv[])
{
// ...
char buf[BUFSIZ];
int content_length;
content_length = recv(clientfd, buf, sizeof(buf) - 1, 0);
buf[content_length] = 0;
printf("%s", buf);
fflush(stdout);
exit(EXIT_SUCCESS);
}
With this code, I often get the expected result like the following:
GET /foo HTTP/1.0
Host: 127.0.0.1:8080
HTTP/1.0 200 OK
Content-Length: 12
Connection: close
abadakedavra
But sometimes, the content of the request doesn't show up.
GET /foo HTTP/1.0
Host: 127.0.0.1:8080
HTTP/1.0 200 OK
Content-Length: 12
Connection: close
What could be the reason for this behavior?
cf. My whole client code looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#define MAX_REQUEST 10000
#define MAX_URL 2048
void error(const char *msg)
{
perror(msg);
exit(EXIT_FAILURE);
}
void parse_url(char *src, char *hostname, char *port, char *url)
{
size_t i, j = 0;
for (i = 7; src[i] != ':'; i++)
hostname[j++] = src[i];
hostname[j] = 0;
j = 0;
for (i = i + 1; src[i] != '/'; i++)
port[j++] = src[i];
port[j] = 0;
j = 0;
for (i = i + 1; src[i]; i++)
url[j++] = src[i];
url[j] = 0;
}
int main(int argc, char *argv[])
{
/*
Expect
argv[0] : ./client (Executable name)
argv[1] : -G (GET) or -P (POST)
argv[2] : http://hostname:port/url
*/
int clientfd;
char hostname[MAX_URL], port[6], url[MAX_URL];
char msg[MAX_REQUEST];
struct addrinfo hints, *listp, *p;
if (argc < 3 || (strcmp(argv[1], "-G") != 0 && strcmp(argv[1], "-P") != 0))
{
printf("Usage:\n %s -P <URL> HTTP 1.0 POST from stdin\n"
" %s -G <URL> HTTP 1.0 GET to stdin\n",
argv[0], argv[0]);
exit(EXIT_FAILURE);
}
parse_url(argv[2], hostname, port, url);
if(strcmp(argv[1], "-P") == 0) fgets(msg, MAX_REQUEST, stdin);
/* Client socket creation */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_socktype = SOCK_STREAM; // Use TCP
hints.ai_flags = AI_NUMERICSERV; // Use numeric port arg
// Generate a list of addrinfo in listp
getaddrinfo(hostname, port, &hints, &listp);
for (p = listp; p; p = p->ai_next)
{
// Create a socket based on addrinfo struct
if ((clientfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) < 0)
continue;
if (connect(clientfd, p->ai_addr, p->ai_addrlen) != -1)
break;
close(clientfd); // Bind fail, loop to try again
}
freeaddrinfo(listp); // Not needed anymore
if (!p) // Entire loop failed
{
error("Failed in socket binding");
}
/* Send HTTP Request */
char httpRequest[MAX_REQUEST];
if(strcmp(argv[1], "-G") == 0) sprintf(httpRequest, "GET /%s HTTP/1.0\r\nHost: %s:%s\r\n\r\n", url, hostname, port);
else if(strcmp(argv[1]), "-P" == 0) sprintf(httpRequest, "POST /%s HTTP/1.0\r\nHost: %s:%s\r\nContent-Type: plain/text\r\nContent-Length: %lu\r\n\r\n%s\n", url, hostname, port, strlen(msg), msg);
else error("Invalid request");
printf("%s", httpRequest);
send(clientfd, httpRequest, strlen(httpRequest), 0);
/* Recieve HTTP response */
char buf[BUFSIZ];
int content_length;
content_length = recv(clientfd, buf, sizeof(buf) - 1, 0);
buf[content_length] = 0;
printf("%s", buf);
fflush(stdout);
exit(EXIT_SUCCESS);
}
You never implemented the HTTP protocol. If you want to receive an HTTP protocol response, you need to write code that receives an HTTP protocol response in accord with the HTTP protocol. Your code just receives a bunch of bytes, so that's all you get out.
I have the following code of a server:
#include <signal.h>
#include <sys/stat.h>
#include "utils.h"
#include "kissdb.h"
#define MY_PORT 6767
#define BUF_SIZE 1160
#define KEY_SIZE 128
#define HASH_SIZE 1024
#define VALUE_SIZE 1024
#define MAX_PENDING_CONNECTIONS 10
// Definition of the operation type.
typedef enum operation {
PUT,
GET
} Operation;
// Definition of the request.
typedef struct request {
Operation operation;
char key[KEY_SIZE];
char value[VALUE_SIZE];
} Request;
// Definition of the database.
KISSDB *db = NULL;
/**
* #name parse_request - Parses a received message and generates a new request.
* #param buffer: A pointer to the received message.
*
* #return Initialized request on Success. NULL on Error.
*/
Request *parse_request(char *buffer) {
char *token = NULL;
Request *req = NULL;
// Check arguments.
if (!buffer)
return NULL;
// Prepare the request.
req = (Request *) malloc(sizeof(Request));
memset(req->key, 0, KEY_SIZE);
memset(req->value, 0, VALUE_SIZE);
// Extract the operation type.
token = strtok(buffer, ":");
if (!strcmp(token, "PUT")) {
req->operation = PUT;
} else if (!strcmp(token, "GET")) {
req->operation = GET;
} else {
free(req);
return NULL;
}
// Extract the key.
token = strtok(NULL, ":");
if (token) {
strncpy(req->key, token, KEY_SIZE);
} else {
free(req);
return NULL;
}
// Extract the value.
token = strtok(NULL, ":");
if (token) {
strncpy(req->value, token, VALUE_SIZE);
} else if (req->operation == PUT) {
free(req);
return NULL;
}
return req;
}
/*
* #name process_request - Process a client request.
* #param socket_fd: The accept descriptor.
*
* #return
*/
void process_request(const int socket_fd) {
char response_str[BUF_SIZE], request_str[BUF_SIZE];
int numbytes = 0;
Request *request = NULL;
// Clean buffers.
memset(response_str, 0, BUF_SIZE);
memset(request_str, 0, BUF_SIZE);
// receive message.
numbytes = read_str_from_socket(socket_fd, request_str, BUF_SIZE);
// parse the request.
if (numbytes) {
request = parse_request(request_str);
if (request) {
switch (request->operation) {
case GET:
// Read the given key from the database.
if (KISSDB_get(db, request->key, request->value))
sprintf(response_str, "GET ERROR\n");
else
sprintf(response_str, "GET OK: %s\n", request->value);
break;
case PUT:
// Write the given key/value pair to the database.
if (KISSDB_put(db, request->key, request->value))
sprintf(response_str, "PUT ERROR\n");
else
sprintf(response_str, "PUT OK\n");
break;
default:
// Unsupported operation.
sprintf(response_str, "UNKOWN OPERATION\n");
}
// Reply to the client.
write_str_to_socket(socket_fd, response_str, strlen(response_str));
if (request)
free(request);
request = NULL;
return;
}
}
// Send an Error reply to the client.
sprintf(response_str, "FORMAT ERROR\n");
write_str_to_socket(socket_fd, response_str, strlen(response_str));
}
/*
* #name main - The main routine.
*
* #return 0 on success, 1 on error.
*/
int main() {
int socket_fd, // listen on this socket for new connections
new_fd; // use this socket to service a new connection
socklen_t clen;
struct sockaddr_in server_addr, // my address information
client_addr; // connector's address information
// create socket
if ((socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
ERROR("socket()");
// Ignore the SIGPIPE signal in order to not crash when a
// client closes the connection unexpectedly.
signal(SIGPIPE, SIG_IGN);
// create socket adress of server (type, IP-adress and port number)
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // any local interface
server_addr.sin_port = htons(MY_PORT);
// bind socket to address
if (bind(socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
ERROR("bind()");
// start listening to socket for incoming connections
listen(socket_fd, MAX_PENDING_CONNECTIONS);
fprintf(stderr, "(Info) main: Listening for new connections on port %d ...\n", MY_PORT);
clen = sizeof(client_addr);
// Allocate memory for the database.
if (!(db = (KISSDB *)malloc(sizeof(KISSDB)))) {
fprintf(stderr, "(Error) main: Cannot allocate memory for the database.\n");
return 1;
}
// Open the database.
if (KISSDB_open(db, "mydb.db", KISSDB_OPEN_MODE_RWCREAT, HASH_SIZE, KEY_SIZE, VALUE_SIZE)) {
fprintf(stderr, "(Error) main: Cannot open the database.\n");
return 1;
}
// main loop: wait for new connection/requests
while (1) {
// wait for incoming connection
if ((new_fd = accept(socket_fd, (struct sockaddr *)&client_addr, &clen)) == -1) {
ERROR("accept()");
}
// got connection, serve request
fprintf(stderr, "(Info) main: Got connection from '%s'\n", inet_ntoa(client_addr.sin_addr));
process_request(new_fd);
close(new_fd);
}
// Destroy the database.
// Close the database.
KISSDB_close(db);
// Free memory.
if (db)
free(db);
db = NULL;
return 0;
}
which handles a database (KISSDB here) that stores and prints values based on a key . I want to modify it , adding threads , producer and consumer ones. Producer thread should accept clients request and consumer thread execute it. I thought about putting all socket functions in a *producer() function that would handle them and let the consumer handle 'process_request() as it is . In main the threads are being created and called . It doesn't seem to run though , it compiles okay , but when executing ./client -a localhost -i 1 -p to start the client in the terminal , the program doesn't stop. I suspect the
pthread_create(&consumer_thread,NULL,process_request,(void*)&thread_args.new_fd);
is the problem. When I try to run the server , I get :
(Info) main: Listening for new connections on port 6767 ...
Error in read_from_socket(). Cause: Bad file descriptor
See what I've tried :
#define _POSIX_C_SOURCE 200809L
#include <inttypes.h>
#include <math.h>
#include<time.h>
#include <sys/time.h>
#include <sys/resource.h>
#include<pthread.h>
pthread_mutex_t mymutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t c = PTHREAD_COND_INITIALIZER;
#include <signal.h>
#include <sys/stat.h>
#include "utils.h"
#include "kissdb.h"
//we have to use it
#define MY_PORT 6767
#define BUF_SIZE 1160
#define KEY_SIZE 128
#define HASH_SIZE 1024
#define VALUE_SIZE 1024
#define MAX_PENDING_CONNECTIONS 10
// =======================================
//struct timespec { // INCLUDE IN <time.h> ?
// time_t tv_sec; /* seconds */
// long tv_nsec; /* nanoseconds */
//};
/*
int socket_fd, // listen on this socket for new connections
new_fd; // use this socket to service a new connection
socklen_t clen;
struct sockaddr_in server_addr, // my address information
client_addr; // connector's address information
*/
struct data {
int socket_fd; // listen on this socket for new connections
int new_fd; // use this socket to service a new connection
};
// Definition of the operation type.
typedef enum operation {
PUT,
GET
} Operation;
// Definition of the request.
typedef struct request {
Operation operation;
char key[KEY_SIZE];
char value[VALUE_SIZE];
} Request;
// Definition of the database.
KISSDB *db = NULL;
/**
* #name parse_request - Parses a received message and generates a new request.
* #param buffer: A pointer to the received message.
*
* #return Initialized request on Success. NULL on Error.
*/
Request *parse_request(char *buffer) {
char *token = NULL;
Request *req = NULL;
// Check arguments.
if (!buffer)
return NULL;
// Prepare the request.
req = (Request *) malloc(sizeof(Request));
memset(req->key, 0, KEY_SIZE);
memset(req->value, 0, VALUE_SIZE);
// Extract the operation type.
token = strtok(buffer, ":");
if (!strcmp(token, "PUT")) {
req->operation = PUT;
} else if (!strcmp(token, "GET")) {
req->operation = GET;
} else {
free(req);
return NULL;
}
// Extract the key.
token = strtok(NULL, ":");
if (token) {
strncpy(req->key, token, KEY_SIZE);
} else {
free(req);
return NULL;
}
// Extract the value.
token = strtok(NULL, ":");
if (token) {
strncpy(req->value, token, VALUE_SIZE);
} else if (req->operation == PUT) {
free(req);
return NULL;
}
return req;
}
/*
* #name process_request - Process a client request.
* #param socket_fd: The accept descriptor.
*
* #return
*/
//for consumer
void *process_request(void * socket_fd) {
char response_str[BUF_SIZE], request_str[BUF_SIZE];
int numbytes = 0;
Request *request = NULL;
// Clean buffers.
memset(response_str, 0, BUF_SIZE);
memset(request_str, 0, BUF_SIZE);
// receive message.
numbytes = read_str_from_socket(socket_fd, request_str, BUF_SIZE);
// parse the request.
if (numbytes) {
request = parse_request(request_str);
if (request) {
switch (request->operation) {
case GET:
// Read the given key from the database.
if (KISSDB_get(db, request->key, request->value))
sprintf(response_str, "GET ERROR\n");
else
sprintf(response_str, "GET OK: %s\n", request->value);
break;
case PUT:
// Write the given key/value pair to the database.
if (KISSDB_put(db, request->key, request->value))
sprintf(response_str, "PUT ERROR\n");
else
sprintf(response_str, "PUT OK\n");
break;
default:
// Unsupported operation.
sprintf(response_str, "UNKOWN OPERATION\n");
}
// Reply to the client.
write_str_to_socket(socket_fd, response_str, strlen(response_str));
if (request)
free(request);
request = NULL;
return;
}
}
// Send an Error reply to the client.
sprintf(response_str, "FORMAT ERROR\n");
write_str_to_socket(socket_fd, response_str, strlen(response_str));
}
///////////////////////////////////////////////////////////////////////////////
void *producer(void *arg) {
// int socket_fd, // listen on this socket for new connections
// new_fd; // use this socket to service a new connection
socklen_t clen;
struct sockaddr_in server_addr, // my address information
client_addr; // connector's address information
struct data *d = (struct data *) arg;
// create socket
if ((d->socket_fd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
ERROR("socket()");
// Ignore the SIGPIPE signal in order to not crash when a
// client closes the connection unexpectedly.
signal(SIGPIPE, SIG_IGN);
// create socket adress of server (type, IP-adress and port number)
bzero(&server_addr, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(INADDR_ANY); // any local interface
server_addr.sin_port = htons(MY_PORT);
// bind socket to address
if (bind(d->socket_fd, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
ERROR("bind()");
// start listening to socket for incoming connections
listen(d->socket_fd, MAX_PENDING_CONNECTIONS);
fprintf(stderr, "(Info) main: Listening for new connections on port %d ...\n", MY_PORT);
clen = sizeof(client_addr);
// wait for incoming connection EDW 8A KANOUME TA THREADS ?
if ((d->new_fd = accept(d->socket_fd, (struct sockaddr *)&client_addr, &clen)) == -1) { // to client_socket pou 8a peira3oume
ERROR("accept()");
}
//clock_gettime(CLOCK_REALTIME, &spec);
//s = spec.tv_sec;
//ms = spec.tv_nsec;
//fprintf(stderr, "Current time: %li . %03ld seconds since the connection\n",(long)s, ms);
// got connection, serve request
fprintf(stderr, "(Info) main: Got connection from '%s'\n", inet_ntoa(client_addr.sin_addr));
}
/*
* #name main - The main routine.
*
* #return 0 on success, 1 on error.
*/
int main() {
long ms; // Milliseconds
time_t s; // Seconds
struct timespec spec;
struct data thread_args;
// Allocate memory for the database.
if (!(db = (KISSDB *)malloc(sizeof(KISSDB)))) {
fprintf(stderr, "(Error) main: Cannot allocate memory for the database.\n");
return 1;
}
// Open the database.
if (KISSDB_open(db, "mydb.db", KISSDB_OPEN_MODE_RWCREAT, HASH_SIZE, KEY_SIZE, VALUE_SIZE)) {
fprintf(stderr, "(Error) main: Cannot open the database.\n");
return 1;
}
pthread_t producer_thread;
pthread_create(&producer_thread,NULL,producer,(void *) &thread_args);
// main loop: wait for new connection/requests
while (1) {
//process_request(new_fd); // nai !
/*teo's new code , for (i) part of project */
pthread_t consumer_thread;
pthread_create(&consumer_thread,NULL,process_request,(void*)&thread_args.new_fd);
pthread_join(consumer_thread,NULL); // necessary
/* */
//close(new_fd);
}
// Destroy the database.
// Close the database.
KISSDB_close(db);
// Free memory.
if (db)
free(db);
db = NULL;
return 0;
}
I am new to UPnP development and trying to discover all UPnP device within the local network, and I followed an example from the online resource, but my code will only keep looping at the first response. How could I get another response other than the first one, could I get some hints for this?
Example :
First Response from 192.168.xxx.123, and it will keeps printing the following result:
HTTP/1.1 200 OK
CACHE-CONTROL: max-age=1790
DATE: Thu, 01 Jan 2015 10:43:15 GMT
ST: uuid:4d696xxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
USN: uuid:4d696xxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
EXT:
SERVER: Linux 2.6 DLNADOC/1.50 UPnP/1.0 ReadyDLNA/1.0.26
LOCATION: http://192.168.xxx.123:xxxx/rootDesc.xml
Content-Length: 0
I checked in Wireshark, and I can see the other device [IP: 192.168.xxx.99] has given me a response, but I am not able to receive it in my code.
I also read a question on SO and used select in my code, but still cannot get it working.
Receiving response(s) from N number of clients in reply to a broadcast request over UDP
The code:
#include <QCoreApplication>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#define RESPONSE_BUFFER_LEN 1024
#define SSDP_MULTICAST "239.255.255.250"
#define SSDP_PORT 1900
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int sock;
size_t ret;
unsigned int socklen;
struct sockaddr_in sockname;
struct sockaddr clientsock;
struct hostent *hostname;
char data[] =
"M-SEARCH * HTTP/1.1\r\n"
"HOST: 239.255.255.250:1900\r\n"
"MAN: \"ssdp:discover\"\r\n"
"ST: ssdp:all\r\n"
"MX: 120\r\n"
"\r\n";
char buffer[RESPONSE_BUFFER_LEN];
unsigned int len = RESPONSE_BUFFER_LEN;
fd_set fds;
struct timeval timeout;
hostname = gethostbyname(SSDP_MULTICAST);
hostname->h_addrtype = AF_INET;
if((sock = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
{
printf("err: socket() failed");
return -1;
}
memset((char *)&sockname, 0, sizeof(struct sockaddr_in));
sockname.sin_family = AF_INET;
sockname.sin_port = htons(SSDP_PORT);
sockname.sin_addr.s_addr = *((unsigned long *)(hostname->h_addr_list[0]));
ret = sendto(sock, data, strlen(data), 0, (struct sockaddr *)&sockname,
sizeof(struct sockaddr_in));
if(ret != strlen(data))
{
printf("err:sendto");
return -1;
}
/* Get response */
FD_ZERO(&fds);
FD_SET(sock, &fds);
timeout.tv_sec = 5;
timeout.tv_usec = 5;
while(select(sock + 1, &fds, NULL, NULL, &timeout) > 0)
{
if(FD_ISSET(sock, &fds))
{
socklen = sizeof(clientsock);
if((len = recvfrom(sock, buffer, len, MSG_PEEK, &clientsock, &socklen)) == (size_t)-1)
{
printf("err: recvfrom");
return -1;
}
buffer[len] = '\0';
/* Check the HTTP response code */
if(strncmp(buffer, "HTTP/1.1 200 OK", 12) != 0)
{
printf("err: ssdp parsing ");
return -1;
}
printf(buffer);
}
else
{
printf("err: no ssdp answer");
}
}
//close(sock);
return a.exec();
}
You are using MSG_PEEK, which means to read the first message in the socket's receive buffer, but not remove it from the buffer.
Therefore every time you call recvfrom you get the first received message.
Change MSG_PEEK to 0 and then each call will read the first message that hasn't been read yet. (So the second call will read the second message, and so on)
I have spring-boot server that I am running in AWS. The server works fine. I can access it using chrome, postman, and curl with no issues. However, I have an embedded device that is running C and I am using sockets to try to connect to my server. The embedded device is running Linux so I can use curl to talk to the server with no issues. However, my C sockets code cannot seem to find the resource on the server. I keep getting 404's.
Here is my embedded client code,
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <errno.h>
int main() {
// Define some parameters
int sockfd, bytes_read;
struct sockaddr_in dest;
char buffer[4000];
char hdr[1000];
// Create Server Client Strings
bzero(hdr, sizeof(hdr));
strcpy(hdr, "GET /hello HTTP/1.1\r\n");
strcat(hdr, "Host: 52.200.39.81\r\n\r\n");
// Clean things up a bit before sarting
printf("\n\n");
// Create Socket
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf("Socket not created\n");
return 0;
}
// Initialize server address/port struct
bzero(&dest, sizeof(dest));
// *** Added this line to fix the code ***
dest.sin_addr.s_addr = inet_addr("52.200.39.81", &dest.sin_addr.s_addr);
dest.sin_family = AF_INET;
dest.sin_port = htons(8080);
if ( inet_addr("52.200.39.81", &dest.sin_addr.s_addr) == 0 ) {
printf("Incorrect Address Expression\n");
return 0;
}
// Connect Socket
if ( connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0 ) {
printf("Socket Connection Failed\n");
close(sockfd);
return 0;
}
// Send data
if (send(sockfd, hdr, strlen(hdr), 0) < 0) {
printf("Send Data Failed\n");
return 0;
}
printf("Socket successfully sent\n");
printf("\nSend Message - TxBufferSize = %d\n\n",strlen(hdr));
printf("%s", hdr);
bzero(buffer, sizeof(buffer));
bytes_read = recv(sockfd, buffer, sizeof(buffer), 0);
if (bytes_read < 0) {
printf("Read Data Failed\n");
}
if (bytes_read > 0) {
// Print out receive buffer
printf("\n\nReceived Message -- RxSize = %d \n\n", strlen(buffer));
printf("%s", buffer);
}
if (bytes_read == 0) {
printf("No Read Bytes Received\n");
}
/*---Clean up---*/
close(sockfd);
return 0;
}
Here is what I get back,
debian#beaglebone:~$ ./helloworld
Socket successfully sent
***** Send Message -- TxBufferSize = 80 *****
GET http://52.200.39.81:8080/hello HTTP/1.1
Host: 52.200.39.81
accept: */*
***** Received Message -- RxBufferSize = 467 *****
HTTP/1.1 404 Not Found
Date: Sat, 02 Apr 2016 17:36:37 GMT
Server: Apache/2.2.22 (Debian)
Vary: Accept-Encoding
Content-Length: 283
Content-Type: text/html; charset=iso-8859-1
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /hello was not found on this server.</p>
<hr>
<address>Apache/2.2.22 (Debian) Server at 52.200.39.81 Port 8080</address>
</body></html>
debian#beaglebone:~$
If I use the curl command on the embedded device,
debian#beaglebone:~$ curl 52.200.39.81:8080/hello
Greetings WebServiceTest1 -- ServiceCount = 11
debian#beaglebone:~$
I get the correct response from the server. So I am confident that the embedded device is talking to my server. Just can't seem to get the sockets code to work. Any help would be appreciated.
Ok, I found out what the problem was. I did not set the socket address. A very simple omission but that what the problem was. I have updated the code and it is now working. I added gethostbyname to make the code more standardized. The new lines of code are in the comment section "// Initialize server address/port struct". I would like to thank Lilas for providing me the reference code that led me to the omission of the dest.sin_addr.s_addr line. Below is the corrected code.
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <resolv.h>
#include <netdb.h>
int main() {
// Define some parameters
int sockfd, bytes_read;
struct sockaddr_in dest;
char *hostname = "skmdev1.net";
struct hostent *hostent;
char buffer[4000];
char hdr[1000];
// Create Server Client Strings
bzero(hdr, sizeof(hdr));
strcpy(hdr, "GET /hello HTTP/1.1\r\n");
strcat(hdr, "Host: skmdev1.net\r\n\r\n");
// Clean things up a bit before sarting
printf("\n\n");
// Build the address
hostent = gethostbyname(hostname);
if (hostent == NULL) {
printf("error: gethostbyname(\"%s\")\n", hostname);
return 0;
}
// Create Socket
if ( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) {
printf("Socket not created\n");
return 0;
}
// Initialize server address/port struct
bzero(&dest, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_port = htons(8080);
dest.sin_addr.s_addr = inet_addr(inet_ntoa(*(struct in_addr*)hostent->h_addr));
if ( dest.sin_addr.s_addr == INADDR_NONE ) {
printf("Incorrect Address Expression\n");
return 0;
}
// Connect Socket
if ( connect(sockfd, (struct sockaddr*)&dest, sizeof(dest)) != 0 ) {
printf("Socket Connection Failed\n");
close(sockfd);
return 0;
}
// Send data
if (send(sockfd, hdr, strlen(hdr), 0) < 0) {
printf("Send Data Failed\n");
return 0;
}
printf("Socket successfully sent\n");
printf("\nSend Message - TxBufferSize = %d\n\n",strlen(hdr));
printf("%s", hdr);
bzero(buffer, sizeof(buffer));
bytes_read = recv(sockfd, buffer, sizeof(buffer), 0);
if (bytes_read < 0) {
printf("Read Data Failed\n");
}
if (bytes_read > 0) {
// Print out receive buffer
printf("\n\nReceived Message -- RxSize = %d \n\n", strlen(buffer));
printf("%s\n\n", buffer);
}
if (bytes_read == 0) {
printf("No Read Bytes Received\n");
}
/*---Clean up---*/
close(sockfd);
return 0;
}