I'm building simple http status checker in C. I've got the network part done, but I'm having trouble with string manipulation. Here how it works:
$ ./client http://domain.com/path.html#anchor
200
This utility simply outputs the status of given page on the command line. I need to parse the given string into hostname and request path. I've also built a "template" string with this define:
#define HTTP_GET_MSG "GET %s HTTP/1.1\nUser-Agent: my-agent-0.01\nHost: %s\n\n"
I'd like to know how should I approach the interpolation of parsed url (host and path) into this defined string before send()ing it to the socket?
A simple approach is to use sprintf:
char req[ SOME_SUITABLE_SIZE ];
sprintf( req, HTTP_GET_MSG, host, path );
but this will be vunerable to buffer overruns unless you check the lengths of "host" and "path" beforehand. If your system has snprintf you can avoid this:
snprintf( req, SOME_SUITABLE_SIZE, HTTP_GET_MSG, host, path );
Related
Consider this typical for Linux function (it returns the current process username):
char* currentUserName(void) {
struct passwd *p = getpwuid(getuid());
return (p? p->pw_name : NULL);
}
How to get it in Unicode (let's say wchar_t)? To be honest, I don't know what is the encoding of pw_name even (system? Which one - File System? Always UTF-8?).
Is there a way to get the username as wchar_t string? Maybe some function similar to Windows's GetUserNameW() (where W is for wide-chars) - to do it without to link with iconv library...
Maybe I can use mbstowcs() but which locale will be used? I plan to call this function from systemd service, so I have not idea what LC_CTYPE/LANG is there...
I am analyzing Chromium OS.
I have captured a dbus method call using dbus-monitor and want to reappear it by dbus-send.
Below is what I want to reappear.
my-chromiumos ! # dbus-monitor --system "path=/org/chromium/SessionManager"
method call time=1632639141.486152 sender=:1.325 -> destination=org.chromium.SessionManager serial=402 path=/org/chromium/SessionManager; interface=org.chromium.SessionManagerInterface; member=RestartJob
file descriptor
inode: 489350
type: socket
address family: unix
name #
peer #
array [
string "/opt/google/chrome/chrome"
string "--gpu-sandbox-failures-fatal=no"
string "--enable-logging"
string "--use-cras"
string "--use-gl=egl"
string "--user-data-dir=/home/chronos"
string "--vmodule=*night_light*=1,*/ash/wm/tablet_mode/*=1,wizard_controller=1,*/webui/chromeos/login/*=1,*/browser/chromeos/login/screens/*=1,enrollment_screen_handler=1,*/browser/chromeos/login/enrollment/*=1,*/ui/ozone/*=1,*/ui/display/manager/chromeos/*=1"
string "--enable-wayland-server"
string "--aura-legacy-power-button"
string "--login-profile=user"
string "--system-developer-mode"
string "--bwsi"
string "--homepage=chrome://newtab/"
string "--incognito"
string "--log-level=1"
string "--login-user=$guest"
]
uint32 0
Please take a look at dbus-send documentation for more details.
dbus-send --dest=org.chromium.SessionManager \
--print-reply \
--type=method_call \
/org/chromium/SessionManager \
org.chromium.SessionManagerInterface.RestartJob
It looks like the above method call do not take any argument, but you should confirm with the available API documentation.
Also, I found this Chrome OS D-Bus Best Practices guide, please take a look at it as well.
When i try to download a set of files using stream sockets over an HTTP protocol, it only gets data from the first file i try to download.
Assume a loop like the following...
char* file = (char*) malloc(enough_space);
char page[] = {"www.foobar.com"};
for(int n=0 ; n<10 ; n++)
{
sprintf(file, "file%i.html", n);
fopen(file, "wb");
sprintf(request, "GET %s HTTP/1.1\nHost: %s\n\n", file, page);
write( socket, request, strlen(request) );
read_file(output_file);
fclose(output_file);
}
Where a connection has been established first.
This code would give me file1.html, including its header from the server.. But only the first file, and this puzzles me.. What will i have to do in order to get them all?
Thanks up front.
HTTP was designed so that just a single file can be downloaded over a TCP connection. To download multiple files over one TCP connection, you could use HTTP Pipelining. You can read more here: HTTP pipelining request text example
Or you could just use one of the many libraries that will handle this, and many other caveats of HTTP for you: libcurl, libsoup...
I want to find out the default network in use. My current method was to find all IP addresses and compare it to the default gateway IP address, but that sounds silly. What is the correct way of doing it ?
UPDATE
I want to use a C program, not by commands ...
You can try a slightly dirtier but infinitely easier approach:
cnicutar#lemon:~$ ip route show to 0.0.0.0/0
default via X.Y.Z.T dev eth0 proto static
^^^^
So you can try:
FILE *cmd = popen("ip route show", "r");
fgets(str, LEN, cmd);
Then you can use strtok, strstr etc.
Here is a telnet site:
telnet://202.85.101.136:8604/
It is from Hong Kong public library, can I write some programme to get the string / result from the telnet service, and send the request from C / Objective C? thz u.
Sure its possible. Telnet is a pretty simple protocol, you simply need to open a TCP socket and connect it to that IP and Port. When you first connect, the telnet server will send some negotiation requests using the binary protocol defined in RFC854, to which your client is expected to respond. Once negotiation is completed you communicate by simply sending and receiving ASCII data, normally a line at a time.
For a simple "get some data from a host" telnet sessions where you aren't trying to have a real interactive session, it sometimes works to simply accept all the servers negotiation settings to avoid implementing the whole negotiation protocol. To do this, just look for the server to send you several 3-byte commands in the format of: 0xFF 0xFD xx, which is basically the server telling you "I want you to use option X", just respond to this with 0xFF 0xFB xx, which basically is just you agreeing to whatever the server is asking for. Then when you get passed negotiations, you just have to receive lines with a socket read and send commands with a socket write.
If you have a telnet program already on your system, you can use it to do all the connection work for you. Here's a program for gnu/Linux that you can use as a starting point.
It uses popen to execute the system's telnet command. Then it just reads all data from the pipe (stdout if you just executed the telnet command by itself from the shell) and prints it. When there's no more data to read, it exits.
You can send data to the server by opening the pipe in rw mode instead of r and then writing like you would any other file. You could conditionally do stuff like scan your input for Username: and then send a username string too, for instance.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
const char *cmd = "telnet 202.85.101.136 8604";
char buffer[256];
FILE *pipe = popen(cmd, "r");
if( !pipe ) { perror("popen"); exit(-1); }
while( fgets(buffer, sizeof(buffer), pipe) != NULL &&
!feof(pipe) )
{
if( ferror(pipe) ) { perror("fgets"); break; }
/* Here you do whatever you want with the data. */
printf("%s", buffer);
}
pclose(pipe);
return 0;
}
If you're using Windows, this link explains the alternative to popen.
There's also a program called Expect that can help you automate stuff like this.