Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Refactoring C Code: Starting With an API

DZone's Guide to

Refactoring C Code: Starting With an API

Need to learn to refactor some code for that pesky legacy app? Read on to see how one dev refactored his C-based code.

· Web Dev Zone ·
Free Resource

Learn how to add document editing and viewing to your web app on .Net (C#), Node.JS, Java, PHP, Ruby, etc.

In my last post, I introduced a basic error handling mechanism for C API. The code I showed had a small memory leak in it. I love that fact about it, because it is hidden away and probably won’t show up very easily for production code until very late in the game. Here is the fix:

image

The problem was that I was freeing the error struct, but wasn’t freeing the actual error message. That is something that is very easy to miss, unfortunately. Especially as we assume that errors are rare. With that minor issue out of the way, let’s look at how we actually write the code. Here is the updated version of creating a connection, with proper error handling:

image

The calling code will check if it got NULL and then can decide whatever it should add it’s own error (for context) and return a failure to its own caller or handle it. The cleanup stuff is still annoying with goto, but I don’t believe that there is much that can be done about it.

I’m going to refactored things a bit, so I have proper separation and an explicit API. Here is what the API looks like now:

image

This is basically a wrapper around all the things we need to around SSL. It handles one time initialization and any other necessary work that is required. Note that I don’t actually expose any state outside, instead just forward declaring the state struct and leaving it at that. In addition to the overall server state, there is also a single connection state, whose API looks like this:

image

Now, let’s bring it all together and see how it works.

int main(int argc, char **argv)
{
int rc;
int sock = -1;
struct server_state* srv_state;

const char* cert = "cert.pem";
const char* key =  "key.pem" ;

sock = create_server_socket(4433);
if (sock == -1) {
goto handle_error;
}

srv_state = server_state_create(cert, key);

if (srv_state == NULL) {
goto handle_error;
}

while (1) {
struct sockaddr_in addr;
struct connection* con;
unsigned int len = sizeof(addr);
char buffer[256];

int client = accept(sock, (struct sockaddr*)&addr, &len);
if (client == INVALID_SOCKET) {
push_error(ENETRESET, "Unable to accept connection, error: %i", GetLastError());
// failure to accept impacts everything, we'll abort
goto handle_error; 
}

con = connection_create(srv_state, client);

if (con == NULL)
{
closesocket(client);
print_all_errors();
continue; // accept the next connection...
}

if (connection_write_format(con, "Connected!\n") == 0) {
goto handle_connection_error;
}

while (1)
{
      // now, let's do echo server...
rc = connection_read(con, buffer, sizeof buffer);
if (rc == 0) {
goto handle_connection_error;
}

if (connection_write(con, buffer, rc) == 0) {
goto handle_connection_error;
}
}

handle_connection_error:
print_all_errors();
if (con != NULL) {
connection_drop(con);
}
// now go back and accept another connection
}

handle_error:

if(srv_state != NULL)
server_state_drop(srv_state);

if (sock != -1)
closesocket(sock);

print_all_errors();


return EINVAL;
}

This is a pretty trivial echo server, I’ll admit, but it actually handles things like SSL setup, good error handling and give us a good baseline to start from.

The code for this series can be found here and this post’s code is this commit. Next, I want to see what it would take to setup client authentication with OpenSSL.

Extend your web service functionality with docx, xlsx and pptx editing. Check out ONLYOFFICE document editors for integration.

Topics:
refactoring c ,web dev ,api development

Published at DZone with permission of

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}