Amiga.org

Amiga computer related discussion => Amiga Software Issues and Discussion => Topic started by: AmigaEd on January 21, 2006, 02:57:04 AM

Title: Example of C source code for getting web page.
Post by: AmigaEd on January 21, 2006, 02:57:04 AM
Hello,
I'm trying to learn C and I am wondering if someone out there might have a very simple example of some C source code that will grab a web page and display it or even just save it as a file.

I've looked at a few programs on aminet, but I can't seem to make sense out of them.

Thank you,
AmigaEd
Title: Re: Example of C source code for getting web page.
Post by: koaftder on January 21, 2006, 03:05:10 AM
Quote

AmigaEd wrote:
Hello,
I'm trying to learn C and I am wondering if someone out there might have a very simple example of some C source code that will grab a web page and display it or even just save it as a file.

I've looked at a few programs on aminet, but I can't seem to make sense out of them.

Thank you,
AmigaEd


This isnt too bad achttp://www.google.com/search?hl=en&q=software+hut&btnG=Google+Searchtually. Learn your tcp library. All you have to do is issue one simple string. something like "GET HTTP 1.0 /"

then the web server simply spits back the result.

so it goes like this:

create socket
set sock addr
set sock port
open socket
send socket ( request_string )
receive result

then write the input uffer to standard output or to a file, what ever

obviously the libs are different for every os

check out the rfc for http for more detial on what you can do with it http://www.faqs.org/rfcs/rfc2616.html

sorry i cant help you with the tcp stuff on amiga, as i have never used socket library on amigaos.


Title: Re: Example of C source code for getting web page.
Post by: koaftder on January 21, 2006, 03:53:38 AM
Ive written a simple program that does what you are talking about, for linux. Theres still a small problem with it though, compiler is telling me that it doesnt know the size for socket_detials....

Code: [Select]

#include <sys/types.h>
#include <sys/socket.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main ( void ) {
        int socket_handle ;
        struct sockaddr_in socket_detials ;
        char * input_buffer;
        char * httpget = &quot;GET HTTP 1.1 / \r\r&quot; ;

        input_buffer = malloc(20000);

        socket_handle = socket ( AF_INET, SOCK_STREAM, 0) ;
        socket_detials.sin_family = AF_INET ;
        socket_detials.sin_addr.s_addr=inet_addr(&quot;68.90.68.66&quot;);
        socket_detials.sin_port = htons(80);

        connect (socket_handle,(struct sockaddr*)&socket_detials, sizeof ( struct sockaddr));
        send ( socket_handle , httpget, strlen(httpget), 0 ) ;
        recv ( socket_handle , input_buffer , 20000, 0 ) ;
        printf ( &quot;%s\n&quot;, input_buffer ) ;

        return 0 ;
}


you may want to check out the simple socket library from http://mysite.verizon.net/astronaut/ssl/

It supports a lot of os's and i seem to remember saying it supported amiga... Socket programming with training wheels
Title: Re: Example of C source code for getting web page.
Post by: AmigaEd on January 21, 2006, 03:59:38 AM
Quote
by koaftder on 2006/1/20 22:05:10
This isnt too bad achttp://www.google.com/search?hl=en&q=software+hut&btnG=Google+Searchtually. (http://achttp://www.google.com/search?hl=en&q=software+hut&btnG=Google+Searchtually.) Learn your tcp library. All you have to do is issue one simple string. something like "GET HTTP 1.0 /"


Hi koaftder,
The link you posted seems to take me to a bunch of links to software hut on google.

Can you please post the link again or point me to the correct site.

Thank you,
AmigaEd



Title: Re: Example of C source code for getting web page.
Post by: koaftder on January 21, 2006, 04:04:28 AM
Quote

AmigaEd wrote:
Quote
by koaftder on 2006/1/20 22:05:10
This isnt too bad achttp://www.google.com/search?hl=en&q=software+hut&btnG=Google+Searchtually. (http://achttp://www.google.com/search?hl=en&q=software+hut&btnG=Google+Searchtually.) Learn your tcp library. All you have to do is issue one simple string. something like "GET HTTP 1.0 /"


Hi koaftder,
The link you posted seems to take me to a bunch of links to software hut on google.

Can you please post the link again or point me to the correct site.

Thank you,
AmigaEd





Sorry ): i must have hit paste when i typed that. Only link i meant to post on that comment was http://www.faqs.org/rfcs/rfc2616.html for the http protocol specification. I was on the hunt for zip ram, i figure if i cant figure out which order they need to be piled up in the sockets, i'll just fill up every socket.
Title: Re: Example of C source code for getting web page.
Post by: Rooster on January 21, 2006, 04:21:17 AM
"Ive written a simple program that does what you are talking about, for linux. Theres still a small problem with it though, compiler is telling me that it doesnt know the size for socket_detials...."

Shouldn't that be socket_details ?  Maybe that's why it doesn't know the size, incorrect syntax?  Not sure, just guessing...  Looked like a typo, and I ran it through some search engines to check, got 0 hits - there are relevent tcp texts mentioning what I listed though..  Just curious. ;)
Title: Re: Example of C source code for getting web page.
Post by: ChaosLord on January 21, 2006, 04:32:26 AM
Quote
koaftder wrote:

you may want to check out the simple socket library from http://mysite.verizon.net/astronaut/ssl/

It supports a lot of os's and i seem to remember saying it supported amiga... Socket programming with training wheels

The word "Amiga" does not exist on that site.

I cannot find any evidence that it has ever been ported to AmigaOS.

Have you personally used Simple Socket Library?
Is it reliable?
Does it limit you in some way?
Title: Re: Example of C source code for getting web page.
Post by: patrik on January 21, 2006, 04:34:08 AM
The request-string should be "GET / HTTP/1.0\r\n\r\n" to get the default page. For another page "GET /somedir/somefile.html HTTP/1.0\r\n\r\n". This will make the HTTP-server respond with a header and then the content.

The easiest way to get the default page is to skip the HTTP-version and make the request-string just "GET /\r\n". This will make the server assume a HTTP/0.9 client and just send the file without any header before it.

When writing a simple client, I would recommend sending "HTTP/1.0" as version, because then you will get the header plus have the possibility to support virtual hosts (which almost all webservers use to share many sites on one the same ip-adress), but not have to support chunked transfer mode.

For example this site requires the client to tell what site he is referring to, as the server is using virtual hosts to host several sites. A request to get the default page of amiga.org would look like this:
Code: [Select]
GET / HTTP/1.0\r\n
Host: amiga.org\r\n\r\n
Without supplying the "Host: amiga.org"-line, the webserver wont know what site you are asking for and will return some default page - try entering the ip-adress (http://68.90.68.66/) for amiga.org in a browser and see what happens then.

\r = Carriage Return (CR = 0x0D)
\n = Line Feed (LF = 0x0A)

This (http://www.jmarshall.com/easy/http/) page, when working, has some rather good information.

(edit): Removed errors.


/Patrik
Title: Re: Example of C source code for getting web page.
Post by: koaftder on January 21, 2006, 04:40:49 AM
ok, finally got my code to work
Code: [Select]

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main ( void ) {
        int socket_handle ;
        struct sockaddr_in socket_detials ;
        char * input_buffer;
        char * httpget = &quot;GET HTTP 1.1 / \x0D\x0A\n\x0D\x0A\n&quot; ;

        input_buffer = malloc(20000);

        socket_handle = socket ( AF_INET, SOCK_STREAM, 0) ;
        socket_detials.sin_family = AF_INET ;
        socket_detials.sin_addr.s_addr=inet_addr(&quot;68.90.68.66&quot;);
        socket_detials.sin_port = htons(80);
        bzero ( &(socket_detials.sin_zero), 8 ) ;

        if ( connect (socket_handle,(struct sockaddr*)&socket_detials, sizeof ( struct sockaddr)) == -1 ){
                printf ( &quot;Couldnt connect to server\n&quot; ) ;
        }
        printf ( &quot;Sending %d bytes\n&quot;,  send ( socket_handle , httpget, strlen(httpget), 0 ) ) ;
        printf ( &quot;Received %d bytes\n&quot;, recv ( socket_handle , input_buffer , 20000, 0 ) ) ;
        printf ( &quot;%s\n&quot;, input_buffer ) ;

        return 0 ;
}


and when i run it i get :

Code: [Select]

koft@macdev:~$ ./socket
Sending 21 bytes
Received 658 bytes
HTTP/1.1 400 Bad Request
Date: Sat, 21 Jan 2006 04:37:48 GMT
Server: Apache/1.3.34 (Unix) mod_auth_passthrough/1.8 mod_log_bytes/1.2 mod_bwlimited/1.4 PHP/4.4.1 FrontPage/5.0.2.2635 mod_ssl/2.8.25 OpenSSL/0.9.7a
Connection: close
Content-Type: text/html; charset=iso-8859-1



400 Bad Request

Bad Request


Your browser sent a request that this server could not understand.


The request line contained invalid characters following the protocol string.





Apache/1.3.34 Server at cpanel1.betterbox.net Port 80



koft@macdev:~$


Tip, when things arent working, use ethereal to view your traffic. I spent some time watching the program hang because i wasnt sending it the right stuff after the get. ( i tried  0d0a0d0a but that didnt do it.... ) I wasnt even sure it actually send the packet to the server, or at the right address or port, untill i fired up ethereal and saw for sure what was really going on.
Title: Re: Example of C source code for getting web page.
Post by: patrik on January 21, 2006, 04:44:34 AM
@koaftder:

The reason why you are getting a "400 Bad Request" response is because you are specifying that your client is a HTTP/1.1 client, which requires you to supply the "Host: something.com" header-line, which is optional in HTTP/1.0, but required for virtual hosts to work, so it is definately recommended to supply it anyhow.

With a simple client, there is no advantage in telling the server that your client supports HTTP/1.1 instead of HTTP/1.0, rather disadvantages as then the server is allowed to send you dynamic pages as chunks using the so called "chunked transfer-coding".


/Patrik
Title: Re: Example of C source code for getting web page.
Post by: koaftder on January 21, 2006, 05:17:21 AM
Quote

patrik wrote:
@koaftder:

The reason why you are getting a "400 Bad Request" response is because you are specifying that your client is a HTTP/1.1 client, which requires you to supply the "Host: something.com" header-line, which is optional in HTTP/1.0, but required for virtual hosts to work, so it is definately recommended to supply it anyhow.

With a simple client, there is no advantage in telling the server that your client supports HTTP/1.1 instead of HTTP/1.0, rather disadvantages as then the server is allowed to send you dynamic pages as chunks using the so called "chunked transfer-coding".


/Patrik


ok, so i will just capture what fire fox sends out when i goto amiga.org, here is the fix  :-)

Code: [Select]

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main ( void ) {
        int socket_handle ;
        struct sockaddr_in socket_detials ;
        char * input_buffer;
        char * httpget =

          &quot;GET / HTTP/1.1\r\n&quot;
          &quot;Host: www.amiga.org\r\n&quot;
          &quot;User-Agent: Mozilla/5.0 (X11; U; Linux ppc; en-US; rv:1.7.10) Gecko/20050825 Firefox/1.0.6 (Ubuntu package 1.0.6)\r\n&quot;
          &quot;Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5\r\n&quot;
          &quot;Accept-Language: en-us,en;q=0.5\r\n&quot;
          &quot;Accept-Encoding: gzip,deflate\r\n&quot;
          &quot;Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7\r\n&quot;
          &quot;Keep-Alive: 300\r\n&quot;
          &quot;Connection: keep-alive\r\n&quot;
          &quot;Referer: http://www.amiga.org/gallery/index.php?n=896=33\r\n&quot;
          &quot;Cookie: PHPSESSID=442105507b7dca6d4042a641fc132c8f; AO_Session=442105507b7dca6d4042a641fc132c8f\r\n&quot;
          &quot;Cache-Control: max-age=0\r\n&quot;
          &quot;\r\n&quot;;

        input_buffer = malloc(20000);

        socket_handle = socket ( AF_INET, SOCK_STREAM, 0) ;
        socket_detials.sin_family = AF_INET ;
        socket_detials.sin_addr.s_addr=inet_addr(&quot;68.90.68.66&quot;);
        socket_detials.sin_port = htons(80);
        bzero ( &(socket_detials.sin_zero), 8 ) ;

        if ( connect (socket_handle,(struct sockaddr*)&socket_detials, sizeof ( struct sockaddr)) == -1 ){
                printf ( &quot;Couldnt connect to server\n&quot; ) ;
        }
        printf ( &quot;Sending %d bytes\n&quot;,  send ( socket_handle , httpget, strlen(httpget), 0 ) ) ;
        printf ( &quot;Received %d bytes\n&quot;, recv ( socket_handle , input_buffer , 20000, 0 ) ) ;
        printf ( &quot;%s\n&quot;, input_buffer ) ;

        return 0 ;
}


and it returns the following now:

Code: [Select]

koft@macdev:~$ ./socket
Sending 612 bytes
Received 1460 bytes
HTTP/1.1 200 OK
Date: Sat, 21 Jan 2006 05:03:13 GMT
Server: Apache/1.3.34 (Unix) mod_auth_passthrough/1.8 mod_log_bytes/1.2 mod_bwlimited/1.4 PHP/4.4.1 FrontPage/5.0.2.2635 mod_ssl/2.8.25 OpenSSL/0.9.7a
X-Powered-By: PHP/4.4.1
Set-Cookie: PHPSESSID=442105507b7dca6d4042a641fc132c8f; path=/
Expires: Mon, 26 Jul 1997 05:00:00 GMT
Cache-Control: private, no-cache
Pragma: no-cache
Set-Cookie: AO_Session=442105507b7dca6d4042a641fc132c8f; expires=Saturday, 28-Jan-06 05:03:14 GMT; path=/
Keep-Alive: timeout=15, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: text/html; charset=ISO-8859-1

d19







Code: [Select]

koft@macdev:~$


i broke up one of thoes lines because it was annoying

Writing network code can be a lot of fun, though it can be a major undertaking if you have to write something more than some hacks for a hobby project.

I have a few books about socket programming for windows and linux, they cover a lot of material but dont seem to dig into some detials i'd like to fill in without having to experiment for years and write mountians of code. Multithreaded socket programming comes into mind, most books seem to skirt around the subject. If i'm writing a server daemon for something, i'm going to need to handle a lot of simultaneous connections. Do i use blocking or non blocking sockets? Do i spawn off a thread for each socket, and make it a blocking socket? Should i spawn of a thread for every 10 sockets and do non blocking io? Should i fork the daemon 5 times and load balance the connections accross the processes? How do i effectively deal with resource starvation caused by jerks who write scripts that keep opening hundreds of connections and letting them hang? Thoes are the topics i'd like to see covered in a book, performance strategies and security issues. I really really dont have time to read all the socket code for apache.
Title: Re: Example of C source code for getting web page.
Post by: AmigaEd on January 21, 2006, 05:39:56 AM
Quote
by ChaosLord on 2006/1/20 23:32:26
The word "Amiga" does not exist on that site.


I agree I looked that site all over and could find no reference to "Amiga".

I really need some code that I can compile and run on an Amiga. Linux is just not an option for me right now.

Best Regards,
AmigaEd
Title: Re: Example of C source code for getting web page.
Post by: patrik on January 21, 2006, 05:45:50 AM
@koaftder:

Dude, no need to send so much! Check my earlier example for amiga.org, which is the only stuff you need to send and should send to make it work with all servers plus make it as easy as possible for you when coding a client. If you dont advertise that your client supports wierd encodings and transfer modes, the server wont utilize such.

This (http://pl.atyp.us/content/tech/servers.html) page is rather good regarding what pitfalls there are when designing high performance server software.


/Patrik
Title: Re: Example of C source code for getting web page.
Post by: patrik on January 21, 2006, 06:35:26 AM
@AmigaEd:

If targetting for the Amiga, you should take a look at the AmiTCP-SDK (http://aminet.net/package.php?package=comm/tcp/AmiTCP-SDK-4.3.lha) which gives you the necessary headers to work with bsdsocket.library (also link-libraries that can do some misc stuff for you, but they are not needed) which is the standard implementation of the BSD sockets API amongst Amiga TCP/IP stacks.

Using bsdsocket.library is not hard, you need to add the AmiTCP-SDKs in your include-path and include , and . Its like using any other shared library - you can utilize its functions after opening it with exec.library/OpenLibrary(). After that, it is more or less identical to programming the BSD sockets API, as far as the networking is concerned.

There are also some examples with the AmiTCP-SDK, even a small HTTP/GET client. If you are new to C, they might not be too straightforward though.


/Patrik
Title: Re: Example of C source code for getting web page.
Post by: koaftder on January 21, 2006, 06:36:49 AM
@patrik

You are right about the extraneous stuff i had put in there. I just wanted to demonstrate the connection and retrieving some stuff, no need to confuse people.

That document you pointed out is a wonderful read.

@AmigaEd

Sorry to point you off into a wrong direction. I grabbed the package and sure enough, doesnt support amiga ): It's a really nice easy lib to work with. It supported dos/windows/os2/unix/linux/vms, etc. I guess i just thought it ran on amiga cause the guy who wrote it is a nasa geek and everybody seems to mention about how much amiga was used in that organisation.
Title: Re: Example of C source code for getting web page.
Post by: Jose on January 21, 2006, 12:37:44 PM
"If targetting for the Amiga, you should take a look at the AmiTCP-SDK which gives you the necessary headers to work with bsdsocket.library (also link-libraries that can do some misc stuff for you, but they are not needed) which is the standard implementation of the BSD sockets API amongst Amiga TCP/IP stacks."

Even Roadshow ?
I'm asking this cause I'm planning on learning some network stuff too. About a year I got a book from Uni's library on networking but got completely let down by the amount of all the different protocols. I guess one doesn't need to know TCP/IP to do some basic network coding, only if I was to do my own stack. But since many hacks one see desbribed on the net imply some TCP/IP knowledge I'd like to learn it to understand it:) 8-)
Title: Re: Example of C source code for getting web page.
Post by: AmigaEd on January 21, 2006, 12:45:16 PM
@koaftder,
Hey no problem, no need to be sorry. All of the information that you have posted has been very helpful and I'm sure that eventually I will also give this a try on windoze or unix (for work purposes of course ) ;-)

Best Regards,
AmigaEd
Title: Re: Example of C source code for getting web page.
Post by: patrik on January 21, 2006, 01:08:14 PM
@Jose:

Yes, all TCP/IP-stacks on the Amiga, except the obselete AS225, gives you access through bsdsocket.library, even Roadshow - else no existing network applications would work with it.

It is always good to have atleast some knowledge about the protocols you are going to use. Not necessary all the nitty gritty details, but it will give you a much better understanding of how to create applications that are suited for them if you have a fair amount of knowledge about how they work, what their strongpoints and drawbacks are, etc.


/Patrik
Title: Re: Example of C source code for getting web page.
Post by: Piru on January 21, 2006, 03:08:49 PM
@koaftder

Bugs:

- You don't check if malloc() fails, but just crash if it does.
- You don't check if socket() fails, but just continue instead.
- bzero ( &(socket_detials.sin_zero), 8 ) ; is wrong. It assumes knowlege of the struct sockaddr_in, which can be different between platforms. Typecally it is 8 though, but there is no guarantee of this.
- You don't bail out if connect() fails, but just continue.
- You don't check if send() succeeds.
- You don't check how much data you manage to recv().
- You limit the recv size to 20000 bytes. If more data would be available you just truncate input.
- There is no guarantee single recv() will get all the input at once. You might get just the header for the 1st call, or part of the header. You should call recv() till -1 (error) or 0 (eof) is returned.
- You printf %s the input buffer, even though it is not '\0' terminated.
- Sending fixed cookies will not work. Esp PHPSESSID will just fail once the session id has expired.
Title: Re: Example of C source code for getting web page.
Post by: ChaosLord on January 21, 2006, 04:03:35 PM
Nothing gets past Piru.   :-D
Title: Re: Example of C source code for getting web page.
Post by: AmigaEd on January 21, 2006, 04:08:29 PM
Hi Piru,
We know you are the Amiga Code master.
How about showing us the correct way to do it.

Thank you,
AmigaEd
Title: Re: Example of C source code for getting web page.
Post by: Piru on January 21, 2006, 05:31:13 PM
Code: [Select]

;/*
gcc -noixemul -Wall -O2 httpget.c -o httpget
quit
*/

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#ifndef STDOUT_FILENO
#define STDOUT_FILENO 1
#endif


#include <proto/exec.h>
#ifdef __SASC
#include <proto/socket.h>
#endif
#include <clib/alib_protos.h>

#define RECV_BUFSIZE 16384

struct MinList *http_get(const char *host, int port, const char *path);
struct MinList *dorecv(int s);
void dumplist(struct MinList *list);
void freelist(struct MinList *list);

struct datanode
{
  struct MinNode node;
  int            len;
};

int main(void)
{
  struct MinList *res;

  res = http_get(&quot;www.amiga.org&quot;, 80, &quot;/&quot;);
  if (res)
  {
    dumplist(res);
    freelist(res);
  }
  else
  {
    fprintf(stderr, &quot;http_get failed\n&quot;);
  }

  return 0;
}

/*
   FUNCTION

   http_get - HTTP GET a location off a web server

   struct MinList *http_get(const char *host, int port, const char *path)
   

   INPUT

   The http-request must be split into valid components for this function.

   host: hostname
   port: port number
   path: the path of object to http get. spaces and special chars should
         be encoded to %<hex>

   RESULT

   struct MinList *

     NULL if error, else list filled with 'struct datanode' nodes. Note
     that the output includes the full header returned by the server, and
     it's left for the caller to parse it (separate header and actual
     data).

   NOTE

   This function blocks, and it can potentially take hours to complete;
   for example if the file is long, or the connection is very slow.
*/

struct MinList *http_get(const char *host, int port, const char *path)
{
  struct MinList *list = NULL;
  int s;

  if (host && host[0] && port > 0 && path)
  {
    struct sockaddr_in saddr;
    struct hostent *he;

    bzero(&saddr, sizeof(saddr));

    he = gethostbyname(host);
    if (he)
    {
      memcpy(&saddr.sin_addr, he->h_addr, he->h_length);
      saddr.sin_family = he->h_addrtype;
    }
    else
    {
      saddr.sin_addr.s_addr = inet_addr(host);
      saddr.sin_family = AF_INET;
    }

    if (saddr.sin_addr.s_addr != INADDR_NONE)
    {
      s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (s != -1)
      {
        saddr.sin_port = htons(port);

        if (connect(s, (struct sockaddr *) &saddr, sizeof(saddr)) != -1)
        {
          const char *fmt =
            &quot;GET %s HTTP/1.0\r\n&quot;
            &quot;Host: %s\r\n&quot;
            &quot;User-Agent: httpget_test_app/1.0\r\n&quot;
            &quot;\r\n&quot;;
          char *req;

          if (path[0] == '\0')
          {
            path = &quot;/&quot;;
          }

          req = malloc(strlen(fmt) +
                       strlen(path) - 2 +
                       strlen(host) - 2 + 1);
          if (req)
          {
            int reqlen;

            sprintf(req, fmt, path, host);
            reqlen = strlen(req);

            if (send(s, req, reqlen, 0) == reqlen)
            {
              list = dorecv(s);
            }

            free(req);
          }

          close(s);
        }
      }
    }
  }

  return list;
}

struct MinList *dorecv(int s)
{
  struct MinList *list = NULL;
  UBYTE *buf;

  buf = malloc(RECV_BUFSIZE);
  if (buf)
  {
    int ok = 0;

    for (;;)
    {
      int actual;

      actual = recv(s, buf, RECV_BUFSIZE, 0);
      if (actual == -1)
      {
        /* error */
        break;
      }
      else if (actual == 0)
      {
        /* eof */
        ok = 1;
        break;
      }
      else
      {
        struct datanode *node;

        if (!list)
        {
          list = malloc(sizeof(*list));
          if (!list)
          {
            break;
          }
          NewList((struct List *) list);
        }

        node = malloc(sizeof(*node) + actual);
        if (!node)
        {
          break;
        }
        node->len = actual;
        memcpy(node + 1, buf, actual);

        AddTail((struct List *) list, (struct Node *) node);
      }
    }

    if (!ok)
    {
      freelist(list);
      list = NULL;
    }

    free(buf);
  }

  return list;
}

void dumplist(struct MinList *list)
{
  if (list)
  {
    struct datanode *node;

    fflush(stdout);

    for (node = (APTR) list->mlh_Head;
         node->node.mln_Succ;
         node = (APTR) node->node.mln_Succ)
    {
      write(STDOUT_FILENO, node + 1, node->len);
    }

    fflush(stdout);
  }
}

void freelist(struct MinList *list)
{
  if (list)
  {
    struct datanode *node, *nextnode;

    for (node = (APTR) list->mlh_Head;
         (nextnode = (APTR) node->node.mln_Succ);
         node = nextnode)
    {
      free(node);
    }

    free(list);
  }
}
Title: Re: Example of C source code for getting web page.
Post by: Piru on January 21, 2006, 05:39:25 PM
Oh, I used exec lists there.

If this thing must be portable you can use dlist (http://www.iki.fi/sintonen/src/dlist/) instead.
Title: Re: Example of C source code for getting web page.
Post by: ChaosLord on January 21, 2006, 06:03:27 PM
I am trying to slowly convert my braincells over from SASC to gcc.


What does -Wall do?

What does -noixemul do?

Title: Re: Example of C source code for getting web page.
Post by: Piru on January 21, 2006, 06:09:49 PM
@ChaosLord

-W is warning option. -Wall means "enable all standard warnings"

-noixemul means 'do not use ixemul.library' (this is stricly gcc thing).

BTW: In this program m68k gcc users might need to drop the -noixemul option, that is to use ixemul.library. Also, dependin on the gcc version -lamiga migth be required to get the thing to link.
Title: Re: Example of C source code for getting web page.
Post by: Dr_Righteous on January 21, 2006, 06:26:08 PM
@Piru
BAH! Who needs error checking?!  :-D
Title: Re: Example of C source code for getting web page.
Post by: Piru on January 21, 2006, 06:30:48 PM
Note: It builds with SAS/C aswell now (at least with MiamiSDK (http://www.aminet.net/package.php?package=comm/tcp/MiamiSDK211.lha)).

sc resopt incdir Path:to/MiamiSDK/netinclude/ link httpget.c lib Path:to/MiamiSDK/netlib/miami.lib

Anyway, if someone has any more questions about the src, just ask. I'm happy to explain it.
Title: Re: Example of C source code for getting web page.
Post by: koaftder on January 21, 2006, 08:42:27 PM
Quote

Piru wrote:
@koaftder

Bugs:

- You don't check if malloc() fails, but just crash if it does.
- You don't check if socket() fails, but just continue instead.
- bzero ( &(socket_detials.sin_zero), 8 ) ; is wrong. It assumes knowlege of the struct sockaddr_in, which can be different between platforms. Typecally it is 8 though, but there is no guarantee of this.
- You don't bail out if connect() fails, but just continue.
- You don't check if send() succeeds.
- You don't check how much data you manage to recv().
- You limit the recv size to 20000 bytes. If more data would be available you just truncate input.
- There is no guarantee single recv() will get all the input at once. You might get just the header for the 1st call, or part of the header. You should call recv() till -1 (error) or 0 (eof) is returned.
- You printf %s the input buffer, even though it is not '\0' terminated.
- Sending fixed cookies will not work. Esp PHPSESSID will just fail once the session id has expired.


haha, i'm supprised you took the time to list all the unresponsible things i did. Since you took the time to review it, i'll take the time to fix it. Here it is:

Code: [Select]

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

int main ( void ) {
int socket_handle ;
struct sockaddr_in socket_detials ;
char * input_buffer;
char * pinput_buffer ;
ssize_t bytes_received ;
ssize_t bytes_sent ;
char * phttpget ;
char * httpget =
 &quot;GET / HTTP/1.0\r\n&quot;
 &quot;Host: www.amiga.org\r\n&quot;
 &quot;\r\n&quot;;

phttpget = httpget ;
bytes_sent = 0 ;

input_buffer = malloc(1024);
if ( input_buffer == NULL ) {
printf ( &quot;Sorry, couldnt allocate memory for input buffer\n&quot; );
return -1 ;
}
memset ( input_buffer, 0, 1024 ) ;

memset ( &socket_detials , 0 , sizeof(struct sockaddr_in) );

socket_handle = socket ( AF_INET, SOCK_STREAM, 0) ;
if ( socket_handle == -1 ) {
printf ( &quot;Could not create socket\n&quot; ) ;
return -1 ;
}
socket_detials.sin_family = AF_INET ;
socket_detials.sin_addr.s_addr=inet_addr(&quot;68.90.68.66&quot;);
socket_detials.sin_port = htons(80);

if ( connect (socket_handle,(struct sockaddr*)&socket_detials, sizeof ( struct sockaddr)) == -1 ){
printf ( &quot;Couldnt connect to server\n&quot; ) ;
return -1 ;
}

printf ( &quot;Attempting to send %d bytes to server\n&quot; , strlen ( httpget ) );
for(;;){
bytes_sent = send ( socket_handle , phttpget, strlen(phttpget), 0 ) ;
if ( bytes_sent == -1 ) {
printf ( &quot;An error occured sending data\n&quot; );
return -1 ;
}
if ( httpget+strlen(httpget) == phttpget )
break ;
phttpget += bytes_sent ;
}

        for (;;) {
bytes_received = recv ( socket_handle , input_buffer , 1023, 0 ) ;
if ( bytes_received == -1 ) {
printf ( &quot;An error occured during the receive procedure \n&quot; ) ;
return 0 ;
}
if ( bytes_received == 0 )
break ;
pinput_buffer = input_buffer + bytes_received ;
*pinput_buffer = 0 ;
printf ( &quot;%s&quot; , input_buffer ) ;
}

printf ( &quot;\nFinished receiving data\n&quot; ) ;
return 0 ;
}
Title: Re: Example of C source code for getting web page.
Post by: AmigaEd on January 22, 2006, 03:57:36 AM
@Piru,
Thank you for posting the code.

When I try to compile the code I get an error. Here is the compiler log....

Compiler: m68k-AmigaOS
Executing  m68k-amigaos-gcc.exe...
m68k-amigaos-gcc.exe "C:\CrossCompiler\AmiDevCpp\MyAmigaCProjects\GetWebPageExamples\Piru's example\PirusExample.c" -o "C:\CrossCompiler\AmiDevCpp\MyAmigaCProjects\GetWebPageExamples\Piru's example\PirusExample.exe"    -I"C:\CrossCompiler\AmiDevCpp\usr\local\amiga\m68k-amigaos\sys-include"  -I"C:\CrossCompiler\AmiDevCpp\usr\local\amiga\m68k-amigaos\include"  -I"C:\CrossCompiler\AmiDevCpp\usr\local\amiga\include\g++-3"   -L"C:\CrossCompiler\AmiDevCpp\usr\local\amiga\m68k-amigaos\lib" -L"C:\CrossCompiler\AmiDevCpp\usr\local\amiga\m68k-amigaos\lib\libnix"
In file included from /usr/local/amiga/lib/gcc/m68k-amigaos/3.4.0/../../../../m68k-amigaos/sys-include/clib/alib_protos.h:22,
                 from C:\CrossCompiler\AmiDevCpp\MyAmigaCProjects\GetWebPageExamples\Piru's example\PirusExample.c:23:
/usr/local/amiga/lib/gcc/m68k-amigaos/3.4.0/../../../../m68k-amigaos/sys-include/devices/timer.h:30: error: redefinition of `struct timeval'
Execution terminated



I can't quite figure out what is going on.

IF I comment out the...
#include
then I can get it to compile and it seems to work.

Thank you,
AmigaEd
Title: Re: Example of C source code for getting web page.
Post by: Piru on January 22, 2006, 04:09:00 AM
@AmigaEd

I believe it's include conflict between sys/time.h and devices/timer.h. I didn't see it as MorphOS includes account for the problem.

Anyway, clib/alib_protos.h isn't really required here as it only declares one of the prototypes (NewList()). As you noticed it works without.
Title: Re: Example of C source code for getting web page.
Post by: uncharted on January 22, 2006, 12:22:39 PM
I missed this thread before.

I dunno if this is still of use to you (i've just skim read most of the thread), but this site has an example program that grabs data from an HTTP server

http://www.ezcyberspace.com/gcc/part9.html

As a nice bonus it also does it with a nice MUI interface :-)

The whole tutorial is pretty good, I've used it to get GCC working in the past.
Title: Re: Example of C source code for getting web page.
Post by: AmigaEd on January 22, 2006, 03:35:18 PM
@uncharted,
Hey that is a pretty nice tutorial, just what a newbie like me needs...  :-D

Thank you,
AmigaEd
Title: Re: Example of C source code for getting web page.
Post by: Piru on January 22, 2006, 04:36:03 PM
@uncharted

I wouldn't really call it that good. Here are the obvious bugs I could find from it:

- The HTTP GET is broken (missing carriage returns, missing "Host:" breaking vhosts etc).

- getservbyname and getprotobyname can return NULL. The program doesn't check for this, but read zeropage instead.

- It leaks sockets in error conditions, eventually (after 64 attempts) you would just run out  and socket() would just return error.

- The code will crash or hang if recv() returns error.

- The GUI is dead while the program is getting the data. (Ok, this is just an example so not offloading the network code to separate thread isn't that bad... :-))
Title: Re: Example of C source code for getting web page.
Post by: uncharted on January 22, 2006, 04:46:30 PM
I meant "good" as in easy to follow and understand.  :-)

Perhaps a constructive thing to do would be to Email the page's maintainer with a list of bugs?
Title: Re: Example of C source code for getting web page.
Post by: AmigaEd on January 22, 2006, 06:04:48 PM
Yes, I also meant nice tutorial as in "easy to follow".

Piru, I understand part of the bugs you are talking about and the other half I'm lost. That's o.k. though... I'm learning and that is the important part.

I hope that someday I will be able to write some C code that works, is mostly bug free and is useful.

Best Regards,
AmigaEd


Title: Re: Example of C source code for getting web page.
Post by: kvasir on March 18, 2012, 06:22:00 PM
Quote from: koaftder;228106
haha, i'm supprised you took the time to list all the unresponsible things i did. Since you took the time to review it, i'll take the time to fix it.


Hello, I'm tryig my hand at this stuff too, and just wanted to make sure I'm on the right track here. I managed to get your code to work with some modifications, I was wondering if this is needed with the compiler/sdk I'm using (BTTR's ADE hardfile), or if I'm doing something wrong?
(Stuck //added comments to stuff I put in there)
Code: [Select]

#include <exec/libraries.h> //added
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h> //added
struct Library *SocketBase = NULL; //added
int bailout(); //added

int main ( void )
{
 int socket_handle ;
 struct sockaddr_in socket_detials ;
 char * input_buffer;
 char * pinput_buffer ;
 ssize_t bytes_received ;
 ssize_t bytes_sent ;
 char * phttpget ;
 char * httpget =
 &quot;GET / HTTP/1.0\r\n&quot;
 &quot;Host: www.amiga.org\r\n&quot;
 &quot;\r\n&quot;;

 phttpget = httpget ;
 bytes_sent = 0 ;

 input_buffer = malloc(1024);
 if ( input_buffer == NULL )
 {
  printf ( &quot;Sorry, couldnt allocate memory for input buffer\n&quot; );
  return bailout() ; // return -1; to return bailout();
 }
 
 SocketBase = OpenLibrary(&quot;bsdsocket.library&quot;, 2); // added
 if(!SocketBase)
 {
  printf(&quot;Unable to open bsdsocket.library\n&quot;);
  return(10);
 }; // </added>
 
 memset ( input_buffer, 0, 1024 ) ;

 memset ( &socket_detials , 0 , sizeof(struct sockaddr_in) );

 socket_handle = socket ( AF_INET, SOCK_STREAM, 0) ;
 if ( socket_handle == -1 )
 {
  printf ( &quot;Could not create socket\n&quot; ) ;
  return bailout() ; // return -1; to return bailout();
 }
 socket_detials.sin_family = AF_INET ;
 socket_detials.sin_addr.s_addr=inet_addr(&quot;68.90.68.66&quot;);
 socket_detials.sin_port = htons(80);

 if ( connect (socket_handle,(struct sockaddr*)&socket_detials, sizeof ( struct sockaddr)) == -1 )
 {
  printf ( &quot;Couldnt connect to server\n&quot; ) ;
  return bailout() ; // return -1; to return bailout();
 }

 printf ( &quot;Attempting to send %d bytes to server\n&quot; , strlen ( httpget ) );
 for(;;)
 {
  bytes_sent = send ( socket_handle , phttpget, strlen(phttpget), 0 ) ;
  if ( bytes_sent == -1 )
  {
   printf ( &quot;An error occured sending data\n&quot; );
   return bailout() ; // return -1; to return bailout();
  }
  if ( httpget+strlen(httpget) == phttpget )
  break ;
  phttpget += bytes_sent ;
 }

 for (;;)
 {
  bytes_received = recv ( socket_handle , input_buffer , 1023, 0 ) ;
  if ( bytes_received == -1 )
  {
   printf ( &quot;An error occured during the receive procedure \n&quot; ) ;
   return bailout() ; // return 0; to return bailout();
  }
  if ( bytes_received == 0 )
  break ;
  pinput_buffer = input_buffer + bytes_received ;
  *pinput_buffer = 0 ;
  printf ( &quot;%s&quot; , input_buffer ) ;
 }
 if(SocketBase) // added
 {
  CloseLibrary(SocketBase);
  SocketBase=NULL;
 }; // </added>
 printf ( &quot;\nFinished receiving data\n&quot; ) ;
 return 0 ;
}

int bailout()
{
 if(SocketBase)
 {
  CloseLibrary(SocketBase);
  SocketBase=NULL;
 };
 return(-1);
};

Then compmilede with:

Code: [Select]

16, Work:Code/network/amiga.org>gcc working.c -o working -noixemul -Inetinclude: -lsocket
working.c: In function `main':
working.c:36: warning: assignment makes pointer from integer without a cast
Nates shell.
16, Work:Code/network/amiga.org>



Kinda wondering if the warning on 36 is a problem? I wouldn't think it is, as the assignment is the problem, and that line actually changes it (I think), but I've seen enough blinking red boxes on my TV to be paranoid. (With this setup, I actually have to change the channel to see those...)
Title: Re: Example of C source code for getting web page.
Post by: Piru on March 18, 2012, 08:40:57 PM
@kvasir

The code is fairly good. However, this code here has a bug:
Code: [Select]
for (;;)
 {
  bytes_received = recv ( socket_handle , input_buffer , 1023, 0 ) ;
  if ( bytes_received == -1 )
  {
   printf ( &quot;An error occured during the receive procedure \n&quot; ) ;
   return bailout() ; // return 0; to return bailout();
  }
  if ( bytes_received == 0 )
  break ;
  pinput_buffer = input_buffer + bytes_received ;
  *pinput_buffer = 0 ;
  printf ( &quot;%s&quot; , input_buffer ) ;
 }
It doesn't handle the response arriving in multiple parts correctly.

Another thing to look for is the inadvertent adding of ; after blocks. It's a bad habit you should learn away from.

Trying to get HTTP GET right with custom code is probably one of the most difficult tasks. Unless if for exercise you really should use libcurl.
Title: Re: Example of C source code for getting web page.
Post by: kvasir on March 18, 2012, 09:57:24 PM
Quote from: Piru;684325
@kvasir
.... It doesn't handle the response arriving in multiple parts correctly.

Another thing to look for is the inadvertent adding of ; after blocks. It's a bad habit you should learn away from.

Trying to get HTTP GET right with custom code is probably one of the most difficult tasks. Unless if for exercise you really should use libcurl.


 Thanks Piru, I think I saw an example that did a stup-up realloc() in a while loop for that. Just wanted to make sure the stuff I added in wasn't because I screwed something else up. Of all the sample code I've managed to dig up, this is the only one that I've been able to get working as well as understand.
 Probably the sort of thing I'll isolate into a aheader file and use that way. Like libcurl doesn't do that anyway, but at least this way I'm learning some stuff, too.