Skip to content

The Bagels Server Code

February 4, 2015

I’m just doing this to re-familiarize myself with the Bagels server code. I want to put some kind of scoring and reporting in before i put it on the public internet.

The main routine initializes the wiznet chip and settles into a loop looking for a client to establish a session whereon it calls handlesession(). handlesession() will eventually close the socket and restart the cycle. Each time through while waiting for a session it cycles the random number generator. Note that a session is not a game of bagels, it’s a single turn.

void main(void){
	unsigned char socket0status;
    unsigned char ip_addr[] = {169,254,180,2};
	delay(500);
    wiz_Init(ip_addr); //initialize the wiznet chip
	while(1){  // Loop forever
		socket0status=wizGetCtl8(SnSR); //socket 0 status
		switch (socket0status){
			case SOCK_CLOSED: //initial condition
				socket0_init();	//initialize socket 0
				break;
			case SOCK_ESTABLISHED: //someone wants to talk to the server
				handlesession();
				break;
			//following are cases where we have to reset and reopen the socket
			case SOCK_FIN_WAIT: case SOCK_CLOSING: case SOCK_TIME_WAIT:
			case SOCK_CLOSE_WAIT: case SOCK_LAST_ACK:
				wizCmd(CR_CLOSE);
				break;
		}
		tbrnd(); //cycle the generator
		delay(100);
	}
}

The session handler first checks to see how much data has been received. Assuming there is some, it retrieves enough of the submitted HTTP to determine what kind of request it is. If we’re not in the middle of a game, it calls bagelsinit() which will send an html welcome page with a form to submit a guess; if it’s from that form, it goes off to bagelsturn() to handle it. In any event, it flushes the data and disconnects the socket to set up for the next session. One game could easily involve a dozen cycles like this and be interleaved with sessions for another game.

void handlesession(){	//handle a session once it's established
	unsigned int rsize,strncmpval;
	rsize=wizGetCtl16(SnRX_RSR); printf("**rsz=%d\n",rsize);
	if (rsize>0){
		thisip.l=getip();
		if (recv0(buf,min(24,rsize))>0){ //get enough characters to distinguish the request
			printf("%s\n",buf);
  			if (strncmp((char *)buf,"POST /",6)==0){
  				bagelsinit(); //initialize game, send the form
			}
			else if (strncmp((char *)buf,"GET /favicon",12)==0){
  				sendnak(); //no favicon here
			}
  			else if (strncmp((char *)buf,"GET /?G=",8)==0){
				bagelsturn();	//give player his turn
			}
  			else if (strncmp((char *)buf,"GET /",5)==0){
 				bagelsinit(0); //initialize game, send the form
			}
  			else{
				printf("\nmystery meat\n");
 				bagelsinit(0); //initialize game, send the form
			}
		}
	}
  	if (rsize>0) flush(rsize);	//get rid of the received data
	wizCmd(CR_DISCON);// Disconnect the connection- we're done here
	printf("done\n>\n");
}

To start a fresh game, bagelsinit() just sends a bunch of raw html/http gobbledygook including instructions and a form for submitting a guess. When the form gets submitted it will come back in the submitted transaction as “GET /G=whatever” triggering the bagelsturn routine. After sending the form, the code gets the ip address of the client and assigns it to one of 32 ip table slots. It then picks a 3 digit secret code which it puts in the table along with the ip. The ip table management is not very sophisticated but it works. if the ip isn’t yet in the table, it goes in the next space, wrapping around when it comes to the last slot. This could certainly overwrite a slot where a game is in progress but i didn’t have a better idea. At least the code will detect the collision and reinitialize the orphaned overwritten ip’s game.

void bagelsinit(){
	int sendrc,ipslot;
	static unsigned char hdr1[]="HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
						"<html><body OnLoad=\"document.mf.G.focus();\">"
						"<span style=\"color:#0000A0\">\r\n"
						"<center>
<h1>Olduino 1802 BAGELS Server On Wiznet W5500</h1>
"
						"</center>";
	static unsigned char Inst1[]=
		"I AM THINKING OF A 3 DIGIT NUMBER.
TRY TO GUESS " //50
		"MY NUMBER AND I WILL GIVE YOU CLUES AS FOLLOWS:
"
		"...PICO - ONE DIGIT IS IN THE WRONG PLACE
"
		"...FERMI - ONE DIGIT IS IN THE CORRECT PLACE
"
        "...BAGELS - NO DIGIT IS CORRECT";
	static unsigned char gform[]="<form name=\"mf\" method=\"GET\">\r\n"
						"<input type=\"text\" name=\"G\">"
						"<input type=\"submit\" value=\"Enter Your Guess\">\r\n"
						"</form>";
	static unsigned char trlr[]="</body></html>\r\n\r\n";
	sendconst(hdr1); 	// Now Send the HTTP Response first part
	sendconst(Inst1); 	// Now Send the instructions
	sendconst(gform); 	// Now Send the rest of the page
	sendconst("<a href=\"http://goo.gl/p4C0Cg\">Olduino</a>: An Arduino for the First of Us");
	sendconst(trlr); 	// Now Send the rest of the page
	thisip.l=getip();
	ipslot=getipslot(thisip);//finds or assigns a slot for the ip
	setsecret();
	strcpy((char*)secrets[ipslot],(char*)secret);
	printf("IP: %d.%d.%d.%d,slot %d,secret %s\n",
		thisip.c[0],thisip.c[1],thisip.c[2],thisip.c[3],ipslot,secrets[ipslot]);
}

For each turn,, bagelsturn() gets the ip address and finds the correct slot in the table and the corresponding secret number. it compares the submitted guess to the secret number and calculates how many digits are correct but in the wrong position(pico) or the correct position(fermi). Then it calls sendrespform() to deal with the result.

void bagelsturn(){
	int i, ipslot, pico=0, fermi=0;
	ipslot=getipslot(thisip);
	printf("IP: %d.%d.%d.%d,slot %d,secret %s\n",
		thisip.c[0],thisip.c[1],thisip.c[2],thisip.c[3],ipslot,secrets[ipslot]);
	strcpy((char*)secret,(char*)secrets[ipslot]);
	printf("got a guess\n");
	cpyguess(guess,buf+8);
	for (i=0;i<3;i++){
		if (guess[i]==secret[i]){
			fermi++;
		}
	}
	if (guess[0]==secret[1]||guess[0]==secret[2]){pico++;}
	if (guess[1]==secret[0]||guess[1]==secret[2]){pico++;}
	if (guess[2]==secret[0]||guess[2]==secret[1]){pico++;}
	if (guess[0]==guess[1]||guess[0]==guess[2]||guess[1]==guess[2]){pico=-1;}
	sendrespform(pico, fermi);
}

sendrespform() completes a turn. It mostly just sends out the cyptic bagels/pico/fermi message and the response form for the next guess. If the guess is completely correct(fermi=3) it sends out a congratulations and sets up to restart. If the guess is malformed it sees pico set to a negative value and sends an error message. I guess realitically the only scoring i could do is the number of games won. There should be some credit for fewer guesses and a way to put in initials for the high scorer but that just feels like a bridge too far.

void sendrespform(int pico, int fermi){
	int sendrc,i;
	static unsigned char hdr1[]="HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
						"<html><body OnLoad=\"document.mf.G.focus();\">"
						"<span style=\"color:#0000A0\">\r\n"
						"<center><h1>Olduino 1802 BAGELS Server</h1></center>";
	static unsigned char gform[]="<p><form name=\"mf\" method=\"GET\">\r\n"
						"<input type=\"text\" name=\"G\">"
						"<input type=\"submit\" value=\"Enter Your Guess\">\r\n"
						"</form>";
	static unsigned char pform[]="<p><form method=\"PUT\">\r\n"
						"<input type=\"submit\" value=\"Press To Play Again\">\r\n"
						"</form>";
	static unsigned char trlr[]="</body></html>\r\n\r\n";
	sendconst(hdr1); 	// Now Send the HTTP Response first part
	sendlit("Your Guess Was: "); 	// Now Send the instructions
	send0s((char *)guess);
	sendlit("  I say ");
	if (fermi==3){
		sendlit("YOU GOT IT!<P>");
		sendconst(pform);
	} else {//once we're here we're going to send the guess form
		if (pico<0){//flag for duplicate digits
			sendlit("<P>Oh, maybe I didn't tell you.  No two digits are the same.<P>");
		} else if ((pico+fermi)==0){
			sendlit("Bagels!");
		} else{
			for(i=0;i<pico;i++) sendlit("Pico ");
			for(i=0;i<fermi;i++) sendlit("Fermi ");
		}
		sendlit("<P>");
		sendconst(gform); 	// Now Send the rest of the page
		sendlit("<a href=\"http://goo.gl/p4C0Cg\">Olduino</a>: An Arduino for the First of Us<p>");
		sendconst(trlr); 	// Now Send the rest of the page
	}
}
//14-07-22 reduced to a single routine to find a slot or make one
int getipslot(union IPaddr whichip){//see if this ip is registered and register it if not
	int i=0, tslot;
	while(whichip.l!=regip[i].l && i<numslots){
		i++;
	}
	if (i<numslots){
		return i;
	}else{
		tslot=nextslot++;
		if (nextslot>=numslots){
			nextslot=0;
		}
		regip[tslot]=thisip; //register the ip
		strcpy((char*)secrets[tslot],"999");//supply a dummy secret on initialization
		ipgames[tslot]=0; ipturns[tslot]=0;//reset stats
		printf("%d,%s\n",tslot,secrets[tslot]);
		return tslot;
	}
}
Advertisements

From → web server

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: