I would like to create a server and client application that communicate via sockets using GIO. GSocketService and GSocketClient seem be perfect for this purpose but unfortunately I couldn't find some tutorial or example code (that a GLib, GIO,... newbie can understand). Does anybody know some good resources or can post example code here?
I finally managed to create both a simple server and client using glib and gio.
My server looks like this:
#include <glib.h>
#include <gio/gio.h>
/* this function will get called everytime a client attempts to connect */
gboolean
incoming_callback (GSocketService *service,
GSocketConnection *connection,
GObject *source_object,
gpointer user_data)
{
g_print("Received Connection from client!\n");
GInputStream * istream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
gchar message[1024];
g_input_stream_read (istream,
message,
1024,
NULL,
NULL);
g_print("Message was: \"%s\"\n", message);
return FALSE;
}
int
main (int argc, char **argv)
{
/* initialize glib */
g_type_init();
GError * error = NULL;
/* create the new socketservice */
GSocketService * service = g_socket_service_new ();
/* connect to the port */
g_socket_listener_add_inet_port ((GSocketListener*)service,
1500, /* your port goes here */
NULL,
&error);
/* don't forget to check for errors */
if (error != NULL)
{
g_error (error->message);
}
/* listen to the 'incoming' signal */
g_signal_connect (service,
"incoming",
G_CALLBACK (incoming_callback),
NULL);
/* start the socket service */
g_socket_service_start (service);
/* enter mainloop */
g_print ("Waiting for client!\n");
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
return 0;
}
and this is the corresponding client:
#include <glib.h>
#include <gio/gio.h>
int
main (int argc, char *argv[])
{
/* initialize glib */
g_type_init ();
GError * error = NULL;
/* create a new connection */
GSocketConnection * connection = NULL;
GSocketClient * client = g_socket_client_new();
/* connect to the host */
connection = g_socket_client_connect_to_host (client,
(gchar*)"localhost",
1500, /* your port goes here */
NULL,
&error);
/* don't forget to check for errors */
if (error != NULL)
{
g_error (error->message);
}
else
{
g_print ("Connection successful!\n");
}
/* use the connection */
GInputStream * istream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
GOutputStream * ostream = g_io_stream_get_output_stream (G_IO_STREAM (connection));
g_output_stream_write (ostream,
"Hello server!", /* your message goes here */
13, /* length of your message */
NULL,
&error);
/* don't forget to check for errors */
if (error != NULL)
{
g_error (error->message);
}
return 0;
}
Note though, that I am still new to glib, gio and even C, so double check my code before using it.
The callback from incoming should not block, from gio documentation: "The handler must initiate the handling of connection , but may not block; in essence, asynchronous operations must be used."
I had some issue with connection in the async version, it has to be referred by the user or the connection will close after the incoming callback returns.
A full example of a server that does not block, based on the example given before:
#include <gio/gio.h>
#include <glib.h>
#define BLOCK_SIZE 1024
#define PORT 2345
struct ConnData {
GSocketConnection *connection;
char message[BLOCK_SIZE];
};
void message_ready (GObject * source_object,
GAsyncResult *res,
gpointer user_data)
{
GInputStream *istream = G_INPUT_STREAM (source_object);
GError *error = NULL;
struct ConnData *data = user_data;
int count;
count = g_input_stream_read_finish (istream,
res,
&error);
if (count == -1) {
g_error ("Error when receiving message");
if (error != NULL) {
g_error ("%s", error->message);
g_clear_error (&error);
}
}
g_message ("Message was: \"%s\"\n", data->message);
g_object_unref (G_SOCKET_CONNECTION (data->connection));
g_free (data);
}
static gboolean
incoming_callback (GSocketService *service,
GSocketConnection * connection,
GObject * source_object,
gpointer user_data)
{
g_message ("Received Connection from client!\n");
GInputStream *istream = g_io_stream_get_input_stream (G_IO_STREAM (connection));
struct ConnData *data = g_new (struct ConnData, 1);
data->connection = g_object_ref (connection);
g_input_stream_read_async (istream,
data->message,
sizeof (data->message),
G_PRIORITY_DEFAULT,
NULL,
message_ready,
data);
return FALSE;
}
int main ()
{
GSocketService *service;
GError *error = NULL;
gboolean ret;
service = g_socket_service_new ();
ret = g_socket_listener_add_inet_port (G_SOCKET_LISTENER (service),
PORT, NULL, &error);
if (ret && error != NULL)
{
g_error ("%s", error->message);
g_clear_error (&error);
return 1;
}
g_signal_connect (service,
"incoming",
G_CALLBACK (incoming_callback),
NULL);
g_socket_service_start (service);
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
/* Stop service when out of the main loop*/
g_socket_service_stop (service);
return 0;
}
Related
Recently, I am trying to use bpf ringbuf in uprobe example of libbpf. But when running, error occurred which is "libbpf: load bpf program failed: Invalid argument". I have no idea why this happened. Could anyone help? Below is my test code.
Kernel space code: uprobe.bpf.c, define a rb struct, and use bpf_ringbuf_reserve in uprobe code block.
#include <linux/bpf.h>
#include <linux/ptrace.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>
char LICENSE[] SEC("license") = "Dual BSD/GPL";
struct {
__uint(type, BPF_MAP_TYPE_RINGBUF);
__uint(max_entries, 256 * 1024);
} rb SEC(".maps");
SEC("uprobe/func")
int BPF_KPROBE(uprobe, int a, int b)
{
__u64* e = bpf_ringbuf_reserve(&rb, sizeof(__u64), 0);
if (!e)
return 0;
bpf_printk("UPROBE ENTRY: a = %d, b = %d\n", a, b);
return 0;
}
SEC("uretprobe/func")
int BPF_KRETPROBE(uretprobe, int ret)
{
bpf_printk("UPROBE EXIT: return = %d\n", ret);
return 0;
}
User space code: uprobe.c
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/resource.h>
#include <bpf/libbpf.h>
#include "uprobe.skel.h"
static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
return vfprintf(stderr, format, args);
}
static void bump_memlock_rlimit(void)
{
struct rlimit rlim_new = {
.rlim_cur = RLIM_INFINITY,
.rlim_max = RLIM_INFINITY,
};
if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) {
fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n");
exit(1);
}
}
/* Find process's base load address. We use /proc/self/maps for that,
* searching for the first executable (r-xp) memory mapping:
*
* 5574fd254000-5574fd258000 r-xp 00002000 fd:01 668759 /usr/bin/cat
* ^^^^^^^^^^^^ ^^^^^^^^
*
* Subtracting that region's offset (4th column) from its absolute start
* memory address (1st column) gives us the process's base load address.
*/
static long get_base_addr() {
size_t start, offset;
char buf[256];
FILE *f;
f = fopen("/proc/self/maps", "r");
if (!f)
return -errno;
while (fscanf(f, "%zx-%*x %s %zx %*[^\n]\n", &start, buf, &offset) == 3) {
if (strcmp(buf, "r-xp") == 0) {
fclose(f);
return start - offset;
}
}
fclose(f);
return -1;
}
static int handle_event(void *ctx, void *data, size_t data_sz)
{
return 0;
}
/* It's a global function to make sure compiler doesn't inline it. */
int uprobed_function(int a, int b)
{
return a + b;
}
int main(int argc, char **argv)
{
struct ring_buffer *rb = NULL;
struct uprobe_bpf *skel;
long base_addr, uprobe_offset;
int err, i;
/* Set up libbpf errors and debug info callback */
libbpf_set_print(libbpf_print_fn);
/* Bump RLIMIT_MEMLOCK to allow BPF sub-system to do anything */
bump_memlock_rlimit();
/* Load and verify BPF application */
skel = uprobe_bpf__open_and_load();
if (!skel) {
fprintf(stderr, "Failed to open and load BPF skeleton\n");
return 1;
}
base_addr = get_base_addr();
if (base_addr < 0) {
fprintf(stderr, "Failed to determine process's load address\n");
err = base_addr;
goto cleanup;
}
/* uprobe/uretprobe expects relative offset of the function to attach
* to. This offset is relateve to the process's base load address. So
* easy way to do this is to take an absolute address of the desired
* function and substract base load address from it. If we were to
* parse ELF to calculate this function, we'd need to add .text
* section offset and function's offset within .text ELF section.
*/
uprobe_offset = (long)&uprobed_function - base_addr;
/* Attach tracepoint handler */
skel->links.uprobe = bpf_program__attach_uprobe(skel->progs.uprobe,
false /* not uretprobe */,
0 /* self pid */,
"/proc/self/exe",
uprobe_offset);
err = libbpf_get_error(skel->links.uprobe);
if (err) {
fprintf(stderr, "Failed to attach uprobe: %d\n", err);
goto cleanup;
}
/* we can also attach uprobe/uretprobe to any existing or future
* processes that use the same binary executable; to do that we need
* to specify -1 as PID, as we do here
*/
skel->links.uretprobe = bpf_program__attach_uprobe(skel->progs.uretprobe,
true /* uretprobe */,
-1 /* any pid */,
"/proc/self/exe",
uprobe_offset);
err = libbpf_get_error(skel->links.uretprobe);
if (err) {
fprintf(stderr, "Failed to attach uprobe: %d\n", err);
goto cleanup;
}
/* Set up ring buffer polling */
rb = ring_buffer__new(bpf_map__fd(skel->maps.rb), handle_event, NULL, NULL);
if (!rb) {
err = -1;
fprintf(stderr, "Failed to create ring buffer\n");
goto cleanup;
}
printf("Successfully started! Please run `sudo cat /sys/kernel/debug/tracing/trace_pipe` "
"to see output of the BPF programs.\n");
for (i = 0; ; i++) {
err = ring_buffer__poll(rb, 100 /* timeout, ms */);
/* trigger our BPF programs */
fprintf(stderr, ".");
uprobed_function(i, i + 1);
sleep(1);
}
cleanup:
ring_buffer__free(rb);
uprobe_bpf__destroy(skel);
return -err;
}
This question has been asked many times, but searching through and implementing some solutions that have worked for others, I still haven't been able to figure out what I'm doing wrong. I am still having issues understanding programming with sockets, so any explanations would be greatly appreciated. The function where I am getting the error is "int forwardClientReq(char* buffer, char* hostname, int clientfd)" and more specifically around this:
numBytesSent = send(serverfd, buffer, strlen(buffer), 0);
if(numBytesSent == -1)
printf("Oh dear, something went wrong with send()! %s\n", strerror(errno));
The full code is as follows:
/* Proxy application called webproxy */
// Copy past http server includes, remove unnecessary
#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* for fgets */
#include <strings.h> /* for bzero, bcopy */
#include <unistd.h> /* for read, write */
#include <sys/socket.h> /* for socket use */
#include <netdb.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <errno.h>
#define MAXBUF 8192 /* max text line length */
#define LISTENQ 1024 /* second argument to listen() */
#define ERRBUFSIZE 1024
#define HEAPBUF 32768 // 2^15
int open_listenfd(int port);
void webProxy(int connfd);
void *thread(void *vargp);
int connect2Client(char* ip, char* port);
void sendErrResponse(char* errBUF, int connfd);
int forwardClientReq(char* buffer, char* host, int clientfd);
int main(int argc, char **argv)
{
int timeout = 0;
/* Check if the function was called correctly */
/* Store arguments provided (port number & cache timeout) */
if(argc < 2 || argc > 3){
fprintf(stderr, "Incorrect arguments, Usage: ./<executableFile> <port#> <timeout(optional)>\n");
exit(0);
}
if(argc == 3)
timeout = atoi(argv[2]);
int listenfd, *connfdp, port, clientlen=sizeof(struct sockaddr_in);
pthread_t tid;
struct sockaddr_in clientaddr;
port = atoi(argv[1]); // store the port number
listenfd = open_listenfd(port); // create persistant TCP socket for client HTTP requests
/* Create,Bind,Listen SOCKET and multithread */
while (1) {
connfdp = malloc(sizeof(int)); // pointer to pass the socket
*connfdp = accept(listenfd, (struct sockaddr*)&clientaddr, &clientlen);
if(*connfdp<0)
printf("There is an error accepting the connection with the client");
pthread_create(&tid, NULL, thread, connfdp); // call thread function with tid
}
}
/* thread routine */
void * thread(void * vargp)
{
int connfd = *((int *)vargp);
pthread_detach(pthread_self());
free(vargp);
webProxy(connfd);
close(connfd);
return NULL;
}
void webProxy(int connfd)
{
size_t n;
char buffer[MAXBUF]; // pointer to pass the socket
char errorBuf[ERRBUFSIZE];
bzero(errorBuf, ERRBUFSIZE);
bzero(buffer, MAXBUF);
char httpmsg[]="HTTP/1.1 200 Document Follows\r\nContent-Type:text/html\r\nContent-Length:32\r\n\r\n<html><h1>Hello CSCI4273 Course!</h1>";
char hostname[50];
n = read(connfd, buffer, MAXBUF); // read the requst up to maxbuf sizeof
printf("server received the following request:\n%s\n",buffer);
/* parse the request */
char requestType[50], fullPath[50];
bzero(requestType, 50);
bzero(fullPath, 50);
sscanf(buffer, "%s %s", requestType, fullPath);
printf("requestType = %s, and fullPath= %s\n", requestType, fullPath);
/* I tried a million different methods and libary suggestions but this is the only
method that I found to easily parse the information I wanted to input */
// sscanf(fullPath, "http://www.%511[^/\n]", hostname);
sscanf(fullPath, "http://%511[^/\n]", hostname);
printf("hostname is = %s\n", hostname);
/* support only GET requests */
if(strcmp(requestType, "GET") != 0)
{
printf("Proxy received a request that was not a 'GET' Request, sending 400 Bad Request response\n");
sendErrResponse(errorBuf, connfd);
}
// // /* support only HTTP/1.1 */
// else if(strcmp(Type, "HTTP/1.1") != 0)
// {
// printf("Proxy received a request that was not an HTTP/1.1 version, sending 400 Bad Request response");
// // I think the error message below is 80, but I could be wrong. Need to double check or use strlen function
// sprintf(errorBuf, "HTTP/1.1 400 Bad Request\r\nContent-Type:text/html\r\nContent-Length: %d\r\n\r\n",80);
// write(connfd, errorBuf, strlen(errorBuf));
// bzero(errorBuf, ERRBUFSIZE);
// }
/* parse and verify the hostname/server */
struct hostent *host = gethostbyname(hostname);
if (host == NULL) {
fprintf(stderr,"ERROR, no such host as %s\n", hostname);
sendErrResponse(errorBuf, connfd);
exit(0);
}
else{
/* Forward request to HTTP server */
forwardClientReq(buffer, hostname, connfd);
printf("buffer = %s\n", buffer);
/* Relay data from server to client */
}
}
int forwardClientReq(char* buffer, char* hostname, int clientfd)
{
char* serverResponse = malloc(HEAPBUF); // create a buffer for receiving the response from the server
bzero(serverResponse, HEAPBUF); // zeroize the buffer
/* open a socket with the server */
struct sockaddr_in serveraddr;
int serverSock, optval =1;
/* Create a socket descriptor */
if(-1 == (serverSock = socket(AF_INET, SOCK_STREAM, 0))) // yoda condition...
{
printf("Error: Unable to create socket in 'open_listenfd' function");
return -1;
}
/* Eliminates "Address already in use" error from bind. */
if (setsockopt(serverSock, SOL_SOCKET, SO_REUSEADDR, &optval , sizeof(int)) < 0){
printf("Error in setsockopt in forwardClientReq function");
return -1;
}
struct hostent* host = gethostbyname(hostname);
serveraddr.sin_family = AF_INET;
memcpy(&serveraddr.sin_addr, host->h_addr_list[0], host->h_length);
serveraddr.sin_port = htons(80); //(you should pick the correct remote port or use the default 80 port if noneis specified).
socklen_t addrlen = sizeof(serveraddr); // The addrlen argument specifies the size of serveraddr.
int serverfd = connect(serverSock, (struct sockaddr*) &serveraddr, addrlen);
if(serverfd < 0)
printf("improper connection when trying to forward client's request/n");
/* send the client message to the server */
int numBytesSent = 0;
printf("buffer before send = %s\n", buffer);
sprintf(buffer, "\r\n\r\n");
numBytesSent = send(serverfd, buffer, strlen(buffer), 0);
if(numBytesSent == -1)
printf("Oh dear, something went wrong with send()! %s\n", strerror(errno));
// printf("Sent %d to the server", numBytesSent);
// /* store the server's response */
// int numBytesRead = 0;
// numBytesRead = read(serverfd, serverResponse, HEAPBUF);
// printf("Sent %d to the server", numBytesRead);
//
// /* send the response to the client. This is a moment here the proxy can cache the page,
// inspect the data, and do all kinds of cool proxy-level things */
// numBytesSent = write(clientfd, serverResponse, strlen(serverResponse));
// printf("Sent %d to the server", numBytesSent);
free(serverResponse); // free malloc'd space
}
int open_listenfd(int port)
{
int listenfd, optval=1;
struct sockaddr_in serveraddr;
/* Create a socket descriptor */
if ((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
printf("Error: Unable to create socket in 'open_listenfd' function");
return -1;
}
/* Eliminates "Address already in use" error from bind. */
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &optval , sizeof(int)) < 0)
return -1;
/* listenfd will be an endpoint for all requests to port
on any IP address for this host */
bzero((char *) &serveraddr, sizeof(serveraddr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_addr.s_addr = htonl(INADDR_ANY);
serveraddr.sin_port = htons((unsigned short)port);
/* bind: associate the parent socket with a port */
if (bind(listenfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0)
return -1;
/* Make it a listening socket ready to accept connection requests */
if (listen(listenfd, LISTENQ) < 0)
return -1;
return listenfd;
} /* end open_listenfd */
void sendErrResponse(char* errorBuf, int connfd)
{
// I think the error message below is 80, but I could be wrong. Need to double check or use strlen function
sprintf(errorBuf, "HTTP/1.1 400 Bad Request\r\nContent-Type:text/html\r\nContent-Length: %d\r\n\r\n",80);
write(connfd, errorBuf, strlen(errorBuf));
bzero(errorBuf, ERRBUFSIZE);
}
The return value of connect is an error code not a socket fd:
If the connection or binding succeeds, zero is returned. On error,
-1 is returned, and errno is set appropriately.
So
numBytesSent = send(serverfd, buffer, strlen(buffer), 0);
Should be
numBytesSent = send(serverSock, buffer, strlen(buffer), 0);
I am trying to set up server that also has a gui using GTK on a Raspberry Pi. The program is just a proof-of-concept demo.
I create a socket and the client can connect and send data, I see it in wireshark. But the read does not complete until the client disconnects. My code uses g_data_input_stream_read_line_async and g_data_input_stream_read_line_finish. The program displays the data the client sent after the client disconnects.
Here is the output of the program (that is the correct data that was sent by the client).
g_socket_listener_add_inet_port status: 1
g_signal_connect status: 2 (waits here until client connects)
socket connection established!
after g_data_input_stream_new
after g_data_input_stream_set_newline_type
after g_data_input_stream_read_line_async (waits here after client connects, and after client sends data)
before g_data_input_stream_read_line_finish (displays remaining output lines after client disconnects)
after g_data_input_stream_read_line_finish
length: 14
0 5 0 4 0 1 0 1 0 6 0 0 0 7
I suspect I am missing something simple since the data is received, but I've spent quite a few hours unsuccessfully trying to figure out what is missing.
// compiles with:
// gcc `pkg-config --cflags gtk+-3.0` gtk3serv.c -o gtk3serv `pkg-config --libs gtk+-3.0`
#include <gtk/gtk.h>
#include <gio/gio.h>
static void
print_hello (GtkWidget *widget,
gpointer data)
{
g_print ("Hello World\n");
}
static void
activate (GtkApplication *app,
gpointer user_data)
{
GtkWidget *window;
GtkWidget *button;
GtkWidget *button_box;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window), "Window");
gtk_window_set_default_size (GTK_WINDOW (window), 200, 200);
button_box = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
gtk_container_add (GTK_CONTAINER (window), button_box);
button = gtk_button_new_with_label ("Hello World");
g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_widget_destroy), window);
gtk_container_add (GTK_CONTAINER (button_box), button);
gtk_widget_show_all (window);
}
// v<>v<>v<>v<>v<>v<>v<>v<>v<>v<>v
static void on_input_read_finish(GObject *object,
GAsyncResult *result,
gpointer user_data)
{
gchar *clientdata;
gsize length = -1;
gsize i;
g_print("before g_data_input_stream_read_line_finish\n"); // only for debug
clientdata = g_data_input_stream_read_line_finish(G_DATA_INPUT_STREAM(object),
result,
&length,
NULL);
g_print("after g_data_input_stream_read_line_finish\n"); // only for debug
g_print("length: %d\n", length); // only for debug
for(i=0; i<length; i++)
{
g_print("%x ", clientdata[i]);
}
g_print("\n");
}
gboolean sockconnectionestablished(GSocketService *sockservice,
GSocketConnection *connection,
GObject *source_object,
gpointer user_Data)
{
char *clientdata;
gsize length = -1;
gsize i;
g_print("socket connection established!\n"); // only for debug
GDataInputStream *gis = g_data_input_stream_new(g_io_stream_get_input_stream(G_IO_STREAM(connection)));
g_print("after g_data_input_stream_new\n"); // only for debug
g_data_input_stream_set_newline_type(G_DATA_INPUT_STREAM(gis), G_DATA_STREAM_NEWLINE_TYPE_ANY);
g_print("after g_data_input_stream_set_newline_type\n"); // only for debug
g_data_input_stream_read_line_async(G_DATA_INPUT_STREAM(gis),
G_PRIORITY_DEFAULT,
NULL,
on_input_read_finish,
NULL);
g_print("after g_data_input_stream_read_line_async\n"); // only for debug
return 1;
}
// ^<>^<>^<>^<>^<>^<>^<>^<>^<>^<>^
int
main (int argc,
char **argv)
{
GtkApplication *app;
int status;
// v<>v<>v<>v<>v<>v<>v<>v<>v<>v<>v
GError *sockerror = NULL;
GSocketService *sockservice;
gboolean sockstatus;
sockservice = g_socket_service_new();
sockstatus = g_socket_listener_add_inet_port(G_SOCKET_LISTENER(sockservice),
8888,
NULL,
NULL);
g_print("g_socket_listener_add_inet_port status: %d\n", sockstatus); // only for debug
status = g_signal_connect(sockservice,
"incoming",
G_CALLBACK(sockconnectionestablished),
NULL);
g_print("g_signal_connect status: %d\n", status); // only for debug
// ^<>^<>^<>^<>^<>^<>^<>^<>^<>^<>^
app = gtk_application_new ("org.gtk.example", G_APPLICATION_FLAGS_NONE);
g_signal_connect (app, "activate", G_CALLBACK (activate), NULL);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
return status;
}
I have got below sample from stackoverflow itself.
#include <glib.h>
#include <gio/gio.h>
gchar *buffer;
gboolean
network_write(GIOChannel *source,
GIOCondition cond,
gpointer data)
{
return TRUE;
}
gboolean
network_read(GIOChannel *source,
GIOCondition cond,
gpointer data)
{
GString *s = g_string_new(NULL);
GError *error;
g_print("Inside network_read function\n");
GIOStatus ret = g_io_channel_read_line_string(source, s, NULL, &error);
if (ret == G_IO_STATUS_ERROR)
g_error ("Error reading: %s\n", error->message);
else
g_print("Got: %s\n", s->str);
return TRUE;
}
gboolean
new_connection(GSocketService *service,
GSocketConnection *connection,
GObject *source_object,
gpointer user_data)
{
GSocketAddress *sockaddr = g_socket_connection_get_remote_address(connection, NULL);
GInetAddress *addr = g_inet_socket_address_get_address(G_INET_SOCKET_ADDRESS(sockaddr));
guint16 port = g_inet_socket_address_get_port(G_INET_SOCKET_ADDRESS(sockaddr));
g_print("New Connection from %s:%d\n", g_inet_address_to_string(addr), port);
GSocket *socket = g_socket_connection_get_socket(connection);
gint fd = g_socket_get_fd(socket);
g_print("Naseeb fd: %d\n", fd);
GIOChannel *channel = g_io_channel_unix_new(fd);
if(!g_io_add_watch(channel, G_IO_IN, (GIOFunc) network_read, NULL))
{
g_print("Got Error while adding network_read\n");
}
// g_io_add_watch(channel, G_IO_OUT, (GIOFunc) network_write, NULL);
return TRUE;
}
int main(int argc, char **argv) {
g_type_init();
GSocketService *service = g_socket_service_new();
GInetAddress *address = g_inet_address_new_from_string("0.0.0.0");
GSocketAddress *socket_address = g_inet_socket_address_new(address, 3001);
g_socket_listener_add_address(G_SOCKET_LISTENER(service), socket_address, G_SOCKET_TYPE_STREAM,
G_SOCKET_PROTOCOL_TCP, NULL, NULL, NULL);
g_object_unref(socket_address);
g_object_unref(address);
g_socket_service_start(service);
g_signal_connect(service, "incoming", G_CALLBACK(new_connection), NULL);
g_socket_service_start(service);
GMainLoop *loop = g_main_loop_new(NULL, FALSE);
g_main_loop_run(loop);
return 0;
}
Using this code, i am able to get the client connected to server. I confirm the same using message printed in the function new_connection
But when i send data from client, callback network_read never gets called at server. Although client side, send() API return value shows total bytes sent.
1) Is there any api missing at server side.
2) What is proper way to invoke network_write ?
You shouldn't be using GIOChannel, new_connection() already has a connection and you can just use stream = g_io_stream_get_input_stream (G_IO_STREAM (connection)); to get a GInputStream to read from.
I'm a new to socket programming. I tried to connect a server to multiple clients and i have two problems in it. 1)I can't send a message unless i get a reply i.e if a client connects and sends a message,client can't send a message again until it gets reply from server. If client types some message it stores the messages and it sends the message after it gets a reply.
2)I want to restrict the number of connections to 1 and if some one connects no one else should connect until the client the client quits. If the client quits the one who is first in waiting should be connected.
server
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<errno.h>
#include<string.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#define MYPORT 3490 /* the port users connect to */
#define BACKLOG 0 /* max no. of pending connections in server queue */
#define MAXDATASIZE 200
void sigchld_handler(int s)
{
while( wait( NULL) > 0); /* wait for any child to finish */
}
int main( void)
{
int listenfd;
/* listening socket */
int connfd;
/* connection socket */
struct sockaddr_in server_addr; /* info for my addr i.e. server */
struct sockaddr_in client_addr; /* client's address info */
int sin_size;
/* size of address structure */
struct sigaction sa; /* deal with signals from dying children! */
int yes = 1;
char clientAddr[ 20]; /* holds ascii dotted quad address */
if ((listenfd = socket( AF_INET, SOCK_STREAM, 0)) == -1)
{
perror( "Server socket");
exit( 1);
}
/* Set Unix socket level to allow address reuse */
if( setsockopt( listenfd, SOL_SOCKET, SO_REUSEADDR,&yes, sizeof( int)) == -1)
{
perror( "Server setsockopt");
exit( 1);
}
sin_size = sizeof( server_addr);
memset( &server_addr, 0, sin_size);
/* zero struct */
server_addr.sin_family = AF_INET;
/* host byte order ... */
server_addr.sin_port = htons( MYPORT); /* . short, network byte order */
server_addr.sin_addr.s_addr = INADDR_ANY; /* any server IP addr */
if( bind( listenfd, (struct sockaddr *)&server_addr,sizeof( struct sockaddr)) == -1)
{
perror( "Server bind");
exit( 1);
}
if( listen( listenfd, BACKLOG) == -1)
{
perror( "Server listen");
exit( 1);
}
/* Signal handler stuff */
sa.sa_handler = sigchld_handler; /* reap all dead processes */
sigemptyset( &sa.sa_mask);
sa.sa_flags = SA_RESTART;
if( sigaction( SIGCHLD, &sa, NULL) == -1)
{
perror( "Server sigaction");
exit( 1);
}
while( 1)
{
/* main accept() loop */
sin_size = sizeof( struct sockaddr_in);
if( (connfd = accept( listenfd,(struct sockaddr *)&client_addr, &sin_size)) == -1)
{
perror( "Server accept");
continue;
}
strcpy( clientAddr, inet_ntoa( client_addr.sin_addr));
printf( "Server: got connection from %s\n", clientAddr);
if( !fork())
{
/* the child process dealing with a client */
char msg[ MAXDATASIZE];
int numbytes;
close( listenfd); /* child does not need the listener */
msg[ 0] = '\0';
/* no message yet! */
do
{
if( (numbytes =recv( connfd, msg, MAXDATASIZE -1, 0)) == -1)
{
perror( "Server recv");
exit( 1);
/* error end of child */
}
msg[ numbytes] = '\0';
/* end of string */
fprintf( stderr, "Message received: %s\n", msg);
do
{
if( strcmp( msg, "quit") == 0)
{
close( connfd);
exit(0);
}
printf( "Message to send: ");
scanf( "%s", msg);
if( send( connfd, msg, strlen( msg), 0) == -1)
{
perror( "server send");
//exit(1);
}
/* error end of child */
}
while( strcmp( msg, "quit") != 0);
if( strcmp( msg, "quit") == 0)
{
close( connfd);
exit(0);
}
//close( connfd);
//exit(0);
/* end of child! */
}
while(1);
//fork();
//close(connfd); /* parent does not need the connection socket */
return 0;
}
}
}
client:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
/* for gethostbyname() */
#define PORT 3490
/* server port the client connects to */
#define MAXDATASIZE 100 /* max bytes to be received at once */</i>
int main( int argc, char * argv[])
{
int sockfd, numbytes;
char buf[ MAXDATASIZE];
struct hostent *he;
struct sockaddr_in their_addr; /* server address info */
char msg[ MAXDATASIZE];
if( argc != 2) {
fprintf( stderr, "usage: client hostname\n");
exit( 1);
}
/* resolve server host name or IP address */
if( (he = gethostbyname( argv[ 1])) == NULL) { /* host server info */
perror( "Client gethostbyname");
exit( 1);
}
if( (sockfd = socket( AF_INET, SOCK_STREAM, 0)) == -1) {
perror( "Client socket");
exit( 1);
}
memset( &their_addr, 0, sizeof( their_addr));
/* zero all */
their_addr.sin_family = AF_INET;
/* host byte order .. */
their_addr.sin_port = htons( PORT);
/* .. short, network byte order */
their_addr.sin_addr = *((struct in_addr *)he -> h_addr);
if( connect( sockfd, (struct sockaddr *)&their_addr,
sizeof( struct sockaddr)) == -1) {
perror( "Client connect");
exit( 1);
}
do {
printf( "Message to send: ");
scanf( "%s", msg);
if( (numbytes = send( sockfd, msg, strlen( msg), 0)) == -1) {
perror( "Client send");
continue;
}
if( (numbytes = recv( sockfd, buf, MAXDATASIZE - 1, 0)) == -1) {
perror( "Client recv");
continue;
}
buf[ numbytes] = '\0';
/* end of string char */
printf( "Received: %s\n", buf);
} while( strcmp( msg, "quit") != 0);
close( sockfd);
return 0;
}
dear you have to use multithreading for this start a new thread to handle new connection
in that thread also use separate threads for receiving data and sending data ...
1)I can't send a message unless i get a reply i.e if a client connects
and sends a message,client can't send a message again until it gets
reply from server.
That's no wonder, since you have programmed this sequential arrangement of scanf and recv in your client's do loop. To handle message input and socket receipt in order of appearance, we can use select; your do loop could then look like:
do
{ fd_set fds;
FD_ZERO(&fds);
FD_SET(STDIN_FILENO, &fds);
FD_SET(sockfd, &fds); // set of descriptors holds stdin and socket
printf("Message to send: "), fflush(stdout);
if (select(sockfd+1, &fds, NULL, NULL, NULL) < 0) break; // error?
// see which descriptors of set are ready
if (FD_ISSET(STDIN_FILENO, &fds))
{ // it is the standard input
scanf("%s", msg);
numbytes = send(sockfd, msg, strlen(msg), 0);
if (numbytes == -1) perror("Client send");
}
if (FD_ISSET(sockfd, &fds))
{ // this is the peer's message or termination
numbytes = recv(sockfd, buf, MAXDATASIZE - 1, 0);
if (numbytes <= 0)
{
perror("Client recv");
break; // no more data from peer, so close the connection
}
buf[numbytes] = '\0'; /* end of string char */
printf("Received: %s\n", buf);
}
} while (strcmp(msg, "quit") != 0);
2)I want to restrict the number of connections to 1 and if some one
connects no one else should connect until the client the client quits.
We can achieve this simply by not forking a server process after we accept a client connection request, but rather handling the message transfer in the one and only server task itself (quite similar as shown above for the client); just omit the lines if( !fork()) as well as return 0; instead uncomment the close(connfd); and don't forget to break out of the do loop when recv returns a nonpositive value.